diff --git a/.cargo/config.toml b/.cargo/config.toml new file mode 100644 index 0000000000000000000000000000000000000000..4087f77f9671a54e6a2757a328cc89ca5703e178 --- /dev/null +++ b/.cargo/config.toml @@ -0,0 +1,12 @@ +[target.wasm32-unknown-unknown] +rustflags = [ + # Currently disabled because of https://github.com/GraphiteEditor/Graphite/issues/1262 + # The current simd implementation leads to undefined behavior + #"-C", + #"target-feature=+simd128", + "-C", + "target-feature=+bulk-memory", + "-C", + "link-arg=--max-memory=4294967296", + "--cfg=web_sys_unstable_apis", +] diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json new file mode 100644 index 0000000000000000000000000000000000000000..6b4ee383f2c74dc85c7c0855e99fb0e27e8862dc --- /dev/null +++ b/.devcontainer/devcontainer.json @@ -0,0 +1,32 @@ +{ + "image": "mcr.microsoft.com/devcontainers/base:debian", + "features": { + "ghcr.io/devcontainers/features/rust:1": { + "profile": "default" + }, + "ghcr.io/devcontainers/features/node:1": {} + }, + "onCreateCommand": "cargo install cargo-watch wasm-pack cargo-about && cargo install -f wasm-bindgen-cli@0.2.100", + "customizations": { + "vscode": { + // NOTE: Keep this in sync with `.vscode/extensions.json` + "extensions": [ + // Rust + "rust-lang.rust-analyzer", + "tamasfe.even-better-toml", + // Web + "dbaeumer.vscode-eslint", + "svelte.svelte-vscode", + "vitaliymaz.vscode-svg-previewer", + // Code quality + "wayou.vscode-todo-highlight", + "streetsidesoftware.code-spell-checker", + // Helpful + "mhutchie.git-graph", + "waderyan.gitblame", + "qezhu.gitlink", + "wmaurer.change-case" + ] + } + } +} diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000000000000000000000000000000000000..455b8bd434545665b5e903fc9ec9d6781e2b40a5 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,7 @@ +[*.{rs,js,ts,svelte,json,toml,svg,html,css,scss}] +indent_style = tab +indent_size = 4 +end_of_line = lf +trim_trailing_whitespace = true +insert_final_newline = true +max_line_length = 200 diff --git a/.envrc b/.envrc new file mode 100644 index 0000000000000000000000000000000000000000..930f30ba2a63988e2f18e61c587a3e15f92c61ea --- /dev/null +++ b/.envrc @@ -0,0 +1 @@ +use flake .nix diff --git a/.gitattributes b/.gitattributes index a6344aac8c09253b3b630fb776ae94478aa0275b..5bff1f8d6eaa7b780937befdfa439a3c50f6db0a 100644 --- a/.gitattributes +++ b/.gitattributes @@ -33,3 +33,12 @@ saved_model/**/* filter=lfs diff=lfs merge=lfs -text *.zip filter=lfs diff=lfs merge=lfs -text *.zst filter=lfs diff=lfs merge=lfs -text *tfevents* filter=lfs diff=lfs merge=lfs -text +frontend/src-tauri/icons/icon.icns filter=lfs diff=lfs merge=lfs -text +node-graph/graphene-cli/test_files/cat.jpg filter=lfs diff=lfs merge=lfs -text +node-graph/graphene-cli/test_files/cow_transparent.png filter=lfs diff=lfs merge=lfs -text +node-graph/graphene-cli/test_files/duck.jpg filter=lfs diff=lfs merge=lfs -text +node-graph/graphene-cli/test_files/football.jpg filter=lfs diff=lfs merge=lfs -text +node-graph/graphene-cli/test_files/mansion.jpg filter=lfs diff=lfs merge=lfs -text +node-graph/graphene-cli/test_files/paper.jpg filter=lfs diff=lfs merge=lfs -text +node-graph/graphene-cli/test_files/pizza.jpg filter=lfs diff=lfs merge=lfs -text +node-graph/graphene-cli/test_files/pizza_transparent.png filter=lfs diff=lfs merge=lfs -text diff --git a/.nix/flake.lock b/.nix/flake.lock new file mode 100644 index 0000000000000000000000000000000000000000..5c11b23de187765bd9d0f5cdf69054e1e29cf2a3 --- /dev/null +++ b/.nix/flake.lock @@ -0,0 +1,99 @@ +{ + "nodes": { + "flake-utils": { + "inputs": { + "systems": "systems" + }, + "locked": { + "lastModified": 1731533236, + "narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=", + "owner": "numtide", + "repo": "flake-utils", + "rev": "11707dc2f618dd54ca8739b309ec4fc024de578b", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "flake-utils", + "type": "github" + } + }, + "nixpkgs": { + "locked": { + "lastModified": 1748190013, + "narHash": "sha256-R5HJFflOfsP5FBtk+zE8FpL8uqE7n62jqOsADvVshhE=", + "owner": "nixos", + "repo": "nixpkgs", + "rev": "62b852f6c6742134ade1abdd2a21685fd617a291", + "type": "github" + }, + "original": { + "owner": "nixos", + "ref": "nixos-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "nixpkgs-unstable": { + "locked": { + "lastModified": 1748190013, + "narHash": "sha256-R5HJFflOfsP5FBtk+zE8FpL8uqE7n62jqOsADvVshhE=", + "owner": "nixos", + "repo": "nixpkgs", + "rev": "62b852f6c6742134ade1abdd2a21685fd617a291", + "type": "github" + }, + "original": { + "owner": "nixos", + "ref": "nixos-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "root": { + "inputs": { + "flake-utils": "flake-utils", + "nixpkgs": "nixpkgs", + "nixpkgs-unstable": "nixpkgs-unstable", + "rust-overlay": "rust-overlay" + } + }, + "rust-overlay": { + "inputs": { + "nixpkgs": [ + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1748399823, + "narHash": "sha256-kahD8D5hOXOsGbNdoLLnqCL887cjHkx98Izc37nDjlA=", + "owner": "oxalica", + "repo": "rust-overlay", + "rev": "d68a69dc71bc19beb3479800392112c2f6218159", + "type": "github" + }, + "original": { + "owner": "oxalica", + "repo": "rust-overlay", + "type": "github" + } + }, + "systems": { + "locked": { + "lastModified": 1681028828, + "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", + "owner": "nix-systems", + "repo": "default", + "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", + "type": "github" + }, + "original": { + "owner": "nix-systems", + "repo": "default", + "type": "github" + } + } + }, + "root": "root", + "version": 7 +} diff --git a/.nix/flake.nix b/.nix/flake.nix new file mode 100644 index 0000000000000000000000000000000000000000..fc0cb6cbe401fb6be2cd70b87f59e61118ebedcc --- /dev/null +++ b/.nix/flake.nix @@ -0,0 +1,115 @@ +# This is a helper file for people using NixOS as their operating system. +# If you don't know what this file does, you can safely ignore it. +# This file defines both the development environment for the project. +# +# Development Environment: +# - Provides all necessary tools for Rust/WASM development +# - Includes Tauri dependencies for desktop app development +# - Sets up profiling and debugging tools +# - Configures mold as the default linker for faster builds +# +# +# Usage: +# - Development shell: `nix develop` +# - Run in dev shell with direnv: add `use flake` to .envrc +{ + description = "Development environment and build configuration"; + + inputs = { + # This url should be changed to match your system packages if you work on tauri because you need to use the same graphics library versions as the ones used by your system + nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable"; + nixpkgs-unstable.url = "github:nixos/nixpkgs/nixos-unstable"; + rust-overlay = { + url = "github:oxalica/rust-overlay"; + inputs.nixpkgs.follows = "nixpkgs"; + }; + flake-utils.url = "github:numtide/flake-utils"; + }; + + outputs = { nixpkgs, nixpkgs-unstable, rust-overlay, flake-utils, ... }: + flake-utils.lib.eachDefaultSystem (system: + let + overlays = [ (import rust-overlay) ]; + pkgs = import nixpkgs { + inherit system overlays; + }; + pkgs-unstable = import nixpkgs-unstable { + inherit system overlays; + }; + + rustc-wasm = pkgs.rust-bin.stable.latest.default.override { + targets = [ "wasm32-unknown-unknown" ]; + extensions = [ "rust-src" "rust-analyzer" "clippy" "cargo" ]; + }; + + # Shared build inputs - system libraries that need to be in LD_LIBRARY_PATH + buildInputs = with pkgs; [ + # System libraries + openssl + vulkan-loader + mesa + libraw + + + # Tauri dependencies: keep in sync with https://v2.tauri.app/start/prerequisites/#system-dependencies (under the NixOS tab) + at-spi2-atk + atkmm + cairo + gdk-pixbuf + glib + gtk3 + harfbuzz + librsvg + libsoup_3 + pango + webkitgtk_4_1 + openssl + ]; + + # Development tools that don't need to be in LD_LIBRARY_PATH + buildTools = [ + rustc-wasm + pkgs.nodejs + pkgs.nodePackages.npm + pkgs.binaryen + pkgs.wasm-bindgen-cli + pkgs-unstable.wasm-pack + pkgs.pkg-config + pkgs.git + pkgs.gobject-introspection + pkgs-unstable.cargo-tauri + pkgs-unstable.cargo-about + + # Linker + pkgs.mold + ]; + # Development tools that don't need to be in LD_LIBRARY_PATH + devTools = with pkgs; [ + cargo-watch + cargo-nextest + cargo-expand + + # Profiling tools + gnuplot + samply + cargo-flamegraph + + ]; + in + { + # Development shell configuration + devShells.default = pkgs.mkShell { + packages = buildInputs ++ buildTools ++ devTools; + + LD_LIBRARY_PATH = pkgs.lib.makeLibraryPath buildInputs; + GIO_MODULE_DIR="${pkgs.glib-networking}/lib/gio/modules/"; + XDG_DATA_DIRS="${pkgs.gsettings-desktop-schemas}/share/gsettings-schemas/${pkgs.gsettings-desktop-schemas.name}:${pkgs.gtk3}/share/gsettings-schemas/${pkgs.gtk3.name}:$XDG_DATA_DIRS"; + + + shellHook = '' + alias cargo='mold --run cargo' + ''; + }; + } + ); +} diff --git a/.nvmrc b/.nvmrc new file mode 100644 index 0000000000000000000000000000000000000000..209e3ef4b6247ce746048d5711befda46206d235 --- /dev/null +++ b/.nvmrc @@ -0,0 +1 @@ +20 diff --git a/.prettierrc b/.prettierrc new file mode 100644 index 0000000000000000000000000000000000000000..efd119c33e4eb6f992093148ad9bd96c71473aa4 --- /dev/null +++ b/.prettierrc @@ -0,0 +1,18 @@ +{ + "singleQuote": false, + "useTabs": true, + "tabWidth": 4, + "printWidth": 200, + "overrides": [ + { + "files": [ + "*.yml", + "*.yaml" + ], + "options": { + "useTabs": false, + "tabWidth": 2 + } + } + ] +} diff --git a/.vscode/extensions.json b/.vscode/extensions.json new file mode 100644 index 0000000000000000000000000000000000000000..e37a0efd117a4d5738053b353cb5de21444d0c03 --- /dev/null +++ b/.vscode/extensions.json @@ -0,0 +1,20 @@ +{ + // NOTE: Keep this in sync with `.devcontainer/devcontainer.json` + "recommendations": [ + // Rust + "rust-lang.rust-analyzer", + "tamasfe.even-better-toml", + // Web + "dbaeumer.vscode-eslint", + "svelte.svelte-vscode", + "vitaliymaz.vscode-svg-previewer", + // Code quality + "wayou.vscode-todo-highlight", + "streetsidesoftware.code-spell-checker", + // Helpful + "mhutchie.git-graph", + "waderyan.gitblame", + "qezhu.gitlink", + "wmaurer.change-case" + ] +} diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000000000000000000000000000000000000..df57674a138db31d98490803b983b6030c9b42bc --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,48 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "type": "lldb", + "request": "launch", + "name": "Graphite debug executable", + "cargo": { + "args": [ + "build", + "--bin=graphite", + "--package=graphite", + ], + "filter": { + "name": "graphite", + "kind": "bin", + }, + }, + "args": [], + "cwd": "${workspaceFolder}", + "env": { + "RUST_LOG": "error", + }, + }, + { + "type": "lldb", + "request": "launch", + "name": "Debug unit tests in executable 'graphite'", + "cargo": { + "args": [ + "test", + "--no-run", + "--bin=graphite", + "--package=graphite", + ], + "filter": { + "name": "graphite", + "kind": "bin", + }, + }, + "args": [], + "cwd": "${workspaceFolder}", + }, + ], +} diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000000000000000000000000000000000000..7f48a1c56a4784b2d5648d98193a04bf0e14e357 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,56 @@ +{ + // Rust: save on format + "[rust]": { + "editor.formatOnSave": true, + "editor.formatOnPaste": true, + "editor.defaultFormatter": "rust-lang.rust-analyzer" + }, + // Web: save on format + "[javascript][typescript][svelte]": { + "editor.codeActionsOnSave": { + "source.fixAll.eslint": "explicit" + }, + "editor.formatOnSave": true, + "editor.defaultFormatter": "dbaeumer.vscode-eslint" + }, + "[scss]": { + "editor.codeActionsOnSave": { + "source.fixAll.eslint": "explicit" + }, + "editor.formatOnSave": true, + // Configured in `.prettierrc` + "editor.defaultFormatter": "esbenp.prettier-vscode" + }, + "[json][jsonc][yaml][github-actions-workflow]": { + "editor.formatOnSave": true, + // Configured in `.prettierrc` + "editor.defaultFormatter": "esbenp.prettier-vscode" + }, + // Handlebars: don't save on format + // (`about.hbs` is used by Cargo About to encode license information) + "[handlebars]": { + "editor.formatOnSave": false + }, + // Rust Analyzer config + "rust-analyzer.cargo.allTargets": false, + // ESLint config + "eslint.format.enable": true, + "eslint.workingDirectories": ["./frontend", "./website/other/bezier-rs-demos", "./website"], + "eslint.validate": ["javascript", "typescript", "svelte"], + // Svelte config + "svelte.plugin.svelte.compilerWarnings": { + // NOTICE: Keep this list in sync with the list in `frontend/vite.config.ts` + "css-unused-selector": "ignore", + "vite-plugin-svelte-css-no-scopable-elements": "ignore", + "a11y-no-static-element-interactions": "ignore", + "a11y-no-noninteractive-element-interactions": "ignore", + "a11y-click-events-have-key-events": "ignore" + }, + // VS Code config + "html.format.wrapLineLength": 200, + "files.eol": "\n", + "files.insertFinalNewline": true, + "files.associations": { + "*.graphite": "json" + } +} diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 0000000000000000000000000000000000000000..da16bddb215904cc2ea163589c10569c3131e63e --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,8508 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "Inflector" +version = "0.11.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe438c63458706e03479442743baae6c88256498e6431708f6dfc520a26515d3" + +[[package]] +name = "ab_glyph" +version = "0.2.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec3672c180e71eeaaac3a541fbbc5f5ad4def8b747c595ad30d674e43049f7b0" +dependencies = [ + "ab_glyph_rasterizer", + "owned_ttf_parser", +] + +[[package]] +name = "ab_glyph_rasterizer" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c71b1793ee61086797f5c80b6efa2b8ffa6d5dd703f118545808a7f2e27f7046" + +[[package]] +name = "addr2line" +version = "0.24.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dfbe277e56a376000877090da837660b4427aad530e3028d44e0bffe4f89a1c1" +dependencies = [ + "gimli", +] + +[[package]] +name = "adler2" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627" + +[[package]] +name = "ahash" +version = "0.8.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011" +dependencies = [ + "cfg-if", + "getrandom 0.2.15", + "once_cell", + "version_check", + "zerocopy 0.7.35", +] + +[[package]] +name = "aho-corasick" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" +dependencies = [ + "memchr", +] + +[[package]] +name = "aligned-vec" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4aa90d7ce82d4be67b64039a3d588d38dbcc6736577de4a847025ce5b0c468d1" + +[[package]] +name = "alloc-no-stdlib" +version = "2.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc7bb162ec39d46ab1ca8c77bf72e890535becd1751bb45f64c597edb4c8c6b3" + +[[package]] +name = "alloc-stdlib" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94fb8275041c72129eb51b7d0322c29b8387a0386127718b096429201a5d6ece" +dependencies = [ + "alloc-no-stdlib", +] + +[[package]] +name = "allocator-api2" +version = "0.2.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923" + +[[package]] +name = "android-activity" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee91c0c2905bae44f84bfa4e044536541df26b7703fd0888deeb9060fcc44289" +dependencies = [ + "android-properties", + "bitflags 2.9.0", + "cc", + "cesu8", + "jni", + "jni-sys", + "libc", + "log", + "ndk 0.8.0", + "ndk-context", + "ndk-sys 0.5.0+25.2.9519653", + "num_enum", + "thiserror 1.0.69", +] + +[[package]] +name = "android-properties" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc7eb209b1518d6bb87b283c20095f5228ecda460da70b44f0802523dea6da04" + +[[package]] +name = "android-tzdata" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0" + +[[package]] +name = "android_system_properties" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" +dependencies = [ + "libc", +] + +[[package]] +name = "anes" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b46cbb362ab8752921c97e041f5e366ee6297bd428a31275b9fcf1e380f7299" + +[[package]] +name = "anstream" +version = "0.6.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8acc5369981196006228e28809f761875c0327210a891e941f4c683b3a99529b" +dependencies = [ + "anstyle", + "anstyle-parse", + "anstyle-query", + "anstyle-wincon", + "colorchoice", + "is_terminal_polyfill", + "utf8parse", +] + +[[package]] +name = "anstyle" +version = "1.0.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55cc3b69f167a1ef2e161439aa98aed94e6028e5f9a59be9a6ffb47aef1651f9" + +[[package]] +name = "anstyle-parse" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b2d16507662817a6a20a9ea92df6652ee4f94f914589377d69f3b21bc5798a9" +dependencies = [ + "utf8parse", +] + +[[package]] +name = "anstyle-query" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "79947af37f4177cfead1110013d678905c37501914fba0efea834c3fe9a8d60c" +dependencies = [ + "windows-sys 0.59.0", +] + +[[package]] +name = "anstyle-wincon" +version = "3.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca3534e77181a9cc07539ad51f2141fe32f6c3ffd4df76db8ad92346b003ae4e" +dependencies = [ + "anstyle", + "once_cell", + "windows-sys 0.59.0", +] + +[[package]] +name = "anyhow" +version = "1.0.97" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dcfed56ad506cb2c684a14971b8861fdc3baaaae314b9e5f9bb532cbe3ba7a4f" + +[[package]] +name = "arbitrary" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dde20b3d026af13f561bdd0f15edf01fc734f0dafcedbaf42bba506a9517f223" + +[[package]] +name = "arg_enum_proc_macro" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ae92a5119aa49cdbcf6b9f893fe4e1d98b04ccbf82ee0584ad948a44a734dea" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.99", +] + +[[package]] +name = "arrayref" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76a2e8124351fda1ef8aaaa3bbd7ebbcb486bbcd4225aca0aa0d84bb2db8fecb" + +[[package]] +name = "arrayvec" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" + +[[package]] +name = "as-raw-xcb-connection" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "175571dd1d178ced59193a6fc02dde1b972eb0bc56c892cde9beeceac5bf0f6b" + +[[package]] +name = "ash" +version = "0.38.0+1.3.281" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0bb44936d800fea8f016d7f2311c6a4f97aebd5dc86f09906139ec848cf3a46f" +dependencies = [ + "libloading 0.8.6", +] + +[[package]] +name = "atk" +version = "0.18.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "241b621213072e993be4f6f3a9e4b45f65b7e6faad43001be957184b7bb1824b" +dependencies = [ + "atk-sys", + "glib", + "libc", +] + +[[package]] +name = "atk-sys" +version = "0.18.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c5e48b684b0ca77d2bbadeef17424c2ea3c897d44d566a1617e7e8f30614d086" +dependencies = [ + "glib-sys", + "gobject-sys", + "libc", + "system-deps", +] + +[[package]] +name = "atomic-waker" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" + +[[package]] +name = "autocfg" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" + +[[package]] +name = "av1-grain" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6678909d8c5d46a42abcf571271e15fdbc0a225e3646cf23762cd415046c78bf" +dependencies = [ + "anyhow", + "arrayvec", + "log", + "nom", + "num-rational", + "v_frame", +] + +[[package]] +name = "avif-serialize" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "98922d6a4cfbcb08820c69d8eeccc05bb1f29bfa06b4f5b1dbfe9a868bd7608e" +dependencies = [ + "arrayvec", +] + +[[package]] +name = "axum" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d6fd624c75e18b3b4c6b9caf42b1afe24437daaee904069137d8bab077be8b8" +dependencies = [ + "axum-core", + "bytes", + "form_urlencoded", + "futures-util", + "http", + "http-body", + "http-body-util", + "hyper", + "hyper-util", + "itoa 1.0.15", + "matchit", + "memchr", + "mime", + "percent-encoding", + "pin-project-lite", + "rustversion", + "serde", + "serde_json", + "serde_path_to_error", + "serde_urlencoded", + "sync_wrapper", + "tokio", + "tower", + "tower-layer", + "tower-service", + "tracing", +] + +[[package]] +name = "axum-core" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df1362f362fd16024ae199c1970ce98f9661bf5ef94b9808fee734bc3698b733" +dependencies = [ + "bytes", + "futures-util", + "http", + "http-body", + "http-body-util", + "mime", + "pin-project-lite", + "rustversion", + "sync_wrapper", + "tower-layer", + "tower-service", + "tracing", +] + +[[package]] +name = "backtrace" +version = "0.3.74" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d82cb332cdfaed17ae235a638438ac4d4839913cc2af585c3c6746e8f8bee1a" +dependencies = [ + "addr2line", + "cfg-if", + "libc", + "miniz_oxide", + "object", + "rustc-demangle", + "windows-targets 0.52.6", +] + +[[package]] +name = "base64" +version = "0.21.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" + +[[package]] +name = "base64" +version = "0.22.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" + +[[package]] +name = "bezier-rs" +version = "0.4.0" +dependencies = [ + "dyn-any", + "glam", + "kurbo", + "serde", +] + +[[package]] +name = "bezier-rs-wasm" +version = "0.0.0" +dependencies = [ + "bezier-rs", + "glam", + "js-sys", + "log", + "wasm-bindgen", +] + +[[package]] +name = "bincode" +version = "1.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad" +dependencies = [ + "serde", +] + +[[package]] +name = "bit-set" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08807e080ed7f9d5433fa9b275196cfc35414f66a0c79d864dc51a0d825231a3" +dependencies = [ + "bit-vec", +] + +[[package]] +name = "bit-vec" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e764a1d40d510daf35e07be9eb06e75770908c27d411ee6c92109c9840eaaf7" + +[[package]] +name = "bit_field" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc827186963e592360843fb5ba4b973e145841266c1357f7180c43526f2e5b61" + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "bitflags" +version = "2.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c8214115b7bf84099f1309324e63141d4c5d7cc26862f97a0a857dbefe165bd" +dependencies = [ + "serde", +] + +[[package]] +name = "bitstream-io" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6099cdc01846bc367c4e7dd630dc5966dccf36b652fae7a74e17b640411a91b2" + +[[package]] +name = "block" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d8c1fef690941d3e7788d328517591fecc684c084084702d6ff1641e993699a" + +[[package]] +name = "block-buffer" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" +dependencies = [ + "generic-array", +] + +[[package]] +name = "block-sys" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae85a0696e7ea3b835a453750bf002770776609115e6d25c6d2ff28a8200f7e7" +dependencies = [ + "objc-sys", +] + +[[package]] +name = "block2" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "15b55663a85f33501257357e6421bb33e769d5c9ffb5ba0921c975a123e35e68" +dependencies = [ + "block-sys", + "objc2 0.4.1", +] + +[[package]] +name = "block2" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c132eebf10f5cad5289222520a4a058514204aed6d791f1cf4fe8088b82d15f" +dependencies = [ + "objc2 0.5.2", +] + +[[package]] +name = "block2" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "340d2f0bdb2a43c1d3cd40513185b2bd7def0aa1052f956455114bc98f82dcf2" +dependencies = [ + "objc2 0.6.1", +] + +[[package]] +name = "brotli" +version = "7.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc97b8f16f944bba54f0433f07e30be199b6dc2bd25937444bbad560bcea29bd" +dependencies = [ + "alloc-no-stdlib", + "alloc-stdlib", + "brotli-decompressor", +] + +[[package]] +name = "brotli-decompressor" +version = "4.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74fa05ad7d803d413eb8380983b092cbbaf9a85f151b871360e7b00cd7060b37" +dependencies = [ + "alloc-no-stdlib", + "alloc-stdlib", +] + +[[package]] +name = "built" +version = "0.7.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56ed6191a7e78c36abdb16ab65341eefd73d64d303fffccdbb00d51e4205967b" + +[[package]] +name = "bumpalo" +version = "3.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1628fb46dfa0b37568d12e5edd512553eccf6a22a78e8bde00bb4aed84d5bdbf" + +[[package]] +name = "bytemuck" +version = "1.23.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c76a5792e44e4abe34d3abf15636779261d45a7450612059293d1d2cfc63422" +dependencies = [ + "bytemuck_derive", +] + +[[package]] +name = "bytemuck_derive" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fa76293b4f7bb636ab88fd78228235b5248b4d05cc589aed610f954af5d7c7a" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.99", +] + +[[package]] +name = "byteorder" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + +[[package]] +name = "byteorder-lite" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f1fe948ff07f4bd06c30984e69f5b4899c516a3ef74f34df92a2df2ab535495" + +[[package]] +name = "bytes" +version = "1.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d71b6127be86fdcfddb610f7182ac57211d4b18a3e9c82eb2d17662f2227ad6a" +dependencies = [ + "serde", +] + +[[package]] +name = "cairo-rs" +version = "0.18.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ca26ef0159422fb77631dc9d17b102f253b876fe1586b03b803e63a309b4ee2" +dependencies = [ + "bitflags 2.9.0", + "cairo-sys-rs", + "glib", + "libc", + "once_cell", + "thiserror 1.0.69", +] + +[[package]] +name = "cairo-sys-rs" +version = "0.18.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "685c9fa8e590b8b3d678873528d83411db17242a73fccaed827770ea0fedda51" +dependencies = [ + "glib-sys", + "libc", + "system-deps", +] + +[[package]] +name = "calloop" +version = "0.12.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fba7adb4dd5aa98e5553510223000e7148f621165ec5f9acd7113f6ca4995298" +dependencies = [ + "bitflags 2.9.0", + "log", + "polling", + "rustix 0.38.44", + "slab", + "thiserror 1.0.69", +] + +[[package]] +name = "calloop-wayland-source" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f0ea9b9476c7fad82841a8dbb380e2eae480c21910feba80725b46931ed8f02" +dependencies = [ + "calloop", + "rustix 0.38.44", + "wayland-backend", + "wayland-client", +] + +[[package]] +name = "camino" +version = "1.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b96ec4966b5813e2c0507c1f86115c8c5abaadc3980879c3424042a02fd1ad3" +dependencies = [ + "serde", +] + +[[package]] +name = "cargo-platform" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e35af189006b9c0f00a064685c727031e3ed2d8020f7ba284d78cc2671bd36ea" +dependencies = [ + "serde", +] + +[[package]] +name = "cargo_metadata" +version = "0.19.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd5eb614ed4c27c5d706420e4320fbe3216ab31fa1c33cd8246ac36dae4479ba" +dependencies = [ + "camino", + "cargo-platform", + "semver", + "serde", + "serde_json", + "thiserror 2.0.12", +] + +[[package]] +name = "cargo_toml" +version = "0.22.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02260d489095346e5cafd04dea8e8cb54d1d74fcd759022a9b72986ebe9a1257" +dependencies = [ + "serde", + "toml", +] + +[[package]] +name = "cast" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5" + +[[package]] +name = "cc" +version = "1.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be714c154be609ec7f5dad223a33bf1482fff90472de28f7362806e6d4832b8c" +dependencies = [ + "jobserver", + "libc", + "shlex", +] + +[[package]] +name = "cesu8" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d43a04d8753f35258c91f8ec639f792891f748a1edbd759cf1dcea3382ad83c" + +[[package]] +name = "cfb" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d38f2da7a0a2c4ccf0065be06397cc26a81f4e528be095826eee9d4adbb8c60f" +dependencies = [ + "byteorder", + "fnv", + "uuid", +] + +[[package]] +name = "cfg-expr" +version = "0.15.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d067ad48b8650848b989a59a86c6c36a995d02d2bf778d45c3c5d57bc2718f02" +dependencies = [ + "smallvec", + "target-lexicon", +] + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "cfg_aliases" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd16c4719339c4530435d38e511904438d07cce7950afa3718a84ac36c10e89e" + +[[package]] +name = "cfg_aliases" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" + +[[package]] +name = "chrono" +version = "0.4.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a7964611d71df112cb1730f2ee67324fcf4d0fc6606acbbe9bfe06df124637c" +dependencies = [ + "android-tzdata", + "iana-time-zone", + "js-sys", + "num-traits", + "serde", + "wasm-bindgen", + "windows-link", +] + +[[package]] +name = "ciborium" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42e69ffd6f0917f5c029256a24d0161db17cea3997d185db0d35926308770f0e" +dependencies = [ + "ciborium-io", + "ciborium-ll", + "serde", +] + +[[package]] +name = "ciborium-io" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05afea1e0a06c9be33d539b876f1ce3692f4afea2cb41f740e7743225ed1c757" + +[[package]] +name = "ciborium-ll" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57663b653d948a338bfb3eeba9bb2fd5fcfaecb9e199e87e1eda4d9e8b240fd9" +dependencies = [ + "ciborium-io", + "half", +] + +[[package]] +name = "clap" +version = "4.5.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "027bb0d98429ae334a8698531da7077bdf906419543a35a55c2cb1b66437d767" +dependencies = [ + "clap_builder", + "clap_derive", +] + +[[package]] +name = "clap_builder" +version = "4.5.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5589e0cba072e0f3d23791efac0fd8627b49c829c196a492e88168e6a669d863" +dependencies = [ + "anstream", + "anstyle", + "clap_lex", + "strsim", +] + +[[package]] +name = "clap_derive" +version = "4.5.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf4ced95c6f4a675af3da73304b9ac4ed991640c36374e4b46795c49e17cf1ed" +dependencies = [ + "heck 0.5.0", + "proc-macro2", + "quote", + "syn 2.0.99", +] + +[[package]] +name = "clap_lex" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f46ad14479a25103f283c0f10005961cf086d8dc42205bb44c46ac563475dca6" + +[[package]] +name = "codespan-reporting" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3538270d33cc669650c4b093848450d380def10c331d38c768e34cac80576e6e" +dependencies = [ + "termcolor", + "unicode-width", +] + +[[package]] +name = "color" +version = "0.1.0" +source = "git+https://github.com/linebender/color.git?rev=a4fa61aff6c3f292b729dc409e7832e5f0166e4a#a4fa61aff6c3f292b729dc409e7832e5f0166e4a" +dependencies = [ + "serde", +] + +[[package]] +name = "color" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ae467d04a8a8aea5d9a49018a6ade2e4221d92968e8ce55a48c0b1164e5f698" + +[[package]] +name = "color_quant" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d7b894f5411737b7867f4827955924d7c254fc9f4d91a6aad6b097804b1018b" + +[[package]] +name = "colorchoice" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990" + +[[package]] +name = "colored" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "117725a109d387c937a1533ce01b450cbde6b88abceea8473c4d7a85853cda3c" +dependencies = [ + "lazy_static", + "windows-sys 0.59.0", +] + +[[package]] +name = "combine" +version = "4.6.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba5a308b75df32fe02788e748662718f03fde005016435c444eea572398219fd" +dependencies = [ + "bytes", + "memchr", +] + +[[package]] +name = "concurrent-queue" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ca0197aee26d1ae37445ee532fefce43251d24cc7c166799f4d46817f1d3973" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "convert_case" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6245d59a3e82a7fc217c5828a6692dbc6dfb63a0c8c90495621f7b9d79704a0e" + +[[package]] +name = "convert_case" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb402b8d4c85569410425650ce3eddc7d698ed96d39a73f941b08fb63082f1e7" +dependencies = [ + "unicode-segmentation", +] + +[[package]] +name = "cookie" +version = "0.18.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ddef33a339a91ea89fb53151bd0a4689cfce27055c291dfa69945475d22c747" +dependencies = [ + "percent-encoding", + "time", + "version_check", +] + +[[package]] +name = "cookie_store" +version = "0.21.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2eac901828f88a5241ee0600950ab981148a18f2f756900ffba1b125ca6a3ef9" +dependencies = [ + "cookie", + "document-features", + "idna", + "log", + "publicsuffix", + "serde", + "serde_derive", + "serde_json", + "time", + "url", +] + +[[package]] +name = "core-foundation" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "core-foundation" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b55271e5c8c478ad3f38ad24ef34923091e0548492a266d19b3c0b4d82574c63" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "core-foundation-sys" +version = "0.8.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" + +[[package]] +name = "core-graphics" +version = "0.23.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c07782be35f9e1140080c6b96f0d44b739e2278479f64e02fdab4e32dfd8b081" +dependencies = [ + "bitflags 1.3.2", + "core-foundation 0.9.4", + "core-graphics-types 0.1.3", + "foreign-types 0.5.0", + "libc", +] + +[[package]] +name = "core-graphics" +version = "0.24.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa95a34622365fa5bbf40b20b75dba8dfa8c94c734aea8ac9a5ca38af14316f1" +dependencies = [ + "bitflags 2.9.0", + "core-foundation 0.10.0", + "core-graphics-types 0.2.0", + "foreign-types 0.5.0", + "libc", +] + +[[package]] +name = "core-graphics-types" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "45390e6114f68f718cc7a830514a96f903cccd70d02a8f6d9f643ac4ba45afaf" +dependencies = [ + "bitflags 1.3.2", + "core-foundation 0.9.4", + "libc", +] + +[[package]] +name = "core-graphics-types" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d44a101f213f6c4cdc1853d4b78aef6db6bdfa3468798cc1d9912f4735013eb" +dependencies = [ + "bitflags 2.9.0", + "core-foundation 0.10.0", + "libc", +] + +[[package]] +name = "core_maths" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77745e017f5edba1a9c1d854f6f3a52dac8a12dd5af5d2f54aecf61e43d80d30" +dependencies = [ + "libm", +] + +[[package]] +name = "cpufeatures" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280" +dependencies = [ + "libc", +] + +[[package]] +name = "crc32fast" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a97769d94ddab943e4510d138150169a2758b5ef3eb191a9ee688de3e23ef7b3" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "criterion" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2b12d017a929603d80db1831cd3a24082f8137ce19c69e6447f54f5fc8d692f" +dependencies = [ + "anes", + "cast", + "ciborium", + "clap", + "criterion-plot", + "is-terminal", + "itertools 0.10.5", + "num-traits", + "once_cell", + "oorandom", + "plotters", + "rayon", + "regex", + "serde", + "serde_derive", + "serde_json", + "tinytemplate", + "walkdir", +] + +[[package]] +name = "criterion-plot" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b50826342786a51a89e2da3a28f1c32b06e387201bc2d19791f622c673706b1" +dependencies = [ + "cast", + "itertools 0.10.5", +] + +[[package]] +name = "crossbeam-channel" +version = "0.5.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06ba6d68e24814cb8de6bb986db8222d3a027d15872cabc0d18817bc3c0e4471" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-deque" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9dd111b7b7f7d55b72c0a6ae361660ee5853c9af73f70c3c2ef6858b950e2e51" +dependencies = [ + "crossbeam-epoch", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.9.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" + +[[package]] +name = "crunchy" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43da5946c66ffcc7745f48db692ffbb10a83bfe0afd96235c5c2a4fb23994929" + +[[package]] +name = "crypto-common" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +dependencies = [ + "generic-array", + "typenum", +] + +[[package]] +name = "cssparser" +version = "0.27.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "754b69d351cdc2d8ee09ae203db831e005560fc6030da058f86ad60c92a9cb0a" +dependencies = [ + "cssparser-macros", + "dtoa-short", + "itoa 0.4.8", + "matches", + "phf 0.8.0", + "proc-macro2", + "quote", + "smallvec", + "syn 1.0.109", +] + +[[package]] +name = "cssparser-macros" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13b588ba4ac1a99f7f2964d24b3d896ddc6bf847ee3855dbd4366f058cfcd331" +dependencies = [ + "quote", + "syn 2.0.99", +] + +[[package]] +name = "ctor" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a2785755761f3ddc1492979ce1e48d2c00d09311c39e4466429188f3dd6501" +dependencies = [ + "quote", + "syn 2.0.99", +] + +[[package]] +name = "cursor-icon" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96a6ac251f4a2aca6b3f91340350eab87ae57c3f127ffeb585e92bd336717991" + +[[package]] +name = "darling" +version = "0.20.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc7f46116c46ff9ab3eb1597a45688b6715c6e628b5c133e288e709a29bcb4ee" +dependencies = [ + "darling_core", + "darling_macro", +] + +[[package]] +name = "darling_core" +version = "0.20.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d00b9596d185e565c2207a0b01f8bd1a135483d02d9b7b0a54b11da8d53412e" +dependencies = [ + "fnv", + "ident_case", + "proc-macro2", + "quote", + "strsim", + "syn 2.0.99", +] + +[[package]] +name = "darling_macro" +version = "0.20.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc34b93ccb385b40dc71c6fceac4b2ad23662c7eeb248cf10d529b7e055b6ead" +dependencies = [ + "darling_core", + "quote", + "syn 2.0.99", +] + +[[package]] +name = "data-url" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c297a1c74b71ae29df00c3e22dd9534821d60eb9af5a0192823fa2acea70c2a" + +[[package]] +name = "deranged" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c9e6a11ca8224451684bc0d7d5a7adbf8f2fd6887261a1cfc3c0432f9d4068e" +dependencies = [ + "powerfmt", + "serde", +] + +[[package]] +name = "derivative" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fcc3dd5e9e9c0b295d6e1e4d811fb6f157d5ffd784b8d202fc62eac8035a770b" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "derive_more" +version = "0.99.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3da29a38df43d6f156149c9b43ded5e018ddff2a855cf2cfd62e8cd7d079c69f" +dependencies = [ + "convert_case 0.4.0", + "proc-macro2", + "quote", + "rustc_version", + "syn 2.0.99", +] + +[[package]] +name = "diff" +version = "0.1.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56254986775e3233ffa9c4d7d3faaf6d36a2c09d30b20687e9f88bc8bafc16c8" + +[[package]] +name = "digest" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +dependencies = [ + "block-buffer", + "crypto-common", +] + +[[package]] +name = "dirs" +version = "6.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3e8aa94d75141228480295a7d0e7feb620b1a5ad9f12bc40be62411e38cce4e" +dependencies = [ + "dirs-sys", +] + +[[package]] +name = "dirs-sys" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e01a3366d27ee9890022452ee61b2b63a67e6f13f58900b651ff5665f0bb1fab" +dependencies = [ + "libc", + "option-ext", + "redox_users", + "windows-sys 0.59.0", +] + +[[package]] +name = "dispatch" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd0c93bb4b0c6d9b77f4435b0ae98c24d17f1c45b2ff844c6151a07256ca923b" + +[[package]] +name = "dispatch2" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89a09f22a6c6069a18470eb92d2298acf25463f14256d24778e1230d789a2aec" +dependencies = [ + "bitflags 2.9.0", + "objc2 0.6.1", +] + +[[package]] +name = "displaydoc" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.99", +] + +[[package]] +name = "dlib" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "330c60081dcc4c72131f8eb70510f1ac07223e5d4163db481a04a0befcffa412" +dependencies = [ + "libloading 0.8.6", +] + +[[package]] +name = "dlopen2" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e1297103d2bbaea85724fcee6294c2d50b1081f9ad47d0f6f6f61eda65315a6" +dependencies = [ + "dlopen2_derive", + "libc", + "once_cell", + "winapi", +] + +[[package]] +name = "dlopen2_derive" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2b99bf03862d7f545ebc28ddd33a665b50865f4dfd84031a393823879bd4c54" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.99", +] + +[[package]] +name = "document-features" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95249b50c6c185bee49034bcb378a49dc2b5dff0be90ff6616d31d64febab05d" +dependencies = [ + "litrs", +] + +[[package]] +name = "downcast-rs" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75b325c5dbd37f80359721ad39aca5a29fb04c89279657cffdda8736d0c0b9d2" + +[[package]] +name = "dpi" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f25c0e292a7ca6d6498557ff1df68f32c99850012b6ea401cf8daf771f22ff53" +dependencies = [ + "serde", +] + +[[package]] +name = "dtoa" +version = "1.0.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6add3b8cff394282be81f3fc1a0605db594ed69890078ca6e2cab1c408bcf04" + +[[package]] +name = "dtoa-short" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd1511a7b6a56299bd043a9c167a6d2bfb37bf84a6dfceaba651168adfb43c87" +dependencies = [ + "dtoa", +] + +[[package]] +name = "dunce" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92773504d58c093f6de2459af4af33faa518c13451eb8f2b5698ed3d36e7c813" + +[[package]] +name = "dyn-any" +version = "0.3.1" +dependencies = [ + "dyn-any-derive", + "glam", + "reqwest", +] + +[[package]] +name = "dyn-any-derive" +version = "0.3.0" +dependencies = [ + "dyn-any", + "proc-macro2", + "quote", + "syn 2.0.99", +] + +[[package]] +name = "dyn-clone" +version = "1.0.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c7a8fb8a9fbf66c1f703fe16184d10ca0ee9d23be5b4436400408ba54a95005" + +[[package]] +name = "either" +version = "1.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" + +[[package]] +name = "embed-resource" +version = "3.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7fbc6e0d8e0c03a655b53ca813f0463d2c956bc4db8138dbc89f120b066551e3" +dependencies = [ + "cc", + "memchr", + "rustc_version", + "toml", + "vswhom", + "winreg", +] + +[[package]] +name = "embed_plist" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ef6b89e5b37196644d8796de5268852ff179b44e96276cf4290264843743bb7" + +[[package]] +name = "encoding_rs" +version = "0.8.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75030f3c4f45dafd7586dd6780965a8c7e8e285a5ecb86713e63a79c5b2766f3" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "env_filter" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "186e05a59d4c50738528153b83b0b0194d3a29507dfec16eccd4b342903397d0" +dependencies = [ + "log", + "regex", +] + +[[package]] +name = "env_logger" +version = "0.11.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dcaee3d8e3cfc3fd92428d477bc97fc29ec8716d180c0d74c643bb26166660e0" +dependencies = [ + "anstream", + "anstyle", + "env_filter", + "humantime", + "log", +] + +[[package]] +name = "equivalent" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" + +[[package]] +name = "erased-serde" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e004d887f51fcb9fef17317a2f3525c887d8aa3f4f50fed920816a688284a5b7" +dependencies = [ + "serde", + "typeid", +] + +[[package]] +name = "errno" +version = "0.3.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33d852cb9b869c2a9b3df2f71a3074817f01e1844f839a144f5fcef059a4eb5d" +dependencies = [ + "libc", + "windows-sys 0.59.0", +] + +[[package]] +name = "euclid" +version = "0.22.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad9cdb4b747e485a12abb0e6566612956c7a1bafa3bdb8d682c5b6d403589e48" +dependencies = [ + "num-traits", +] + +[[package]] +name = "exr" +version = "1.73.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f83197f59927b46c04a183a619b7c29df34e63e63c7869320862268c0ef687e0" +dependencies = [ + "bit_field", + "half", + "lebe", + "miniz_oxide", + "rayon-core", + "smallvec", + "zune-inflate", +] + +[[package]] +name = "fastnoise-lite" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3e5f3c3cc9081e5d0e18bcd50e80cd33cba47fc22f88a9da9c33ecd1c87ea5c0" +dependencies = [ + "num-traits", +] + +[[package]] +name = "fastrand" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" + +[[package]] +name = "fdeflate" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e6853b52649d4ac5c0bd02320cddc5ba956bdb407c4b75a2c6b75bf51500f8c" +dependencies = [ + "simd-adler32", +] + +[[package]] +name = "fern" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4316185f709b23713e41e3195f90edef7fb00c3ed4adc79769cf09cc762a3b29" +dependencies = [ + "colored", + "log", +] + +[[package]] +name = "field-offset" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38e2275cc4e4fc009b0669731a1e5ab7ebf11f469eaede2bab9309a5b4d6057f" +dependencies = [ + "memoffset", + "rustc_version", +] + +[[package]] +name = "fixedbitset" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80" + +[[package]] +name = "fixedbitset" +version = "0.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d674e81391d1e1ab681a28d99df07927c6d4aa5b027d7da16ba32d1d21ecd99" + +[[package]] +name = "flate2" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11faaf5a5236997af9848be0bef4db95824b1d534ebc64d0f0c6cf3e67bd38dc" +dependencies = [ + "crc32fast", + "miniz_oxide", +] + +[[package]] +name = "float-cmp" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "98de4bbd547a563b716d8dfa9aad1cb19bfab00f4fa09a6a4ed21dbcf44ce9c4" + +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[package]] +name = "foldhash" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a0d2fde1f7b3d48b8395d5f2de76c18a528bd6a9cdde438df747bfcba3e05d6f" + +[[package]] +name = "font-types" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d868ec188a98bb014c606072edd47e52e7ab7297db943b0b28503121e1d037bd" +dependencies = [ + "bytemuck", +] + +[[package]] +name = "font-types" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02a596f5713680923a2080d86de50fe472fb290693cf0f701187a1c8b36996b7" +dependencies = [ + "bytemuck", +] + +[[package]] +name = "fontconfig-cache-parser" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7f8afb20c8069fd676d27b214559a337cc619a605d25a87baa90b49a06f3b18" +dependencies = [ + "bytemuck", + "thiserror 1.0.69", +] + +[[package]] +name = "fontconfig-parser" +version = "0.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1fcfcd44ca6e90c921fee9fa665d530b21ef1327a4c1a6c5250ea44b776ada7" +dependencies = [ + "roxmltree", +] + +[[package]] +name = "fontdb" +version = "0.22.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a3a6f9af55fb97ad673fb7a69533eb2f967648a06fa21f8c9bb2cd6d33975716" +dependencies = [ + "fontconfig-parser", + "log", + "memmap2", + "slotmap", + "tinyvec", + "ttf-parser 0.24.1", +] + +[[package]] +name = "fontique" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39f97079e1293b8c1e9fb03a2875d328bd2ee8f3b95ce62959c0acc04049c708" +dependencies = [ + "bytemuck", + "fontconfig-cache-parser", + "hashbrown 0.15.4", + "icu_locid", + "memmap2", + "objc2 0.6.1", + "objc2-core-foundation", + "objc2-core-text", + "objc2-foundation 0.3.1", + "peniko 0.4.0", + "read-fonts 0.29.3", + "roxmltree", + "smallvec", + "windows 0.58.0", + "windows-core 0.58.0", +] + +[[package]] +name = "foreign-types" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" +dependencies = [ + "foreign-types-shared 0.1.1", +] + +[[package]] +name = "foreign-types" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d737d9aa519fb7b749cbc3b962edcf310a8dd1f4b67c91c4f83975dbdd17d965" +dependencies = [ + "foreign-types-macros", + "foreign-types-shared 0.3.1", +] + +[[package]] +name = "foreign-types-macros" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a5c6c585bc94aaf2c7b51dd4c2ba22680844aba4c687be581871a6f518c5742" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.99", +] + +[[package]] +name = "foreign-types-shared" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" + +[[package]] +name = "foreign-types-shared" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa9a19cbb55df58761df49b23516a86d432839add4af60fc256da840f66ed35b" + +[[package]] +name = "form_urlencoded" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" +dependencies = [ + "percent-encoding", +] + +[[package]] +name = "futf" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df420e2e84819663797d1ec6544b13c5be84629e7bb00dc960d6917db2987843" +dependencies = [ + "mac", + "new_debug_unreachable", +] + +[[package]] +name = "futures" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "65bc07b1a8bc7c85c5f2e110c476c7389b4554ba72af57d8445ea63a576b0876" +dependencies = [ + "futures-channel", + "futures-core", + "futures-executor", + "futures-io", + "futures-sink", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-channel" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10" +dependencies = [ + "futures-core", + "futures-sink", +] + +[[package]] +name = "futures-core" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" + +[[package]] +name = "futures-executor" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e28d1d997f585e54aebc3f97d39e72338912123a67330d723fdbb564d646c9f" +dependencies = [ + "futures-core", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-intrusive" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d930c203dd0b6ff06e0201a4a2fe9149b43c684fd4420555b26d21b1a02956f" +dependencies = [ + "futures-core", + "lock_api", + "parking_lot", +] + +[[package]] +name = "futures-io" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6" + +[[package]] +name = "futures-macro" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.99", +] + +[[package]] +name = "futures-sink" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7" + +[[package]] +name = "futures-task" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988" + +[[package]] +name = "futures-util" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" +dependencies = [ + "futures-channel", + "futures-core", + "futures-io", + "futures-macro", + "futures-sink", + "futures-task", + "memchr", + "pin-project-lite", + "pin-utils", + "slab", +] + +[[package]] +name = "fxhash" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c31b6d751ae2c7f11320402d34e41349dd1016f8d5d45e48c4312bc8625af50c" +dependencies = [ + "byteorder", +] + +[[package]] +name = "gdk" +version = "0.18.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9f245958c627ac99d8e529166f9823fb3b838d1d41fd2b297af3075093c2691" +dependencies = [ + "cairo-rs", + "gdk-pixbuf", + "gdk-sys", + "gio", + "glib", + "libc", + "pango", +] + +[[package]] +name = "gdk-pixbuf" +version = "0.18.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50e1f5f1b0bfb830d6ccc8066d18db35c487b1b2b1e8589b5dfe9f07e8defaec" +dependencies = [ + "gdk-pixbuf-sys", + "gio", + "glib", + "libc", + "once_cell", +] + +[[package]] +name = "gdk-pixbuf-sys" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9839ea644ed9c97a34d129ad56d38a25e6756f99f3a88e15cd39c20629caf7" +dependencies = [ + "gio-sys", + "glib-sys", + "gobject-sys", + "libc", + "system-deps", +] + +[[package]] +name = "gdk-sys" +version = "0.18.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c2d13f38594ac1e66619e188c6d5a1adb98d11b2fcf7894fc416ad76aa2f3f7" +dependencies = [ + "cairo-sys-rs", + "gdk-pixbuf-sys", + "gio-sys", + "glib-sys", + "gobject-sys", + "libc", + "pango-sys", + "pkg-config", + "system-deps", +] + +[[package]] +name = "gdkwayland-sys" +version = "0.18.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "140071d506d223f7572b9f09b5e155afbd77428cd5cc7af8f2694c41d98dfe69" +dependencies = [ + "gdk-sys", + "glib-sys", + "gobject-sys", + "libc", + "pkg-config", + "system-deps", +] + +[[package]] +name = "gdkx11" +version = "0.18.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3caa00e14351bebbc8183b3c36690327eb77c49abc2268dd4bd36b856db3fbfe" +dependencies = [ + "gdk", + "gdkx11-sys", + "gio", + "glib", + "libc", + "x11", +] + +[[package]] +name = "gdkx11-sys" +version = "0.18.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e2e7445fe01ac26f11601db260dd8608fe172514eb63b3b5e261ea6b0f4428d" +dependencies = [ + "gdk-sys", + "glib-sys", + "libc", + "system-deps", + "x11", +] + +[[package]] +name = "generic-array" +version = "0.14.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +dependencies = [ + "typenum", + "version_check", +] + +[[package]] +name = "gethostname" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0176e0459c2e4a1fe232f984bca6890e681076abb9934f6cea7c326f3fc47818" +dependencies = [ + "libc", + "windows-targets 0.48.5", +] + +[[package]] +name = "getrandom" +version = "0.1.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fc3cb4d91f53b50155bdcfd23f6a4c39ae1969c2ae85982b135750cccaf5fce" +dependencies = [ + "cfg-if", + "libc", + "wasi 0.9.0+wasi-snapshot-preview1", +] + +[[package]] +name = "getrandom" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" +dependencies = [ + "cfg-if", + "js-sys", + "libc", + "wasi 0.11.0+wasi-snapshot-preview1", + "wasm-bindgen", +] + +[[package]] +name = "getrandom" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43a49c392881ce6d5c3b8cb70f98717b7c07aabbdff06687b9030dbfbe2725f8" +dependencies = [ + "cfg-if", + "libc", + "wasi 0.13.3+wasi-0.2.2", + "windows-targets 0.52.6", +] + +[[package]] +name = "gif" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fb2d69b19215e18bb912fa30f7ce15846e301408695e44e0ef719f1da9e19f2" +dependencies = [ + "color_quant", + "weezl", +] + +[[package]] +name = "gimli" +version = "0.31.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" + +[[package]] +name = "gio" +version = "0.18.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4fc8f532f87b79cbc51a79748f16a6828fb784be93145a322fa14d06d354c73" +dependencies = [ + "futures-channel", + "futures-core", + "futures-io", + "futures-util", + "gio-sys", + "glib", + "libc", + "once_cell", + "pin-project-lite", + "smallvec", + "thiserror 1.0.69", +] + +[[package]] +name = "gio-sys" +version = "0.18.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37566df850baf5e4cb0dfb78af2e4b9898d817ed9263d1090a2df958c64737d2" +dependencies = [ + "glib-sys", + "gobject-sys", + "libc", + "system-deps", + "winapi", +] + +[[package]] +name = "gl_generator" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a95dfc23a2b4a9a2f5ab41d194f8bfda3cabec42af4e39f08c339eb2a0c124d" +dependencies = [ + "khronos_api", + "log", + "xml-rs", +] + +[[package]] +name = "glam" +version = "0.29.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc46dd3ec48fdd8e693a98d2b8bafae273a2d54c1de02a2a7e3d57d501f39677" +dependencies = [ + "serde", +] + +[[package]] +name = "glib" +version = "0.18.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "233daaf6e83ae6a12a52055f568f9d7cf4671dabb78ff9560ab6da230ce00ee5" +dependencies = [ + "bitflags 2.9.0", + "futures-channel", + "futures-core", + "futures-executor", + "futures-task", + "futures-util", + "gio-sys", + "glib-macros", + "glib-sys", + "gobject-sys", + "libc", + "memchr", + "once_cell", + "smallvec", + "thiserror 1.0.69", +] + +[[package]] +name = "glib-macros" +version = "0.18.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0bb0228f477c0900c880fd78c8759b95c7636dbd7842707f49e132378aa2acdc" +dependencies = [ + "heck 0.4.1", + "proc-macro-crate 2.0.0", + "proc-macro-error", + "proc-macro2", + "quote", + "syn 2.0.99", +] + +[[package]] +name = "glib-sys" +version = "0.18.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "063ce2eb6a8d0ea93d2bf8ba1957e78dbab6be1c2220dd3daca57d5a9d869898" +dependencies = [ + "libc", + "system-deps", +] + +[[package]] +name = "glob" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8d1add55171497b4705a648c6b583acafb01d58050a51727785f0b2c8e0a2b2" + +[[package]] +name = "glow" +version = "0.14.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d51fa363f025f5c111e03f13eda21162faeacb6911fe8caa0c0349f9cf0c4483" +dependencies = [ + "js-sys", + "slotmap", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "glutin_wgl_sys" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c4ee00b289aba7a9e5306d57c2d05499b2e5dc427f84ac708bd2c090212cf3e" +dependencies = [ + "gl_generator", +] + +[[package]] +name = "gobject-sys" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0850127b514d1c4a4654ead6dedadb18198999985908e6ffe4436f53c785ce44" +dependencies = [ + "glib-sys", + "libc", + "system-deps", +] + +[[package]] +name = "gpu-alloc" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fbcd2dba93594b227a1f57ee09b8b9da8892c34d55aa332e034a228d0fe6a171" +dependencies = [ + "bitflags 2.9.0", + "gpu-alloc-types", +] + +[[package]] +name = "gpu-alloc-types" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "98ff03b468aa837d70984d55f5d3f846f6ec31fe34bbb97c4f85219caeee1ca4" +dependencies = [ + "bitflags 2.9.0", +] + +[[package]] +name = "gpu-allocator" +version = "0.27.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c151a2a5ef800297b4e79efa4f4bec035c5f51d5ae587287c9b952bdf734cacd" +dependencies = [ + "log", + "presser", + "thiserror 1.0.69", + "windows 0.58.0", +] + +[[package]] +name = "gpu-descriptor" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dcf29e94d6d243368b7a56caa16bc213e4f9f8ed38c4d9557069527b5d5281ca" +dependencies = [ + "bitflags 2.9.0", + "gpu-descriptor-types", + "hashbrown 0.15.4", +] + +[[package]] +name = "gpu-descriptor-types" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fdf242682df893b86f33a73828fb09ca4b2d3bb6cc95249707fc684d27484b91" +dependencies = [ + "bitflags 2.9.0", +] + +[[package]] +name = "graph-craft" +version = "0.1.0" +dependencies = [ + "bezier-rs", + "criterion", + "dyn-any", + "glam", + "graph-craft", + "graphene-application-io", + "graphene-brush", + "graphene-core", + "graphene-path-bool", + "graphene-raster-nodes", + "graphene-svg-renderer", + "iai-callgrind", + "js-sys", + "log", + "pretty_assertions", + "reqwest", + "rustc-hash 2.1.1", + "serde", + "serde_json", + "specta", + "tokio", + "url", + "wasm-bindgen", + "web-sys", + "wgpu-executor", + "winit", +] + +[[package]] +name = "graphene-application-io" +version = "0.1.0" +dependencies = [ + "dyn-any", + "glam", + "graphene-core", + "log", + "serde", + "web-sys", + "wgpu", +] + +[[package]] +name = "graphene-brush" +version = "0.1.0" +dependencies = [ + "dyn-any", + "glam", + "graphene-core", + "graphene-raster-nodes", + "node-macro", + "serde", + "tokio", +] + +[[package]] +name = "graphene-cli" +version = "0.1.0" +dependencies = [ + "chrono", + "clap", + "fern", + "futures", + "graph-craft", + "graphene-core", + "graphene-std", + "interpreted-executor", + "log", + "preprocessor", + "tokio", + "wgpu", + "wgpu-executor", +] + +[[package]] +name = "graphene-core" +version = "0.1.0" +dependencies = [ + "base64 0.22.1", + "bezier-rs", + "bytemuck", + "ctor", + "dyn-any", + "glam", + "half", + "image", + "kurbo", + "log", + "node-macro", + "num-derive", + "num-traits", + "parley", + "petgraph 0.7.1", + "rand 0.9.0", + "rand_chacha 0.9.0", + "rustc-hash 2.1.1", + "serde", + "serde_json", + "skrifa 0.32.0", + "specta", + "tinyvec", + "tokio", + "wgpu", +] + +[[package]] +name = "graphene-math-nodes" +version = "0.1.0" +dependencies = [ + "glam", + "graphene-core", + "log", + "math-parser", + "node-macro", + "rand 0.9.0", +] + +[[package]] +name = "graphene-path-bool" +version = "0.1.0" +dependencies = [ + "bezier-rs", + "dyn-any", + "glam", + "graphene-core", + "log", + "node-macro", + "path-bool", + "serde", + "specta", +] + +[[package]] +name = "graphene-raster-nodes" +version = "0.1.0" +dependencies = [ + "bezier-rs", + "bytemuck", + "dyn-any", + "fastnoise-lite", + "futures", + "glam", + "graphene-core", + "image", + "ndarray", + "node-macro", + "rand 0.9.0", + "rand_chacha 0.9.0", + "serde", + "specta", + "tokio", +] + +[[package]] +name = "graphene-std" +version = "0.1.0" +dependencies = [ + "base64 0.22.1", + "bytemuck", + "dyn-any", + "fastnoise-lite", + "futures", + "glam", + "graph-craft", + "graphene-application-io", + "graphene-brush", + "graphene-core", + "graphene-math-nodes", + "graphene-path-bool", + "graphene-raster-nodes", + "graphene-svg-renderer", + "image", + "log", + "ndarray", + "node-macro", + "rand 0.9.0", + "rand_chacha 0.9.0", + "reqwest", + "tokio", + "vello", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", + "wgpu-executor", +] + +[[package]] +name = "graphene-svg-renderer" +version = "0.1.0" +dependencies = [ + "base64 0.22.1", + "bezier-rs", + "dyn-any", + "glam", + "graphene-core", + "log", + "num-traits", + "serde", + "usvg", + "vello", +] + +[[package]] +name = "graphite-desktop" +version = "0.1.0" +dependencies = [ + "axum", + "chrono", + "fern", + "futures", + "graphite-editor", + "log", + "ron", + "tauri", + "tauri-build", + "tauri-plugin-http", + "tauri-plugin-shell", + "tokio", +] + +[[package]] +name = "graphite-editor" +version = "0.0.0" +dependencies = [ + "bezier-rs", + "bitflags 2.9.0", + "derivative", + "dyn-any", + "env_logger", + "futures", + "glam", + "graph-craft", + "graphene-std", + "graphite-proc-macros", + "interpreted-executor", + "js-sys", + "kurbo", + "log", + "num_enum", + "once_cell", + "preprocessor", + "ron", + "serde", + "serde_json", + "specta", + "spin", + "thiserror 2.0.12", + "tokio", + "usvg", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", + "wgpu-executor", +] + +[[package]] +name = "graphite-proc-macros" +version = "0.0.0" +dependencies = [ + "graphite-editor", + "proc-macro2", + "quote", + "serde", + "syn 2.0.99", +] + +[[package]] +name = "graphite-wasm" +version = "0.0.0" +dependencies = [ + "graph-craft", + "graphene-std", + "graphite-editor", + "js-sys", + "log", + "math-parser", + "serde", + "serde-wasm-bindgen", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", + "wgpu", +] + +[[package]] +name = "gtk" +version = "0.18.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd56fb197bfc42bd5d2751f4f017d44ff59fbb58140c6b49f9b3b2bdab08506a" +dependencies = [ + "atk", + "cairo-rs", + "field-offset", + "futures-channel", + "gdk", + "gdk-pixbuf", + "gio", + "glib", + "gtk-sys", + "gtk3-macros", + "libc", + "pango", + "pkg-config", +] + +[[package]] +name = "gtk-sys" +version = "0.18.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f29a1c21c59553eb7dd40e918be54dccd60c52b049b75119d5d96ce6b624414" +dependencies = [ + "atk-sys", + "cairo-sys-rs", + "gdk-pixbuf-sys", + "gdk-sys", + "gio-sys", + "glib-sys", + "gobject-sys", + "libc", + "pango-sys", + "system-deps", +] + +[[package]] +name = "gtk3-macros" +version = "0.18.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52ff3c5b21f14f0736fed6dcfc0bfb4225ebf5725f3c0209edeec181e4d73e9d" +dependencies = [ + "proc-macro-crate 1.3.1", + "proc-macro-error", + "proc-macro2", + "quote", + "syn 2.0.99", +] + +[[package]] +name = "guillotiere" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b62d5865c036cb1393e23c50693df631d3f5d7bcca4c04fe4cc0fd592e74a782" +dependencies = [ + "euclid", + "svg_fmt", +] + +[[package]] +name = "h2" +version = "0.4.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5017294ff4bb30944501348f6f8e42e6ad28f42c8bbef7a74029aff064a4e3c2" +dependencies = [ + "atomic-waker", + "bytes", + "fnv", + "futures-core", + "futures-sink", + "http", + "indexmap 2.7.1", + "slab", + "tokio", + "tokio-util", + "tracing", +] + +[[package]] +name = "half" +version = "2.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6dd08c532ae367adf81c312a4580bc67f1d0fe8bc9c460520283f4c0ff277888" +dependencies = [ + "bytemuck", + "cfg-if", + "crunchy", + "serde", +] + +[[package]] +name = "hashbrown" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" + +[[package]] +name = "hashbrown" +version = "0.15.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5971ac85611da7067dbfcabef3c70ebb5606018acd9e2a3903a0da507521e0d5" +dependencies = [ + "allocator-api2", + "equivalent", + "foldhash", +] + +[[package]] +name = "heck" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" + +[[package]] +name = "heck" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" + +[[package]] +name = "hermit-abi" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fbf6a919d6cf397374f7dfeeea91d974c7c0a7221d0d0f4f20d859d329e53fcc" + +[[package]] +name = "hermit-abi" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fbd780fe5cc30f81464441920d82ac8740e2e46b29a6fad543ddd075229ce37e" + +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" + +[[package]] +name = "hexf-parse" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dfa686283ad6dd069f105e5ab091b04c62850d3e4cf5d67debad1933f55023df" + +[[package]] +name = "html5ever" +version = "0.26.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bea68cab48b8459f17cf1c944c67ddc572d272d9f2b274140f223ecb1da4a3b7" +dependencies = [ + "log", + "mac", + "markup5ever", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "http" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f16ca2af56261c99fba8bac40a10251ce8188205a4c448fbb745a2e4daa76fea" +dependencies = [ + "bytes", + "fnv", + "itoa 1.0.15", +] + +[[package]] +name = "http-body" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184" +dependencies = [ + "bytes", + "http", +] + +[[package]] +name = "http-body-util" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "793429d76616a256bcb62c2a2ec2bed781c8307e797e2598c50010f2bee2544f" +dependencies = [ + "bytes", + "futures-util", + "http", + "http-body", + "pin-project-lite", +] + +[[package]] +name = "httparse" +version = "1.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87" + +[[package]] +name = "httpdate" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" + +[[package]] +name = "humantime" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" + +[[package]] +name = "hyper" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc2b571658e38e0c01b1fdca3bbbe93c00d3d71693ff2770043f8c29bc7d6f80" +dependencies = [ + "bytes", + "futures-channel", + "futures-util", + "h2", + "http", + "http-body", + "httparse", + "httpdate", + "itoa 1.0.15", + "pin-project-lite", + "smallvec", + "tokio", + "want", +] + +[[package]] +name = "hyper-rustls" +version = "0.27.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d191583f3da1305256f22463b9bb0471acad48a4e534a5218b9963e9c1f59b2" +dependencies = [ + "futures-util", + "http", + "hyper", + "hyper-util", + "rustls", + "rustls-pki-types", + "tokio", + "tokio-rustls", + "tower-service", + "webpki-roots", +] + +[[package]] +name = "hyper-tls" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70206fc6890eaca9fde8a0bf71caa2ddfc9fe045ac9e5c70df101a7dbde866e0" +dependencies = [ + "bytes", + "http-body-util", + "hyper", + "hyper-util", + "native-tls", + "tokio", + "tokio-native-tls", + "tower-service", +] + +[[package]] +name = "hyper-util" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df2dcfbe0677734ab2f3ffa7fa7bfd4706bfdc1ef393f2ee30184aed67e631b4" +dependencies = [ + "bytes", + "futures-channel", + "futures-util", + "http", + "http-body", + "hyper", + "pin-project-lite", + "socket2", + "tokio", + "tower-service", + "tracing", +] + +[[package]] +name = "iai-callgrind" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "283f598a969822c70af13aae1272ba09c97014c7344d3b24652e5b1d7b771c36" +dependencies = [ + "bincode", + "iai-callgrind-macros", + "iai-callgrind-runner", +] + +[[package]] +name = "iai-callgrind-macros" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04e2ff2e86bdba764b66d94b65f2caa03da60d971a6930fdc2e67f12582c5bb8" +dependencies = [ + "proc-macro-error", + "proc-macro2", + "quote", + "serde", + "serde_json", + "syn 2.0.99", +] + +[[package]] +name = "iai-callgrind-runner" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fb92a65def0d3a0ef41029c411dc2ecdd3518708c062f8bd576fd4143be1c56b" +dependencies = [ + "serde", +] + +[[package]] +name = "iana-time-zone" +version = "0.1.61" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "235e081f3925a06703c2d0117ea8b91f042756fd6e7a6e5d901e8ca1a996b220" +dependencies = [ + "android_system_properties", + "core-foundation-sys", + "iana-time-zone-haiku", + "js-sys", + "wasm-bindgen", + "windows-core 0.52.0", +] + +[[package]] +name = "iana-time-zone-haiku" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" +dependencies = [ + "cc", +] + +[[package]] +name = "ico" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc50b891e4acf8fe0e71ef88ec43ad82ee07b3810ad09de10f1d01f072ed4b98" +dependencies = [ + "byteorder", + "png", +] + +[[package]] +name = "icrate" +version = "0.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "99d3aaff8a54577104bafdf686ff18565c3b6903ca5782a2026ef06e2c7aa319" +dependencies = [ + "block2 0.3.0", + "dispatch", + "objc2 0.4.1", +] + +[[package]] +name = "icu_collections" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db2fa452206ebee18c4b5c2274dbf1de17008e874b4dc4f0aea9d01ca79e4526" +dependencies = [ + "displaydoc", + "yoke", + "zerofrom", + "zerovec", +] + +[[package]] +name = "icu_locid" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13acbb8371917fc971be86fc8057c41a64b521c184808a698c02acc242dbf637" +dependencies = [ + "displaydoc", + "litemap", + "tinystr", + "writeable", + "zerovec", +] + +[[package]] +name = "icu_locid_transform" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "01d11ac35de8e40fdeda00d9e1e9d92525f3f9d887cdd7aa81d727596788b54e" +dependencies = [ + "displaydoc", + "icu_locid", + "icu_locid_transform_data", + "icu_provider", + "tinystr", + "zerovec", +] + +[[package]] +name = "icu_locid_transform_data" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fdc8ff3388f852bede6b579ad4e978ab004f139284d7b28715f773507b946f6e" + +[[package]] +name = "icu_normalizer" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19ce3e0da2ec68599d193c93d088142efd7f9c5d6fc9b803774855747dc6a84f" +dependencies = [ + "displaydoc", + "icu_collections", + "icu_normalizer_data", + "icu_properties", + "icu_provider", + "smallvec", + "utf16_iter", + "utf8_iter", + "write16", + "zerovec", +] + +[[package]] +name = "icu_normalizer_data" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8cafbf7aa791e9b22bec55a167906f9e1215fd475cd22adfcf660e03e989516" + +[[package]] +name = "icu_properties" +version = "1.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93d6020766cfc6302c15dbbc9c8778c37e62c14427cb7f6e601d849e092aeef5" +dependencies = [ + "displaydoc", + "icu_collections", + "icu_locid_transform", + "icu_properties_data", + "icu_provider", + "tinystr", + "zerovec", +] + +[[package]] +name = "icu_properties_data" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67a8effbc3dd3e4ba1afa8ad918d5684b8868b3b26500753effea8d2eed19569" + +[[package]] +name = "icu_provider" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ed421c8a8ef78d3e2dbc98a973be2f3770cb42b606e3ab18d6237c4dfde68d9" +dependencies = [ + "displaydoc", + "icu_locid", + "icu_provider_macros", + "stable_deref_trait", + "tinystr", + "writeable", + "yoke", + "zerofrom", + "zerovec", +] + +[[package]] +name = "icu_provider_macros" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ec89e9337638ecdc08744df490b221a7399bf8d164eb52a665454e60e075ad6" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.99", +] + +[[package]] +name = "ident_case" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" + +[[package]] +name = "idna" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "686f825264d630750a544639377bae737628043f20d38bbc029e8f29ea968a7e" +dependencies = [ + "idna_adapter", + "smallvec", + "utf8_iter", +] + +[[package]] +name = "idna_adapter" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "daca1df1c957320b2cf139ac61e7bd64fed304c5040df000a745aa1de3b4ef71" +dependencies = [ + "icu_normalizer", + "icu_properties", +] + +[[package]] +name = "image" +version = "0.25.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd6f44aed642f18953a158afeb30206f4d50da59fbc66ecb53c66488de73563b" +dependencies = [ + "bytemuck", + "byteorder-lite", + "color_quant", + "exr", + "gif", + "image-webp 0.2.1", + "num-traits", + "png", + "qoi", + "ravif", + "rayon", + "rgb", + "tiff", + "zune-core", + "zune-jpeg", +] + +[[package]] +name = "image-webp" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f79afb8cbee2ef20f59ccd477a218c12a93943d075b492015ecb1bb81f8ee904" +dependencies = [ + "byteorder-lite", + "quick-error", +] + +[[package]] +name = "image-webp" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b77d01e822461baa8409e156015a1d91735549f0f2c17691bd2d996bef238f7f" +dependencies = [ + "byteorder-lite", + "quick-error", +] + +[[package]] +name = "imagesize" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "edcd27d72f2f071c64249075f42e205ff93c9a4c5f6c6da53e79ed9f9832c285" + +[[package]] +name = "imgref" +version = "1.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0263a3d970d5c054ed9312c0057b4f3bde9c0b33836d3637361d4a9e6e7a408" + +[[package]] +name = "indexmap" +version = "1.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" +dependencies = [ + "autocfg", + "hashbrown 0.12.3", + "serde", +] + +[[package]] +name = "indexmap" +version = "2.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c9c992b02b5b4c94ea26e32fe5bccb7aa7d9f390ab5c1221ff895bc7ea8b652" +dependencies = [ + "equivalent", + "hashbrown 0.15.4", + "serde", +] + +[[package]] +name = "indoc" +version = "2.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4c7245a08504955605670dbf141fceab975f15ca21570696aebe9d2e71576bd" + +[[package]] +name = "infer" +version = "0.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a588916bfdfd92e71cacef98a63d9b1f0d74d6599980d11894290e7ddefffcf7" +dependencies = [ + "cfb", +] + +[[package]] +name = "interpolate_name" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c34819042dc3d3971c46c2190835914dfbe0c3c13f61449b2997f4e9722dfa60" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.99", +] + +[[package]] +name = "interpreted-executor" +version = "0.1.0" +dependencies = [ + "criterion", + "dyn-any", + "futures", + "glam", + "graph-craft", + "graphene-core", + "graphene-path-bool", + "graphene-std", + "log", + "once_cell", + "serde", + "wgpu-executor", +] + +[[package]] +name = "ipnet" +version = "2.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "469fb0b9cefa57e3ef31275ee7cacb78f2fdca44e4765491884a2b119d4eb130" + +[[package]] +name = "is-docker" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "928bae27f42bc99b60d9ac7334e3a21d10ad8f1835a4e12ec3ec0464765ed1b3" +dependencies = [ + "once_cell", +] + +[[package]] +name = "is-terminal" +version = "0.4.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e04d7f318608d35d4b61ddd75cbdaee86b023ebe2bd5a66ee0915f0bf93095a9" +dependencies = [ + "hermit-abi 0.5.0", + "libc", + "windows-sys 0.59.0", +] + +[[package]] +name = "is-wsl" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "173609498df190136aa7dea1a91db051746d339e18476eed5ca40521f02d7aa5" +dependencies = [ + "is-docker", + "once_cell", +] + +[[package]] +name = "is_terminal_polyfill" +version = "1.70.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" + +[[package]] +name = "itertools" +version = "0.10.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" +dependencies = [ + "either", +] + +[[package]] +name = "itertools" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba291022dbbd398a455acf126c1e341954079855bc60dfdda641363bd6922569" +dependencies = [ + "either", +] + +[[package]] +name = "itoa" +version = "0.4.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b71991ff56294aa922b450139ee08b3bfc70982c6b2c7562771375cf73542dd4" + +[[package]] +name = "itoa" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" + +[[package]] +name = "javascriptcore-rs" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca5671e9ffce8ffba57afc24070e906da7fc4b1ba66f2cabebf61bf2ea257fcc" +dependencies = [ + "bitflags 1.3.2", + "glib", + "javascriptcore-rs-sys", +] + +[[package]] +name = "javascriptcore-rs-sys" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af1be78d14ffa4b75b66df31840478fef72b51f8c2465d4ca7c194da9f7a5124" +dependencies = [ + "glib-sys", + "gobject-sys", + "libc", + "system-deps", +] + +[[package]] +name = "jni" +version = "0.21.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a87aa2bb7d2af34197c04845522473242e1aa17c12f4935d5856491a7fb8c97" +dependencies = [ + "cesu8", + "cfg-if", + "combine", + "jni-sys", + "log", + "thiserror 1.0.69", + "walkdir", + "windows-sys 0.45.0", +] + +[[package]] +name = "jni-sys" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8eaf4bc02d17cbdd7ff4c7438cafcdf7fb9a4613313ad11b4f8fefe7d3fa0130" + +[[package]] +name = "jobserver" +version = "0.1.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48d1dbcbbeb6a7fec7e059840aa538bd62aaccf972c7346c4d9d2059312853d0" +dependencies = [ + "libc", +] + +[[package]] +name = "jpeg-decoder" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f5d4a7da358eff58addd2877a45865158f0d78c911d43a5784ceb7bbf52833b0" + +[[package]] +name = "js-sys" +version = "0.3.77" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1cfaf33c695fc6e08064efbc1f72ec937429614f25eef83af942d0e227c3a28f" +dependencies = [ + "once_cell", + "wasm-bindgen", +] + +[[package]] +name = "json-patch" +version = "3.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "863726d7afb6bc2590eeff7135d923545e5e964f004c2ccf8716c25e70a86f08" +dependencies = [ + "jsonptr", + "serde", + "serde_json", + "thiserror 1.0.69", +] + +[[package]] +name = "jsonptr" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5dea2b27dd239b2556ed7a25ba842fe47fd602e7fc7433c2a8d6106d4d9edd70" +dependencies = [ + "serde", + "serde_json", +] + +[[package]] +name = "keyboard-types" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b750dcadc39a09dbadd74e118f6dd6598df77fa01df0cfcdc52c28dece74528a" +dependencies = [ + "bitflags 2.9.0", + "serde", + "unicode-segmentation", +] + +[[package]] +name = "khronos-egl" +version = "6.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6aae1df220ece3c0ada96b8153459b67eebe9ae9212258bb0134ae60416fdf76" +dependencies = [ + "libc", + "libloading 0.8.6", + "pkg-config", +] + +[[package]] +name = "khronos_api" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2db585e1d738fc771bf08a151420d3ed193d9d895a36df7f6f8a9456b911ddc" + +[[package]] +name = "kuchikiki" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f29e4755b7b995046f510a7520c42b2fed58b77bd94d5a87a8eb43d2fd126da8" +dependencies = [ + "cssparser", + "html5ever", + "indexmap 1.9.3", + "matches", + "selectors", +] + +[[package]] +name = "kurbo" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1077d333efea6170d9ccb96d3c3026f300ca0773da4938cc4c811daa6df68b0c" +dependencies = [ + "arrayvec", + "serde", + "smallvec", +] + +[[package]] +name = "lazy_static" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" + +[[package]] +name = "lebe" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03087c2bad5e1034e8cace5926dec053fb3790248370865f5117a7d0213354c8" + +[[package]] +name = "libappindicator" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03589b9607c868cc7ae54c0b2a22c8dc03dd41692d48f2d7df73615c6a95dc0a" +dependencies = [ + "glib", + "gtk", + "gtk-sys", + "libappindicator-sys", + "log", +] + +[[package]] +name = "libappindicator-sys" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e9ec52138abedcc58dc17a7c6c0c00a2bdb4f3427c7f63fa97fd0d859155caf" +dependencies = [ + "gtk-sys", + "libloading 0.7.4", + "once_cell", +] + +[[package]] +name = "libc" +version = "0.2.170" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "875b3680cb2f8f71bdcf9a30f38d48282f5d3c95cbf9b3fa57269bb5d5c06828" + +[[package]] +name = "libfuzzer-sys" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf78f52d400cf2d84a3a973a78a592b4adc535739e0a5597a0da6f0c357adc75" +dependencies = [ + "arbitrary", + "cc", +] + +[[package]] +name = "libloading" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b67380fd3b2fbe7527a606e18729d21c6f3951633d0500574c4dc22d2d638b9f" +dependencies = [ + "cfg-if", + "winapi", +] + +[[package]] +name = "libloading" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc2f4eb4bc735547cfed7c0a4922cbd04a4655978c09b54f1f7b228750664c34" +dependencies = [ + "cfg-if", + "windows-targets 0.52.6", +] + +[[package]] +name = "libm" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8355be11b20d696c8f18f6cc018c4e372165b1fa8126cef092399c9951984ffa" + +[[package]] +name = "libredox" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d" +dependencies = [ + "bitflags 2.9.0", + "libc", + "redox_syscall 0.5.10", +] + +[[package]] +name = "linux-raw-sys" +version = "0.4.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d26c52dbd32dccf2d10cac7725f8eae5296885fb5703b261f7d0a0739ec807ab" + +[[package]] +name = "linux-raw-sys" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6db9c683daf087dc577b7506e9695b3d556a9f3849903fa28186283afd6809e9" + +[[package]] +name = "litemap" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23fb14cb19457329c82206317a5663005a4d404783dc74f4252769b0d5f42856" + +[[package]] +name = "litrs" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4ce301924b7887e9d637144fdade93f9dfff9b60981d4ac161db09720d39aa5" + +[[package]] +name = "lock_api" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17" +dependencies = [ + "autocfg", + "scopeguard", +] + +[[package]] +name = "log" +version = "0.4.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "30bde2b3dc3671ae49d8e2e9f044c7c005836e7a023ee57cffa25ab82764bb9e" + +[[package]] +name = "loop9" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fae87c125b03c1d2c0150c90365d7d6bcc53fb73a9acaef207d2d065860f062" +dependencies = [ + "imgref", +] + +[[package]] +name = "mac" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c41e0c4fef86961ac6d6f8a82609f55f31b05e4fce149ac5710e439df7619ba4" + +[[package]] +name = "malloc_buf" +version = "0.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62bb907fe88d54d8d9ce32a3cceab4218ed2f6b7d35617cafe9adf84e43919cb" +dependencies = [ + "libc", +] + +[[package]] +name = "markup5ever" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a2629bb1404f3d34c2e921f21fd34ba00b206124c81f65c50b43b6aaefeb016" +dependencies = [ + "log", + "phf 0.10.1", + "phf_codegen 0.10.0", + "string_cache", + "string_cache_codegen", + "tendril", +] + +[[package]] +name = "matches" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2532096657941c2fea9c289d370a250971c689d4f143798ff67113ec042024a5" + +[[package]] +name = "matchit" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47e1ffaa40ddd1f3ed91f717a33c8c0ee23fff369e3aa8772b9605cc1d22f4c3" + +[[package]] +name = "math-parser" +version = "0.0.0" +dependencies = [ + "criterion", + "lazy_static", + "num-complex", + "pest", + "pest_derive", + "thiserror 2.0.12", +] + +[[package]] +name = "matrixmultiply" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9380b911e3e96d10c1f415da0876389aaf1b56759054eeb0de7df940c456ba1a" +dependencies = [ + "autocfg", + "rawpointer", +] + +[[package]] +name = "maybe-rayon" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ea1f30cedd69f0a2954655f7188c6a834246d2bcf1e315e2ac40c4b24dc9519" +dependencies = [ + "cfg-if", + "rayon", +] + +[[package]] +name = "memchr" +version = "2.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" + +[[package]] +name = "memmap2" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd3f7eed9d3848f8b98834af67102b720745c4ec028fcd0aa0239277e7de374f" +dependencies = [ + "libc", +] + +[[package]] +name = "memoffset" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "488016bfae457b036d996092f6cb448677611ce4449e970ceaf42695203f218a" +dependencies = [ + "autocfg", +] + +[[package]] +name = "metal" +version = "0.29.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ecfd3296f8c56b7c1f6fbac3c71cefa9d78ce009850c45000015f206dc7fa21" +dependencies = [ + "bitflags 2.9.0", + "block", + "core-graphics-types 0.1.3", + "foreign-types 0.5.0", + "log", + "objc", + "paste", +] + +[[package]] +name = "mime" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" + +[[package]] +name = "minimal-lexical" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" + +[[package]] +name = "miniz_oxide" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e3e04debbb59698c15bacbb6d93584a8c0ca9cc3213cb423d31f760d8843ce5" +dependencies = [ + "adler2", + "simd-adler32", +] + +[[package]] +name = "mio" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2886843bf800fba2e3377cff24abf6379b4c4d5c6681eaf9ea5b0d15090450bd" +dependencies = [ + "libc", + "wasi 0.11.0+wasi-snapshot-preview1", + "windows-sys 0.52.0", +] + +[[package]] +name = "muda" +version = "0.16.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4de14a9b5d569ca68d7c891d613b390cf5ab4f851c77aaa2f9e435555d3d9492" +dependencies = [ + "crossbeam-channel", + "dpi", + "gtk", + "keyboard-types", + "objc2 0.6.1", + "objc2-app-kit", + "objc2-core-foundation", + "objc2-foundation 0.3.1", + "once_cell", + "png", + "serde", + "thiserror 2.0.12", + "windows-sys 0.59.0", +] + +[[package]] +name = "naga" +version = "23.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "364f94bc34f61332abebe8cad6f6cd82a5b65cff22c828d05d0968911462ca4f" +dependencies = [ + "arrayvec", + "bit-set", + "bitflags 2.9.0", + "cfg_aliases 0.1.1", + "codespan-reporting", + "hexf-parse", + "indexmap 2.7.1", + "log", + "petgraph 0.6.5", + "rustc-hash 1.1.0", + "spirv", + "termcolor", + "thiserror 1.0.69", + "unicode-xid", +] + +[[package]] +name = "native-tls" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87de3442987e9dbec73158d5c715e7ad9072fda936bb03d19d7fa10e00520f0e" +dependencies = [ + "libc", + "log", + "openssl", + "openssl-probe", + "openssl-sys", + "schannel", + "security-framework", + "security-framework-sys", + "tempfile", +] + +[[package]] +name = "ndarray" +version = "0.16.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "882ed72dce9365842bf196bdeedf5055305f11fc8c03dee7bb0194a6cad34841" +dependencies = [ + "matrixmultiply", + "num-complex", + "num-integer", + "num-traits", + "portable-atomic", + "portable-atomic-util", + "rawpointer", +] + +[[package]] +name = "ndk" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2076a31b7010b17a38c01907c45b945e8f11495ee4dd588309718901b1f7a5b7" +dependencies = [ + "bitflags 2.9.0", + "jni-sys", + "log", + "ndk-sys 0.5.0+25.2.9519653", + "num_enum", + "raw-window-handle", + "thiserror 1.0.69", +] + +[[package]] +name = "ndk" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3f42e7bbe13d351b6bead8286a43aac9534b82bd3cc43e47037f012ebfd62d4" +dependencies = [ + "bitflags 2.9.0", + "jni-sys", + "log", + "ndk-sys 0.6.0+11769913", + "num_enum", + "raw-window-handle", + "thiserror 1.0.69", +] + +[[package]] +name = "ndk-context" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "27b02d87554356db9e9a873add8782d4ea6e3e58ea071a9adb9a2e8ddb884a8b" + +[[package]] +name = "ndk-sys" +version = "0.5.0+25.2.9519653" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c196769dd60fd4f363e11d948139556a344e79d451aeb2fa2fd040738ef7691" +dependencies = [ + "jni-sys", +] + +[[package]] +name = "ndk-sys" +version = "0.6.0+11769913" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee6cda3051665f1fb8d9e08fc35c96d5a244fb1be711a03b71118828afc9a873" +dependencies = [ + "jni-sys", +] + +[[package]] +name = "new_debug_unreachable" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "650eef8c711430f1a879fdd01d4745a7deea475becfb90269c06775983bbf086" + +[[package]] +name = "node-macro" +version = "0.0.0" +dependencies = [ + "convert_case 0.7.1", + "graphene-core", + "indoc", + "proc-macro-crate 3.3.0", + "proc-macro-error2", + "proc-macro2", + "quote", + "syn 2.0.99", +] + +[[package]] +name = "nodrop" +version = "0.1.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72ef4a56884ca558e5ddb05a1d1e7e1bfd9a68d9ed024c21704cc98872dae1bb" + +[[package]] +name = "nom" +version = "7.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" +dependencies = [ + "memchr", + "minimal-lexical", +] + +[[package]] +name = "noop_proc_macro" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0676bb32a98c1a483ce53e500a81ad9c3d5b3f7c920c28c24e9cb0980d0b5bc8" + +[[package]] +name = "num-bigint" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9" +dependencies = [ + "num-integer", + "num-traits", +] + +[[package]] +name = "num-complex" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73f88a1307638156682bada9d7604135552957b7818057dcef22705b4d509495" +dependencies = [ + "num-traits", +] + +[[package]] +name = "num-conv" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" + +[[package]] +name = "num-derive" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed3955f1a9c7c0c15e092f9c887db08b1fc683305fdf6eb6684f22555355e202" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.99", +] + +[[package]] +name = "num-integer" +version = "0.1.46" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" +dependencies = [ + "num-traits", +] + +[[package]] +name = "num-rational" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f83d14da390562dca69fc84082e73e548e1ad308d24accdedd2720017cb37824" +dependencies = [ + "num-bigint", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-traits" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +dependencies = [ + "autocfg", +] + +[[package]] +name = "num_enum" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e613fc340b2220f734a8595782c551f1250e969d87d3be1ae0579e8d4065179" +dependencies = [ + "num_enum_derive", +] + +[[package]] +name = "num_enum_derive" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af1844ef2428cc3e1cb900be36181049ef3d3193c63e43026cfe202983b27a56" +dependencies = [ + "proc-macro-crate 3.3.0", + "proc-macro2", + "quote", + "syn 2.0.99", +] + +[[package]] +name = "objc" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "915b1b472bc21c53464d6c8461c9d3af805ba1ef837e1cac254428f4a77177b1" +dependencies = [ + "malloc_buf", +] + +[[package]] +name = "objc-sys" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cdb91bdd390c7ce1a8607f35f3ca7151b65afc0ff5ff3b34fa350f7d7c7e4310" + +[[package]] +name = "objc2" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "559c5a40fdd30eb5e344fbceacf7595a81e242529fb4e21cf5f43fb4f11ff98d" +dependencies = [ + "objc-sys", + "objc2-encode 3.0.0", +] + +[[package]] +name = "objc2" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46a785d4eeff09c14c487497c162e92766fbb3e4059a71840cecc03d9a50b804" +dependencies = [ + "objc-sys", + "objc2-encode 4.1.0", +] + +[[package]] +name = "objc2" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88c6597e14493ab2e44ce58f2fdecf095a51f12ca57bec060a11c57332520551" +dependencies = [ + "objc2-encode 4.1.0", + "objc2-exception-helper", +] + +[[package]] +name = "objc2-app-kit" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5906f93257178e2f7ae069efb89fbd6ee94f0592740b5f8a1512ca498814d0fb" +dependencies = [ + "bitflags 2.9.0", + "block2 0.6.1", + "libc", + "objc2 0.6.1", + "objc2-cloud-kit", + "objc2-core-data", + "objc2-core-foundation", + "objc2-core-graphics", + "objc2-core-image", + "objc2-foundation 0.3.1", + "objc2-quartz-core 0.3.0", +] + +[[package]] +name = "objc2-cloud-kit" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c1948a9be5f469deadbd6bcb86ad7ff9e47b4f632380139722f7d9840c0d42c" +dependencies = [ + "bitflags 2.9.0", + "objc2 0.6.1", + "objc2-foundation 0.3.1", +] + +[[package]] +name = "objc2-core-data" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f860f8e841f6d32f754836f51e6bc7777cd7e7053cf18528233f6811d3eceb4" +dependencies = [ + "bitflags 2.9.0", + "objc2 0.6.1", + "objc2-foundation 0.3.1", +] + +[[package]] +name = "objc2-core-foundation" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c10c2894a6fed806ade6027bcd50662746363a9589d3ec9d9bef30a4e4bc166" +dependencies = [ + "bitflags 2.9.0", + "dispatch2", + "objc2 0.6.1", +] + +[[package]] +name = "objc2-core-graphics" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8dca602628b65356b6513290a21a6405b4d4027b8b250f0b98dddbb28b7de02" +dependencies = [ + "bitflags 2.9.0", + "objc2 0.6.1", + "objc2-core-foundation", + "objc2-io-surface", +] + +[[package]] +name = "objc2-core-image" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ffa6bea72bf42c78b0b34e89c0bafac877d5f80bf91e159a5d96ea7f693ca56" +dependencies = [ + "objc2 0.6.1", + "objc2-foundation 0.3.1", +] + +[[package]] +name = "objc2-core-text" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ba833d4a1cb1aac330f8c973fd92b6ff1858e4aef5cdd00a255eefb28022fb5" +dependencies = [ + "bitflags 2.9.0", + "objc2-core-foundation", +] + +[[package]] +name = "objc2-encode" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d079845b37af429bfe5dfa76e6d087d788031045b25cfc6fd898486fd9847666" + +[[package]] +name = "objc2-encode" +version = "4.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef25abbcd74fb2609453eb695bd2f860d389e457f67dc17cafc8b8cbc89d0c33" + +[[package]] +name = "objc2-exception-helper" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7a1c5fbb72d7735b076bb47b578523aedc40f3c439bea6dfd595c089d79d98a" +dependencies = [ + "cc", +] + +[[package]] +name = "objc2-foundation" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ee638a5da3799329310ad4cfa62fbf045d5f56e3ef5ba4149e7452dcf89d5a8" +dependencies = [ + "bitflags 2.9.0", + "block2 0.5.1", + "libc", + "objc2 0.5.2", +] + +[[package]] +name = "objc2-foundation" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "900831247d2fe1a09a683278e5384cfb8c80c79fe6b166f9d14bfdde0ea1b03c" +dependencies = [ + "bitflags 2.9.0", + "block2 0.6.1", + "libc", + "objc2 0.6.1", + "objc2-core-foundation", +] + +[[package]] +name = "objc2-io-surface" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "161a8b87e32610086e1a7a9e9ec39f84459db7b3a0881c1f16ca5a2605581c19" +dependencies = [ + "bitflags 2.9.0", + "objc2 0.6.1", + "objc2-core-foundation", +] + +[[package]] +name = "objc2-metal" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd0cba1276f6023976a406a14ffa85e1fdd19df6b0f737b063b95f6c8c7aadd6" +dependencies = [ + "bitflags 2.9.0", + "block2 0.5.1", + "objc2 0.5.2", + "objc2-foundation 0.2.2", +] + +[[package]] +name = "objc2-quartz-core" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e42bee7bff906b14b167da2bac5efe6b6a07e6f7c0a21a7308d40c960242dc7a" +dependencies = [ + "bitflags 2.9.0", + "block2 0.5.1", + "objc2 0.5.2", + "objc2-foundation 0.2.2", + "objc2-metal", +] + +[[package]] +name = "objc2-quartz-core" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6fb3794501bb1bee12f08dcad8c61f2a5875791ad1c6f47faa71a0f033f20071" +dependencies = [ + "bitflags 2.9.0", + "objc2 0.6.1", + "objc2-foundation 0.3.1", +] + +[[package]] +name = "objc2-ui-kit" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "777a571be14a42a3990d4ebedaeb8b54cd17377ec21b92e8200ac03797b3bee1" +dependencies = [ + "bitflags 2.9.0", + "objc2 0.6.1", + "objc2-core-foundation", + "objc2-foundation 0.3.1", +] + +[[package]] +name = "objc2-web-kit" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b717127e4014b0f9f3e8bba3d3f2acec81f1bde01f656823036e823ed2c94dce" +dependencies = [ + "bitflags 2.9.0", + "block2 0.6.1", + "objc2 0.6.1", + "objc2-app-kit", + "objc2-core-foundation", + "objc2-foundation 0.3.1", +] + +[[package]] +name = "object" +version = "0.36.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62948e14d923ea95ea2c7c86c71013138b66525b86bdc08d2dcc262bdb497b87" +dependencies = [ + "memchr", +] + +[[package]] +name = "once_cell" +version = "1.20.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "945462a4b81e43c4e3ba96bd7b49d834c6f61198356aa858733bc4acf3cbe62e" + +[[package]] +name = "oorandom" +version = "11.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6790f58c7ff633d8771f42965289203411a5e5c68388703c06e14f24770b41e" + +[[package]] +name = "open" +version = "5.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2483562e62ea94312f3576a7aca397306df7990b8d89033e18766744377ef95" +dependencies = [ + "dunce", + "is-wsl", + "libc", + "pathdiff", +] + +[[package]] +name = "openssl" +version = "0.10.72" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fedfea7d58a1f73118430a55da6a286e7b044961736ce96a16a17068ea25e5da" +dependencies = [ + "bitflags 2.9.0", + "cfg-if", + "foreign-types 0.3.2", + "libc", + "once_cell", + "openssl-macros", + "openssl-sys", +] + +[[package]] +name = "openssl-macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.99", +] + +[[package]] +name = "openssl-probe" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d05e27ee213611ffe7d6348b942e8f942b37114c00cc03cec254295a4a17852e" + +[[package]] +name = "openssl-sys" +version = "0.9.107" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8288979acd84749c744a9014b4382d42b8f7b2592847b5afb2ed29e5d16ede07" +dependencies = [ + "cc", + "libc", + "pkg-config", + "vcpkg", +] + +[[package]] +name = "option-ext" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d" + +[[package]] +name = "orbclient" +version = "0.3.48" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba0b26cec2e24f08ed8bb31519a9333140a6599b867dac464bb150bdb796fd43" +dependencies = [ + "libredox", +] + +[[package]] +name = "os_pipe" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ffd2b0a5634335b135d5728d84c5e0fd726954b87111f7506a61c502280d982" +dependencies = [ + "libc", + "windows-sys 0.59.0", +] + +[[package]] +name = "owned_ttf_parser" +version = "0.25.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22ec719bbf3b2a81c109a4e20b1f129b5566b7dce654bc3872f6a05abf82b2c4" +dependencies = [ + "ttf-parser 0.25.1", +] + +[[package]] +name = "pango" +version = "0.18.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ca27ec1eb0457ab26f3036ea52229edbdb74dee1edd29063f5b9b010e7ebee4" +dependencies = [ + "gio", + "glib", + "libc", + "once_cell", + "pango-sys", +] + +[[package]] +name = "pango-sys" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "436737e391a843e5933d6d9aa102cb126d501e815b83601365a948a518555dc5" +dependencies = [ + "glib-sys", + "gobject-sys", + "libc", + "system-deps", +] + +[[package]] +name = "parking_lot" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27" +dependencies = [ + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.9.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall 0.5.10", + "smallvec", + "windows-targets 0.52.6", +] + +[[package]] +name = "parley" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13e57638545cf2ba4c3e72cc5715e53b1880b829cc3dbefda3d1700c58efe723" +dependencies = [ + "fontique", + "hashbrown 0.15.4", + "peniko 0.4.0", + "skrifa 0.31.3", + "swash", +] + +[[package]] +name = "paste" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" + +[[package]] +name = "path-bool" +version = "0.1.0" +dependencies = [ + "criterion", + "glam", + "glob", + "image", + "regex", + "resvg", + "slotmap", + "svg", +] + +[[package]] +name = "pathdiff" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df94ce210e5bc13cb6651479fa48d14f601d9858cfe0467f43ae157023b938d3" + +[[package]] +name = "peniko" +version = "0.2.0" +source = "git+https://github.com/linebender/peniko.git?rev=d114c62#d114c6292dbcfb03e7360692198be423168a0edd" +dependencies = [ + "color 0.1.0", + "kurbo", + "smallvec", +] + +[[package]] +name = "peniko" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f9529efd019889b2a205193c14ffb6e2839b54ed9d2720674f10f4b04d87ac9" +dependencies = [ + "color 0.3.1", + "kurbo", + "smallvec", +] + +[[package]] +name = "percent-encoding" +version = "2.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" + +[[package]] +name = "pest" +version = "2.7.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b7cafe60d6cf8e62e1b9b2ea516a089c008945bb5a275416789e7db0bc199dc" +dependencies = [ + "memchr", + "thiserror 2.0.12", + "ucd-trie", +] + +[[package]] +name = "pest_derive" +version = "2.7.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "816518421cfc6887a0d62bf441b6ffb4536fcc926395a69e1a85852d4363f57e" +dependencies = [ + "pest", + "pest_generator", +] + +[[package]] +name = "pest_generator" +version = "2.7.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d1396fd3a870fc7838768d171b4616d5c91f6cc25e377b673d714567d99377b" +dependencies = [ + "pest", + "pest_meta", + "proc-macro2", + "quote", + "syn 2.0.99", +] + +[[package]] +name = "pest_meta" +version = "2.7.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1e58089ea25d717bfd31fb534e4f3afcc2cc569c70de3e239778991ea3b7dea" +dependencies = [ + "once_cell", + "pest", + "sha2", +] + +[[package]] +name = "petgraph" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4c5cc86750666a3ed20bdaf5ca2a0344f9c67674cae0515bec2da16fbaa47db" +dependencies = [ + "fixedbitset 0.4.2", + "indexmap 2.7.1", +] + +[[package]] +name = "petgraph" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3672b37090dbd86368a4145bc067582552b29c27377cad4e0a306c97f9bd7772" +dependencies = [ + "fixedbitset 0.5.7", + "indexmap 2.7.1", +] + +[[package]] +name = "phf" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3dfb61232e34fcb633f43d12c58f83c1df82962dcdfa565a4e866ffc17dafe12" +dependencies = [ + "phf_macros 0.8.0", + "phf_shared 0.8.0", + "proc-macro-hack", +] + +[[package]] +name = "phf" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fabbf1ead8a5bcbc20f5f8b939ee3f5b0f6f281b6ad3468b84656b658b455259" +dependencies = [ + "phf_shared 0.10.0", +] + +[[package]] +name = "phf" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd6780a80ae0c52cc120a26a1a42c1ae51b247a253e4e06113d23d2c2edd078" +dependencies = [ + "phf_macros 0.11.3", + "phf_shared 0.11.3", +] + +[[package]] +name = "phf_codegen" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cbffee61585b0411840d3ece935cce9cb6321f01c45477d30066498cd5e1a815" +dependencies = [ + "phf_generator 0.8.0", + "phf_shared 0.8.0", +] + +[[package]] +name = "phf_codegen" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fb1c3a8bc4dd4e5cfce29b44ffc14bedd2ee294559a294e2a4d4c9e9a6a13cd" +dependencies = [ + "phf_generator 0.10.0", + "phf_shared 0.10.0", +] + +[[package]] +name = "phf_generator" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "17367f0cc86f2d25802b2c26ee58a7b23faeccf78a396094c13dced0d0182526" +dependencies = [ + "phf_shared 0.8.0", + "rand 0.7.3", +] + +[[package]] +name = "phf_generator" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d5285893bb5eb82e6aaf5d59ee909a06a16737a8970984dd7746ba9283498d6" +dependencies = [ + "phf_shared 0.10.0", + "rand 0.8.5", +] + +[[package]] +name = "phf_generator" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c80231409c20246a13fddb31776fb942c38553c51e871f8cbd687a4cfb5843d" +dependencies = [ + "phf_shared 0.11.3", + "rand 0.8.5", +] + +[[package]] +name = "phf_macros" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f6fde18ff429ffc8fe78e2bf7f8b7a5a5a6e2a8b58bc5a9ac69198bbda9189c" +dependencies = [ + "phf_generator 0.8.0", + "phf_shared 0.8.0", + "proc-macro-hack", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "phf_macros" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f84ac04429c13a7ff43785d75ad27569f2951ce0ffd30a3321230db2fc727216" +dependencies = [ + "phf_generator 0.11.3", + "phf_shared 0.11.3", + "proc-macro2", + "quote", + "syn 2.0.99", +] + +[[package]] +name = "phf_shared" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c00cf8b9eafe68dde5e9eaa2cef8ee84a9336a47d566ec55ca16589633b65af7" +dependencies = [ + "siphasher 0.3.11", +] + +[[package]] +name = "phf_shared" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6796ad771acdc0123d2a88dc428b5e38ef24456743ddb1744ed628f9815c096" +dependencies = [ + "siphasher 0.3.11", +] + +[[package]] +name = "phf_shared" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67eabc2ef2a60eb7faa00097bd1ffdb5bd28e62bf39990626a582201b7a754e5" +dependencies = [ + "siphasher 1.0.1", +] + +[[package]] +name = "pico-args" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5be167a7af36ee22fe3115051bc51f6e6c7054c9348e28deb4f49bd6f705a315" + +[[package]] +name = "pin-project-lite" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b" + +[[package]] +name = "pin-utils" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" + +[[package]] +name = "pkg-config" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c" + +[[package]] +name = "plist" +version = "1.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eac26e981c03a6e53e0aee43c113e3202f5581d5360dae7bd2c70e800dd0451d" +dependencies = [ + "base64 0.22.1", + "indexmap 2.7.1", + "quick-xml 0.32.0", + "serde", + "time", +] + +[[package]] +name = "plotters" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5aeb6f403d7a4911efb1e33402027fc44f29b5bf6def3effcc22d7bb75f2b747" +dependencies = [ + "num-traits", + "plotters-backend", + "plotters-svg", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "plotters-backend" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df42e13c12958a16b3f7f4386b9ab1f3e7933914ecea48da7139435263a4172a" + +[[package]] +name = "plotters-svg" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51bae2ac328883f7acdfea3d66a7c35751187f870bc81f94563733a154d7a670" +dependencies = [ + "plotters-backend", +] + +[[package]] +name = "png" +version = "0.17.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "82151a2fc869e011c153adc57cf2789ccb8d9906ce52c0b39a6b5697749d7526" +dependencies = [ + "bitflags 1.3.2", + "crc32fast", + "fdeflate", + "flate2", + "miniz_oxide", +] + +[[package]] +name = "polling" +version = "3.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a604568c3202727d1507653cb121dbd627a58684eb09a820fd746bee38b4442f" +dependencies = [ + "cfg-if", + "concurrent-queue", + "hermit-abi 0.4.0", + "pin-project-lite", + "rustix 0.38.44", + "tracing", + "windows-sys 0.59.0", +] + +[[package]] +name = "portable-atomic" +version = "1.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "350e9b48cbc6b0e028b0473b114454c6316e57336ee184ceab6e53f72c178b3e" + +[[package]] +name = "portable-atomic-util" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8a2f0d8d040d7848a709caf78912debcc3f33ee4b3cac47d73d1e1069e83507" +dependencies = [ + "portable-atomic", +] + +[[package]] +name = "powerfmt" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" + +[[package]] +name = "ppv-lite86" +version = "0.2.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77957b295656769bb8ad2b6a6b09d897d94f05c41b069aede1fcdaa675eaea04" +dependencies = [ + "zerocopy 0.7.35", +] + +[[package]] +name = "precomputed-hash" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c" + +[[package]] +name = "preprocessor" +version = "0.1.0" +dependencies = [ + "graph-craft", + "graphene-std", + "interpreted-executor", +] + +[[package]] +name = "presser" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8cf8e6a8aa66ce33f63993ffc4ea4271eb5b0530a9002db8455ea6050c77bfa" + +[[package]] +name = "pretty_assertions" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ae130e2f271fbc2ac3a40fb1d07180839cdbbe443c7a27e1e3c13c5cac0116d" +dependencies = [ + "diff", + "yansi", +] + +[[package]] +name = "proc-macro-crate" +version = "1.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f4c021e1093a56626774e81216a4ce732a735e5bad4868a03f3ed65ca0c3919" +dependencies = [ + "once_cell", + "toml_edit 0.19.15", +] + +[[package]] +name = "proc-macro-crate" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e8366a6159044a37876a2b9817124296703c586a5c92e2c53751fa06d8d43e8" +dependencies = [ + "toml_edit 0.20.7", +] + +[[package]] +name = "proc-macro-crate" +version = "3.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "edce586971a4dfaa28950c6f18ed55e0406c1ab88bbce2c6f6293a7aaba73d35" +dependencies = [ + "toml_edit 0.22.24", +] + +[[package]] +name = "proc-macro-error" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" +dependencies = [ + "proc-macro-error-attr", + "proc-macro2", + "quote", + "syn 1.0.109", + "version_check", +] + +[[package]] +name = "proc-macro-error-attr" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" +dependencies = [ + "proc-macro2", + "quote", + "version_check", +] + +[[package]] +name = "proc-macro-error-attr2" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96de42df36bb9bba5542fe9f1a054b8cc87e172759a1868aa05c1f3acc89dfc5" +dependencies = [ + "proc-macro2", + "quote", +] + +[[package]] +name = "proc-macro-error2" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11ec05c52be0a07b08061f7dd003e7d7092e0472bc731b4af7bb1ef876109802" +dependencies = [ + "proc-macro-error-attr2", + "proc-macro2", + "quote", + "syn 2.0.99", +] + +[[package]] +name = "proc-macro-hack" +version = "0.5.20+deprecated" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc375e1527247fe1a97d8b7156678dfe7c1af2fc075c9a4db3690ecd2a148068" + +[[package]] +name = "proc-macro2" +version = "1.0.94" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a31971752e70b8b2686d7e46ec17fb38dad4051d94024c88df49b667caea9c84" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "profiling" +version = "1.0.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "afbdc74edc00b6f6a218ca6a5364d6226a259d4b8ea1af4a0ea063f27e179f4d" +dependencies = [ + "profiling-procmacros", +] + +[[package]] +name = "profiling-procmacros" +version = "1.0.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a65f2e60fbf1063868558d69c6beacf412dc755f9fc020f514b7955fc914fe30" +dependencies = [ + "quote", + "syn 2.0.99", +] + +[[package]] +name = "psl-types" +version = "2.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33cb294fe86a74cbcf50d4445b37da762029549ebeea341421c7c70370f86cac" + +[[package]] +name = "publicsuffix" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f42ea446cab60335f76979ec15e12619a2165b5ae2c12166bef27d283a9fadf" +dependencies = [ + "idna", + "psl-types", +] + +[[package]] +name = "qoi" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f6d64c71eb498fe9eae14ce4ec935c555749aef511cca85b5568910d6e48001" +dependencies = [ + "bytemuck", +] + +[[package]] +name = "quick-error" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a993555f31e5a609f617c12db6250dedcac1b0a85076912c436e6fc9b2c8e6a3" + +[[package]] +name = "quick-xml" +version = "0.32.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d3a6e5838b60e0e8fa7a43f22ade549a37d61f8bdbe636d0d7816191de969c2" +dependencies = [ + "memchr", +] + +[[package]] +name = "quick-xml" +version = "0.37.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "165859e9e55f79d67b96c5d96f4e88b6f2695a1972849c15a6a3f5c59fc2c003" +dependencies = [ + "memchr", +] + +[[package]] +name = "quinn" +version = "0.11.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62e96808277ec6f97351a2380e6c25114bc9e67037775464979f3037c92d05ef" +dependencies = [ + "bytes", + "pin-project-lite", + "quinn-proto", + "quinn-udp", + "rustc-hash 2.1.1", + "rustls", + "socket2", + "thiserror 2.0.12", + "tokio", + "tracing", +] + +[[package]] +name = "quinn-proto" +version = "0.11.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2fe5ef3495d7d2e377ff17b1a8ce2ee2ec2a18cde8b6ad6619d65d0701c135d" +dependencies = [ + "bytes", + "getrandom 0.2.15", + "rand 0.8.5", + "ring", + "rustc-hash 2.1.1", + "rustls", + "rustls-pki-types", + "slab", + "thiserror 2.0.12", + "tinyvec", + "tracing", + "web-time 1.1.0", +] + +[[package]] +name = "quinn-udp" +version = "0.5.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e46f3055866785f6b92bc6164b76be02ca8f2eb4b002c0354b28cf4c119e5944" +dependencies = [ + "cfg_aliases 0.2.1", + "libc", + "once_cell", + "socket2", + "tracing", + "windows-sys 0.59.0", +] + +[[package]] +name = "quote" +version = "1.0.39" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1f1914ce909e1658d9907913b4b91947430c7d9be598b15a1912935b8c04801" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "rand" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03" +dependencies = [ + "getrandom 0.1.16", + "libc", + "rand_chacha 0.2.2", + "rand_core 0.5.1", + "rand_hc", + "rand_pcg", +] + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha 0.3.1", + "rand_core 0.6.4", +] + +[[package]] +name = "rand" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3779b94aeb87e8bd4e834cee3650289ee9e0d5677f976ecdb6d219e5f4f6cd94" +dependencies = [ + "rand_chacha 0.9.0", + "rand_core 0.9.3", + "zerocopy 0.8.23", +] + +[[package]] +name = "rand_chacha" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402" +dependencies = [ + "ppv-lite86", + "rand_core 0.5.1", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core 0.6.4", +] + +[[package]] +name = "rand_chacha" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb" +dependencies = [ + "ppv-lite86", + "rand_core 0.9.3", +] + +[[package]] +name = "rand_core" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" +dependencies = [ + "getrandom 0.1.16", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom 0.2.15", +] + +[[package]] +name = "rand_core" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "99d9a13982dcf210057a8a78572b2217b667c3beacbf3a0d8b454f6f82837d38" +dependencies = [ + "getrandom 0.3.1", +] + +[[package]] +name = "rand_hc" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c" +dependencies = [ + "rand_core 0.5.1", +] + +[[package]] +name = "rand_pcg" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "16abd0c1b639e9eb4d7c50c0b8100b0d0f849be2349829c740fe8e6eb4816429" +dependencies = [ + "rand_core 0.5.1", +] + +[[package]] +name = "range-alloc" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3d6831663a5098ea164f89cff59c6284e95f4e3c76ce9848d4529f5ccca9bde" + +[[package]] +name = "rav1e" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd87ce80a7665b1cce111f8a16c1f3929f6547ce91ade6addf4ec86a8dda5ce9" +dependencies = [ + "arbitrary", + "arg_enum_proc_macro", + "arrayvec", + "av1-grain", + "bitstream-io", + "built", + "cfg-if", + "interpolate_name", + "itertools 0.12.1", + "libc", + "libfuzzer-sys", + "log", + "maybe-rayon", + "new_debug_unreachable", + "noop_proc_macro", + "num-derive", + "num-traits", + "once_cell", + "paste", + "profiling", + "rand 0.8.5", + "rand_chacha 0.3.1", + "simd_helpers", + "system-deps", + "thiserror 1.0.69", + "v_frame", + "wasm-bindgen", +] + +[[package]] +name = "ravif" +version = "0.11.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2413fd96bd0ea5cdeeb37eaf446a22e6ed7b981d792828721e74ded1980a45c6" +dependencies = [ + "avif-serialize", + "imgref", + "loop9", + "quick-error", + "rav1e", + "rayon", + "rgb", +] + +[[package]] +name = "raw-window-handle" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "20675572f6f24e9e76ef639bc5552774ed45f1c30e2951e1e99c59888861c539" + +[[package]] +name = "rawpointer" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60a357793950651c4ed0f3f52338f53b2f809f32d83a07f72909fa13e4c6c1e3" + +[[package]] +name = "rayon" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b418a60154510ca1a002a752ca9714984e21e4241e804d32555251faf8b78ffa" +dependencies = [ + "either", + "rayon-core", +] + +[[package]] +name = "rayon-core" +version = "1.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1465873a3dfdaa8ae7cb14b4383657caab0b3e8a0aa9ae8e04b044854c8dfce2" +dependencies = [ + "crossbeam-deque", + "crossbeam-utils", +] + +[[package]] +name = "read-fonts" +version = "0.25.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6f9e8a4f503e5c8750e4cd3b32a4e090035c46374b305a15c70bad833dca05f" +dependencies = [ + "bytemuck", + "font-types 0.8.3", +] + +[[package]] +name = "read-fonts" +version = "0.29.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04ca636dac446b5664bd16c069c00a9621806895b8bb02c2dc68542b23b8f25d" +dependencies = [ + "bytemuck", + "font-types 0.9.0", +] + +[[package]] +name = "read-fonts" +version = "0.30.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "192735ef611aac958468e670cb98432c925426f3cb71521fda202130f7388d91" +dependencies = [ + "bytemuck", + "font-types 0.9.0", +] + +[[package]] +name = "redox_syscall" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "567664f262709473930a4bf9e51bf2ebf3348f2e748ccc50dea20646858f8f29" +dependencies = [ + "bitflags 1.3.2", +] + +[[package]] +name = "redox_syscall" +version = "0.5.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b8c0c260b63a8219631167be35e6a988e9554dbd323f8bd08439c8ed1302bd1" +dependencies = [ + "bitflags 2.9.0", +] + +[[package]] +name = "redox_users" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd6f9d3d47bdd2ad6945c5015a226ec6155d0bcdfd8f7cd29f86b71f8de99d2b" +dependencies = [ + "getrandom 0.2.15", + "libredox", + "thiserror 2.0.12", +] + +[[package]] +name = "regex" +version = "1.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" + +[[package]] +name = "renderdoc-sys" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19b30a45b0cd0bcca8037f3d0dc3421eaf95327a17cad11964fb8179b4fc4832" + +[[package]] +name = "reqwest" +version = "0.12.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43e734407157c3c2034e0258f5e4473ddb361b1e85f95a66690d67264d7cd1da" +dependencies = [ + "base64 0.22.1", + "bytes", + "cookie", + "cookie_store", + "encoding_rs", + "futures-channel", + "futures-core", + "futures-util", + "h2", + "http", + "http-body", + "http-body-util", + "hyper", + "hyper-rustls", + "hyper-tls", + "hyper-util", + "ipnet", + "js-sys", + "log", + "mime", + "native-tls", + "once_cell", + "percent-encoding", + "pin-project-lite", + "quinn", + "rustls", + "rustls-pemfile", + "rustls-pki-types", + "serde", + "serde_json", + "serde_urlencoded", + "sync_wrapper", + "system-configuration", + "tokio", + "tokio-native-tls", + "tokio-rustls", + "tokio-util", + "tower", + "tower-service", + "url", + "wasm-bindgen", + "wasm-bindgen-futures", + "wasm-streams", + "web-sys", + "webpki-roots", + "windows-registry", +] + +[[package]] +name = "resvg" +version = "0.44.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a325d5e8d1cebddd070b13f44cec8071594ab67d1012797c121f27a669b7958" +dependencies = [ + "gif", + "image-webp 0.1.3", + "log", + "pico-args", + "rgb", + "svgtypes", + "tiny-skia", + "usvg", + "zune-jpeg", +] + +[[package]] +name = "rgb" +version = "0.8.50" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57397d16646700483b67d2dd6511d79318f9d057fdbd21a4066aeac8b41d310a" +dependencies = [ + "bytemuck", +] + +[[package]] +name = "ring" +version = "0.17.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70ac5d832aa16abd7d1def883a8545280c20a60f523a370aa3a9617c2b8550ee" +dependencies = [ + "cc", + "cfg-if", + "getrandom 0.2.15", + "libc", + "untrusted", + "windows-sys 0.52.0", +] + +[[package]] +name = "ron" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b91f7eff05f748767f183df4320a63d6936e9c6107d97c9e6bdd9784f4289c94" +dependencies = [ + "base64 0.21.7", + "bitflags 2.9.0", + "serde", + "serde_derive", +] + +[[package]] +name = "roxmltree" +version = "0.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c20b6793b5c2fa6553b250154b78d6d0db37e72700ae35fad9387a46f487c97" + +[[package]] +name = "rustc-demangle" +version = "0.1.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" + +[[package]] +name = "rustc-hash" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" + +[[package]] +name = "rustc-hash" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "357703d41365b4b27c590e3ed91eabb1b663f07c4c084095e60cbed4362dff0d" + +[[package]] +name = "rustc_version" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" +dependencies = [ + "semver", +] + +[[package]] +name = "rustix" +version = "0.38.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fdb5bc1ae2baa591800df16c9ca78619bf65c0488b41b96ccec5d11220d8c154" +dependencies = [ + "bitflags 2.9.0", + "errno", + "libc", + "linux-raw-sys 0.4.15", + "windows-sys 0.59.0", +] + +[[package]] +name = "rustix" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dade4812df5c384711475be5fcd8c162555352945401aed22a35bffeab61f657" +dependencies = [ + "bitflags 2.9.0", + "errno", + "libc", + "linux-raw-sys 0.9.2", + "windows-sys 0.59.0", +] + +[[package]] +name = "rustls" +version = "0.23.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47796c98c480fce5406ef69d1c76378375492c3b0a0de587be0c1d9feb12f395" +dependencies = [ + "once_cell", + "ring", + "rustls-pki-types", + "rustls-webpki", + "subtle", + "zeroize", +] + +[[package]] +name = "rustls-pemfile" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dce314e5fee3f39953d46bb63bb8a46d40c2f8fb7cc5a3b6cab2bde9721d6e50" +dependencies = [ + "rustls-pki-types", +] + +[[package]] +name = "rustls-pki-types" +version = "1.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "917ce264624a4b4db1c364dcc35bfca9ded014d0a958cd47ad3e960e988ea51c" +dependencies = [ + "web-time 1.1.0", +] + +[[package]] +name = "rustls-webpki" +version = "0.102.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64ca1bc8749bd4cf37b5ce386cc146580777b4e8572c7b97baf22c83f444bee9" +dependencies = [ + "ring", + "rustls-pki-types", + "untrusted", +] + +[[package]] +name = "rustversion" +version = "1.0.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eded382c5f5f786b989652c49544c4877d9f015cc22e145a5ea8ea66c2921cd2" + +[[package]] +name = "rustybuzz" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c85d1ccd519e61834798eb52c4e886e8c2d7d698dd3d6ce0b1b47eb8557f1181" +dependencies = [ + "bitflags 2.9.0", + "bytemuck", + "core_maths", + "log", + "smallvec", + "ttf-parser 0.24.1", + "unicode-bidi-mirroring", + "unicode-ccc", + "unicode-properties", + "unicode-script", +] + +[[package]] +name = "ryu" +version = "1.0.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f" + +[[package]] +name = "same-file" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "schannel" +version = "0.1.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f29ebaa345f945cec9fbbc532eb307f0fdad8161f281b6369539c8d84876b3d" +dependencies = [ + "windows-sys 0.59.0", +] + +[[package]] +name = "schemars" +version = "0.8.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fbf2ae1b8bc8e02df939598064d22402220cd5bbcca1c76f7d6a310974d5615" +dependencies = [ + "dyn-clone", + "indexmap 1.9.3", + "schemars_derive", + "serde", + "serde_json", + "url", + "uuid", +] + +[[package]] +name = "schemars_derive" +version = "0.8.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32e265784ad618884abaea0600a9adf15393368d840e0222d101a072f3f7534d" +dependencies = [ + "proc-macro2", + "quote", + "serde_derive_internals", + "syn 2.0.99", +] + +[[package]] +name = "scoped-tls" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1cf6437eb19a8f4a6cc0f7dca544973b0b78843adbfeb3683d1a94a0024a294" + +[[package]] +name = "scopeguard" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" + +[[package]] +name = "sctk-adwaita" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70b31447ca297092c5a9916fc3b955203157b37c19ca8edde4f52e9843e602c7" +dependencies = [ + "ab_glyph", + "log", + "memmap2", + "smithay-client-toolkit", + "tiny-skia", +] + +[[package]] +name = "security-framework" +version = "2.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "897b2245f0b511c87893af39b033e5ca9cce68824c4d7e7630b5a1d339658d02" +dependencies = [ + "bitflags 2.9.0", + "core-foundation 0.9.4", + "core-foundation-sys", + "libc", + "security-framework-sys", +] + +[[package]] +name = "security-framework-sys" +version = "2.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49db231d56a190491cb4aeda9527f1ad45345af50b0851622a7adb8c03b01c32" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "selectors" +version = "0.22.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df320f1889ac4ba6bc0cdc9c9af7af4bd64bb927bccdf32d81140dc1f9be12fe" +dependencies = [ + "bitflags 1.3.2", + "cssparser", + "derive_more", + "fxhash", + "log", + "matches", + "phf 0.8.0", + "phf_codegen 0.8.0", + "precomputed-hash", + "servo_arc", + "smallvec", + "thin-slice", +] + +[[package]] +name = "semver" +version = "1.0.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56e6fa9c48d24d85fb3de5ad847117517440f6beceb7798af16b4a87d616b8d0" +dependencies = [ + "serde", +] + +[[package]] +name = "serde" +version = "1.0.219" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f0e2c6ed6606019b4e29e69dbaba95b11854410e5347d525002456dbbb786b6" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde-untagged" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "299d9c19d7d466db4ab10addd5703e4c615dec2a5a16dbbafe191045e87ee66e" +dependencies = [ + "erased-serde", + "serde", + "typeid", +] + +[[package]] +name = "serde-wasm-bindgen" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8302e169f0eddcc139c70f139d19d6467353af16f9fce27e8c30158036a1e16b" +dependencies = [ + "js-sys", + "serde", + "wasm-bindgen", +] + +[[package]] +name = "serde_derive" +version = "1.0.219" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.99", +] + +[[package]] +name = "serde_derive_internals" +version = "0.29.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "18d26a20a969b9e3fdf2fc2d9f21eda6c40e2de84c9408bb5d3b05d499aae711" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.99", +] + +[[package]] +name = "serde_json" +version = "1.0.140" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "20068b6e96dc6c9bd23e01df8827e6c7e1f2fddd43c21810382803c136b99373" +dependencies = [ + "itoa 1.0.15", + "memchr", + "ryu", + "serde", +] + +[[package]] +name = "serde_path_to_error" +version = "0.1.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59fab13f937fa393d08645bf3a84bdfe86e296747b506ada67bb15f10f218b2a" +dependencies = [ + "itoa 1.0.15", + "serde", +] + +[[package]] +name = "serde_repr" +version = "0.1.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "175ee3e80ae9982737ca543e96133087cbd9a485eecc3bc4de9c1a37b47ea59c" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.99", +] + +[[package]] +name = "serde_spanned" +version = "0.6.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87607cb1398ed59d48732e575a4c28a7a8ebf2454b964fe3f224f2afc07909e1" +dependencies = [ + "serde", +] + +[[package]] +name = "serde_urlencoded" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" +dependencies = [ + "form_urlencoded", + "itoa 1.0.15", + "ryu", + "serde", +] + +[[package]] +name = "serde_with" +version = "3.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6b6f7f2fcb69f747921f79f3926bd1e203fce4fef62c268dd3abfb6d86029aa" +dependencies = [ + "base64 0.22.1", + "chrono", + "hex", + "indexmap 1.9.3", + "indexmap 2.7.1", + "serde", + "serde_derive", + "serde_json", + "serde_with_macros", + "time", +] + +[[package]] +name = "serde_with_macros" +version = "3.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d00caa5193a3c8362ac2b73be6b9e768aa5a4b2f721d8f4b339600c3cb51f8e" +dependencies = [ + "darling", + "proc-macro2", + "quote", + "syn 2.0.99", +] + +[[package]] +name = "serialize-to-javascript" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c9823f2d3b6a81d98228151fdeaf848206a7855a7a042bbf9bf870449a66cafb" +dependencies = [ + "serde", + "serde_json", + "serialize-to-javascript-impl", +] + +[[package]] +name = "serialize-to-javascript-impl" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74064874e9f6a15f04c1f3cb627902d0e6b410abbf36668afa873c61889f1763" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "servo_arc" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d98238b800e0d1576d8b6e3de32827c2d74bee68bb97748dcf5071fb53965432" +dependencies = [ + "nodrop", + "stable_deref_trait", +] + +[[package]] +name = "sha2" +version = "0.10.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + +[[package]] +name = "shared_child" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09fa9338aed9a1df411814a5b2252f7cd206c55ae9bf2fa763f8de84603aa60c" +dependencies = [ + "libc", + "windows-sys 0.59.0", +] + +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + +[[package]] +name = "simd-adler32" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d66dc143e6b11c1eddc06d5c423cfc97062865baf299914ab64caa38182078fe" + +[[package]] +name = "simd_helpers" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95890f873bec569a0362c235787f3aca6e1e887302ba4840839bcc6459c42da6" +dependencies = [ + "quote", +] + +[[package]] +name = "simplecss" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a9c6883ca9c3c7c90e888de77b7a5c849c779d25d74a1269b0218b14e8b136c" +dependencies = [ + "log", +] + +[[package]] +name = "siphasher" +version = "0.3.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38b58827f4464d87d377d175e90bf58eb00fd8716ff0a62f80356b5e61555d0d" + +[[package]] +name = "siphasher" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56199f7ddabf13fe5074ce809e7d3f42b42ae711800501b5b16ea82ad029c39d" + +[[package]] +name = "skrifa" +version = "0.26.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8cc1aa86c26dbb1b63875a7180aa0819709b33348eb5b1491e4321fae388179d" +dependencies = [ + "bytemuck", + "read-fonts 0.25.3", +] + +[[package]] +name = "skrifa" +version = "0.31.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dbeb4ca4399663735553a09dd17ce7e49a0a0203f03b706b39628c4d913a8607" +dependencies = [ + "bytemuck", + "read-fonts 0.29.3", +] + +[[package]] +name = "skrifa" +version = "0.32.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6d632b5a73f566303dbeabd344dc3e716fd4ddc9a70d6fc8ea8e6f06617da97" +dependencies = [ + "bytemuck", + "read-fonts 0.30.1", +] + +[[package]] +name = "slab" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" +dependencies = [ + "autocfg", +] + +[[package]] +name = "slotmap" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dbff4acf519f630b3a3ddcfaea6c06b42174d9a44bc70c620e9ed1649d58b82a" +dependencies = [ + "version_check", +] + +[[package]] +name = "smallvec" +version = "1.15.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" +dependencies = [ + "serde", +] + +[[package]] +name = "smithay-client-toolkit" +version = "0.18.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "922fd3eeab3bd820d76537ce8f582b1cf951eceb5475c28500c7457d9d17f53a" +dependencies = [ + "bitflags 2.9.0", + "calloop", + "calloop-wayland-source", + "cursor-icon", + "libc", + "log", + "memmap2", + "rustix 0.38.44", + "thiserror 1.0.69", + "wayland-backend", + "wayland-client", + "wayland-csd-frame", + "wayland-cursor", + "wayland-protocols", + "wayland-protocols-wlr", + "wayland-scanner", + "xkeysym", +] + +[[package]] +name = "smol_str" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd538fb6910ac1099850255cf94a94df6551fbdd602454387d0adb2d1ca6dead" +dependencies = [ + "serde", +] + +[[package]] +name = "socket2" +version = "0.5.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c970269d99b64e60ec3bd6ad27270092a5394c4e309314b18ae3fe575695fbe8" +dependencies = [ + "libc", + "windows-sys 0.52.0", +] + +[[package]] +name = "softbuffer" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "18051cdd562e792cad055119e0cdb2cfc137e44e3987532e0f9659a77931bb08" +dependencies = [ + "bytemuck", + "cfg_aliases 0.2.1", + "core-graphics 0.24.0", + "foreign-types 0.5.0", + "js-sys", + "log", + "objc2 0.5.2", + "objc2-foundation 0.2.2", + "objc2-quartz-core 0.2.2", + "raw-window-handle", + "redox_syscall 0.5.10", + "wasm-bindgen", + "web-sys", + "windows-sys 0.59.0", +] + +[[package]] +name = "soup3" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "471f924a40f31251afc77450e781cb26d55c0b650842efafc9c6cbd2f7cc4f9f" +dependencies = [ + "futures-channel", + "gio", + "glib", + "libc", + "soup3-sys", +] + +[[package]] +name = "soup3-sys" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ebe8950a680a12f24f15ebe1bf70db7af98ad242d9db43596ad3108aab86c27" +dependencies = [ + "gio-sys", + "glib-sys", + "gobject-sys", + "libc", + "system-deps", +] + +[[package]] +name = "specta" +version = "2.0.0-rc.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab7f01e9310a820edd31c80fde3cae445295adde21a3f9416517d7d65015b971" +dependencies = [ + "glam", + "specta-macros", + "thiserror 1.0.69", +] + +[[package]] +name = "specta-macros" +version = "2.0.0-rc.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0074b9e30ed84c6924eb63ad8d2fe71cdc82628525d84b1fcb1f2fd40676517" +dependencies = [ + "Inflector", + "proc-macro2", + "quote", + "syn 2.0.99", +] + +[[package]] +name = "spin" +version = "0.9.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" +dependencies = [ + "lock_api", +] + +[[package]] +name = "spirv" +version = "0.3.0+sdk-1.3.268.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eda41003dc44290527a59b13432d4a0379379fa074b70174882adfbdfd917844" +dependencies = [ + "bitflags 2.9.0", +] + +[[package]] +name = "stable_deref_trait" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" + +[[package]] +name = "static_assertions" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" + +[[package]] +name = "strict-num" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6637bab7722d379c8b41ba849228d680cc12d0a45ba1fa2b48f2a30577a06731" +dependencies = [ + "float-cmp", +] + +[[package]] +name = "string_cache" +version = "0.8.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf776ba3fa74f83bf4b63c3dcbbf82173db2632ed8452cb2d891d33f459de70f" +dependencies = [ + "new_debug_unreachable", + "parking_lot", + "phf_shared 0.11.3", + "precomputed-hash", + "serde", +] + +[[package]] +name = "string_cache_codegen" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c711928715f1fe0fe509c53b43e993a9a557babc2d0a3567d0a3006f1ac931a0" +dependencies = [ + "phf_generator 0.11.3", + "phf_shared 0.11.3", + "proc-macro2", + "quote", +] + +[[package]] +name = "strsim" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" + +[[package]] +name = "subtle" +version = "2.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" + +[[package]] +name = "svg" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94afda9cd163c04f6bee8b4bf2501c91548deae308373c436f36aeff3cf3c4a3" + +[[package]] +name = "svg_fmt" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce5d813d71d82c4cbc1742135004e4a79fd870214c155443451c139c9470a0aa" + +[[package]] +name = "svgtypes" +version = "0.15.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68c7541fff44b35860c1a7a47a7cadf3e4a304c457b58f9870d9706ece028afc" +dependencies = [ + "kurbo", + "siphasher 1.0.1", +] + +[[package]] +name = "swash" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f745de914febc7c9ab4388dfaf94bbc87e69f57bb41133a9b0c84d4be49856f3" +dependencies = [ + "skrifa 0.31.3", + "yazi", + "zeno", +] + +[[package]] +name = "swift-rs" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4057c98e2e852d51fdcfca832aac7b571f6b351ad159f9eda5db1655f8d0c4d7" +dependencies = [ + "base64 0.21.7", + "serde", + "serde_json", +] + +[[package]] +name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn" +version = "2.0.99" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e02e925281e18ffd9d640e234264753c43edc62d64b2d4cf898f1bc5e75f3fc2" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "sync_wrapper" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0bf256ce5efdfa370213c1dabab5935a12e49f2c58d15e9eac2870d3b4f27263" +dependencies = [ + "futures-core", +] + +[[package]] +name = "synstructure" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.99", +] + +[[package]] +name = "system-configuration" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c879d448e9d986b661742763247d3693ed13609438cf3d006f51f5368a5ba6b" +dependencies = [ + "bitflags 2.9.0", + "core-foundation 0.9.4", + "system-configuration-sys", +] + +[[package]] +name = "system-configuration-sys" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e1d1b10ced5ca923a1fcb8d03e96b8d3268065d724548c0211415ff6ac6bac4" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "system-deps" +version = "6.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a3e535eb8dded36d55ec13eddacd30dec501792ff23a0b1682c38601b8cf2349" +dependencies = [ + "cfg-expr", + "heck 0.5.0", + "pkg-config", + "toml", + "version-compare", +] + +[[package]] +name = "tao" +version = "0.32.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "63c8b1020610b9138dd7b1e06cf259ae91aa05c30f3bd0d6b42a03997b92dec1" +dependencies = [ + "bitflags 2.9.0", + "core-foundation 0.10.0", + "core-graphics 0.24.0", + "crossbeam-channel", + "dispatch", + "dlopen2", + "dpi", + "gdkwayland-sys", + "gdkx11-sys", + "gtk", + "jni", + "lazy_static", + "libc", + "log", + "ndk 0.9.0", + "ndk-context", + "ndk-sys 0.6.0+11769913", + "objc2 0.6.1", + "objc2-app-kit", + "objc2-foundation 0.3.1", + "once_cell", + "parking_lot", + "raw-window-handle", + "scopeguard", + "tao-macros", + "unicode-segmentation", + "url", + "windows 0.60.0", + "windows-core 0.60.1", + "windows-version", + "x11-dl", +] + +[[package]] +name = "tao-macros" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4e16beb8b2ac17db28eab8bca40e62dbfbb34c0fcdc6d9826b11b7b5d047dfd" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.99", +] + +[[package]] +name = "target-lexicon" +version = "0.12.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61c41af27dd6d1e27b1b16b489db798443478cef1f06a660c96db617ba5de3b1" + +[[package]] +name = "tauri" +version = "2.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4d08db1ff9e011e04014e737ec022610d756c0eae0b3b3a9037bccaf3003173a" +dependencies = [ + "anyhow", + "bytes", + "dirs", + "dunce", + "embed_plist", + "futures-util", + "getrandom 0.2.15", + "glob", + "gtk", + "heck 0.5.0", + "http", + "jni", + "libc", + "log", + "mime", + "muda", + "objc2 0.6.1", + "objc2-app-kit", + "objc2-foundation 0.3.1", + "percent-encoding", + "plist", + "raw-window-handle", + "reqwest", + "serde", + "serde_json", + "serde_repr", + "serialize-to-javascript", + "swift-rs", + "tauri-build", + "tauri-macros", + "tauri-runtime", + "tauri-runtime-wry", + "tauri-utils", + "thiserror 2.0.12", + "tokio", + "tray-icon", + "url", + "urlpattern", + "webkit2gtk", + "webview2-com", + "window-vibrancy", + "windows 0.60.0", +] + +[[package]] +name = "tauri-build" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fd20e4661c2cce65343319e6e8da256958f5af958cafc47c0d0af66a55dcd17" +dependencies = [ + "anyhow", + "cargo_toml", + "dirs", + "glob", + "heck 0.5.0", + "json-patch", + "schemars", + "semver", + "serde", + "serde_json", + "tauri-utils", + "tauri-winres", + "toml", + "walkdir", +] + +[[package]] +name = "tauri-codegen" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "458258b19032450ccf975840116ecf013e539eadbb74420bd890e8c56ab2b1a4" +dependencies = [ + "base64 0.22.1", + "brotli", + "ico", + "json-patch", + "plist", + "png", + "proc-macro2", + "quote", + "semver", + "serde", + "serde_json", + "sha2", + "syn 2.0.99", + "tauri-utils", + "thiserror 2.0.12", + "time", + "url", + "uuid", + "walkdir", +] + +[[package]] +name = "tauri-macros" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d402813d3b9c773a0fa58697c457c771f10e735498fdcb7b343264d18e5a601f" +dependencies = [ + "heck 0.5.0", + "proc-macro2", + "quote", + "syn 2.0.99", + "tauri-codegen", + "tauri-utils", +] + +[[package]] +name = "tauri-plugin" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4190775d6ff73fe66d9af44c012739a2659720efd9c0e1e56a918678038699d" +dependencies = [ + "anyhow", + "glob", + "plist", + "schemars", + "serde", + "serde_json", + "tauri-utils", + "toml", + "walkdir", +] + +[[package]] +name = "tauri-plugin-fs" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88371e340ad2f07409a3b68294abe73f20bc9c1bc1b631a31dc37a3d0161f682" +dependencies = [ + "anyhow", + "dunce", + "glob", + "percent-encoding", + "schemars", + "serde", + "serde_json", + "serde_repr", + "tauri", + "tauri-plugin", + "tauri-utils", + "thiserror 2.0.12", + "toml", + "url", + "uuid", +] + +[[package]] +name = "tauri-plugin-http" +version = "2.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "40dcd6c922a1885e1f0bcebc6768fec6e005bd4b9001c5d90a2f5d4cab297729" +dependencies = [ + "bytes", + "cookie_store", + "data-url", + "http", + "regex", + "reqwest", + "schemars", + "serde", + "serde_json", + "tauri", + "tauri-plugin", + "tauri-plugin-fs", + "thiserror 2.0.12", + "tokio", + "url", + "urlpattern", +] + +[[package]] +name = "tauri-plugin-shell" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69d5eb3368b959937ad2aeaf6ef9a8f5d11e01ffe03629d3530707bbcb27ff5d" +dependencies = [ + "encoding_rs", + "log", + "open", + "os_pipe", + "regex", + "schemars", + "serde", + "serde_json", + "shared_child", + "tauri", + "tauri-plugin", + "thiserror 2.0.12", + "tokio", +] + +[[package]] +name = "tauri-runtime" +version = "2.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00ada7ac2f9276f09b8c3afffd3215fd5d9bff23c22df8a7c70e7ef67cacd532" +dependencies = [ + "cookie", + "dpi", + "gtk", + "http", + "jni", + "raw-window-handle", + "serde", + "serde_json", + "tauri-utils", + "thiserror 2.0.12", + "url", + "windows 0.60.0", +] + +[[package]] +name = "tauri-runtime-wry" +version = "2.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf2e5842c57e154af43a20a49c7efee0ce2578c20b4c2bdf266852b422d2e421" +dependencies = [ + "gtk", + "http", + "jni", + "log", + "objc2 0.6.1", + "objc2-app-kit", + "objc2-foundation 0.3.1", + "once_cell", + "percent-encoding", + "raw-window-handle", + "softbuffer", + "tao", + "tauri-runtime", + "tauri-utils", + "url", + "webkit2gtk", + "webview2-com", + "windows 0.60.0", + "wry", +] + +[[package]] +name = "tauri-utils" +version = "2.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f037e66c7638cc0a2213f61566932b9a06882b8346486579c90e4b019bac447" +dependencies = [ + "anyhow", + "brotli", + "cargo_metadata", + "ctor", + "dunce", + "glob", + "html5ever", + "http", + "infer", + "json-patch", + "kuchikiki", + "log", + "memchr", + "phf 0.11.3", + "proc-macro2", + "quote", + "regex", + "schemars", + "semver", + "serde", + "serde-untagged", + "serde_json", + "serde_with", + "swift-rs", + "thiserror 2.0.12", + "toml", + "url", + "urlpattern", + "uuid", + "walkdir", +] + +[[package]] +name = "tauri-winres" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56eaa45f707bedf34d19312c26d350bc0f3c59a47e58e8adbeecdc850d2c13a0" +dependencies = [ + "embed-resource", + "toml", +] + +[[package]] +name = "tempfile" +version = "3.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c317e0a526ee6120d8dabad239c8dadca62b24b6f168914bbbc8e2fb1f0e567" +dependencies = [ + "cfg-if", + "fastrand", + "getrandom 0.3.1", + "once_cell", + "rustix 1.0.1", + "windows-sys 0.59.0", +] + +[[package]] +name = "tendril" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d24a120c5fc464a3458240ee02c299ebcb9d67b5249c8848b09d639dca8d7bb0" +dependencies = [ + "futf", + "mac", + "utf-8", +] + +[[package]] +name = "termcolor" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06794f8f6c5c898b3275aebefa6b8a1cb24cd2c6c79397ab15774837a0bc5755" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "thin-slice" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8eaa81235c7058867fa8c0e7314f33dcce9c215f535d1913822a2b3f5e289f3c" + +[[package]] +name = "thiserror" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" +dependencies = [ + "thiserror-impl 1.0.69", +] + +[[package]] +name = "thiserror" +version = "2.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "567b8a2dae586314f7be2a752ec7474332959c6460e02bde30d702a66d488708" +dependencies = [ + "thiserror-impl 2.0.12", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.99", +] + +[[package]] +name = "thiserror-impl" +version = "2.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f7cf42b4507d8ea322120659672cf1b9dbb93f8f2d4ecfd6e51350ff5b17a1d" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.99", +] + +[[package]] +name = "tiff" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba1310fcea54c6a9a4fd1aad794ecc02c31682f6bfbecdf460bf19533eed1e3e" +dependencies = [ + "flate2", + "jpeg-decoder", + "weezl", +] + +[[package]] +name = "time" +version = "0.3.41" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a7619e19bc266e0f9c5e6686659d394bc57973859340060a69221e57dbc0c40" +dependencies = [ + "deranged", + "itoa 1.0.15", + "num-conv", + "powerfmt", + "serde", + "time-core", + "time-macros", +] + +[[package]] +name = "time-core" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c9e9a38711f559d9e3ce1cdb06dd7c5b8ea546bc90052da6d06bb76da74bb07c" + +[[package]] +name = "time-macros" +version = "0.2.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3526739392ec93fd8b359c8e98514cb3e8e021beb4e5f597b00a0221f8ed8a49" +dependencies = [ + "num-conv", + "time-core", +] + +[[package]] +name = "tiny-skia" +version = "0.11.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83d13394d44dae3207b52a326c0c85a8bf87f1541f23b0d143811088497b09ab" +dependencies = [ + "arrayref", + "arrayvec", + "bytemuck", + "cfg-if", + "log", + "png", + "tiny-skia-path", +] + +[[package]] +name = "tiny-skia-path" +version = "0.11.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c9e7fc0c2e86a30b117d0462aa261b72b7a99b7ebd7deb3a14ceda95c5bdc93" +dependencies = [ + "arrayref", + "bytemuck", + "strict-num", +] + +[[package]] +name = "tinystr" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9117f5d4db391c1cf6927e7bea3db74b9a1c1add8f7eda9ffd5364f40f57b82f" +dependencies = [ + "displaydoc", + "zerovec", +] + +[[package]] +name = "tinytemplate" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be4d6b5f19ff7664e8c98d03e2139cb510db9b0a60b55f8e8709b689d939b6bc" +dependencies = [ + "serde", + "serde_json", +] + +[[package]] +name = "tinyvec" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09b3661f17e86524eccd4371ab0429194e0d7c008abb45f7a7495b1719463c71" +dependencies = [ + "tinyvec_macros", +] + +[[package]] +name = "tinyvec_macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" + +[[package]] +name = "tokio" +version = "1.45.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2513ca694ef9ede0fb23fe71a4ee4107cb102b9dc1930f6d0fd77aae068ae165" +dependencies = [ + "backtrace", + "bytes", + "libc", + "mio", + "pin-project-lite", + "socket2", + "tokio-macros", + "windows-sys 0.52.0", +] + +[[package]] +name = "tokio-macros" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e06d43f1345a3bcd39f6a56dbb7dcab2ba47e68e8ac134855e7e2bdbaf8cab8" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.99", +] + +[[package]] +name = "tokio-native-tls" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbae76ab933c85776efabc971569dd6119c580d8f5d448769dec1764bf796ef2" +dependencies = [ + "native-tls", + "tokio", +] + +[[package]] +name = "tokio-rustls" +version = "0.26.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e727b36a1a0e8b74c376ac2211e40c2c8af09fb4013c60d910495810f008e9b" +dependencies = [ + "rustls", + "tokio", +] + +[[package]] +name = "tokio-util" +version = "0.7.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7fcaa8d55a2bdd6b83ace262b016eca0d79ee02818c5c1bcdf0305114081078" +dependencies = [ + "bytes", + "futures-core", + "futures-sink", + "pin-project-lite", + "tokio", +] + +[[package]] +name = "toml" +version = "0.8.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd87a5cdd6ffab733b2f74bc4fd7ee5fff6634124999ac278c35fc78c6120148" +dependencies = [ + "serde", + "serde_spanned", + "toml_datetime", + "toml_edit 0.22.24", +] + +[[package]] +name = "toml_datetime" +version = "0.6.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0dd7358ecb8fc2f8d014bf86f6f638ce72ba252a2c3a2572f2a795f1d23efb41" +dependencies = [ + "serde", +] + +[[package]] +name = "toml_edit" +version = "0.19.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421" +dependencies = [ + "indexmap 2.7.1", + "toml_datetime", + "winnow 0.5.40", +] + +[[package]] +name = "toml_edit" +version = "0.20.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70f427fce4d84c72b5b732388bf4a9f4531b53f74e2887e3ecb2481f68f66d81" +dependencies = [ + "indexmap 2.7.1", + "toml_datetime", + "winnow 0.5.40", +] + +[[package]] +name = "toml_edit" +version = "0.22.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "17b4795ff5edd201c7cd6dca065ae59972ce77d1b80fa0a84d94950ece7d1474" +dependencies = [ + "indexmap 2.7.1", + "serde", + "serde_spanned", + "toml_datetime", + "winnow 0.7.3", +] + +[[package]] +name = "tower" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d039ad9159c98b70ecfd540b2573b97f7f52c3e8d9f8ad57a24b916a536975f9" +dependencies = [ + "futures-core", + "futures-util", + "pin-project-lite", + "sync_wrapper", + "tokio", + "tower-layer", + "tower-service", + "tracing", +] + +[[package]] +name = "tower-layer" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "121c2a6cda46980bb0fcd1647ffaf6cd3fc79a013de288782836f6df9c48780e" + +[[package]] +name = "tower-service" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3" + +[[package]] +name = "tracing" +version = "0.1.41" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0" +dependencies = [ + "log", + "pin-project-lite", + "tracing-core", +] + +[[package]] +name = "tracing-core" +version = "0.1.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e672c95779cf947c5311f83787af4fa8fffd12fb27e4993211a84bdfd9610f9c" +dependencies = [ + "once_cell", +] + +[[package]] +name = "tray-icon" +version = "0.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d433764348e7084bad2c5ea22c96c71b61b17afe3a11645710f533bd72b6a2b5" +dependencies = [ + "crossbeam-channel", + "dirs", + "libappindicator", + "muda", + "objc2 0.6.1", + "objc2-app-kit", + "objc2-core-foundation", + "objc2-core-graphics", + "objc2-foundation 0.3.1", + "once_cell", + "png", + "serde", + "thiserror 2.0.12", + "windows-sys 0.59.0", +] + +[[package]] +name = "try-lock" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" + +[[package]] +name = "ttf-parser" +version = "0.24.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5be21190ff5d38e8b4a2d3b6a3ae57f612cc39c96e83cedeaf7abc338a8bac4a" +dependencies = [ + "core_maths", +] + +[[package]] +name = "ttf-parser" +version = "0.25.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2df906b07856748fa3f6e0ad0cbaa047052d4a7dd609e231c4f72cee8c36f31" + +[[package]] +name = "typeid" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc7d623258602320d5c55d1bc22793b57daff0ec7efc270ea7d55ce1d5f5471c" + +[[package]] +name = "typenum" +version = "1.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1dccffe3ce07af9386bfd29e80c0ab1a8205a2fc34e4bcd40364df902cfa8f3f" + +[[package]] +name = "ucd-trie" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2896d95c02a80c6d6a5d6e953d479f5ddf2dfdb6a244441010e373ac0fb88971" + +[[package]] +name = "unic-char-property" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8c57a407d9b6fa02b4795eb81c5b6652060a15a7903ea981f3d723e6c0be221" +dependencies = [ + "unic-char-range", +] + +[[package]] +name = "unic-char-range" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0398022d5f700414f6b899e10b8348231abf9173fa93144cbc1a43b9793c1fbc" + +[[package]] +name = "unic-common" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "80d7ff825a6a654ee85a63e80f92f054f904f21e7d12da4e22f9834a4aaa35bc" + +[[package]] +name = "unic-ucd-ident" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e230a37c0381caa9219d67cf063aa3a375ffed5bf541a452db16e744bdab6987" +dependencies = [ + "unic-char-property", + "unic-char-range", + "unic-ucd-version", +] + +[[package]] +name = "unic-ucd-version" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96bd2f2237fe450fcd0a1d2f5f4e91711124f7857ba2e964247776ebeeb7b0c4" +dependencies = [ + "unic-common", +] + +[[package]] +name = "unicode-bidi" +version = "0.3.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c1cb5db39152898a79168971543b1cb5020dff7fe43c8dc468b0885f5e29df5" + +[[package]] +name = "unicode-bidi-mirroring" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64af057ad7466495ca113126be61838d8af947f41d93a949980b2389a118082f" + +[[package]] +name = "unicode-ccc" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "260bc6647b3893a9a90668360803a15f96b85a5257b1c3a0c3daf6ae2496de42" + +[[package]] +name = "unicode-ident" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512" + +[[package]] +name = "unicode-properties" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e70f2a8b45122e719eb623c01822704c4e0907e7e426a05927e1a1cfff5b75d0" + +[[package]] +name = "unicode-script" +version = "0.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9fb421b350c9aff471779e262955939f565ec18b86c15364e6bdf0d662ca7c1f" + +[[package]] +name = "unicode-segmentation" +version = "1.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493" + +[[package]] +name = "unicode-vo" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1d386ff53b415b7fe27b50bb44679e2cc4660272694b7b6f3326d8480823a94" + +[[package]] +name = "unicode-width" +version = "0.1.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af" + +[[package]] +name = "unicode-xid" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" + +[[package]] +name = "untrusted" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" + +[[package]] +name = "url" +version = "2.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32f8b686cadd1473f4bd0117a5d28d36b1ade384ea9b5069a1c40aefed7fda60" +dependencies = [ + "form_urlencoded", + "idna", + "percent-encoding", + "serde", +] + +[[package]] +name = "urlpattern" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70acd30e3aa1450bc2eece896ce2ad0d178e9c079493819301573dae3c37ba6d" +dependencies = [ + "regex", + "serde", + "unic-ucd-ident", + "url", +] + +[[package]] +name = "usvg" +version = "0.44.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7447e703d7223b067607655e625e0dbca80822880248937da65966194c4864e6" +dependencies = [ + "base64 0.22.1", + "data-url", + "flate2", + "fontdb", + "imagesize", + "kurbo", + "log", + "pico-args", + "roxmltree", + "rustybuzz", + "simplecss", + "siphasher 1.0.1", + "strict-num", + "svgtypes", + "tiny-skia-path", + "unicode-bidi", + "unicode-script", + "unicode-vo", + "xmlwriter", +] + +[[package]] +name = "utf-8" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" + +[[package]] +name = "utf16_iter" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8232dd3cdaed5356e0f716d285e4b40b932ac434100fe9b7e0e8e935b9e6246" + +[[package]] +name = "utf8_iter" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" + +[[package]] +name = "utf8parse" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" + +[[package]] +name = "uuid" +version = "1.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "458f7a779bf54acc9f347480ac654f68407d3aab21269a6e3c9f922acd9e2da9" +dependencies = [ + "getrandom 0.3.1", + "serde", +] + +[[package]] +name = "v_frame" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6f32aaa24bacd11e488aa9ba66369c7cd514885742c9fe08cfe85884db3e92b" +dependencies = [ + "aligned-vec", + "num-traits", + "wasm-bindgen", +] + +[[package]] +name = "vcpkg" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" + +[[package]] +name = "vello" +version = "0.3.0" +source = "git+https://github.com/linebender/vello.git?rev=3275ec8#3275ec85d831180be81820de06cca29a97a757f5" +dependencies = [ + "bytemuck", + "futures-intrusive", + "log", + "peniko 0.2.0", + "png", + "skrifa 0.26.6", + "static_assertions", + "thiserror 2.0.12", + "vello_encoding", + "vello_shaders", + "wgpu", +] + +[[package]] +name = "vello_encoding" +version = "0.3.0" +source = "git+https://github.com/linebender/vello.git?rev=3275ec8#3275ec85d831180be81820de06cca29a97a757f5" +dependencies = [ + "bytemuck", + "guillotiere", + "peniko 0.2.0", + "skrifa 0.26.6", + "smallvec", +] + +[[package]] +name = "vello_shaders" +version = "0.3.0" +source = "git+https://github.com/linebender/vello.git?rev=3275ec8#3275ec85d831180be81820de06cca29a97a757f5" +dependencies = [ + "bytemuck", + "naga", + "thiserror 2.0.12", + "vello_encoding", +] + +[[package]] +name = "version-compare" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "852e951cb7832cb45cb1169900d19760cfa39b82bc0ea9c0e5a14ae88411c98b" + +[[package]] +name = "version_check" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" + +[[package]] +name = "vswhom" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be979b7f07507105799e854203b470ff7c78a1639e330a58f183b5fea574608b" +dependencies = [ + "libc", + "vswhom-sys", +] + +[[package]] +name = "vswhom-sys" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fb067e4cbd1ff067d1df46c9194b5de0e98efd2810bbc95c5d5e5f25a3231150" +dependencies = [ + "cc", + "libc", +] + +[[package]] +name = "walkdir" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" +dependencies = [ + "same-file", + "winapi-util", +] + +[[package]] +name = "want" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e" +dependencies = [ + "try-lock", +] + +[[package]] +name = "wasi" +version = "0.9.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + +[[package]] +name = "wasi" +version = "0.13.3+wasi-0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26816d2e1a4a36a2940b96c5296ce403917633dff8f3440e9b236ed6f6bacad2" +dependencies = [ + "wit-bindgen-rt", +] + +[[package]] +name = "wasm-bindgen" +version = "0.2.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1edc8929d7499fc4e8f0be2262a241556cfc54a0bea223790e71446f2aab1ef5" +dependencies = [ + "cfg-if", + "once_cell", + "rustversion", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2f0a0651a5c2bc21487bde11ee802ccaf4c51935d0d3d42a6101f98161700bc6" +dependencies = [ + "bumpalo", + "log", + "proc-macro2", + "quote", + "syn 2.0.99", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-futures" +version = "0.4.50" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "555d470ec0bc3bb57890405e5d4322cc9ea83cebb085523ced7be4144dac1e61" +dependencies = [ + "cfg-if", + "js-sys", + "once_cell", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7fe63fc6d09ed3792bd0897b314f53de8e16568c2b3f7982f468c0bf9bd0b407" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.99", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a05d73b933a847d6cccdda8f838a22ff101ad9bf93e33684f39c1f5f0eece3d" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "wasm-streams" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "15053d8d85c7eccdbefef60f06769760a563c7f0a9d6902a13d35c7800b0ad65" +dependencies = [ + "futures-util", + "js-sys", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", +] + +[[package]] +name = "wayland-backend" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7208998eaa3870dad37ec8836979581506e0c5c64c20c9e79e9d2a10d6f47bf" +dependencies = [ + "cc", + "downcast-rs", + "rustix 0.38.44", + "scoped-tls", + "smallvec", + "wayland-sys", +] + +[[package]] +name = "wayland-client" +version = "0.31.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2120de3d33638aaef5b9f4472bff75f07c56379cf76ea320bd3a3d65ecaf73f" +dependencies = [ + "bitflags 2.9.0", + "rustix 0.38.44", + "wayland-backend", + "wayland-scanner", +] + +[[package]] +name = "wayland-csd-frame" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "625c5029dbd43d25e6aa9615e88b829a5cad13b2819c4ae129fdbb7c31ab4c7e" +dependencies = [ + "bitflags 2.9.0", + "cursor-icon", + "wayland-backend", +] + +[[package]] +name = "wayland-cursor" +version = "0.31.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a93029cbb6650748881a00e4922b076092a6a08c11e7fbdb923f064b23968c5d" +dependencies = [ + "rustix 0.38.44", + "wayland-client", + "xcursor", +] + +[[package]] +name = "wayland-protocols" +version = "0.31.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f81f365b8b4a97f422ac0e8737c438024b5951734506b0e1d775c73030561f4" +dependencies = [ + "bitflags 2.9.0", + "wayland-backend", + "wayland-client", + "wayland-scanner", +] + +[[package]] +name = "wayland-protocols-plasma" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23803551115ff9ea9bce586860c5c5a971e360825a0309264102a9495a5ff479" +dependencies = [ + "bitflags 2.9.0", + "wayland-backend", + "wayland-client", + "wayland-protocols", + "wayland-scanner", +] + +[[package]] +name = "wayland-protocols-wlr" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad1f61b76b6c2d8742e10f9ba5c3737f6530b4c243132c2a2ccc8aa96fe25cd6" +dependencies = [ + "bitflags 2.9.0", + "wayland-backend", + "wayland-client", + "wayland-protocols", + "wayland-scanner", +] + +[[package]] +name = "wayland-scanner" +version = "0.31.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "896fdafd5d28145fce7958917d69f2fd44469b1d4e861cb5961bcbeebc6d1484" +dependencies = [ + "proc-macro2", + "quick-xml 0.37.2", + "quote", +] + +[[package]] +name = "wayland-sys" +version = "0.31.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dbcebb399c77d5aa9fa5db874806ee7b4eba4e73650948e8f93963f128896615" +dependencies = [ + "dlib", + "log", + "once_cell", + "pkg-config", +] + +[[package]] +name = "web-sys" +version = "0.3.77" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33b6dd2ef9186f1f2072e409e99cd22a975331a6b3591b12c764e0e55c60d5d2" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "web-time" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa30049b1c872b72c89866d458eae9f20380ab280ffd1b1e18df2d3e2d98cfe0" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "web-time" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a6580f308b1fad9207618087a65c04e7a10bc77e02c8e84e9b00dd4b12fa0bb" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "webkit2gtk" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76b1bc1e54c581da1e9f179d0b38512ba358fb1af2d634a1affe42e37172361a" +dependencies = [ + "bitflags 1.3.2", + "cairo-rs", + "gdk", + "gdk-sys", + "gio", + "gio-sys", + "glib", + "glib-sys", + "gobject-sys", + "gtk", + "gtk-sys", + "javascriptcore-rs", + "libc", + "once_cell", + "soup3", + "webkit2gtk-sys", +] + +[[package]] +name = "webkit2gtk-sys" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62daa38afc514d1f8f12b8693d30d5993ff77ced33ce30cd04deebc267a6d57c" +dependencies = [ + "bitflags 1.3.2", + "cairo-sys-rs", + "gdk-sys", + "gio-sys", + "glib-sys", + "gobject-sys", + "gtk-sys", + "javascriptcore-rs-sys", + "libc", + "pkg-config", + "soup3-sys", + "system-deps", +] + +[[package]] +name = "webpki-roots" +version = "0.26.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2210b291f7ea53617fbafcc4939f10914214ec15aace5ba62293a668f322c5c9" +dependencies = [ + "rustls-pki-types", +] + +[[package]] +name = "webview2-com" +version = "0.36.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0d606f600e5272b514dbb66539dd068211cc20155be8d3958201b4b5bd79ed3" +dependencies = [ + "webview2-com-macros", + "webview2-com-sys", + "windows 0.60.0", + "windows-core 0.60.1", + "windows-implement 0.59.0", + "windows-interface 0.59.1", +] + +[[package]] +name = "webview2-com-macros" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d228f15bba3b9d56dde8bddbee66fa24545bd17b48d5128ccf4a8742b18e431" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.99", +] + +[[package]] +name = "webview2-com-sys" +version = "0.36.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfb27fccd3c27f68e9a6af1bcf48c2d82534b8675b83608a4d81446d095a17ac" +dependencies = [ + "thiserror 2.0.12", + "windows 0.60.0", + "windows-core 0.60.1", +] + +[[package]] +name = "weezl" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53a85b86a771b1c87058196170769dd264f66c0782acf1ae6cc51bfd64b39082" + +[[package]] +name = "wgpu" +version = "23.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "80f70000db37c469ea9d67defdc13024ddf9a5f1b89cb2941b812ad7cde1735a" +dependencies = [ + "arrayvec", + "cfg_aliases 0.1.1", + "document-features", + "js-sys", + "log", + "naga", + "parking_lot", + "profiling", + "raw-window-handle", + "smallvec", + "static_assertions", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", + "wgpu-core", + "wgpu-hal", + "wgpu-types", +] + +[[package]] +name = "wgpu-core" +version = "23.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d63c3c478de8e7e01786479919c8769f62a22eec16788d8c2ac77ce2c132778a" +dependencies = [ + "arrayvec", + "bit-vec", + "bitflags 2.9.0", + "bytemuck", + "cfg_aliases 0.1.1", + "document-features", + "indexmap 2.7.1", + "log", + "naga", + "once_cell", + "parking_lot", + "profiling", + "raw-window-handle", + "rustc-hash 1.1.0", + "smallvec", + "thiserror 1.0.69", + "wgpu-hal", + "wgpu-types", +] + +[[package]] +name = "wgpu-executor" +version = "0.1.0" +dependencies = [ + "anyhow", + "dyn-any", + "futures", + "glam", + "graphene-application-io", + "graphene-core", + "graphene-svg-renderer", + "node-macro", + "vello", + "web-sys", + "wgpu", + "winit", +] + +[[package]] +name = "wgpu-hal" +version = "23.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89364b8a0b211adc7b16aeaf1bd5ad4a919c1154b44c9ce27838213ba05fd821" +dependencies = [ + "android_system_properties", + "arrayvec", + "ash", + "bit-set", + "bitflags 2.9.0", + "block", + "bytemuck", + "cfg_aliases 0.1.1", + "core-graphics-types 0.1.3", + "glow", + "glutin_wgl_sys", + "gpu-alloc", + "gpu-allocator", + "gpu-descriptor", + "js-sys", + "khronos-egl", + "libc", + "libloading 0.8.6", + "log", + "metal", + "naga", + "ndk-sys 0.5.0+25.2.9519653", + "objc", + "once_cell", + "parking_lot", + "profiling", + "range-alloc", + "raw-window-handle", + "renderdoc-sys", + "rustc-hash 1.1.0", + "smallvec", + "thiserror 1.0.69", + "wasm-bindgen", + "web-sys", + "wgpu-types", + "windows 0.58.0", + "windows-core 0.58.0", +] + +[[package]] +name = "wgpu-types" +version = "23.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "610f6ff27778148c31093f3b03abc4840f9636d58d597ca2f5977433acfe0068" +dependencies = [ + "bitflags 2.9.0", + "js-sys", + "web-sys", +] + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-util" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb" +dependencies = [ + "windows-sys 0.59.0", +] + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "window-vibrancy" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9bec5a31f3f9362f2258fd0e9c9dd61a9ca432e7306cc78c444258f0dce9a9c" +dependencies = [ + "objc2 0.6.1", + "objc2-app-kit", + "objc2-core-foundation", + "objc2-foundation 0.3.1", + "raw-window-handle", + "windows-sys 0.59.0", + "windows-version", +] + +[[package]] +name = "windows" +version = "0.58.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd04d41d93c4992d421894c18c8b43496aa748dd4c081bac0dc93eb0489272b6" +dependencies = [ + "windows-core 0.58.0", + "windows-targets 0.52.6", +] + +[[package]] +name = "windows" +version = "0.60.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ddf874e74c7a99773e62b1c671427abf01a425e77c3d3fb9fb1e4883ea934529" +dependencies = [ + "windows-collections", + "windows-core 0.60.1", + "windows-future", + "windows-link", + "windows-numerics", +] + +[[package]] +name = "windows-collections" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5467f79cc1ba3f52ebb2ed41dbb459b8e7db636cc3429458d9a852e15bc24dec" +dependencies = [ + "windows-core 0.60.1", +] + +[[package]] +name = "windows-core" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" +dependencies = [ + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-core" +version = "0.58.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ba6d44ec8c2591c134257ce647b7ea6b20335bf6379a27dac5f1641fcf59f99" +dependencies = [ + "windows-implement 0.58.0", + "windows-interface 0.58.0", + "windows-result 0.2.0", + "windows-strings 0.1.0", + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-core" +version = "0.60.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca21a92a9cae9bf4ccae5cf8368dce0837100ddf6e6d57936749e85f152f6247" +dependencies = [ + "windows-implement 0.59.0", + "windows-interface 0.59.1", + "windows-link", + "windows-result 0.3.1", + "windows-strings 0.3.1", +] + +[[package]] +name = "windows-future" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a787db4595e7eb80239b74ce8babfb1363d8e343ab072f2ffe901400c03349f0" +dependencies = [ + "windows-core 0.60.1", + "windows-link", +] + +[[package]] +name = "windows-implement" +version = "0.58.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2bbd5b46c938e506ecbce286b6628a02171d56153ba733b6c741fc627ec9579b" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.99", +] + +[[package]] +name = "windows-implement" +version = "0.59.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83577b051e2f49a058c308f17f273b570a6a758386fc291b5f6a934dd84e48c1" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.99", +] + +[[package]] +name = "windows-interface" +version = "0.58.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "053c4c462dc91d3b1504c6fe5a726dd15e216ba718e84a0e46a88fbe5ded3515" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.99", +] + +[[package]] +name = "windows-interface" +version = "0.59.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd9211b69f8dcdfa817bfd14bf1c97c9188afa36f4750130fcdf3f400eca9fa8" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.99", +] + +[[package]] +name = "windows-link" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6dccfd733ce2b1753b03b6d3c65edf020262ea35e20ccdf3e288043e6dd620e3" + +[[package]] +name = "windows-numerics" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "005dea54e2f6499f2cee279b8f703b3cf3b5734a2d8d21867c8f44003182eeed" +dependencies = [ + "windows-core 0.60.1", + "windows-link", +] + +[[package]] +name = "windows-registry" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e400001bb720a623c1c69032f8e3e4cf09984deec740f007dd2b03ec864804b0" +dependencies = [ + "windows-result 0.2.0", + "windows-strings 0.1.0", + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-result" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d1043d8214f791817bab27572aaa8af63732e11bf84aa21a45a78d6c317ae0e" +dependencies = [ + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-result" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06374efe858fab7e4f881500e6e86ec8bc28f9462c47e5a9941a0142ad86b189" +dependencies = [ + "windows-link", +] + +[[package]] +name = "windows-strings" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4cd9b125c486025df0eabcb585e62173c6c9eddcec5d117d3b6e8c30e2ee4d10" +dependencies = [ + "windows-result 0.2.0", + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-strings" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87fa48cc5d406560701792be122a10132491cff9d0aeb23583cc2dcafc847319" +dependencies = [ + "windows-link", +] + +[[package]] +name = "windows-sys" +version = "0.45.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0" +dependencies = [ + "windows-targets 0.42.2", +] + +[[package]] +name = "windows-sys" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" +dependencies = [ + "windows-targets 0.48.5", +] + +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-sys" +version = "0.59.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" +dependencies = [ + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-targets" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071" +dependencies = [ + "windows_aarch64_gnullvm 0.42.2", + "windows_aarch64_msvc 0.42.2", + "windows_i686_gnu 0.42.2", + "windows_i686_msvc 0.42.2", + "windows_x86_64_gnu 0.42.2", + "windows_x86_64_gnullvm 0.42.2", + "windows_x86_64_msvc 0.42.2", +] + +[[package]] +name = "windows-targets" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" +dependencies = [ + "windows_aarch64_gnullvm 0.48.5", + "windows_aarch64_msvc 0.48.5", + "windows_i686_gnu 0.48.5", + "windows_i686_msvc 0.48.5", + "windows_x86_64_gnu 0.48.5", + "windows_x86_64_gnullvm 0.48.5", + "windows_x86_64_msvc 0.48.5", +] + +[[package]] +name = "windows-targets" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" +dependencies = [ + "windows_aarch64_gnullvm 0.52.6", + "windows_aarch64_msvc 0.52.6", + "windows_i686_gnu 0.52.6", + "windows_i686_gnullvm", + "windows_i686_msvc 0.52.6", + "windows_x86_64_gnu 0.52.6", + "windows_x86_64_gnullvm 0.52.6", + "windows_x86_64_msvc 0.52.6", +] + +[[package]] +name = "windows-version" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7bfbcc4996dd183ff1376a20ade1242da0d2dcaff83cc76710a588d24fd4c5db" +dependencies = [ + "windows-link", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8" + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" + +[[package]] +name = "windows_i686_gnu" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f" + +[[package]] +name = "windows_i686_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" + +[[package]] +name = "windows_i686_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060" + +[[package]] +name = "windows_i686_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" + +[[package]] +name = "winit" +version = "0.29.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d59ad965a635657faf09c8f062badd885748428933dad8e8bdd64064d92e5ca" +dependencies = [ + "ahash", + "android-activity", + "atomic-waker", + "bitflags 2.9.0", + "bytemuck", + "calloop", + "cfg_aliases 0.1.1", + "core-foundation 0.9.4", + "core-graphics 0.23.2", + "cursor-icon", + "icrate", + "js-sys", + "libc", + "log", + "memmap2", + "ndk 0.8.0", + "ndk-sys 0.5.0+25.2.9519653", + "objc2 0.4.1", + "once_cell", + "orbclient", + "percent-encoding", + "raw-window-handle", + "redox_syscall 0.3.5", + "rustix 0.38.44", + "sctk-adwaita", + "smithay-client-toolkit", + "smol_str", + "unicode-segmentation", + "wasm-bindgen", + "wasm-bindgen-futures", + "wayland-backend", + "wayland-client", + "wayland-protocols", + "wayland-protocols-plasma", + "web-sys", + "web-time 0.2.4", + "windows-sys 0.48.0", + "x11-dl", + "x11rb", + "xkbcommon-dl", +] + +[[package]] +name = "winnow" +version = "0.5.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f593a95398737aeed53e489c785df13f3618e41dbcd6718c6addbf1395aa6876" +dependencies = [ + "memchr", +] + +[[package]] +name = "winnow" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e7f4ea97f6f78012141bcdb6a216b2609f0979ada50b20ca5b52dde2eac2bb1" +dependencies = [ + "memchr", +] + +[[package]] +name = "winreg" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a277a57398d4bfa075df44f501a17cfdf8542d224f0d36095a2adc7aee4ef0a5" +dependencies = [ + "cfg-if", + "windows-sys 0.48.0", +] + +[[package]] +name = "wit-bindgen-rt" +version = "0.33.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3268f3d866458b787f390cf61f4bbb563b922d091359f9608842999eaee3943c" +dependencies = [ + "bitflags 2.9.0", +] + +[[package]] +name = "write16" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d1890f4022759daae28ed4fe62859b1236caebfc61ede2f63ed4e695f3f6d936" + +[[package]] +name = "writeable" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e9df38ee2d2c3c5948ea468a8406ff0db0b29ae1ffde1bcf20ef305bcc95c51" + +[[package]] +name = "wry" +version = "0.50.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b19b78efae8b853c6c817e8752fc1dbf9cab8a8ffe9c30f399bd750ccf0f0730" +dependencies = [ + "base64 0.22.1", + "block2 0.6.1", + "cookie", + "crossbeam-channel", + "dpi", + "dunce", + "gdkx11", + "gtk", + "html5ever", + "http", + "javascriptcore-rs", + "jni", + "kuchikiki", + "libc", + "ndk 0.9.0", + "objc2 0.6.1", + "objc2-app-kit", + "objc2-core-foundation", + "objc2-foundation 0.3.1", + "objc2-ui-kit", + "objc2-web-kit", + "once_cell", + "percent-encoding", + "raw-window-handle", + "sha2", + "soup3", + "tao-macros", + "thiserror 2.0.12", + "url", + "webkit2gtk", + "webkit2gtk-sys", + "webview2-com", + "windows 0.60.0", + "windows-core 0.60.1", + "windows-version", + "x11-dl", +] + +[[package]] +name = "x11" +version = "2.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "502da5464ccd04011667b11c435cb992822c2c0dbde1770c988480d312a0db2e" +dependencies = [ + "libc", + "pkg-config", +] + +[[package]] +name = "x11-dl" +version = "2.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38735924fedd5314a6e548792904ed8c6de6636285cb9fec04d5b1db85c1516f" +dependencies = [ + "libc", + "once_cell", + "pkg-config", +] + +[[package]] +name = "x11rb" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d91ffca73ee7f68ce055750bf9f6eca0780b8c85eff9bc046a3b0da41755e12" +dependencies = [ + "as-raw-xcb-connection", + "gethostname", + "libc", + "libloading 0.8.6", + "once_cell", + "rustix 0.38.44", + "x11rb-protocol", +] + +[[package]] +name = "x11rb-protocol" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec107c4503ea0b4a98ef47356329af139c0a4f7750e621cf2973cd3385ebcb3d" + +[[package]] +name = "xcursor" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ef33da6b1660b4ddbfb3aef0ade110c8b8a781a3b6382fa5f2b5b040fd55f61" + +[[package]] +name = "xkbcommon-dl" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d039de8032a9a8856a6be89cea3e5d12fdd82306ab7c94d74e6deab2460651c5" +dependencies = [ + "bitflags 2.9.0", + "dlib", + "log", + "once_cell", + "xkeysym", +] + +[[package]] +name = "xkeysym" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9cc00251562a284751c9973bace760d86c0276c471b4be569fe6b068ee97a56" + +[[package]] +name = "xml-rs" +version = "0.8.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c5b940ebc25896e71dd073bad2dbaa2abfe97b0a391415e22ad1326d9c54e3c4" + +[[package]] +name = "xmlwriter" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec7a2a501ed189703dba8b08142f057e887dfc4b2cc4db2d343ac6376ba3e0b9" + +[[package]] +name = "yansi" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfe53a6657fd280eaa890a3bc59152892ffa3e30101319d168b781ed6529b049" + +[[package]] +name = "yazi" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e01738255b5a16e78bbb83e7fbba0a1e7dd506905cfc53f4622d89015a03fbb5" + +[[package]] +name = "yoke" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "120e6aef9aa629e3d4f52dc8cc43a015c7724194c97dfaf45180d2daf2b77f40" +dependencies = [ + "serde", + "stable_deref_trait", + "yoke-derive", + "zerofrom", +] + +[[package]] +name = "yoke-derive" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2380878cad4ac9aac1e2435f3eb4020e8374b5f13c296cb75b4620ff8e229154" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.99", + "synstructure", +] + +[[package]] +name = "zeno" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6df3dc4292935e51816d896edcd52aa30bc297907c26167fec31e2b0c6a32524" + +[[package]] +name = "zerocopy" +version = "0.7.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" +dependencies = [ + "byteorder", + "zerocopy-derive 0.7.35", +] + +[[package]] +name = "zerocopy" +version = "0.8.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd97444d05a4328b90e75e503a34bad781f14e28a823ad3557f0750df1ebcbc6" +dependencies = [ + "zerocopy-derive 0.8.23", +] + +[[package]] +name = "zerocopy-derive" +version = "0.7.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.99", +] + +[[package]] +name = "zerocopy-derive" +version = "0.8.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6352c01d0edd5db859a63e2605f4ea3183ddbd15e2c4a9e7d32184df75e4f154" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.99", +] + +[[package]] +name = "zerofrom" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50cc42e0333e05660c3587f3bf9d0478688e15d870fab3346451ce7f8c9fbea5" +dependencies = [ + "zerofrom-derive", +] + +[[package]] +name = "zerofrom-derive" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.99", + "synstructure", +] + +[[package]] +name = "zeroize" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde" + +[[package]] +name = "zerovec" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa2b893d79df23bfb12d5461018d408ea19dfafe76c2c7ef6d4eba614f8ff079" +dependencies = [ + "yoke", + "zerofrom", + "zerovec-derive", +] + +[[package]] +name = "zerovec-derive" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6eafa6dfb17584ea3e2bd6e76e0cc15ad7af12b09abdd1ca55961bed9b1063c6" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.99", +] + +[[package]] +name = "zune-core" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f423a2c17029964870cfaabb1f13dfab7d092a62a29a89264f4d36990ca414a" + +[[package]] +name = "zune-inflate" +version = "0.2.54" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73ab332fe2f6680068f3582b16a24f90ad7096d5d39b974d1c0aff0125116f02" +dependencies = [ + "simd-adler32", +] + +[[package]] +name = "zune-jpeg" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "99a5bab8d7dedf81405c4bb1f2b83ea057643d9cb28778cea9eecddeedd2e028" +dependencies = [ + "zune-core", +] diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000000000000000000000000000000000000..35c5e7040da1d752a4e184b95ed8c34b2026ec5b --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,179 @@ +[workspace] +members = [ + "editor", + "proc-macros", + "frontend/wasm", + "frontend/src-tauri", + "node-graph/gapplication-io", + "node-graph/gbrush", + "node-graph/gcore", + "node-graph/gstd", + "node-graph/gmath-nodes", + "node-graph/gpath-bool", + "node-graph/graph-craft", + "node-graph/graphene-cli", + "node-graph/graster-nodes", + "node-graph/gsvg-renderer", + "node-graph/interpreted-executor", + "node-graph/node-macro", + "node-graph/preprocessor", + "libraries/dyn-any", + "libraries/path-bool", + "libraries/bezier-rs", + "libraries/math-parser", + "website/other/bezier-rs-demos/wasm", +] +default-members = [ + "editor", + "frontend/wasm", + "node-graph/gbrush", + "node-graph/gcore", + "node-graph/gstd", + "node-graph/gmath-nodes", + "node-graph/gpath-bool", + "node-graph/graph-craft", + "node-graph/graphene-cli", + "node-graph/graster-nodes", + "node-graph/gsvg-renderer", + "node-graph/interpreted-executor", + "node-graph/node-macro", +] +resolver = "2" + +[workspace.dependencies] +# Local dependencies +bezier-rs = { path = "libraries/bezier-rs", features = ["dyn-any", "serde"] } +dyn-any = { path = "libraries/dyn-any", features = ["derive", "glam", "reqwest", "log-bad-types", "rc"] } +preprocessor = { path = "node-graph/preprocessor"} +math-parser = { path = "libraries/math-parser" } +path-bool = { path = "libraries/path-bool" } +graphene-application-io = { path = "node-graph/gapplication-io" } +graphene-brush = { path = "node-graph/gbrush" } +graphene-core = { path = "node-graph/gcore" } +graphene-math-nodes = { path = "node-graph/gmath-nodes" } +graphene-path-bool = { path = "node-graph/gpath-bool" } +graph-craft = { path = "node-graph/graph-craft" } +graphene-raster-nodes = { path = "node-graph/graster-nodes" } +graphene-std = { path = "node-graph/gstd" } +graphene-svg-renderer = { path = "node-graph/gsvg-renderer" } +interpreted-executor = { path = "node-graph/interpreted-executor" } +node-macro = { path = "node-graph/node-macro" } +wgpu-executor = { path = "node-graph/wgpu-executor" } +graphite-proc-macros = { path = "proc-macros" } + +# Workspace dependencies +rustc-hash = "2.0" +bytemuck = { version = "1.13", features = ["derive"] } +serde = { version = "1.0", features = ["derive", "rc"] } +serde_json = "1.0" +serde-wasm-bindgen = "0.6" +reqwest = { version = "0.12", features = ["blocking", "rustls-tls", "json"] } +futures = "0.3" +env_logger = "0.11" +log = "0.4" +bitflags = { version = "2.4", features = ["serde"] } +ctor = "0.2" +convert_case = "0.7" +derivative = "2.2" +thiserror = "2" +anyhow = "1.0" +proc-macro2 = { version = "1", features = [ "span-locations" ] } +quote = "1.0" +axum = "0.8" +chrono = "0.4" +ron = "0.8" +fastnoise-lite = "1.1" +wgpu = { version = "23", features = [ + # We don't have wgpu on multiple threads (yet) https://github.com/gfx-rs/wgpu/blob/trunk/CHANGELOG.md#wgpu-types-now-send-sync-on-wasm + "fragile-send-sync-non-atomic-wasm", + "spirv", + "strict_asserts", +] } +once_cell = "1.13" # Remove when `core::cell::LazyCell` () is stabilized in Rust 1.80 and we bump our MSRV +wasm-bindgen = "=0.2.100" # NOTICE: ensure this stays in sync with the `wasm-bindgen-cli` version in `website/content/volunteer/guide/project-setup/_index.md`. We pin this version because wasm-bindgen upgrades may break various things. +wasm-bindgen-futures = "0.4" +js-sys = "=0.3.77" +web-sys = { version = "=0.3.77", features = [ + "Document", + "DomRect", + "Element", + "HtmlCanvasElement", + "CanvasRenderingContext2d", + "CanvasPattern", + "OffscreenCanvas", + "OffscreenCanvasRenderingContext2d", + "TextMetrics", + "Window", + "IdleRequestOptions", + "ImageData", + "Navigator", + "Gpu", + "HtmlImageElement", + "ImageBitmapRenderingContext", +] } +winit = "0.29" +url = "2.5" +tokio = { version = "1.29", features = ["fs", "macros", "io-std", "rt"] } +vello = { git = "https://github.com/linebender/vello.git", rev = "3275ec8" } # TODO switch back to stable when a release is made +resvg = "0.44" +usvg = "0.44" +rand = { version = "0.9", default-features = false, features = ["std_rng"] } +rand_chacha = "0.9" +glam = { version = "0.29", default-features = false, features = ["serde", "scalar-math", "debug-glam-assert"] } +base64 = "0.22" +image = { version = "0.25", default-features = false, features = ["png", "jpeg", "bmp"] } +parley = "0.5.0" +skrifa = "0.32.0" +pretty_assertions = "1.4.1" +fern = { version = "0.7", features = ["colored"] } +num_enum = "0.7" +num-derive = "0.4" +num-traits = { version = "0.2", default-features = false, features = ["i128"] } +specta = { version = "2.0.0-rc.22", features = [ + "glam", + "derive", + # "typescript", +] } +syn = { version = "2.0", default-features = false, features = [ + "full", + "derive", + "parsing", + "printing", + "visit-mut", + "visit", + "clone-impls", + "extra-traits", + "proc-macro", +] } +kurbo = { version = "0.11.0", features = ["serde"] } +petgraph = { version = "0.7.1", default-features = false, features = [ + "graphmap", +] } +half = { version = "2.4.1", default-features = false, features = ["bytemuck", "serde"] } +tinyvec = { version = "1", features = ["std"] } +criterion = { version = "0.5", features = ["html_reports"] } +iai-callgrind = { version = "0.12.3" } +ndarray = "0.16.1" + +[profile.dev] +opt-level = 1 + +[profile.dev.package] +graphite-editor = { opt-level = 1 } +graphene-core = { opt-level = 1 } +graphene-std = { opt-level = 1 } +interpreted-executor = { opt-level = 1 } # This is a mitigation for https://github.com/rustwasm/wasm-pack/issues/981 which is needed because the node_registry function is too large +graphite-proc-macros = { opt-level = 1 } +image = { opt-level = 2 } +rustc-hash = { opt-level = 3 } +serde_derive = { opt-level = 1 } +specta-macros = { opt-level = 1 } +syn = { opt-level = 1 } + +[profile.release] +lto = "thin" +debug = true + +[profile.profiling] +inherits = "release" +debug = true diff --git a/LICENSE.txt b/LICENSE.txt new file mode 100644 index 0000000000000000000000000000000000000000..261eeb9e9f8b2b4b0d119366dda99c6fd7d35c64 --- /dev/null +++ b/LICENSE.txt @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/README.md b/README.md index 990901a1730ccaf8aa052a4ddf0234bc009fad07..d0bd4a45e3cac51a4879547f09df1fbb2aa7f138 100644 --- a/README.md +++ b/README.md @@ -1,12 +1,22 @@ --- title: Graphite2 -emoji: 📉 -colorFrom: pink -colorTo: yellow +emoji: 🚀 +colorFrom: blue +colorTo: green sdk: gradio -sdk_version: 5.35.0 +sdk_version: "5.35.0" app_file: app.py pinned: false --- +# Graphite2 + + + +Deployed from: https://github.com/seawolf2357/Graphite + +## Features +This Space provides a Gradio interface for the repository's main functionality. +The app.py was automatically generated based on repository analysis. + Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference diff --git a/about.hbs b/about.hbs new file mode 100644 index 0000000000000000000000000000000000000000..e8cb48ace59a487e67f96202aceae16d9c93e5a5 --- /dev/null +++ b/about.hbs @@ -0,0 +1,27 @@ +{{! +Be careful to prevent auto-formatting from breaking this file's indentation. +Replace this file with JSON output once this is resolved: https://github.com/EmbarkStudios/cargo-about/issues/73 + +The `GENERATED_BY_CARGO_ABOUT` prefix is a JS labeled statement +() +used so the reader of the generated file can verify the file does indeed start with that string, +while remaining valid JS for subsequent parsing. +}} +GENERATED_BY_CARGO_ABOUT: [ + {{#each licenses}} + { + licenseName: `{{name}}`, + licenseText: `{{text}}`, + packages: [ + {{#each used_by}} + { + name: `{{crate.name}}`, + version: `{{crate.version}}`, + author: `{{crate.authors}}`, + repository: `{{crate.repository}}`, + }, + {{/each}} + ], + }, + {{/each}} +] diff --git a/about.toml b/about.toml new file mode 100644 index 0000000000000000000000000000000000000000..279ba1068ffa0d0e88702c9a8ff57cc815193917 --- /dev/null +++ b/about.toml @@ -0,0 +1,36 @@ +# Keep this list in sync with those in `/deny.toml` and `/frontend/vite.config.ts`. +accepted = [ + "Apache-2.0 WITH LLVM-exception", + "Apache-2.0", + "BSD-2-Clause", + "BSD-3-Clause", + "BSL-1.0", + "CC0-1.0", + "ISC", + "MIT-0", + "MIT", + "MPL-2.0", + "OpenSSL", + "Unicode-3.0", + "Unicode-DFS-2016", + "Zlib", +] +workarounds = ["ring"] +ignore-build-dependencies = true +ignore-dev-dependencies = true +# Clearly Defined's API would occasionally (every few months) return errors for at least a full day (maybe some weird rate limiting?), but we can just disable to perform local checking (see #1653) +no-clearly-defined = true + +# https://raw.githubusercontent.com/briansmith/webpki/main/LICENSE +# is the ISC license but test code within the repo is BSD-3-Clause, but is not compiled into the crate when we use it +[webpki.clarify] +license = "ISC" +[[webpki.clarify.files]] +path = "LICENSE" +checksum = "5b698ca13897be3afdb7174256fa1574f8c6892b8bea1a66dd6469d3fe27885a" + +[rustls-webpki.clarify] +license = "ISC" +[[rustls-webpki.clarify.files]] +path = "LICENSE" +checksum = "5b698ca13897be3afdb7174256fa1574f8c6892b8bea1a66dd6469d3fe27885a" diff --git a/app.py b/app.py new file mode 100644 index 0000000000000000000000000000000000000000..9cda8f0547bf777f166db357cc15ae0751f5746d --- /dev/null +++ b/app.py @@ -0,0 +1,29 @@ +import gradio as gr + +# Function to simulate the Graphite tool functionality + +def create_graphics_tool(api_key, description): + if not api_key: + return "Error: API key is required. Please enter a valid API key." + if not description: + return "Error: Description is required. Please provide a description for the graphics tool." + # Simulate some processing (this would be replaced with actual functionality) + return f"Graphics tool created with description: '{description}'!" + +# Gradio interface setup + +def main(): + with gr.Blocks() as demo: + gr.Markdown("# Graphite Graphics Tool\n\nCreate your own graphics tool using Graphite!\n\n## Instructions:\n1. Enter your API key (required).\n2. Provide a description for your graphics tool (required).\n3. Click 'Create Tool' to simulate the creation of a graphics tool.") + + api_key = gr.Textbox(label="API Key", placeholder="Enter your API key here...") + description = gr.Textbox(label="Tool Description", placeholder="Describe your graphics tool...") + create_button = gr.Button("Create Tool") + output = gr.Textbox(label="Output") + + create_button.click(create_graphics_tool, inputs=[api_key, description], outputs=output) + + demo.launch() + +if __name__ == '__main__': + main() \ No newline at end of file diff --git a/demo-artwork/changing-seasons.graphite b/demo-artwork/changing-seasons.graphite new file mode 100644 index 0000000000000000000000000000000000000000..4192970aa717d6c0c133299758769191c6fc8414 --- /dev/null +++ b/demo-artwork/changing-seasons.graphite @@ -0,0 +1 @@ +{"network_interface":{"network":{"exports":[{"Node":{"node_id":3143874172491239000,"output_index":0,"lambda":false}}],"nodes":[[10316247453530667000,{"inputs":[{"Node":{"node_id":9079109751490757000,"output_index":0,"lambda":false}},{"Node":{"node_id":12796400626461303056,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":false,"skip_deduplication":false}],[7954638344846060000,{"inputs":[{"Node":{"node_id":5991296268862790000,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"Fill":{"Solid":{"red":0.1875,"green":0.0,"blue":0.0,"alpha":0.203125}}},"exposed":false}},{"Value":{"tagged_value":{"OptionalColor":{"red":0.19140625,"green":0.0,"blue":0.0,"alpha":0.203125}},"exposed":false}},{"Value":{"tagged_value":{"Gradient":{"stops":[[0.0,{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}],[1.0,{"red":1.0,"green":1.0,"blue":1.0,"alpha":1.0}]],"gradient_type":"Linear","start":[0.0,0.5],"end":[1.0,0.5],"transform":[1.0,0.0,0.0,1.0,0.0,0.0]}},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::FillNode"}},"visible":true,"skip_deduplication":false}],[17021405646895729000,{"inputs":[{"Value":{"tagged_value":"None","exposed":false}},{"Value":{"tagged_value":{"GradientStops":[[0.0,{"red":1.0,"green":0.31764707,"blue":0.15686275,"alpha":1.0}],[0.5,{"red":1.0,"green":0.5686275,"blue":0.25490198,"alpha":1.0}],[1.0,{"red":1.0,"green":0.7294118,"blue":0.16078432,"alpha":1.0}]]},"exposed":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_math_nodes::GradientValueNode"}},"visible":true,"skip_deduplication":false}],[8366826746721323000,{"inputs":[{"Node":{"node_id":5591755359500854000,"output_index":0,"lambda":false}},{"Node":{"node_id":13846904447064916285,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[1250460246919467000,{"inputs":[{"Node":{"node_id":4742778578215475000,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"BooleanOperation":"Union"},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::style::Fill","alias":null}},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_path_bool::BooleanOperationNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":2,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::BoundlessFootprintNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::FreezeRealTimeNode"}},"visible":true,"skip_deduplication":false}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MemoNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[5991296268862790000,{"inputs":[{"Value":{"tagged_value":"None","exposed":false}},{"Value":{"tagged_value":{"F64":2000.0},"exposed":false}},{"Value":{"tagged_value":{"F64":1000.0},"exposed":false}},{"Value":{"tagged_value":{"Bool":false},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"Bool":true},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::generator_nodes::RectangleNode"}},"visible":true,"skip_deduplication":false}],[26023588519449590,{"inputs":[{"Node":{"node_id":4002029424845293600,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"Fill":{"Solid":{"red":0.9765625,"green":0.7715821,"blue":0.2861023,"alpha":1.0}}},"exposed":false}},{"Value":{"tagged_value":{"OptionalColor":{"red":0.9765625,"green":0.7715821,"blue":0.2861023,"alpha":1.0}},"exposed":false}},{"Value":{"tagged_value":{"Gradient":{"stops":[[0.0,{"red":1.0,"green":1.0,"blue":1.0,"alpha":1.0}],[1.0,{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}]],"gradient_type":"Linear","start":[0.09778450863315612,0.7264556766766779],"end":[0.09778450863315612,0.3634234796342139],"transform":[-371.95192745983906,4.5550973740038046e-14,0.0,965.1086770605688,766.3711364618157,-61.108677060568766]}},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::FillNode"}},"visible":true,"skip_deduplication":false}],[3143874172491239000,{"inputs":[{"Value":{"tagged_value":{"ArtboardGroup":{"instance":[],"transform":[],"alpha_blending":[],"source_node_id":[]}},"exposed":true}},{"Node":{"node_id":18233215297647862000,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"IVec2":[0,0]},"exposed":false}},{"Value":{"tagged_value":{"IVec2":[2000,1000]},"exposed":false}},{"Value":{"tagged_value":{"Color":{"red":1.0,"green":1.0,"blue":1.0,"alpha":1.0}},"exposed":false}},{"Value":{"tagged_value":{"Bool":true},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":2,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graph_craft::document::value::TaggedValue","alias":null}},"import_index":1}},{"Value":{"tagged_value":{"String":"Artboard"},"exposed":false}},{"Network":{"import_type":{"Concrete":{"name":"graph_craft::document::value::TaggedValue","alias":null}},"import_index":2}},{"Network":{"import_type":{"Concrete":{"name":"graph_craft::document::value::TaggedValue","alias":null}},"import_index":3}},{"Network":{"import_type":{"Concrete":{"name":"graph_craft::document::value::TaggedValue","alias":null}},"import_index":4}},{"Network":{"import_type":{"Concrete":{"name":"graph_craft::document::value::TaggedValue","alias":null}},"import_index":5}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToArtboardNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Network":{"import_type":{"Fn":[{"Concrete":{"name":"core::option::Option>","alias":null}},{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}}]},"import_index":0}},{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::AppendArtboardNode"}},"visible":true,"skip_deduplication":false}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[15908863353600836000,{"inputs":[{"Node":{"node_id":7094974507355892337,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"F64":350.0},"exposed":false}},{"Node":{"node_id":4373650744391914031,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":1}},{"Network":{"import_type":{"Concrete":{"name":"u32","alias":null}},"import_index":2}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::PoissonDiskPointsNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":2,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::BoundlessFootprintNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::FreezeRealTimeNode"}},"visible":true,"skip_deduplication":false}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MemoNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[8895289679682140000,{"inputs":[{"Node":{"node_id":213744308682803360,"output_index":0,"lambda":false}},{"Node":{"node_id":7954638344846060000,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[17725188707009528000,{"inputs":[{"Node":{"node_id":10316247453530667000,"output_index":0,"lambda":false}},{"Node":{"node_id":17025512774010843000,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":false,"skip_deduplication":false}],[5591755359500854000,{"inputs":[{"Value":{"tagged_value":{"GraphicGroup":{"instance":[],"transform":[],"alpha_blending":[],"source_node_id":[]}},"exposed":true}},{"Node":{"node_id":1789832635968548900,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[12796400626461303056,{"inputs":[{"Node":{"node_id":1250460246919467000,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":2,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MemoNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::BoundlessFootprintNode"}},"visible":true,"skip_deduplication":false}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::FreezeRealTimeNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[1789832635968548900,{"inputs":[{"Node":{"node_id":1924303400883620400,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"Fill":{"Solid":{"red":0.99215686,"green":0.49019608,"blue":0.11764706,"alpha":1.0}}},"exposed":false}},{"Value":{"tagged_value":{"OptionalColor":{"red":1.0,"green":1.0,"blue":1.0,"alpha":0.25}},"exposed":false}},{"Value":{"tagged_value":{"Gradient":{"stops":[[0.0,{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}],[1.0,{"red":1.0,"green":1.0,"blue":1.0,"alpha":1.0}]],"gradient_type":"Linear","start":[0.0,0.5],"end":[1.0,0.5],"transform":[1.0,0.0,0.0,1.0,0.0,0.0]}},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::FillNode"}},"visible":true,"skip_deduplication":false}],[17855766443650990000,{"inputs":[{"Value":{"tagged_value":"None","exposed":false}},{"Value":{"tagged_value":{"GradientStops":[[0.0,{"red":0.1764706,"green":0.44313726,"blue":0.05882353,"alpha":1.0}],[0.5,{"red":0.45490196,"green":0.627451,"blue":0.3254902,"alpha":1.0}],[1.0,{"red":1.0,"green":0.5529412,"blue":0.16078432,"alpha":1.0}]]},"exposed":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_math_nodes::GradientValueNode"}},"visible":true,"skip_deduplication":false}],[16084834641749443000,{"inputs":[{"Node":{"node_id":16141281339223525000,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"Fill":{"Solid":{"red":0.99215686,"green":0.49019608,"blue":0.11764706,"alpha":1.0}}},"exposed":false}},{"Value":{"tagged_value":{"OptionalColor":{"red":1.0,"green":1.0,"blue":1.0,"alpha":0.25}},"exposed":false}},{"Value":{"tagged_value":{"Gradient":{"stops":[[0.0,{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}],[1.0,{"red":1.0,"green":1.0,"blue":1.0,"alpha":1.0}]],"gradient_type":"Linear","start":[0.0,0.5],"end":[1.0,0.5],"transform":[1.0,0.0,0.0,1.0,0.0,0.0]}},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::FillNode"}},"visible":true,"skip_deduplication":false}],[1924303400883620400,{"inputs":[{"Value":{"tagged_value":{"VectorData":{"instance":[{"style":{"stroke":{"color":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0},"weight":0.0,"dash_lengths":[],"dash_offset":0.0,"cap":"Butt","join":"Miter","join_miter_limit":4.0,"align":"Center","transform":[1.0,0.0,0.0,1.0,0.0,0.0],"non_scaling":false,"paint_order":"StrokeAbove"},"fill":"None"},"colinear_manipulators":[],"point_domain":{"id":[],"position":[]},"segment_domain":{"id":[],"start_point":[],"end_point":[],"handles":[],"stroke":[]},"region_domain":{"id":[],"segment_range":[],"fill":[]},"upstream_graphic_group":null}],"transform":[[1.0,0.0,0.0,1.0,0.0,0.0]],"alpha_blending":[{"blend_mode":"Normal","opacity":1.0,"fill":1.0,"clip":false}],"source_node_id":[null]}},"exposed":true}},{"Value":{"tagged_value":{"VectorModification":{"points":{"add":[12399235852192450000,16255990754021933000,15620668684239604000,5432878891027338000],"remove":[5992115648840007000],"delta":[[5432878891027338000,[-0.8525377229081244,-6.779663923182397]],[12399235852192450000,[3.4492455418381667,-6.252914951989055]],[15620668684239604000,[-7.105427357601002e-15,61.89300411522633]],[16255990754021933000,[3.423868312757215,60.83950617283953]]]},"segments":{"add":[1366074222973177300,9911415907547690000,3820594103877681000,5933636287523951000],"remove":[16939395239973712000],"start_point":[[5933636287523951000,5432878891027338000],[9911415907547690000,16255990754021933000],[3820594103877681000,15620668684239604000],[1366074222973177300,12399235852192450000]],"end_point":[[5933636287523951000,12399235852192450000],[9911415907547690000,15620668684239604000],[3820594103877681000,5432878891027338000],[1366074222973177300,16255990754021933000]],"handle_primary":[[9911415907547690000,[-0.6380090646381761,1.00935799390129]],[1366074222973177300,[-12.729766803840905,34.6776406035666]],[5933636287523951000,[0.0,0.0]],[3820594103877681000,[-1.2746024488136916,-0.5300005080526233]]],"handle_end":[[3820594103877681000,[-11.281207133058956,31.692729766803836]],[1366074222973177300,[1.0502464055275982,-1.6615353350607336]],[9911415907547690000,[1.1025726645520375,0.4584677151070898]],[5933636287523951000,[0.0,0.0]]],"stroke":[[9911415907547690000,0],[1366074222973177300,0],[3820594103877681000,0],[5933636287523951000,0]]},"regions":{"add":[],"remove":[],"segment_range":[],"fill":[]},"add_g1_continuous":[[{"ty":"Primary","segment":9911415907547690000},{"ty":"End","segment":1366074222973177300}],[{"ty":"Primary","segment":3820594103877681000},{"ty":"End","segment":9911415907547690000}]],"remove_g1_continuous":[[{"ty":"Primary","segment":1366074222973177300},{"ty":"End","segment":5933636287523951000}],[{"ty":"End","segment":3820594103877681000},{"ty":"Primary","segment":16939395239973712000}]]}},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::vector_data::modification::VectorModification","alias":null}},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::vector_data::modification::PathModifyNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[2233138531352324200,{"inputs":[{"Node":{"node_id":366962978353611840,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":2,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MemoNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::BoundlessFootprintNode"}},"visible":true,"skip_deduplication":false}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::FreezeRealTimeNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[4040070953711778000,{"inputs":[{"Node":{"node_id":15908863353600836000,"output_index":0,"lambda":false}},{"Node":{"node_id":2166474486859326700,"output_index":0,"lambda":false}},{"Node":{"node_id":10690271318666670633,"output_index":0,"lambda":false}},{"Node":{"node_id":12004715210677400127,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"U32":0},"exposed":false}},{"Value":{"tagged_value":{"F64":360.0},"exposed":false}},{"Value":{"tagged_value":{"U32":0},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::CopyToPointsNode"}},"visible":true,"skip_deduplication":false}],[17025512774010843000,{"inputs":[{"Node":{"node_id":13712392741217151405,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"Fill":{"Solid":{"red":0.9490196,"green":0.38039216,"blue":0.10980392,"alpha":1.0}}},"exposed":false}},{"Value":{"tagged_value":{"OptionalColor":{"red":0.9490196,"green":0.38039216,"blue":0.10980392,"alpha":1.0}},"exposed":false}},{"Value":{"tagged_value":{"Gradient":{"stops":[[0.3155737704918033,{"red":0.0,"green":0.0,"blue":0.0,"alpha":0.0}],[1.0,{"red":0.0,"green":0.0,"blue":0.0,"alpha":0.203125}]],"gradient_type":"Radial","start":[0.5024847204000202,0.41434795196968177],"end":[0.9633481630366972,0.41434795196968194],"transform":[1191.785811691441,0.0,0.0,1109.5999999999997,274.8958396355149,62.489512494441215]}},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::FillNode"}},"visible":true,"skip_deduplication":false}],[4742778578215475000,{"inputs":[{"Node":{"node_id":6102164880094062000,"output_index":0,"lambda":false}},{"Node":{"node_id":8876924567444570473,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[10463288500489480000,{"inputs":[{"Node":{"node_id":4600332392291315000,"output_index":0,"lambda":false}},{"Node":{"node_id":4040070953711778000,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[3602127523880426500,{"inputs":[{"Value":{"tagged_value":{"RasterData":{"instance":[{"width":0,"height":0,"data":[0,""]}],"transform":[[1.0,0.0,0.0,1.0,0.0,0.0]],"alpha_blending":[{"blend_mode":"Normal","opacity":1.0,"fill":1.0,"clip":false}],"source_node_id":[null]}},"exposed":true}},{"Node":{"node_id":17725188707009528000,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":false,"skip_deduplication":false}],[6102164880094062000,{"inputs":[{"Value":{"tagged_value":{"GraphicGroup":{"instance":[],"transform":[],"alpha_blending":[],"source_node_id":[]}},"exposed":true}},{"Node":{"node_id":14253625255053304000,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[4002029424845293600,{"inputs":[{"Node":{"node_id":16141281339223525000,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"VectorModification":{"points":{"add":[],"remove":[],"delta":[[15620564416450861000,[-47.66529492455423,-18.042524005486992]],[10418348123687606000,[-61.3893894663837,-52.000301612710835]],[6358127410693457000,[-37.72290809327849,-10.54183813443079]],[16211201987812043000,[-7.105427357601002e-15,-23.90123456790124]],[891169987742051100,[-4.148148148148122,-38.03703703703696]],[7888691908524886000,[4.351165980795637,-8.105624142661181]],[12582713598977278000,[9.333333333333268,-66.33333333333327]],[353992768245212100,[-42.27413685969588,-41.62581710194484]],[9664410344080632000,[-35.276890617605005,-25.55103086414088]],[9934671969500465000,[-43.209876543209866,-14.975308641975468]],[16594203120813726000,[-62.53607037678802,-36.02218510909459]],[4839542169175255000,[-127.45378793812174,-12.06205126188287]],[753144493519442600,[-50.013717421124845,21.17283950617286]],[5755835744378529000,[-17.333333333333343,-33.1358024691358]],[11897064075526275000,[-61.65765794556601,-32.902083082000814]],[11874978858302702000,[5.843621399176955,-10.914951989026145]],[4570709177617499000,[-62.76543209876538,-6.827160493827164]],[4305429814263425000,[-22.598416051654286,-32.71009758017498]]]},"segments":{"add":[],"remove":[],"start_point":[],"end_point":[],"handle_primary":[[2092445122112560000,[-7.308641975308667,2.9629629629629903]],[9552874240071498000,[-5.53086419753086,-0.9657064471879552]],[1562499453192082400,[-0.08779149519892826,-1.6680384087791111]],[3359087961315235300,[-0.2881601545358876,-1.8891182956799923]],[5680639457836474000,[0.0,0.0]],[2416974091592514600,[0.0,0.0]],[4590600976245504500,[-6.49657064471878,1.2290809327846404]],[15866454419016458000,[-9.913311783442964,6.121455371873111]],[17948338937502876000,[0.0,0.0]],[3270826560526153000,[-10.966434817733528,4.317749647005792]],[4183498485018509000,[-37.13580246913581,14.485596707818928]],[18320159308706247000,[0.0,0.0]],[16362428386097514000,[-23.70370370370371,19.950617283950606]],[14351209823603001000,[0.0,0.0]],[3138315255762406000,[4.038408779149492,-14.5733882030178]],[8119312711427333000,[0.0,0.0]],[12441313998107066000,[-4.938271604938336,6.518518518518476]]],"handle_end":[[8119312711427333000,[-16.241426611796967,5.355281207133061]],[4183498485018509000,[-21.94787379972564,36.565157750342905]],[3270826560526153000,[-49.33882030178324,27.10562414266127]],[16362428386097514000,[-6.962962962962983,53.17283950617292]],[15866454419016458000,[2.458161865569238,7.637860082304542]],[1562499453192082400,[-0.6668238551234532,2.406364346749864]],[3359087961315235300,[-7.813443072702299,7.725651577503442]],[3138315255762406000,[-8.098765432098759,2.947337553780912]],[17948338937502876000,[-50.30452674897121,26.776406035665325]],[9552874240071498000,[-7.286694101508885,7.55006858710567]],[2416974091592514600,[37.06995884773662,-14.595336076817532]],[7709585677887591000,[-8.603566529492472,0.8779149519890552]],[14351209823603001000,[-7.374485596707803,5.70644718792866]],[4590600976245504500,[14.222222222222207,7.989026063100134]],[2092445122112560000,[-9.086419753086416,21.135802469135797]],[12441313998107066000,[5.171144805176233,13.506721506057374]],[5680639457836474000,[0.2881601545359018,1.8891182956799923]],[18320159308706247000,[-41.26200274348419,15.978052126200277]]],"stroke":[]},"regions":{"add":[],"remove":[],"segment_range":[],"fill":[]},"add_g1_continuous":[],"remove_g1_continuous":[]}},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::vector_data::modification::VectorModification","alias":null}},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::vector_data::modification::PathModifyNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[366962978353611840,{"inputs":[{"Node":{"node_id":8366826746721323000,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"BooleanOperation":"Union"},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::style::Fill","alias":null}},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_path_bool::BooleanOperationNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":2,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::BoundlessFootprintNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::FreezeRealTimeNode"}},"visible":true,"skip_deduplication":false}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MemoNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[16379524086934900000,{"inputs":[{"Node":{"node_id":9609388203059839318,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"Fill":{"Solid":{"red":0.41796875,"green":0.1028595,"blue":0.1028595,"alpha":1.0}}},"exposed":false}},{"Value":{"tagged_value":{"OptionalColor":{"red":0.421875,"green":0.1038208,"blue":0.1038208,"alpha":1.0}},"exposed":false}},{"Value":{"tagged_value":{"Gradient":{"stops":[[0.0,{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}],[1.0,{"red":1.0,"green":1.0,"blue":1.0,"alpha":1.0}]],"gradient_type":"Linear","start":[0.0,0.5],"end":[1.0,0.5],"transform":[1.0,0.0,0.0,1.0,0.0,0.0]}},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::FillNode"}},"visible":true,"skip_deduplication":false}],[4600332392291315000,{"inputs":[{"Node":{"node_id":4040070953711778000,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"Bool":true},"exposed":false}},{"Value":{"tagged_value":{"Bool":false},"exposed":false}},{"Node":{"node_id":11677958249556146000,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"Bool":false},"exposed":false}},{"Value":{"tagged_value":{"Bool":true},"exposed":false}},{"Value":{"tagged_value":{"U32":0},"exposed":false}},{"Value":{"tagged_value":{"U32":0},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::AssignColorsNode"}},"visible":true,"skip_deduplication":false}],[7386572856931342000,{"inputs":[{"Value":{"tagged_value":"None","exposed":false}},{"Value":{"tagged_value":{"F64":100.0},"exposed":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_math_nodes::PercentageValueNode"}},"visible":true,"skip_deduplication":false}],[4373650744391914031,{"inputs":[{"Node":{"node_id":9641606876402405523,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_math_nodes::ToU32Node"}},"visible":true,"skip_deduplication":false}],[16141281339223525000,{"inputs":[{"Value":{"tagged_value":{"VectorData":{"instance":[{"style":{"stroke":{"color":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0},"weight":0.0,"dash_lengths":[],"dash_offset":0.0,"cap":"Butt","join":"Miter","join_miter_limit":4.0,"align":"Center","transform":[1.0,0.0,0.0,1.0,0.0,0.0],"non_scaling":false,"paint_order":"StrokeAbove"},"fill":"None"},"colinear_manipulators":[],"point_domain":{"id":[],"position":[]},"segment_domain":{"id":[],"start_point":[],"end_point":[],"handles":[],"stroke":[]},"region_domain":{"id":[],"segment_range":[],"fill":[]},"upstream_graphic_group":null}],"transform":[[1.0,0.0,0.0,1.0,0.0,0.0]],"alpha_blending":[{"blend_mode":"Normal","opacity":1.0,"fill":1.0,"clip":false}],"source_node_id":[null]}},"exposed":true}},{"Value":{"tagged_value":{"VectorModification":{"points":{"add":[8940743774820468000,11897064075526275000,9664410344080632000,10418348123687606000,16594203120813726000,4839542169175255000,353992768245212100,4305429814263425000,15620564416450861000,4570709177617499000,9934671969500465000,6358127410693457000,753144493519442600,11874978858302702000,7888691908524886000,12582713598977278000,891169987742051100,5755835744378529000,16211201987812043000],"remove":[],"delta":[[7888691908524886000,[66.32098765432096,-154.30864197530863]],[15620564416450861000,[141.77777777777777,-86.60493827160491]],[9664410344080632000,[64.51145851883956,11.32880864191867]],[4305429814263425000,[91.25136529719612,-51.92090379156713]],[9934671969500465000,[125.38271604938268,-124.67901234567891]],[4839542169175255000,[157.56627079134535,-37.10118604950259]],[11874978858302702000,[92.39506172839504,-161.41975308641972]],[6358127410693457000,[115.50617283950618,-132.38271604938265]],[5755835744378529000,[28.444444444444457,-210.4567901234568]],[16211201987812043000,[0.0,-231.0]],[753144493519442600,[136.8395061728395,-177.6172839506173]],[4570709177617499000,[114.716049382716,-90.16049382716052]],[891169987742051100,[63.802469135802426,-190.90123456790127]],[12582713598977278000,[49.135802469135854,-136.33333333333334]],[16594203120813726000,[126.09711290079348,-8.575894451947931]],[353992768245212100,[114.87770338918835,-41.33714586101814]],[10418348123687606000,[112.8352056529406,14.952290638773944]],[11897064075526275000,[72.71938634062775,26.932261408475423]],[8940743774820468000,[0.0,0.0]]]},"segments":{"add":[7709585677887591000,14351209823603001000,18320159308706247000,8119312711427333000,4590600976245504500,17948338937502876000,1562499453192082400,3138315255762406000,2416974091592514600,3270826560526153000,5680639457836474000,3359087961315235300,9552874240071498000,15866454419016458000,4183498485018509000,2092445122112560000,16362428386097514000,12441313998107066000],"remove":[],"start_point":[[4590600976245504500,16594203120813726000],[18320159308706247000,9664410344080632000],[9552874240071498000,753144493519442600],[3359087961315235300,6358127410693457000],[5680639457836474000,9934671969500465000],[8119312711427333000,10418348123687606000],[12441313998107066000,5755835744378529000],[14351209823603001000,11897064075526275000],[2092445122112560000,12582713598977278000],[3138315255762406000,4305429814263425000],[3270826560526153000,4570709177617499000],[4183498485018509000,7888691908524886000],[15866454419016458000,11874978858302702000],[1562499453192082400,353992768245212100],[2416974091592514600,15620564416450861000],[17948338937502876000,4839542169175255000],[7709585677887591000,8940743774820468000],[16362428386097514000,891169987742051100]],"end_point":[[16362428386097514000,5755835744378529000],[3138315255762406000,15620564416450861000],[7709585677887591000,11897064075526275000],[2416974091592514600,4570709177617499000],[12441313998107066000,16211201987812043000],[2092445122112560000,891169987742051100],[4183498485018509000,12582713598977278000],[17948338937502876000,353992768245212100],[4590600976245504500,4839542169175255000],[8119312711427333000,16594203120813726000],[3270826560526153000,9934671969500465000],[18320159308706247000,10418348123687606000],[3359087961315235300,753144493519442600],[1562499453192082400,4305429814263425000],[9552874240071498000,11874978858302702000],[15866454419016458000,7888691908524886000],[5680639457836474000,6358127410693457000],[14351209823603001000,9664410344080632000]],"handle_primary":[[3138315255762406000,[-2.469006630399008,-5.902063388586043]],[3359087961315235300,[2.7654320987655296,-14.419753086419746]],[9552874240071498000,[-21.33333333333331,12.049382716049422]],[18320159308706247000,[0.0,0.0]],[2416974091592514600,[0.0,0.0]],[14351209823603001000,[0.0,0.0]],[7709585677887591000,[0.0,0.0]],[8119312711427333000,[0.0,0.0]],[15866454419016458000,[-10.469135802469168,13.432098765432102]],[3270826560526153000,[-9.086419753086432,-7.506172839506121]],[17948338937502876000,[0.0,0.0]],[2092445122112560000,[-1.5802469135804245,-5.5308641975308035]],[12441313998107066000,[-4.938271604938336,6.518518518518533]],[1562499453192082400,[-15.34246181071461,-3.7168967220297873]],[4183498485018509000,[-6.617283950617207,15.308641975308689]],[16362428386097514000,[-14.913580246913511,12.641975308642031]],[4590600976245504500,[-7.759646437163781,-18.695929243596197]],[5680639457836474000,[0.0,0.0]]],"handle_end":[[7709585677887591000,[-42.51530058403631,-10.382498109968708]],[18320159308706247000,[-24.983271918092953,-7.776766653003392]],[4183498485018509000,[4.938271604938336,-1.1851851851851052]],[3138315255762406000,[-21.33333333333337,3.753086419753061]],[3359087961315235300,[-27.099224819820336,19.753086419753146]],[14351209823603001000,[5.742854988208705,6.327636391047918]],[16362428386097514000,[-8.0,38.419753086419746]],[12441313998107066000,[13.234567901234527,34.5679012345679]],[2416974091592514600,[9.086419753086377,7.506172839506235]],[2092445122112560000,[-20.345679012345613,18.5679012345679]],[1562499453192082400,[2.0974057383288596,5.01376604938514]],[4590600976245504500,[-5.92501398131742,10.665547436428083]],[5680639457836474000,[-2.7654320987655296,14.419753086419746]],[9552874240071498000,[4.938271604938279,11.061728395061806]],[17948338937502876000,[25.51458639999055,20.651563178633637]],[3270826560526153000,[-13.03703703703701,9.679012345678984]],[8119312711427333000,[-40.68684029964413,7.631779585305026]],[15866454419016458000,[0.19753086419757435,13.827160493827137]]],"stroke":[[7709585677887591000,0],[9552874240071498000,0],[4183498485018509000,0],[8119312711427333000,0],[15866454419016458000,0],[18320159308706247000,0],[2416974091592514600,0],[3138315255762406000,0],[17948338937502876000,0],[3270826560526153000,0],[4590600976245504500,0],[1562499453192082400,0],[2092445122112560000,0],[16362428386097514000,0],[5680639457836474000,0],[12441313998107066000,0],[3359087961315235300,0],[14351209823603001000,0]]},"regions":{"add":[],"remove":[],"segment_range":[],"fill":[]},"add_g1_continuous":[[{"ty":"End","segment":1562499453192082400},{"ty":"Primary","segment":3138315255762406000}],[{"ty":"End","segment":2416974091592514600},{"ty":"Primary","segment":3270826560526153000}],[{"ty":"End","segment":5680639457836474000},{"ty":"Primary","segment":3359087961315235300}]],"remove_g1_continuous":[[{"ty":"End","segment":4183498485018509000},{"ty":"Primary","segment":2092445122112560000}]]}},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::vector_data::modification::VectorModification","alias":null}},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::vector_data::modification::PathModifyNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[9641606876402405523,{"inputs":[],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::InstanceIndexNode"}},"visible":true,"skip_deduplication":false}],[9609388203059839318,{"inputs":[{"Value":{"tagged_value":"None","exposed":false}},{"Value":{"tagged_value":{"F64":2000.0},"exposed":false}},{"Value":{"tagged_value":{"F64":1000.0},"exposed":false}},{"Value":{"tagged_value":{"Bool":false},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"Bool":true},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::generator_nodes::RectangleNode"}},"visible":true,"skip_deduplication":false}],[799182088624980700,{"inputs":[{"Node":{"node_id":7386572856931342000,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"F64":100.0},"exposed":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_math_nodes::DivideNode"}},"visible":true,"skip_deduplication":false}],[9079109751490757000,{"inputs":[{"Value":{"tagged_value":{"RasterData":{"instance":[{"width":0,"height":0,"data":[0,""]}],"transform":[[1.0,0.0,0.0,1.0,0.0,0.0]],"alpha_blending":[{"blend_mode":"Normal","opacity":1.0,"fill":1.0,"clip":false}],"source_node_id":[null]}},"exposed":true}},{"Node":{"node_id":2233138531352324200,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":false,"skip_deduplication":false}],[11677958249556146000,{"inputs":[{"Node":{"node_id":17021405646895729000,"output_index":0,"lambda":false}},{"Node":{"node_id":17855766443650990000,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"BlendMode":"Normal"},"exposed":false}},{"Node":{"node_id":7386572856931342000,"output_index":0,"lambda":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::raster::adjustments::BlendNode"}},"visible":true,"skip_deduplication":false}],[13846904447064916285,{"inputs":[{"Node":{"node_id":16084834641749443000,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"ReferencePoint":"CenterLeft"},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"Bool":true},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::MirrorNode"}},"visible":true,"skip_deduplication":false}],[16236970157339521798,{"inputs":[{"Node":{"node_id":8895289679682140000,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"U64":8},"exposed":false}},{"Value":{"tagged_value":{"Bool":false},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::InstanceRepeatNode"}},"visible":true,"skip_deduplication":false}],[7094974507355892337,{"inputs":[{"Value":{"tagged_value":"None","exposed":false}},{"Value":{"tagged_value":{"F64":2000.0},"exposed":false}},{"Value":{"tagged_value":{"F64":1000.0},"exposed":false}},{"Value":{"tagged_value":{"Bool":false},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"Bool":true},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::generator_nodes::RectangleNode"}},"visible":true,"skip_deduplication":false}],[2166474486859326700,{"inputs":[{"Node":{"node_id":13712392741217151405,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"Fill":{"Gradient":{"stops":[[0.0,{"red":1.0,"green":1.0,"blue":1.0,"alpha":0.0}],[0.6885245901639344,{"red":0.08984375,"green":0.08984375,"blue":0.08984375,"alpha":0.08775313}],[1.0,{"red":0.0,"green":0.0,"blue":0.0,"alpha":0.20392157}]],"gradient_type":"Radial","start":[0.5024847204000202,0.41434795196968177],"end":[0.9633481630366972,0.41434795196968194],"transform":[1191.785811691441,0.0,0.0,1109.5999999999997,274.8958396355149,62.489512494441215]}}},"exposed":false}},{"Value":{"tagged_value":{"OptionalColor":{"red":0.9490196,"green":0.38039216,"blue":0.10980392,"alpha":1.0}},"exposed":false}},{"Value":{"tagged_value":{"Gradient":{"stops":[[0.0,{"red":1.0,"green":1.0,"blue":1.0,"alpha":0.0}],[0.6885245901639344,{"red":0.08984375,"green":0.08984375,"blue":0.08984375,"alpha":0.08775313}],[1.0,{"red":0.0,"green":0.0,"blue":0.0,"alpha":0.20392157}]],"gradient_type":"Radial","start":[0.5024847204000202,0.41434795196968177],"end":[0.9633481630366972,0.41434795196968194],"transform":[1191.785811691441,0.0,0.0,1109.5999999999997,274.8958396355149,62.489512494441215]}},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::FillNode"}},"visible":true,"skip_deduplication":false}],[13712392741217151405,{"inputs":[{"Node":{"node_id":5348726859432207000,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":2,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MemoNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::BoundlessFootprintNode"}},"visible":true,"skip_deduplication":false}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::FreezeRealTimeNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[5348726859432207000,{"inputs":[{"Node":{"node_id":12796400626461303056,"output_index":0,"lambda":false}},{"Node":{"node_id":2233138531352324200,"output_index":0,"lambda":false}},{"Node":{"node_id":799182088624980700,"output_index":0,"lambda":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::MorphNode"}},"visible":true,"skip_deduplication":false}],[10690271318666670633,{"inputs":[{"Node":{"node_id":12004715210677400127,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"F64":0.2},"exposed":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_math_nodes::SubtractNode"}},"visible":true,"skip_deduplication":false}],[3430686124240113700,{"inputs":[{"Node":{"node_id":3602127523880426500,"output_index":0,"lambda":false}},{"Node":{"node_id":16379524086934900000,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[18233215297647862000,{"inputs":[{"Node":{"node_id":14337610765966946000,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"DVec2":[1000.0,500.0]},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[1.0,1.0]},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[0.0,0.0]},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[0.5,0.5]},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":1}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":2}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":3}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":4}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":5}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::TransformNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[8876924567444570473,{"inputs":[{"Node":{"node_id":26023588519449590,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"ReferencePoint":"CenterLeft"},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"Bool":true},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::MirrorNode"}},"visible":true,"skip_deduplication":false}],[213744308682803360,{"inputs":[{"Value":{"tagged_value":{"GraphicGroup":{"instance":[],"transform":[],"alpha_blending":[],"source_node_id":[]}},"exposed":true}},{"Node":{"node_id":10463288500489480000,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[12004715210677400127,{"inputs":[{"Node":{"node_id":3223387122603246085,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"F64":1.1},"exposed":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_math_nodes::MaxNode"}},"visible":true,"skip_deduplication":false}],[14250786159408925409,{"inputs":[{"Node":{"node_id":3430686124240113700,"output_index":0,"lambda":false}},{"Node":{"node_id":16236970157339521798,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[14337610765966946000,{"inputs":[{"Node":{"node_id":14250786159408925409,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"GraphicGroup":{"instance":[],"transform":[],"alpha_blending":[],"source_node_id":[]}},"exposed":true}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[14253625255053304000,{"inputs":[{"Node":{"node_id":1924303400883620400,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"Fill":{"Solid":{"red":0.9765625,"green":0.7715821,"blue":0.2861023,"alpha":1.0}}},"exposed":false}},{"Value":{"tagged_value":{"OptionalColor":{"red":0.9765625,"green":0.7715821,"blue":0.2861023,"alpha":1.0}},"exposed":false}},{"Value":{"tagged_value":{"Gradient":{"stops":[[0.0,{"red":1.0,"green":1.0,"blue":1.0,"alpha":1.0}],[1.0,{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}]],"gradient_type":"Linear","start":[0.09778450863315612,0.7264556766766779],"end":[0.09778450863315612,0.3634234796342139],"transform":[-371.95192745983906,4.5550973740038046e-14,0.0,965.1086770605688,766.3711364618157,-61.108677060568766]}},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::FillNode"}},"visible":true,"skip_deduplication":false}],[3223387122603246085,{"inputs":[{"Node":{"node_id":9641606876402405523,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"String":"2 - 0.2A"},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_math_nodes::MathNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]},"network_metadata":{"persistent_metadata":{"node_metadata":[[213744308682803360,{"persistent_metadata":{"reference":"Merge","display_name":"Leaves","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":["Out"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":0}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[16236970157339521798,{"persistent_metadata":{"reference":"Instance Repeat","display_name":"","input_properties":[{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null}],"output_names":["Future>"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[5991296268862790000,{"persistent_metadata":{"reference":"Rectangle","display_name":"","input_properties":[{"input_data":{"input_name":"Primary"},"widget_override":null},{"input_data":{"input_name":"Width"},"widget_override":null},{"input_data":{"input_name":"Height"},"widget_override":null},{"input_data":{"input_name":"Individual Corner Radii"},"widget_override":null},{"input_data":{"input_name":"Corner Radius"},"widget_override":null},{"input_data":{"input_name":"Clamped"},"widget_override":null}],"output_names":["Vector"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[3223387122603246085,{"persistent_metadata":{"reference":"Math","display_name":"","input_properties":[{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null}],"output_names":["Future"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-33,-35]}}},"network_metadata":null}}],[12796400626461303056,{"persistent_metadata":{"reference":"Cache","display_name":"","input_properties":[{"input_data":{},"widget_override":null}],"output_names":["Data"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-19,-25]}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"Freeze Real Time","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Boundless Footprint","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[14,0]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"Memoize","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[15908863353600836000,{"persistent_metadata":{"reference":"Scatter Points","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"min":0.01,"is_integer":false,"mode":"Range","range_max":100,"input_name":"Separation Disk Diameter","range_min":1,"blank_assist":true},"widget_override":"number"},{"input_data":{"mode":"Increment","is_integer":true,"blank_assist":true,"input_name":"Seed","min":0},"widget_override":"number"}],"output_names":["Vector"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-19,-38]}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[2,{"persistent_metadata":{"reference":null,"display_name":"Freeze Real Time","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[14,0]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Boundless Footprint","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[21,0]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"Memoize","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"Poisson-Disk Points","input_properties":[{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[17025512774010843000,{"persistent_metadata":{"reference":"Fill","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Fill"},"widget_override":null},{"input_data":{"input_name":"Backup Color"},"widget_override":null},{"input_data":{"input_name":"Backup Gradient"},"widget_override":null}],"output_names":["Vector"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[3602127523880426500,{"persistent_metadata":{"reference":"Merge","display_name":"Individual Leaf Views","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":["Out"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":3}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[10463288500489480000,{"persistent_metadata":{"reference":"Merge","display_name":"","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":["Out"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[6102164880094062000,{"persistent_metadata":{"reference":"Merge","display_name":"","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":["Out"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":0}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[7094974507355892337,{"persistent_metadata":{"reference":"Rectangle","display_name":"","input_properties":[{"input_data":{"input_name":"Primary"},"widget_override":null},{"input_data":{"input_name":"Width"},"widget_override":null},{"input_data":{"input_name":"Height"},"widget_override":null},{"input_data":{"input_name":"Individual Corner Radii"},"widget_override":null},{"input_data":{"input_name":"Corner Radius"},"widget_override":null},{"input_data":{"input_name":"Clamped"},"widget_override":null}],"output_names":["Vector"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-26,-38]}}},"network_metadata":null}}],[1924303400883620400,{"persistent_metadata":{"reference":"Path","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Modification"},"widget_override":null}],"output_names":["Vector Data"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-44,-19]}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"Path Modify","input_properties":[{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[9641606876402405523,{"persistent_metadata":{"reference":"Instance Index","display_name":"","input_properties":[],"output_names":["Future"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-40,-36]}}},"network_metadata":null}}],[7954638344846060000,{"persistent_metadata":{"reference":"Fill","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Fill"},"widget_override":null},{"input_data":{"input_name":"Backup Color"},"widget_override":null},{"input_data":{"input_name":"Backup Gradient"},"widget_override":null}],"output_names":["Vector"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[4742778578215475000,{"persistent_metadata":{"reference":"Merge","display_name":"","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":["Out"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Absolute":[-30,-22]}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[799182088624980700,{"persistent_metadata":{"reference":"Divide","display_name":"","input_properties":[{"input_data":{"input_name":"Numerator"},"widget_override":null},{"input_data":{"input_name":"Denominator"},"widget_override":null}],"output_names":["Output"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-40,-30]}}},"network_metadata":null}}],[12004715210677400127,{"persistent_metadata":{"reference":"Max","display_name":"","input_properties":[{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null}],"output_names":["Future"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-26,-35]}}},"network_metadata":null}}],[17725188707009528000,{"persistent_metadata":{"reference":"Merge","display_name":"Morph","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":["Out"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Absolute":[9,-29]}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[17855766443650990000,{"persistent_metadata":{"reference":"Gradient Value","display_name":"","input_properties":[{"input_data":{"input_name":"Primary"},"widget_override":null},{"input_data":{"input_name":"Gradient"},"widget_override":null}],"output_names":["GradientStops"],"has_primary_output":true,"locked":false,"pinned":true,"node_type_metadata":{"Node":{"position":{"Absolute":[-47,-40]}}},"network_metadata":null}}],[14337610765966946000,{"persistent_metadata":{"reference":"Merge","display_name":"NOTE: Change seasons with the \"Percentage Value\" parameter","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":["Out"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Absolute":[14,-52]}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[3143874172491239000,{"persistent_metadata":{"reference":"Artboard","display_name":"","input_properties":[{"input_data":{"input_name":"Artboards"},"widget_override":null},{"input_data":{"input_name":"Contents"},"widget_override":"hidden"},{"input_data":{"x":"X","input_name":"Location","y":"Y","unit":" px"},"widget_override":"vec2"},{"input_data":{"input_name":"Dimensions","x":"W","unit":" px","y":"H"},"widget_override":"vec2"},{"input_data":{"input_name":"Background"},"widget_override":"artboard_background"},{"input_data":{"input_name":"Clip"},"widget_override":null}],"output_names":["Out"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Absolute":[26,-56]}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"To Artboard","input_properties":[{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-10,-3]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Append Artboards","input_properties":[{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[6,-4]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-2,-3]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[4600332392291315000,{"persistent_metadata":{"reference":"Assign Colors","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Group"},"widget_override":"hidden"},{"input_data":{"input_name":"Fill"},"widget_override":null},{"input_data":{"input_name":"Stroke"},"widget_override":null},{"input_data":{"input_name":"Gradient"},"widget_override":"assign_colors_gradient"},{"input_data":{"input_name":"Reverse"},"widget_override":null},{"input_data":{"input_name":"Randomize"},"widget_override":null},{"input_data":{"input_name":"Seed"},"widget_override":null},{"input_data":{"input_name":"Repeat Every"},"widget_override":"assign_colors_repeat_every"}],"output_names":["Vector Group"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[2166474486859326700,{"persistent_metadata":{"reference":"Fill","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Fill"},"widget_override":null},{"input_data":{"input_name":"Backup Color"},"widget_override":null},{"input_data":{"input_name":"Backup Gradient"},"widget_override":null}],"output_names":["Vector"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[2,-32]}}},"network_metadata":null}}],[2233138531352324200,{"persistent_metadata":{"reference":"Cache","display_name":"","input_properties":[{"input_data":{},"widget_override":null}],"output_names":["Data"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-19,-16]}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"Freeze Real Time","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"Memoize","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Boundless Footprint","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[14,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[366962978353611840,{"persistent_metadata":{"reference":"Boolean Operation","display_name":"","input_properties":[{"input_data":{"input_name":"Group of Paths"},"widget_override":null},{"input_data":{"input_name":"Operation"},"widget_override":null}],"output_names":["Vector"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-26,-16]}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[2,{"persistent_metadata":{"reference":null,"display_name":"Freeze Real Time","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[14,0]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Boundless Footprint","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[21,0]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"Memoize","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"Boolean Operation","input_properties":[{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[17021405646895729000,{"persistent_metadata":{"reference":"Gradient Value","display_name":"","input_properties":[{"input_data":{"input_name":"Primary"},"widget_override":null},{"input_data":{"input_name":"Gradient"},"widget_override":null}],"output_names":["GradientStops"],"has_primary_output":true,"locked":false,"pinned":true,"node_type_metadata":{"Node":{"position":{"Absolute":[-47,-41]}}},"network_metadata":null}}],[18233215297647862000,{"persistent_metadata":{"reference":"Transform","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"unit":" px","y":"Y","x":"X","input_name":"Translation"},"widget_override":"vec2"},{"input_data":{"input_name":"Rotation"},"widget_override":"transform_rotation"},{"input_data":{"unit":"x","x":"W","y":"H","input_name":"Scale"},"widget_override":"vec2"},{"input_data":{"input_name":"Skew"},"widget_override":"hidden"},{"input_data":{"input_name":"Pivot"},"widget_override":"hidden"}],"output_names":["Data"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"Transform","input_properties":[{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[8366826746721323000,{"persistent_metadata":{"reference":"Merge","display_name":"","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":["Out"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Absolute":[-30,-13]}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[9609388203059839318,{"persistent_metadata":{"reference":"Rectangle","display_name":"","input_properties":[{"input_data":{"input_name":"Primary"},"widget_override":null},{"input_data":{"input_name":"Width"},"widget_override":null},{"input_data":{"input_name":"Height"},"widget_override":null},{"input_data":{"input_name":"Individual Corner Radii"},"widget_override":null},{"input_data":{"input_name":"Corner Radius"},"widget_override":null},{"input_data":{"input_name":"Clamped"},"widget_override":null}],"output_names":["Vector"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[5348726859432207000,{"persistent_metadata":{"reference":"Morph","display_name":"","input_properties":[{"input_data":{"input_name":"Source"},"widget_override":null},{"input_data":{"input_name":"Target"},"widget_override":null},{"input_data":{"input_name":"Time"},"widget_override":null},{"input_data":{"input_name":"Start Index"},"widget_override":null}],"output_names":["Instances"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-12,-32]}}},"network_metadata":null}}],[8876924567444570473,{"persistent_metadata":{"reference":"Mirror","display_name":"","input_properties":[{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null}],"output_names":["Future>"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[14253625255053304000,{"persistent_metadata":{"reference":"Fill","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Fill"},"widget_override":null},{"input_data":{"input_name":"Backup Color"},"widget_override":null},{"input_data":{"input_name":"Backup Gradient"},"widget_override":null}],"output_names":["Vector"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[16084834641749443000,{"persistent_metadata":{"reference":"Fill","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Fill"},"widget_override":null},{"input_data":{"input_name":"Backup Color"},"widget_override":null},{"input_data":{"input_name":"Backup Gradient"},"widget_override":null}],"output_names":["Vector"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[14250786159408925409,{"persistent_metadata":{"reference":"Merge","display_name":"Leaf Levels","input_properties":[{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null}],"output_names":["Out"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":0}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[1250460246919467000,{"persistent_metadata":{"reference":"Boolean Operation","display_name":"","input_properties":[{"input_data":{"input_name":"Group of Paths"},"widget_override":null},{"input_data":{"input_name":"Operation"},"widget_override":null}],"output_names":["Vector"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-26,-25]}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"Boolean Operation","input_properties":[{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Freeze Real Time","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[14,0]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"Memoize","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Boundless Footprint","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[21,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[8895289679682140000,{"persistent_metadata":{"reference":"Merge","display_name":"Depth Shadow","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":["Out"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Absolute":[2,-45]}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[4040070953711778000,{"persistent_metadata":{"reference":"Copy to Points","display_name":"","input_properties":[{"input_data":{"input_name":"Points"},"widget_override":null},{"input_data":{"tooltip":"Artwork to be copied and placed at each point","input_name":"Instance"},"widget_override":null},{"input_data":{"mode":"Range","input_name":"Random Scale Min","min":0,"range_max":2,"range_min":0,"is_integer":false,"unit":"x","tooltip":"Minimum range of randomized sizes given to each instance","blank_assist":true},"widget_override":"number"},{"input_data":{"range_max":2,"mode":"Range","input_name":"Random Scale Max","blank_assist":true,"is_integer":false,"min":0,"tooltip":"Minimum range of randomized sizes given to each instance","unit":"x","range_min":0},"widget_override":"number"},{"input_data":{"range_max":50,"tooltip":"Bias for the probability distribution of randomized sizes (0 is uniform, negatives favor more of small sizes, positives favor more of large sizes)","blank_assist":true,"input_name":"Random Scale Bias","mode":"Range","is_integer":false,"range_min":-50},"widget_override":"number"},{"input_data":{"tooltip":"Seed to determine unique variations on all the randomized instance sizes","min":0,"blank_assist":true,"mode":"Increment","is_integer":true,"input_name":"Random Scale Seed"},"widget_override":"number"},{"input_data":{"unit":"°","mode":"Range","min":0,"input_name":"Random Rotation","is_integer":false,"blank_assist":true,"max":360,"tooltip":"Range of randomized angles given to each instance, in degrees ranging from furthest clockwise to counterclockwise"},"widget_override":"number"},{"input_data":{"input_name":"Random Rotation Seed","tooltip":"Seed to determine unique variations on all the randomized instance angles","blank_assist":true,"is_integer":true,"mode":"Increment","min":0},"widget_override":"number"}],"output_names":["Vector"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-12,-38]}}},"network_metadata":null}}],[11677958249556146000,{"persistent_metadata":{"reference":"Blend","display_name":"","input_properties":[{"input_data":{"input_name":"Over"},"widget_override":null},{"input_data":{"input_name":"Under"},"widget_override":null},{"input_data":{"input_name":"Blend Mode"},"widget_override":null},{"input_data":{"input_name":"Opacity"},"widget_override":null}],"output_names":["Color"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-40,-41]}}},"network_metadata":null}}],[13712392741217151405,{"persistent_metadata":{"reference":"Cache","display_name":"","input_properties":[{"input_data":{},"widget_override":null}],"output_names":["Data"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-5,-32]}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"Freeze Real Time","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Boundless Footprint","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[14,0]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"Memoize","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[5591755359500854000,{"persistent_metadata":{"reference":"Merge","display_name":"","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":["Out"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":0}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[9079109751490757000,{"persistent_metadata":{"reference":"Merge","display_name":"Maple Leaf","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":["Out"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":6}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[13846904447064916285,{"persistent_metadata":{"reference":"Mirror","display_name":"","input_properties":[{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null}],"output_names":["Future>"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[16141281339223525000,{"persistent_metadata":{"reference":"Path","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Modification"},"widget_override":null}],"output_names":["Vector Data"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-58,-22]}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"Path Modify","input_properties":[{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[10316247453530667000,{"persistent_metadata":{"reference":"Merge","display_name":"Oak Leaf","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":["Out"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":1}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[1789832635968548900,{"persistent_metadata":{"reference":"Fill","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Fill"},"widget_override":null},{"input_data":{"input_name":"Backup Color"},"widget_override":null},{"input_data":{"input_name":"Backup Gradient"},"widget_override":null}],"output_names":["Vector"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[16379524086934900000,{"persistent_metadata":{"reference":"Fill","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Fill"},"widget_override":null},{"input_data":{"input_name":"Backup Color"},"widget_override":null},{"input_data":{"input_name":"Backup Gradient"},"widget_override":null}],"output_names":["Vector"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[7386572856931342000,{"persistent_metadata":{"reference":"Percentage Value","display_name":"","input_properties":[{"input_data":{"input_name":"Primary"},"widget_override":null},{"input_data":{"input_name":"Percentage"},"widget_override":null}],"output_names":["f64"],"has_primary_output":true,"locked":false,"pinned":true,"node_type_metadata":{"Node":{"position":{"Absolute":[-47,-39]}}},"network_metadata":null}}],[10690271318666670633,{"persistent_metadata":{"reference":"Subtract","display_name":"","input_properties":[{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null}],"output_names":["Future"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-19,-36]}}},"network_metadata":null}}],[4373650744391914031,{"persistent_metadata":{"reference":"To u32","display_name":"","input_properties":[{"input_data":{},"widget_override":null}],"output_names":["Future"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-33,-37]}}},"network_metadata":null}}],[26023588519449590,{"persistent_metadata":{"reference":"Fill","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Fill"},"widget_override":null},{"input_data":{"input_name":"Backup Color"},"widget_override":null},{"input_data":{"input_name":"Backup Gradient"},"widget_override":null}],"output_names":["Vector"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[3430686124240113700,{"persistent_metadata":{"reference":"Merge","display_name":"Solid Backdrop","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":["Out"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":8}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[4002029424845293600,{"persistent_metadata":{"reference":"Path","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Modification"},"widget_override":null}],"output_names":["Vector Data"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"Path Modify","input_properties":[{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[287.6272550000002,767.89247],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,1278.0,1349.0],"node_graph_top_right":[1980.800048828125,0.0]},"selection_undo_history":[[1924303400883620400,8366826746721323000,16084834641749443000,13846904447064916285,366962978353611840,14253625255053304000,4002029424845293600,6102164880094062000,1250460246919467000,26023588519449590,5591755359500854000,8876924567444570473,4742778578215475000,1789832635968548900,16141281339223525000],[799182088624980700,4002029424845293600,366962978353611840,14253625255053304000,5348726859432207000,4742778578215475000,16084834641749443000,8876924567444570473,1924303400883620400,26023588519449590,16141281339223525000,1789832635968548900,1250460246919467000,13846904447064916285,5591755359500854000,6102164880094062000,8366826746721323000],[8876924567444570473,799182088624980700,26023588519449590,8366826746721323000,16084834641749443000,5591755359500854000,6102164880094062000,16141281339223525000,366962978353611840,1250460246919467000,4002029424845293600,1789832635968548900,1924303400883620400,14253625255053304000,13712392741217151405,13846904447064916285,5348726859432207000,4742778578215475000],[1250460246919467000,16084834641749443000,8366826746721323000,4002029424845293600,799182088624980700,26023588519449590,5348726859432207000,366962978353611840,8876924567444570473,6102164880094062000,13712392741217151405,13846904447064916285,9079109751490757000,5591755359500854000,16141281339223525000,1789832635968548900,1924303400883620400,14253625255053304000,4742778578215475000],[1250460246919467000,5348726859432207000,8366826746721323000,14253625255053304000,5591755359500854000,13846904447064916285,26023588519449590,799182088624980700,4742778578215475000,8876924567444570473,6102164880094062000,1924303400883620400,10316247453530667000,13712392741217151405,366962978353611840,1789832635968548900,4002029424845293600,16084834641749443000,9079109751490757000,16141281339223525000],[4742778578215475000,13712392741217151405,9079109751490757000,8876924567444570473,8366826746721323000,10316247453530667000,5348726859432207000,16084834641749443000,13846904447064916285,5591755359500854000,1789832635968548900,16141281339223525000,1250460246919467000,14253625255053304000,799182088624980700,366962978353611840,4002029424845293600,1924303400883620400,17725188707009528000,26023588519449590,6102164880094062000,17025512774010843000],[5591755359500854000,366962978353611840,4002029424845293600,3602127523880426500,5348726859432207000,13846904447064916285,6102164880094062000,26023588519449590,17025512774010843000,14253625255053304000,17725188707009528000,13712392741217151405,4742778578215475000,1924303400883620400,1789832635968548900,1250460246919467000,16141281339223525000,799182088624980700,8366826746721323000,9079109751490757000,8876924567444570473,10316247453530667000,16084834641749443000],[5591755359500854000,8366826746721323000,366962978353611840,6102164880094062000],[8366826746721323000,6102164880094062000,5591755359500854000,14253625255053304000,1789832635968548900,8876924567444570473,4742778578215475000,13846904447064916285,366962978353611840],[1789832635968548900,8366826746721323000,366962978353611840,5591755359500854000,4742778578215475000,26023588519449590,8876924567444570473,6102164880094062000,13846904447064916285,16084834641749443000,14253625255053304000],[8366826746721323000,13846904447064916285,26023588519449590,8876924567444570473,366962978353611840,4002029424845293600,1789832635968548900,16084834641749443000,4742778578215475000,6102164880094062000,5591755359500854000,1250460246919467000,14253625255053304000],[8876924567444570473,799182088624980700,5348726859432207000,13846904447064916285,366962978353611840,8366826746721323000,5591755359500854000,4742778578215475000,26023588519449590,4002029424845293600,16084834641749443000,14253625255053304000,1250460246919467000,6102164880094062000,1789832635968548900],[6102164880094062000,16084834641749443000,4742778578215475000,366962978353611840,16141281339223525000,1789832635968548900,26023588519449590,5591755359500854000,8876924567444570473,13846904447064916285,1924303400883620400,799182088624980700,8366826746721323000,4002029424845293600,5348726859432207000,1250460246919467000,14253625255053304000],[1250460246919467000,26023588519449590,13846904447064916285,14253625255053304000,1924303400883620400,16141281339223525000,6102164880094062000,4742778578215475000,5348726859432207000,8366826746721323000,799182088624980700,1789832635968548900,4002029424845293600,16084834641749443000,8876924567444570473,366962978353611840,13712392741217151405,5591755359500854000],[8366826746721323000,8876924567444570473,1924303400883620400,1250460246919467000,26023588519449590,366962978353611840,14253625255053304000,6102164880094062000,4002029424845293600,16084834641749443000,4742778578215475000,13846904447064916285,1789832635968548900,5348726859432207000,5591755359500854000,799182088624980700,16141281339223525000],[799182088624980700,8366826746721323000,6102164880094062000,26023588519449590,1250460246919467000,1789832635968548900,16084834641749443000,8876924567444570473,4002029424845293600,4742778578215475000,5348726859432207000,13846904447064916285,366962978353611840,14253625255053304000,5591755359500854000],[16084834641749443000,4742778578215475000,6102164880094062000,13846904447064916285,5348726859432207000,1789832635968548900,1250460246919467000,14253625255053304000,799182088624980700,26023588519449590,5591755359500854000,366962978353611840,8366826746721323000,8876924567444570473],[8876924567444570473,26023588519449590,366962978353611840,1250460246919467000,4742778578215475000,14253625255053304000,5591755359500854000,13846904447064916285,6102164880094062000,4002029424845293600,16084834641749443000,8366826746721323000,5348726859432207000,799182088624980700,1789832635968548900],[5591755359500854000,8876924567444570473,16141281339223525000,4002029424845293600,1789832635968548900,1250460246919467000,5348726859432207000,4742778578215475000,6102164880094062000,366962978353611840,16084834641749443000,8366826746721323000,1924303400883620400,799182088624980700,26023588519449590,14253625255053304000,13846904447064916285],[1924303400883620400,8876924567444570473,1789832635968548900,4002029424845293600,799182088624980700,16084834641749443000,13846904447064916285,8366826746721323000,26023588519449590,6102164880094062000,13712392741217151405,5348726859432207000,366962978353611840,16141281339223525000,14253625255053304000,4742778578215475000,5591755359500854000,1250460246919467000],[5591755359500854000,8366826746721323000,366962978353611840,6102164880094062000],[8366826746721323000,366962978353611840,4742778578215475000,5591755359500854000,6102164880094062000],[14253625255053304000,8366826746721323000,366962978353611840,1789832635968548900,8876924567444570473,5591755359500854000,4742778578215475000,6102164880094062000,13846904447064916285],[4742778578215475000,5591755359500854000,13846904447064916285,366962978353611840,14253625255053304000,8876924567444570473,16084834641749443000,8366826746721323000,1789832635968548900,26023588519449590,6102164880094062000],[1789832635968548900,5591755359500854000,4742778578215475000,8366826746721323000,13846904447064916285,6102164880094062000,1250460246919467000,16084834641749443000,8876924567444570473,14253625255053304000,4002029424845293600,366962978353611840,26023588519449590],[1789832635968548900,5348726859432207000,5591755359500854000,8876924567444570473,8366826746721323000,26023588519449590,6102164880094062000,366962978353611840,16084834641749443000,4742778578215475000,13846904447064916285,14253625255053304000,1250460246919467000,4002029424845293600],[16084834641749443000,4002029424845293600,8366826746721323000,5591755359500854000,6102164880094062000,14253625255053304000,4742778578215475000,8876924567444570473,13846904447064916285,16141281339223525000,1924303400883620400,26023588519449590,1250460246919467000,366962978353611840,1789832635968548900,5348726859432207000],[1789832635968548900,13846904447064916285,1924303400883620400,6102164880094062000,4742778578215475000,8876924567444570473,16084834641749443000,5591755359500854000,13712392741217151405,366962978353611840,16141281339223525000,26023588519449590,8366826746721323000,1250460246919467000,5348726859432207000,4002029424845293600,14253625255053304000],[6102164880094062000,26023588519449590,8876924567444570473,4002029424845293600,4742778578215475000,8366826746721323000,5348726859432207000,5591755359500854000,16141281339223525000,13846904447064916285,1789832635968548900,1250460246919467000,14253625255053304000,16084834641749443000,366962978353611840,1924303400883620400],[1250460246919467000,13712392741217151405,1924303400883620400,16141281339223525000,6102164880094062000,8876924567444570473,366962978353611840,13846904447064916285,8366826746721323000,14253625255053304000,16084834641749443000,1789832635968548900,26023588519449590,4742778578215475000,5348726859432207000,4002029424845293600,5591755359500854000],[9079109751490757000],[9079109751490757000,10316247453530667000],[10316247453530667000,9079109751490757000,5348726859432207000],[10316247453530667000,4742778578215475000,8366826746721323000,1250460246919467000,6102164880094062000,366962978353611840,5591755359500854000,9079109751490757000,5348726859432207000],[4742778578215475000,9079109751490757000,17725188707009528000,10316247453530667000,5591755359500854000,8366826746721323000,5348726859432207000,366962978353611840,1250460246919467000,6102164880094062000],[1250460246919467000,14253625255053304000,1789832635968548900,17725188707009528000,5348726859432207000,5591755359500854000,8366826746721323000,9079109751490757000,10316247453530667000,8876924567444570473,4742778578215475000,13846904447064916285,366962978353611840,6102164880094062000],[4742778578215475000,5348726859432207000,14253625255053304000,10316247453530667000,9079109751490757000,366962978353611840,1789832635968548900,13846904447064916285,5591755359500854000,1250460246919467000,6102164880094062000,799182088624980700,8876924567444570473,8366826746721323000,17725188707009528000],[9079109751490757000,13846904447064916285,5591755359500854000,5348726859432207000,366962978353611840,799182088624980700,4742778578215475000,8876924567444570473,1789832635968548900,14253625255053304000,17725188707009528000,8366826746721323000,10316247453530667000,6102164880094062000,16084834641749443000,26023588519449590,1250460246919467000],[10316247453530667000,366962978353611840,17025512774010843000,799182088624980700,6102164880094062000,16084834641749443000,8366826746721323000,17725188707009528000,5348726859432207000,14253625255053304000,4002029424845293600,1250460246919467000,26023588519449590,9079109751490757000,13846904447064916285,1789832635968548900,5591755359500854000,4742778578215475000,13712392741217151405,8876924567444570473],[17725188707009528000,1250460246919467000,1789832635968548900,366962978353611840,5591755359500854000,9079109751490757000,14253625255053304000,5348726859432207000,4742778578215475000,6102164880094062000,10316247453530667000,799182088624980700,4002029424845293600,13846904447064916285,1924303400883620400,17025512774010843000,8876924567444570473,26023588519449590,13712392741217151405,16141281339223525000,16084834641749443000,8366826746721323000],[9641606876402405523,7094974507355892337,2166474486859326700,4373650744391914031,15908863353600836000,10690271318666670633,5348726859432207000,3223387122603246085,799182088624980700,17725188707009528000,4040070953711778000,12004715210677400127,13712392741217151405],[4040070953711778000,10690271318666670633,9641606876402405523,799182088624980700,12004715210677400127,13712392741217151405,17725188707009528000,2166474486859326700,4373650744391914031,7094974507355892337,3223387122603246085,15908863353600836000,17025512774010843000,5348726859432207000],[10690271318666670633,5348726859432207000,17725188707009528000,3223387122603246085,12004715210677400127,13712392741217151405,1250460246919467000,4373650744391914031,799182088624980700,9641606876402405523,4040070953711778000,7094974507355892337,15908863353600836000,17025512774010843000,2166474486859326700],[7094974507355892337,3223387122603246085,13712392741217151405,10316247453530667000,15908863353600836000,12004715210677400127,4040070953711778000,1250460246919467000,799182088624980700,17725188707009528000,2166474486859326700,5348726859432207000,9641606876402405523,10690271318666670633,17025512774010843000,4373650744391914031],[13712392741217151405,17025512774010843000,15908863353600836000,12004715210677400127,10690271318666670633,17725188707009528000,4373650744391914031,7094974507355892337,3602127523880426500,2166474486859326700,799182088624980700,10316247453530667000,5348726859432207000,3223387122603246085,4040070953711778000,1250460246919467000,9641606876402405523],[17025512774010843000,4040070953711778000,5348726859432207000,12004715210677400127,17725188707009528000,3602127523880426500,10690271318666670633,7094974507355892337,3223387122603246085,1250460246919467000,4742778578215475000,4002029424845293600,10316247453530667000,799182088624980700,4373650744391914031,9641606876402405523,2166474486859326700,13712392741217151405,15908863353600836000],[17725188707009528000,17025512774010843000,13712392741217151405,10690271318666670633,7094974507355892337,12004715210677400127,3223387122603246085,26023588519449590,15908863353600836000,10316247453530667000,3602127523880426500,4002029424845293600,799182088624980700,5348726859432207000,4373650744391914031,9641606876402405523,4742778578215475000,4040070953711778000,2166474486859326700,1250460246919467000],[2166474486859326700,1250460246919467000,3223387122603246085,9641606876402405523,8366826746721323000,799182088624980700,8876924567444570473,16141281339223525000,10316247453530667000,13846904447064916285,26023588519449590,7094974507355892337,15908863353600836000,3602127523880426500,4742778578215475000,5348726859432207000,17025512774010843000,6102164880094062000,4040070953711778000,14253625255053304000,17725188707009528000,10690271318666670633,4002029424845293600,12004715210677400127,13712392741217151405,16084834641749443000,4373650744391914031],[1250460246919467000,3223387122603246085,10316247453530667000,5348726859432207000,2166474486859326700,6102164880094062000,17725188707009528000,12004715210677400127,3602127523880426500,4742778578215475000,4373650744391914031,8876924567444570473,1789832635968548900,799182088624980700,17025512774010843000,4040070953711778000,7094974507355892337,9641606876402405523,5591755359500854000,4002029424845293600,26023588519449590,13712392741217151405,15908863353600836000,16141281339223525000,1924303400883620400,8366826746721323000,13846904447064916285,10690271318666670633,16084834641749443000,14253625255053304000],[13846904447064916285,4373650744391914031,4742778578215475000,366962978353611840,4002029424845293600,17725188707009528000,17025512774010843000,3223387122603246085,15908863353600836000,8876924567444570473,1924303400883620400,8366826746721323000,6102164880094062000,12004715210677400127,16141281339223525000,10316247453530667000,3602127523880426500,1789832635968548900,799182088624980700,7094974507355892337,2166474486859326700,26023588519449590,10690271318666670633,14253625255053304000,1250460246919467000,4040070953711778000,9641606876402405523,13712392741217151405,16084834641749443000,5348726859432207000,5591755359500854000],[9079109751490757000],[17725188707009528000],[13712392741217151405,17725188707009528000,5348726859432207000,17025512774010843000,2166474486859326700],[17725188707009528000,2166474486859326700,17025512774010843000,5348726859432207000,1250460246919467000,13712392741217151405],[2166474486859326700,10316247453530667000,1250460246919467000,17025512774010843000,17725188707009528000,13712392741217151405,5348726859432207000],[17025512774010843000,2166474486859326700,17725188707009528000,5348726859432207000,13712392741217151405,9079109751490757000,1250460246919467000,10316247453530667000],[17025512774010843000,13712392741217151405,8366826746721323000,2166474486859326700,1250460246919467000,5348726859432207000,9079109751490757000,10316247453530667000,5591755359500854000,17725188707009528000],[6102164880094062000,5591755359500854000,17025512774010843000,17725188707009528000,9079109751490757000,1250460246919467000,2166474486859326700,8366826746721323000,10316247453530667000,5348726859432207000,366962978353611840,13712392741217151405],[6102164880094062000,4742778578215475000,1250460246919467000,366962978353611840,1789832635968548900,14253625255053304000,5591755359500854000,2166474486859326700,13712392741217151405,17025512774010843000,17725188707009528000,9079109751490757000,10316247453530667000,5348726859432207000,13846904447064916285,8366826746721323000],[13846904447064916285,16084834641749443000,1789832635968548900,2166474486859326700,5348726859432207000,26023588519449590,1250460246919467000,6102164880094062000,366962978353611840,13712392741217151405,5591755359500854000,9079109751490757000,10316247453530667000,8876924567444570473,17725188707009528000,17025512774010843000,8366826746721323000,14253625255053304000,4742778578215475000,1924303400883620400],[9079109751490757000,366962978353611840,8876924567444570473,2166474486859326700,5348726859432207000,26023588519449590,13712392741217151405,14253625255053304000,10316247453530667000,1924303400883620400,17025512774010843000,6102164880094062000,16084834641749443000,5591755359500854000,1789832635968548900,13846904447064916285,1250460246919467000,17725188707009528000,8366826746721323000,4742778578215475000,4002029424845293600],[4002029424845293600,2166474486859326700,1924303400883620400,16084834641749443000,17725188707009528000,4742778578215475000,13846904447064916285,16141281339223525000,9079109751490757000,6102164880094062000,5591755359500854000,13712392741217151405,26023588519449590,10316247453530667000,17025512774010843000,5348726859432207000,1789832635968548900,366962978353611840,1250460246919467000,8876924567444570473,14253625255053304000,8366826746721323000],[16141281339223525000,4002029424845293600,4742778578215475000,8876924567444570473,799182088624980700,26023588519449590],[16141281339223525000,4742778578215475000,799182088624980700,4002029424845293600,1250460246919467000,26023588519449590,8876924567444570473,6102164880094062000],[14253625255053304000,8876924567444570473,1924303400883620400,1250460246919467000,799182088624980700,16141281339223525000,4742778578215475000,6102164880094062000,26023588519449590,4002029424845293600],[1924303400883620400,6102164880094062000,799182088624980700,1250460246919467000,26023588519449590,5348726859432207000,16141281339223525000,8876924567444570473,4002029424845293600,4742778578215475000,14253625255053304000],[8876924567444570473,799182088624980700,26023588519449590,14253625255053304000,6102164880094062000,1924303400883620400,16141281339223525000,4002029424845293600,366962978353611840,5348726859432207000,4742778578215475000,1250460246919467000],[26023588519449590,4742778578215475000,8366826746721323000,8876924567444570473,1250460246919467000,5348726859432207000,366962978353611840,14253625255053304000,799182088624980700,1924303400883620400,6102164880094062000,16141281339223525000,4002029424845293600],[1924303400883620400,799182088624980700,8366826746721323000,14253625255053304000,16141281339223525000,17725188707009528000,1250460246919467000,26023588519449590,5348726859432207000,4002029424845293600,6102164880094062000,4742778578215475000,8876924567444570473,366962978353611840],[1250460246919467000,8876924567444570473,14253625255053304000,16141281339223525000,1924303400883620400,17725188707009528000,4742778578215475000,13846904447064916285,6102164880094062000,8366826746721323000,16084834641749443000,17025512774010843000,4002029424845293600,799182088624980700,26023588519449590,366962978353611840,5348726859432207000],[14253625255053304000,26023588519449590,4742778578215475000,16084834641749443000,6102164880094062000,366962978353611840,17725188707009528000,799182088624980700,1924303400883620400,16141281339223525000,5591755359500854000,4002029424845293600,1250460246919467000,13846904447064916285,8876924567444570473,5348726859432207000,8366826746721323000,17025512774010843000],[799182088624980700,5591755359500854000,1789832635968548900,8366826746721323000,17025512774010843000,1250460246919467000,26023588519449590,13846904447064916285,1924303400883620400,16084834641749443000,5348726859432207000,14253625255053304000,4742778578215475000,6102164880094062000,8876924567444570473,366962978353611840,17725188707009528000,16141281339223525000,4002029424845293600],[8366826746721323000,4742778578215475000,10316247453530667000,26023588519449590,5348726859432207000,9079109751490757000,799182088624980700,13846904447064916285,14253625255053304000,1789832635968548900,366962978353611840,8876924567444570473,16084834641749443000,17725188707009528000,17025512774010843000,5591755359500854000,16141281339223525000,1924303400883620400,1250460246919467000,6102164880094062000,4002029424845293600],[16084834641749443000,17725188707009528000,16141281339223525000,799182088624980700,14253625255053304000,13712392741217151405,8366826746721323000,17025512774010843000,5348726859432207000,8876924567444570473,4002029424845293600,9079109751490757000,6102164880094062000,1250460246919467000,5591755359500854000,4742778578215475000,1789832635968548900,10316247453530667000,13846904447064916285,366962978353611840,26023588519449590,1924303400883620400],[16084834641749443000,14253625255053304000,1789832635968548900,8876924567444570473,5591755359500854000,366962978353611840,2166474486859326700,17725188707009528000,13712392741217151405,17025512774010843000,4002029424845293600,10316247453530667000,1924303400883620400,26023588519449590,1250460246919467000,9079109751490757000,8366826746721323000,16141281339223525000,799182088624980700,5348726859432207000,13846904447064916285,4742778578215475000,6102164880094062000],[3602127523880426500],[5591755359500854000,8366826746721323000],[6102164880094062000,2233138531352324200,5591755359500854000,8366826746721323000,366962978353611840],[8366826746721323000,13846904447064916285,6102164880094062000,8876924567444570473,5591755359500854000,366962978353611840,2233138531352324200,4742778578215475000,14253625255053304000,1789832635968548900],[13846904447064916285,2233138531352324200,8876924567444570473,366962978353611840,1924303400883620400,1789832635968548900,14253625255053304000,5591755359500854000,16084834641749443000,8366826746721323000,26023588519449590,4742778578215475000,6102164880094062000],[14253625255053304000,4742778578215475000,6102164880094062000,1789832635968548900,12796400626461303056,2233138531352324200,8876924567444570473,26023588519449590,8366826746721323000,366962978353611840,13846904447064916285,1924303400883620400,1250460246919467000,16084834641749443000,5591755359500854000],[4002029424845293600,366962978353611840,1789832635968548900,14253625255053304000,4742778578215475000,13846904447064916285,1924303400883620400,2233138531352324200,1250460246919467000,6102164880094062000,16084834641749443000,12796400626461303056,5591755359500854000,8366826746721323000,26023588519449590,8876924567444570473],[4002029424845293600,14253625255053304000,366962978353611840,1924303400883620400,12796400626461303056,5591755359500854000,16141281339223525000,1789832635968548900,16084834641749443000,26023588519449590,13846904447064916285,8366826746721323000,2233138531352324200,1250460246919467000,6102164880094062000,8876924567444570473,4742778578215475000],[9079109751490757000],[9079109751490757000,10316247453530667000],[10316247453530667000,17725188707009528000,9079109751490757000],[3602127523880426500],[9079109751490757000],[2233138531352324200,9079109751490757000],[2233138531352324200,8366826746721323000,366962978353611840,5591755359500854000,9079109751490757000],[366962978353611840,2233138531352324200,5591755359500854000,8366826746721323000,6102164880094062000,9079109751490757000],[5591755359500854000,9079109751490757000,13846904447064916285,2233138531352324200,366962978353611840,1789832635968548900,14253625255053304000,6102164880094062000,8366826746721323000],[1924303400883620400,13846904447064916285,366962978353611840,14253625255053304000,8366826746721323000,2233138531352324200,16084834641749443000,5591755359500854000,6102164880094062000,9079109751490757000,1789832635968548900],[366962978353611840,8366826746721323000,6102164880094062000,14253625255053304000,2233138531352324200,1924303400883620400,9079109751490757000,5591755359500854000,16084834641749443000,4742778578215475000,13846904447064916285,1789832635968548900],[14253625255053304000,1924303400883620400,26023588519449590,5591755359500854000,16084834641749443000,1789832635968548900,9079109751490757000,13846904447064916285,366962978353611840,6102164880094062000,4742778578215475000,4002029424845293600,2233138531352324200,8366826746721323000],[1789832635968548900,26023588519449590,5591755359500854000,1924303400883620400,16084834641749443000,13846904447064916285,4742778578215475000,9079109751490757000,366962978353611840,8876924567444570473,2233138531352324200,14253625255053304000,8366826746721323000,4002029424845293600,6102164880094062000],[5591755359500854000,16141281339223525000,4742778578215475000,14253625255053304000,26023588519449590,2233138531352324200,13846904447064916285,1789832635968548900,1924303400883620400,16084834641749443000,8366826746721323000,8876924567444570473,6102164880094062000,9079109751490757000,366962978353611840,4002029424845293600],[16141281339223525000,1789832635968548900,16084834641749443000,26023588519449590,8876924567444570473,13846904447064916285,1924303400883620400,2233138531352324200,8366826746721323000,10316247453530667000,5591755359500854000,4742778578215475000,6102164880094062000,366962978353611840,4002029424845293600,9079109751490757000,14253625255053304000],[4002029424845293600,2233138531352324200,1789832635968548900,1924303400883620400,16084834641749443000,1250460246919467000,5591755359500854000,4742778578215475000,14253625255053304000,9079109751490757000,8876924567444570473,10316247453530667000,13846904447064916285,6102164880094062000,8366826746721323000,26023588519449590,12796400626461303056,366962978353611840,16141281339223525000],[]],"selection_redo_history":[]}}},"collapsed":[17725188707009528001,9079109751490757001,3602127523880426501],"name":"changing-seasons.graphite","commit_hash":"e647ca9f91a5e823137122126fe9e980f65d62ea","document_ptz":{"pan":[-999.7861718531644,-499.944688737096],"tilt":0.0,"zoom":0.940975,"flip":false},"document_mode":"DesignMode","view_mode":"Normal","overlays_visibility_settings":{"all":true,"artboard_name":true,"compass_rose":true,"quick_measurement":true,"transform_measurement":true,"transform_cage":true,"hover_outline":true,"selection_outline":true,"pivot":true,"path":true,"anchors":true,"handles":true},"rulers_visible":true,"snapping_state":{"snapping_enabled":true,"grid_snapping":false,"artboards":true,"tolerance":8.0,"bounding_box":{"center_point":true,"corner_point":true,"edge_midpoint":true,"align_with_edges":true,"distribute_evenly":true},"path":{"anchor_point":true,"line_midpoint":true,"along_path":true,"normal_to_path":true,"tangent_to_path":true,"path_intersection_point":true,"align_with_anchor_point":true,"perpendicular_from_endpoint":true},"grid":{"origin":[0.0,0.0],"grid_type":{"Rectangular":{"spacing":[1.0,1.0]}},"rectangular_spacing":[1.0,1.0],"isometric_y_spacing":1.0,"isometric_angle_a":30.0,"isometric_angle_b":30.0,"grid_color":{"red":0.6038274,"green":0.6038274,"blue":0.6038274,"alpha":1.0},"dot_display":false}},"graph_view_overlay_open":false,"graph_fade_artwork_percentage":80.0} \ No newline at end of file diff --git a/demo-artwork/isometric-fountain.graphite b/demo-artwork/isometric-fountain.graphite new file mode 100644 index 0000000000000000000000000000000000000000..c66a44e3eeab2e4d001ab9e46f7d5910c5ad18f9 --- /dev/null +++ b/demo-artwork/isometric-fountain.graphite @@ -0,0 +1 @@ +{"network_interface":{"network":{"exports":[{"Node":{"node_id":15709488322180832347,"output_index":0,"lambda":false}}],"nodes":[[10507084483235320484,{"inputs":[{"Node":{"node_id":9157963288496356916,"output_index":0,"lambda":false}},{"Node":{"node_id":1396768435017101055,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[4741515246389989284,{"inputs":[{"Node":{"node_id":14255588039347536657,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"DVec2":[-261.2435565297001,-70.0]},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[1.0,1.0]},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[0.0,0.0]},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[0.5,0.5]},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":1}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":2}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":3}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":4}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":5}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::TransformNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[4105329493214975815,{"inputs":[{"Node":{"node_id":12931264630175648107,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"DVec2":[-261.24355652969916,-70.0]},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[1.0,1.0]},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[0.0,0.0]},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[0.5,0.5]},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":1}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":2}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":3}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":4}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":5}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::TransformNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[16229837691656808412,{"inputs":[{"Value":{"tagged_value":{"VectorData":{"instance":[{"style":{"stroke":{"color":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0},"weight":0.0,"dash_lengths":[],"dash_offset":0.0,"cap":"Butt","join":"Miter","join_miter_limit":4.0,"align":"Center","transform":[1.0,0.0,0.0,1.0,0.0,0.0],"non_scaling":false,"paint_order":"StrokeAbove"},"fill":"None"},"colinear_manipulators":[],"point_domain":{"id":[],"position":[]},"segment_domain":{"id":[],"start_point":[],"end_point":[],"handles":[],"stroke":[]},"region_domain":{"id":[],"segment_range":[],"fill":[]},"upstream_graphic_group":null}],"transform":[[1.0,0.0,0.0,1.0,0.0,0.0]],"alpha_blending":[{"blend_mode":"Normal","opacity":1.0,"fill":1.0,"clip":false}],"source_node_id":[null]}},"exposed":true}},{"Value":{"tagged_value":{"VectorModification":{"points":{"add":[1,2,3,4],"remove":[],"delta":[[1,[74.85684586229115,93.12923138495351]],[2,[76.83345669875837,107.20900827532364]],[4,[119.2038270691288,10.452135486817724]],[3,[130.01864188394373,17.639788893964138]]]},"segments":{"add":[1,2,3,4],"remove":[],"start_point":[[2,2],[3,3],[1,1],[4,4]],"end_point":[[1,2],[4,1],[3,4],[2,3]],"handle_primary":[[3,[0.0,0.0]],[4,[0.0,0.0]],[1,[0.0,0.0]],[2,[0.0,0.0]]],"handle_end":[[1,[0.0,0.0]],[4,[43.97876382175265,-36.84748630595526]],[3,[0.0,0.0]],[2,[-7.85185185185199,56.395434425300664]]],"stroke":[[4,0],[1,0],[3,0],[2,0]]},"regions":{"add":[0],"remove":[],"segment_range":[[0,{"start":1,"end":4}]],"fill":[[0,0]]},"add_g1_continuous":[],"remove_g1_continuous":[]}},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::vector_data::modification::VectorModification","alias":null}},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::vector_data::modification::PathModifyNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[12172015233077238737,{"inputs":[{"Node":{"node_id":13287180494862716983,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"OptionalColor":{"red":0.9372549,"green":0.90588236,"blue":0.7764706,"alpha":0.7490196}},"exposed":false}},{"Value":{"tagged_value":{"F64":3.0},"exposed":false}},{"Value":{"tagged_value":{"StrokeAlign":"Center"},"exposed":false}},{"Value":{"tagged_value":{"StrokeCap":"Round"},"exposed":false}},{"Value":{"tagged_value":{"StrokeJoin":"Miter"},"exposed":false}},{"Value":{"tagged_value":{"F64":4.0},"exposed":false}},{"Value":{"tagged_value":{"PaintOrder":"StrokeAbove"},"exposed":false}},{"Value":{"tagged_value":{"VecF64":[]},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::StrokeNode"}},"visible":true,"skip_deduplication":false}],[15166516760575860563,{"inputs":[{"Node":{"node_id":18085100003956405261,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"DVec2":[-36.95875397623445,-115.11453403741598]},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[1.442673035713692,1.442673035713692]},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[0.0,0.0]},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[0.5,0.5]},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":1}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":2}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":3}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":4}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":5}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::TransformNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[10477328336261010694,{"inputs":[{"Node":{"node_id":10189927996178548902,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"DVec2":[-261.24355652970024,-64.0]},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[1.0,1.0]},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[0.0,0.0]},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[0.5,0.5]},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":1}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":2}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":3}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":4}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":5}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::TransformNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[3185536512640676801,{"inputs":[{"Value":{"tagged_value":{"GraphicGroup":{"instance":[],"transform":[],"alpha_blending":[],"source_node_id":[]}},"exposed":true}},{"Node":{"node_id":4101813853952238986,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[5258402282444994019,{"inputs":[{"Node":{"node_id":958845362613832240,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"DVec2":[-299.97967195575075,-74.37931084632919]},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[0.9999999999999984,0.9999999999999984]},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[0.0,0.0]},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[0.5,0.5]},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":1}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":2}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":3}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":4}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":5}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::TransformNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[3970872207068447290,{"inputs":[{"Node":{"node_id":2077983679740571162,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"DVec2":[1.2314781197853364,-154.7967075368743]},"exposed":false}},{"Value":{"tagged_value":{"F64":-1.0453527814904993},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[1.809730022247584,0.552568608414892]},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[-0.4027772116731048,0.0]},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[0.5,0.5]},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":1}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":2}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":3}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":4}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":5}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::TransformNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[9115451226763736660,{"inputs":[{"Node":{"node_id":7067047867039575315,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"Fill":{"Gradient":{"stops":[[0.0,{"red":0.4745098,"green":0.68235296,"blue":0.60784316,"alpha":1.0}],[1.0,{"red":0.5568628,"green":0.7529412,"blue":0.6392157,"alpha":1.0}]],"gradient_type":"Linear","start":[0.02103945787988068,0.9859744936226362],"end":[0.6072632276568447,0.28531051081023584],"transform":[864.8574591113804,0.0,0.0,195.5288174655342,170.80386791692547,510.2135732107871]}}},"exposed":false}},{"Value":{"tagged_value":{"OptionalColor":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}},"exposed":false}},{"Value":{"tagged_value":{"Gradient":{"stops":[[0.0,{"red":0.4745098,"green":0.68235296,"blue":0.60784316,"alpha":1.0}],[1.0,{"red":0.5568628,"green":0.7529412,"blue":0.6392157,"alpha":1.0}]],"gradient_type":"Linear","start":[0.02103945787988068,0.9859744936226362],"end":[0.6072632276568447,0.28531051081023584],"transform":[864.8574591113804,0.0,0.0,195.5288174655342,170.80386791692547,510.2135732107871]}},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::FillNode"}},"visible":true,"skip_deduplication":false}],[11860177410232537211,{"inputs":[{"Node":{"node_id":5882319123081134737,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"BooleanOperation":"SubtractFront"},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":2,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::style::Fill","alias":null}},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_path_bool::BooleanOperationNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::BoundlessFootprintNode"}},"visible":true,"skip_deduplication":false}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::FreezeRealTimeNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[14019233912018234740,{"inputs":[{"Node":{"node_id":16069762220015310717,"output_index":0,"lambda":false}},{"Node":{"node_id":17785019773455930267,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[4197544064668946479,{"inputs":[{"Value":{"tagged_value":{"VectorData":{"instance":[{"style":{"stroke":{"color":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0},"weight":0.0,"dash_lengths":[],"dash_offset":0.0,"cap":"Butt","join":"Miter","join_miter_limit":4.0,"align":"Center","transform":[1.0,0.0,0.0,1.0,0.0,0.0],"non_scaling":false,"paint_order":"StrokeAbove"},"fill":"None"},"colinear_manipulators":[],"point_domain":{"id":[],"position":[]},"segment_domain":{"id":[],"start_point":[],"end_point":[],"handles":[],"stroke":[]},"region_domain":{"id":[],"segment_range":[],"fill":[]},"upstream_graphic_group":null}],"transform":[[1.0,0.0,0.0,1.0,0.0,0.0]],"alpha_blending":[{"blend_mode":"Normal","opacity":1.0,"fill":1.0,"clip":false}],"source_node_id":[null]}},"exposed":true}},{"Value":{"tagged_value":{"VectorModification":{"points":{"add":[1,2,3,4,5,6,7],"remove":[],"delta":[[7,[578.4678751731759,580.0]],[5,[615.7883832488644,560.0000000000001]],[2,[363.87495373796554,587.4999999999999]],[3,[345.21469970012123,592.5]],[4,[419.8557158514987,612.5]],[6,[634.4486372867087,565.0]],[1,[391.8653347947321,595.0]]]},"segments":{"add":[1,2,3,4,5,6],"remove":[],"start_point":[[3,3],[5,5],[2,2],[4,4],[6,6],[1,1]],"end_point":[[1,2],[6,7],[4,5],[3,4],[2,3],[5,6]],"handle_primary":[[6,[0.0,0.0]],[5,[0.0,0.0]],[2,[0.0,0.0]],[4,[0.0,0.0]],[3,[0.0,0.0]],[1,[0.0,0.0]]],"handle_end":[[2,[0.0,0.0]],[1,[0.0,0.0]],[4,[0.0,0.0]],[3,[0.0,0.0]],[5,[0.0,0.0]],[6,[0.0,0.0]]],"stroke":[[2,0],[4,0],[3,0],[5,0],[1,0],[6,0]]},"regions":{"add":[],"remove":[],"segment_range":[],"fill":[]},"add_g1_continuous":[],"remove_g1_continuous":[]}},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::vector_data::modification::VectorModification","alias":null}},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::vector_data::modification::PathModifyNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[5448146793323825465,{"inputs":[{"Value":{"tagged_value":{"VectorData":{"instance":[{"style":{"stroke":{"color":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0},"weight":0.0,"dash_lengths":[],"dash_offset":0.0,"cap":"Butt","join":"Miter","join_miter_limit":4.0,"align":"Center","transform":[1.0,0.0,0.0,1.0,0.0,0.0],"non_scaling":false,"paint_order":"StrokeAbove"},"fill":"None"},"colinear_manipulators":[],"point_domain":{"id":[],"position":[]},"segment_domain":{"id":[],"start_point":[],"end_point":[],"handles":[],"stroke":[]},"region_domain":{"id":[],"segment_range":[],"fill":[]},"upstream_graphic_group":null}],"transform":[[1.0,0.0,0.0,1.0,0.0,0.0]],"alpha_blending":[{"blend_mode":"Normal","opacity":1.0,"fill":1.0,"clip":false}],"source_node_id":[null]}},"exposed":true}},{"Value":{"tagged_value":{"VectorModification":{"points":{"add":[1,2,3,4],"remove":[],"delta":[[3,[783.730669589464,550.0]],[1,[709.0896534380863,630.0]],[4,[895.6921938165308,580.0000000000001]],[2,[597.1281292110198,599.9999999999999]]]},"segments":{"add":[1,2,3,4],"remove":[],"start_point":[[3,3],[2,2],[4,4],[1,1]],"end_point":[[2,3],[4,1],[1,2],[3,4]],"handle_primary":[[1,[0.0,0.0]],[2,[0.0,0.0]],[4,[0.0,0.0]],[3,[0.0,0.0]]],"handle_end":[[3,[0.0,0.0]],[2,[0.0,0.0]],[1,[0.0,0.0]],[4,[0.0,0.0]]],"stroke":[[1,0],[4,0],[2,0],[3,0]]},"regions":{"add":[0],"remove":[],"segment_range":[[0,{"start":1,"end":4}]],"fill":[[0,0]]},"add_g1_continuous":[],"remove_g1_continuous":[]}},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::vector_data::modification::VectorModification","alias":null}},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::vector_data::modification::PathModifyNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[4187349759243468746,{"inputs":[{"Value":{"tagged_value":{"VectorData":{"instance":[{"style":{"stroke":{"color":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0},"weight":0.0,"dash_lengths":[],"dash_offset":0.0,"cap":"Butt","join":"Miter","join_miter_limit":4.0,"align":"Center","transform":[1.0,0.0,0.0,1.0,0.0,0.0],"non_scaling":false,"paint_order":"StrokeAbove"},"fill":"None"},"colinear_manipulators":[],"point_domain":{"id":[],"position":[]},"segment_domain":{"id":[],"start_point":[],"end_point":[],"handles":[],"stroke":[]},"region_domain":{"id":[],"segment_range":[],"fill":[]},"upstream_graphic_group":null}],"transform":[[1.0,0.0,0.0,1.0,0.0,0.0]],"alpha_blending":[{"blend_mode":"Normal","opacity":1.0,"fill":1.0,"clip":false}],"source_node_id":[null]}},"exposed":true}},{"Value":{"tagged_value":{"VectorModification":{"points":{"add":[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18],"remove":[],"delta":[[9,[606.0246913580247,486.803840877915]],[14,[650.6666666666667,398.2222222222223]],[13,[609.7997256515774,497.6899862825788]],[17,[668.3566529492455,433.2510288065844]],[11,[615.6378600823045,431.5390946502058]],[2,[533.9259259259258,420.7407407407407]],[18,[618.4910836762688,499.9725651577503]],[12,[609.0096021947874,496.4609053497942]],[15,[615.4183813443072,491.19341563786]],[1,[583.5500685871057,499.53360768175577]],[10,[607.8683127572016,488.3840877914952]],[3,[589.8710562414265,497.0754458161865]],[6,[594.4362139917694,493.6515775034293]],[16,[616.0751917898693,491.077444156548]],[8,[580.9382716049382,401.9753086419752]],[7,[596.3676268861453,491.9835390946502]],[5,[574.0246913580246,440.2962962962963]],[4,[591.18792866941,498.3045267489712]]]},"segments":{"add":[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18],"remove":[],"start_point":[[17,17],[5,5],[13,13],[1,1],[2,2],[7,7],[18,18],[4,4],[15,15],[6,6],[12,12],[3,3],[8,8],[11,11],[16,16],[9,9],[10,10],[14,14]],"end_point":[[5,6],[8,9],[1,2],[17,18],[6,7],[3,4],[2,3],[15,16],[13,14],[9,10],[12,13],[18,1],[10,11],[7,8],[14,15],[11,12],[16,17],[4,5]],"handle_primary":[[15,[0.0,0.0]],[6,[0.0,0.0]],[12,[0.0,0.0]],[16,[0.0,0.0]],[5,[18.392318244170156,23.769547325102906]],[9,[0.0,0.0]],[1,[0.0,0.0]],[3,[0.0,0.0]],[7,[0.0,0.0]],[8,[22.10150891632361,44.44444444444463]],[13,[0.0,0.0]],[10,[0.0,0.0]],[18,[-6.945585968035971,18.68277302655963]],[4,[0.0,0.0]],[2,[44.005486968450214,35.16049382716062]],[17,[-38.27709190672158,34.5020576131688]],[11,[-3.906721536351256,29.62962962962956]],[14,[-18.3045267489714,37.31138545953348]]],"handle_end":[[8,null],[4,[21.113854595336193,37.201646090535064]],[5,null],[9,[0.0,0.0]],[11,[0.0,0.0]],[14,null],[7,[25.964334705075316,61.47599451303165]],[2,null],[18,[7.8075669002856785,13.340866152962064]],[15,[0.0,0.0]],[13,[-23.747599451303245,35.4677640603565]],[6,[0.0,0.0]],[16,[-35.29218106995893,26.337448559670804]],[1,[48.21947873799752,48.855967078189394]],[3,[0.0,0.0]],[17,null],[12,[0.0,0.0]],[10,[-6.189300411522709,26.732510288065782]]],"stroke":[[13,0],[18,0],[17,0],[1,0],[7,0],[8,0],[3,0],[4,0],[10,0],[5,0],[16,0],[6,0],[15,0],[12,0],[2,0],[11,0],[14,0],[9,0]]},"regions":{"add":[0],"remove":[],"segment_range":[[0,{"start":1,"end":18}]],"fill":[[0,0]]},"add_g1_continuous":[],"remove_g1_continuous":[]}},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::vector_data::modification::VectorModification","alias":null}},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::vector_data::modification::PathModifyNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[9684750473849891261,{"inputs":[{"Node":{"node_id":70804263053697201,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"Fill":{"Gradient":{"stops":[[0.0,{"red":0.96862745,"green":0.8352941,"blue":0.62352943,"alpha":1.0}],[0.5772391174087621,{"red":0.7921569,"green":0.8019608,"blue":0.6450981,"alpha":1.0}],[1.0,{"red":0.6156863,"green":0.76862746,"blue":0.6666667,"alpha":1.0}]],"gradient_type":"Linear","start":[0.0,0.5],"end":[1.0,0.5],"transform":[1306.217782649108,0.0,0.0,739.9999999999992,405.99999999999864,284.9999999999999]}}},"exposed":false}},{"Value":{"tagged_value":{"OptionalColor":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}},"exposed":false}},{"Value":{"tagged_value":{"Gradient":{"stops":[[0.0,{"red":0.96862745,"green":0.8352941,"blue":0.62352943,"alpha":1.0}],[0.5772391174087621,{"red":0.7921569,"green":0.8019608,"blue":0.6450981,"alpha":1.0}],[1.0,{"red":0.6156863,"green":0.76862746,"blue":0.6666667,"alpha":1.0}]],"gradient_type":"Linear","start":[0.0,0.5],"end":[1.0,0.5],"transform":[1306.217782649108,0.0,0.0,739.9999999999992,405.99999999999864,284.9999999999999]}},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::FillNode"}},"visible":true,"skip_deduplication":false}],[13531127678140037818,{"inputs":[{"Node":{"node_id":3970872207068447290,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"Fill":{"Solid":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}}},"exposed":false}},{"Value":{"tagged_value":{"OptionalColor":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}},"exposed":false}},{"Value":{"tagged_value":{"Gradient":{"stops":[[0.0,{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}],[1.0,{"red":1.0,"green":1.0,"blue":1.0,"alpha":1.0}]],"gradient_type":"Linear","start":[0.0,0.5],"end":[1.0,0.5],"transform":[1.0,0.0,0.0,1.0,0.0,0.0]}},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::FillNode"}},"visible":true,"skip_deduplication":false}],[14055195208113082127,{"inputs":[{"Node":{"node_id":2510483139353274965,"output_index":0,"lambda":false}},{"Node":{"node_id":12360435709959435360,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[18187802220803838247,{"inputs":[{"Node":{"node_id":11634445349252640936,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"BlendMode":"Screen"},"exposed":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::blending_nodes::BlendModeNode"}},"visible":true,"skip_deduplication":false}],[8015732980153557800,{"inputs":[{"Node":{"node_id":3806549994589872867,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"DVec2":[-261.2435565297002,-70.0]},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[1.0,1.0]},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[0.0,0.0]},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[0.5,0.5]},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":1}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":2}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":3}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":4}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":5}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::TransformNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[2791109467690716388,{"inputs":[{"Value":{"tagged_value":{"VectorData":{"instance":[{"style":{"stroke":{"color":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0},"weight":0.0,"dash_lengths":[],"dash_offset":0.0,"cap":"Butt","join":"Miter","join_miter_limit":4.0,"align":"Center","transform":[1.0,0.0,0.0,1.0,0.0,0.0],"non_scaling":false,"paint_order":"StrokeAbove"},"fill":"None"},"colinear_manipulators":[],"point_domain":{"id":[],"position":[]},"segment_domain":{"id":[],"start_point":[],"end_point":[],"handles":[],"stroke":[]},"region_domain":{"id":[],"segment_range":[],"fill":[]},"upstream_graphic_group":null}],"transform":[[1.0,0.0,0.0,1.0,0.0,0.0]],"alpha_blending":[{"blend_mode":"Normal","opacity":1.0,"fill":1.0,"clip":false}],"source_node_id":[null]}},"exposed":true}},{"Value":{"tagged_value":{"VectorModification":{"points":{"add":[1,2,3,4,5,6],"remove":[],"delta":[[2,[877.0319397786863,584.9999999999998]],[6,[1044.9742261192855,480.0]],[5,[596.8912314546803,600.0634765625]],[1,[1156.9357503463468,509.9999999999987]],[3,[783.7306695894646,560.0]],[4,[615.5514854925251,605.0634765625002]]]},"segments":{"add":[1,2,3,4,5,6],"remove":[],"start_point":[[3,3],[2,2],[4,4],[1,1],[5,5],[6,6]],"end_point":[[4,5],[2,3],[6,1],[1,2],[3,4],[5,6]],"handle_primary":[[2,[0.0,0.0]],[1,[0.0,0.0]],[6,[0.0,0.0]],[3,null],[4,null],[5,[448.0829946646052,-120.0634765625]]],"handle_end":[[6,[0.0,0.0]],[1,[0.0,0.0]],[2,null],[5,null],[4,null],[3,null]],"stroke":[[3,0],[6,0],[4,0],[2,0],[1,0],[5,0]]},"regions":{"add":[0],"remove":[],"segment_range":[[0,{"start":1,"end":6}]],"fill":[[0,0]]},"add_g1_continuous":[],"remove_g1_continuous":[]}},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::vector_data::modification::VectorModification","alias":null}},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::vector_data::modification::PathModifyNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[13747030364552895864,{"inputs":[{"Value":{"tagged_value":{"VectorData":{"instance":[{"style":{"stroke":{"color":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0},"weight":0.0,"dash_lengths":[],"dash_offset":0.0,"cap":"Butt","join":"Miter","join_miter_limit":4.0,"align":"Center","transform":[1.0,0.0,0.0,1.0,0.0,0.0],"non_scaling":false,"paint_order":"StrokeAbove"},"fill":"None"},"colinear_manipulators":[],"point_domain":{"id":[],"position":[]},"segment_domain":{"id":[],"start_point":[],"end_point":[],"handles":[],"stroke":[]},"region_domain":{"id":[],"segment_range":[],"fill":[]},"upstream_graphic_group":null}],"transform":[[1.0,0.0,0.0,1.0,0.0,0.0]],"alpha_blending":[{"blend_mode":"Normal","opacity":1.0,"fill":1.0,"clip":false}],"source_node_id":[null]}},"exposed":true}},{"Value":{"tagged_value":{"VectorModification":{"points":{"add":[1,2,3,4,5],"remove":[],"delta":[[2,[1231.576766497729,510.00000000000233]],[1,[709.0896534380864,650.0]],[3,[1231.6308657449686,540.0144958496094]],[5,[709.0896534380863,660.0]],[4,[1156.9357503463516,540.0]]]},"segments":{"add":[1,2,3,4,5],"remove":[],"start_point":[[4,4],[2,2],[1,1],[3,3],[5,5]],"end_point":[[1,2],[2,3],[4,5],[5,1],[3,4]],"handle_primary":[[1,[0.0,0.0]],[5,[0.0,0.0]],[4,[0.0,0.0]],[3,[-74.69511539861696,-0.014495849609375]],[2,[0.0,0.0]]],"handle_end":[[1,[0.0,0.0]],[2,null],[4,[0.0,0.0]],[3,null],[5,[-2.273736754432321e-13,-2.273736754432321e-13]]],"stroke":[[5,0],[3,0],[1,0],[2,0],[4,0]]},"regions":{"add":[0],"remove":[],"segment_range":[[0,{"start":1,"end":5}]],"fill":[[0,0]]},"add_g1_continuous":[],"remove_g1_continuous":[]}},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::vector_data::modification::VectorModification","alias":null}},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::vector_data::modification::PathModifyNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[8034980397175569257,{"inputs":[{"Node":{"node_id":4243146970185091100,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"DVec2":[55.4066256813212,48.820258260598735]},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[1.093432966432927,1.093432966432927]},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[0.0,0.0]},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[0.5,0.5]},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":1}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":2}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":3}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":4}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":5}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::TransformNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[11776939455674933130,{"inputs":[{"Value":{"tagged_value":{"GraphicGroup":{"instance":[],"transform":[],"alpha_blending":[],"source_node_id":[]}},"exposed":true}},{"Node":{"node_id":9684750473849891261,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[4968550668755026811,{"inputs":[{"Node":{"node_id":585709295659496998,"output_index":0,"lambda":false}},{"Node":{"node_id":13609749019463823009,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[17533670083736420411,{"inputs":[{"Node":{"node_id":7005645574203740491,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"Fill":{"Gradient":{"stops":[[0.0,{"red":0.27058825,"green":0.49411765,"blue":0.5137255,"alpha":1.0}],[0.8397260273972602,{"red":0.27058825,"green":0.49411765,"blue":0.5137255,"alpha":1.0}],[1.0,{"red":0.27058825,"green":0.49411765,"blue":0.5137255,"alpha":0.0}]],"gradient_type":"Radial","start":[0.9711254481326403,-0.313902431217137],"end":[1.0169100960157926,0.2104743282968058],"transform":[1332.3243231154509,0.0,0.0,297.49602202927537,-250.85405534350912,609.3847245924164]}}},"exposed":false}},{"Value":{"tagged_value":{"OptionalColor":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}},"exposed":false}},{"Value":{"tagged_value":{"Gradient":{"stops":[[0.0,{"red":0.27058825,"green":0.49411765,"blue":0.5137255,"alpha":1.0}],[0.8397260273972602,{"red":0.27058825,"green":0.49411765,"blue":0.5137255,"alpha":1.0}],[1.0,{"red":0.27058825,"green":0.49411765,"blue":0.5137255,"alpha":0.0}]],"gradient_type":"Radial","start":[0.9711254481326403,-0.313902431217137],"end":[1.0169100960157926,0.2104743282968058],"transform":[1332.3243231154509,0.0,0.0,297.49602202927537,-250.85405534350912,609.3847245924164]}},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::FillNode"}},"visible":true,"skip_deduplication":false}],[12683405703338263457,{"inputs":[{"Node":{"node_id":12537712543904859919,"output_index":0,"lambda":false}},{"Node":{"node_id":14449710315388146362,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[1229809699395562135,{"inputs":[{"Node":{"node_id":2843751023378786714,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"DVec2":[-36.95875397623445,-88.44786737074935]},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[1.442673035713692,1.442673035713692]},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[0.0,0.0]},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[0.5,0.5]},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":1}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":2}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":3}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":4}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":5}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::TransformNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[12302362769310895852,{"inputs":[{"Node":{"node_id":15347111149235590492,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"Fill":{"Gradient":{"stops":[[0.0,{"red":0.8014369,"green":0.8203125,"blue":0.63446045,"alpha":1.0}],[0.4047792425110607,{"red":0.70046544,"green":0.765625,"blue":0.57421875,"alpha":1.0}],[0.6425390774124099,{"red":0.6,"green":0.70980394,"blue":0.56078434,"alpha":1.0}],[0.8010456340133093,{"red":0.47058824,"green":0.6509804,"blue":0.53333336,"alpha":1.0}],[0.894708599277477,{"red":0.40392157,"green":0.6117647,"blue":0.5176471,"alpha":1.0}],[1.0,{"red":0.26666668,"green":0.5176471,"blue":0.4745098,"alpha":1.0}]],"gradient_type":"Radial","start":[0.5027713289486062,0.6166666666666667],"end":[0.502771328948606,-0.08890027761186703],"transform":[-221.0038859407525,2.7065170151646932e-14,-2.814144532415396e-30,-196.7148850451868,1204.8351529382844,632.1259668592257]}}},"exposed":false}},{"Value":{"tagged_value":{"OptionalColor":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}},"exposed":false}},{"Value":{"tagged_value":{"Gradient":{"stops":[[0.0,{"red":0.8014369,"green":0.8203125,"blue":0.63446045,"alpha":1.0}],[0.4047792425110607,{"red":0.70046544,"green":0.765625,"blue":0.57421875,"alpha":1.0}],[0.6425390774124099,{"red":0.6,"green":0.70980394,"blue":0.56078434,"alpha":1.0}],[0.8010456340133093,{"red":0.47058824,"green":0.6509804,"blue":0.53333336,"alpha":1.0}],[0.894708599277477,{"red":0.40392157,"green":0.6117647,"blue":0.5176471,"alpha":1.0}],[1.0,{"red":0.26666668,"green":0.5176471,"blue":0.4745098,"alpha":1.0}]],"gradient_type":"Radial","start":[0.5027713289486062,0.6166666666666667],"end":[0.502771328948606,-0.08890027761186703],"transform":[-221.0038859407525,2.7065170151646932e-14,-2.814144532415396e-30,-196.7148850451868,1204.8351529382844,632.1259668592257]}},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::FillNode"}},"visible":true,"skip_deduplication":false}],[15488533792651297821,{"inputs":[{"Node":{"node_id":14019233912018234740,"output_index":0,"lambda":false}},{"Node":{"node_id":183952488591282082,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[14791465604033956302,{"inputs":[{"Node":{"node_id":18187802220803838247,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"F64":50.0},"exposed":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::blending_nodes::OpacityNode"}},"visible":true,"skip_deduplication":false}],[1147521068928676110,{"inputs":[{"Value":{"tagged_value":{"GraphicGroup":{"instance":[],"transform":[],"alpha_blending":[],"source_node_id":[]}},"exposed":true}},{"Node":{"node_id":938033825024582130,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[6821938959315178556,{"inputs":[{"Node":{"node_id":12683405703338263457,"output_index":0,"lambda":false}},{"Node":{"node_id":5326013268137833446,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[1490537476612110327,{"inputs":[{"Node":{"node_id":2900504420179573771,"output_index":0,"lambda":false}},{"Node":{"node_id":429913874753911073,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[3365825508845848745,{"inputs":[{"Node":{"node_id":7156963182187517674,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"Fill":{"Gradient":{"stops":[[0.0,{"red":0.4509804,"green":0.6745098,"blue":0.627451,"alpha":1.0}],[1.0,{"red":0.27058825,"green":0.49411765,"blue":0.5137255,"alpha":1.0}]],"gradient_type":"Linear","start":[0.008641111778101118,0.8823529411764692],"end":[0.9918085332369128,0.12352941176470456],"transform":[485.1666049839542,0.0,0.0,170.00000000000006,377.80762113533183,514.0000000000002]}}},"exposed":false}},{"Value":{"tagged_value":{"OptionalColor":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}},"exposed":false}},{"Value":{"tagged_value":{"Gradient":{"stops":[[0.0,{"red":0.4509804,"green":0.6745098,"blue":0.627451,"alpha":1.0}],[1.0,{"red":0.27058825,"green":0.49411765,"blue":0.5137255,"alpha":1.0}]],"gradient_type":"Linear","start":[0.008641111778101118,0.8823529411764692],"end":[0.9918085332369128,0.12352941176470456],"transform":[485.1666049839542,0.0,0.0,170.00000000000006,377.80762113533183,514.0000000000002]}},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::FillNode"}},"visible":true,"skip_deduplication":false}],[9157963288496356916,{"inputs":[{"Node":{"node_id":10188337730058049439,"output_index":0,"lambda":false}},{"Node":{"node_id":1108089904278882840,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[3679103217373457623,{"inputs":[{"Node":{"node_id":7910743362843097140,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"OptionalColor":{"red":0.9372549,"green":0.90588236,"blue":0.7764706,"alpha":0.7490196}},"exposed":false}},{"Value":{"tagged_value":{"F64":3.0},"exposed":false}},{"Value":{"tagged_value":{"StrokeAlign":"Center"},"exposed":false}},{"Value":{"tagged_value":{"StrokeCap":"Round"},"exposed":false}},{"Value":{"tagged_value":{"StrokeJoin":"Miter"},"exposed":false}},{"Value":{"tagged_value":{"F64":4.0},"exposed":false}},{"Value":{"tagged_value":{"PaintOrder":"StrokeAbove"},"exposed":false}},{"Value":{"tagged_value":{"VecF64":[]},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::StrokeNode"}},"visible":true,"skip_deduplication":false}],[13442128106088307772,{"inputs":[{"Value":{"tagged_value":{"GraphicGroup":{"instance":[],"transform":[],"alpha_blending":[],"source_node_id":[]}},"exposed":true}},{"Node":{"node_id":13700218159488557234,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[2225749123534781340,{"inputs":[{"Value":{"tagged_value":{"VectorData":{"instance":[{"style":{"stroke":{"color":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0},"weight":0.0,"dash_lengths":[],"dash_offset":0.0,"cap":"Butt","join":"Miter","join_miter_limit":4.0,"align":"Center","transform":[1.0,0.0,0.0,1.0,0.0,0.0],"non_scaling":false,"paint_order":"StrokeAbove"},"fill":"None"},"colinear_manipulators":[],"point_domain":{"id":[],"position":[]},"segment_domain":{"id":[],"start_point":[],"end_point":[],"handles":[],"stroke":[]},"region_domain":{"id":[],"segment_range":[],"fill":[]},"upstream_graphic_group":null}],"transform":[[1.0,0.0,0.0,1.0,0.0,0.0]],"alpha_blending":[{"blend_mode":"Normal","opacity":1.0,"fill":1.0,"clip":false}],"source_node_id":[null]}},"exposed":true}},{"Value":{"tagged_value":{"VectorModification":{"points":{"add":[1,2,3,4],"remove":[],"delta":[[1,[1138.2754963085072,550.0000000000001]],[4,[1110.285115251741,542.5]],[3,[1128.9453692895852,537.5000000000001]],[2,[1156.9357503463518,545.0000000000001]]]},"segments":{"add":[1,2,3,4],"remove":[],"start_point":[[4,4],[2,2],[3,3],[1,1]],"end_point":[[1,2],[4,1],[2,3],[3,4]],"handle_primary":[[4,[0.0,0.0]],[3,[0.0,0.0]],[1,[0.0,0.0]],[2,[0.0,0.0]]],"handle_end":[[1,[0.0,0.0]],[2,[0.0,0.0]],[3,[0.0,0.0]],[4,[0.0,0.0]]],"stroke":[[3,0],[1,0],[4,0],[2,0]]},"regions":{"add":[0],"remove":[],"segment_range":[[0,{"start":1,"end":4}]],"fill":[[0,0]]},"add_g1_continuous":[],"remove_g1_continuous":[]}},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::vector_data::modification::VectorModification","alias":null}},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::vector_data::modification::PathModifyNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[11490835759023283071,{"inputs":[{"Node":{"node_id":16923062582661131268,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"DVec2":[-261.2435565297001,-64.0]},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[1.0,1.0]},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[0.0,0.0]},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[0.5,0.5]},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":1}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":2}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":3}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":4}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":5}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::TransformNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[15517065353723874205,{"inputs":[{"Node":{"node_id":3616319631707471648,"output_index":0,"lambda":false}},{"Node":{"node_id":12548387328300782726,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[3014633976566537110,{"inputs":[{"Node":{"node_id":5346759588580719138,"output_index":0,"lambda":false}},{"Node":{"node_id":11860177410232537211,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[9981992739451603109,{"inputs":[{"Node":{"node_id":13852123721901366011,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"Fill":{"Gradient":{"stops":[[0.0,{"red":0.16078432,"green":0.2901961,"blue":0.16078432,"alpha":0.59765625}],[0.8744713248939212,{"red":0.16078432,"green":0.29411766,"blue":0.16078432,"alpha":0.4453125}],[1.0,{"red":0.16078432,"green":0.2784314,"blue":0.16078432,"alpha":0.2109375}]],"gradient_type":"Radial","start":[0.4917953695426216,3.5168687748431413],"end":[0.4917953695426216,-0.06740196271505461],"transform":[-746.5804084818038,9.142973075533649e-14,0.0,-200.04561753794505,1239.1647878825902,870.5228087689718]}}},"exposed":false}},{"Value":{"tagged_value":{"OptionalColor":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}},"exposed":false}},{"Value":{"tagged_value":{"Gradient":{"stops":[[0.0,{"red":0.16078432,"green":0.2901961,"blue":0.16078432,"alpha":0.59765625}],[0.8744713248939212,{"red":0.16078432,"green":0.29411766,"blue":0.16078432,"alpha":0.4453125}],[1.0,{"red":0.16078432,"green":0.2784314,"blue":0.16078432,"alpha":0.2109375}]],"gradient_type":"Radial","start":[0.4917953695426216,3.5168687748431413],"end":[0.4917953695426216,-0.06740196271505461],"transform":[-746.5804084818038,9.142973075533649e-14,0.0,-200.04561753794505,1239.1647878825902,870.5228087689718]}},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::FillNode"}},"visible":true,"skip_deduplication":false}],[18128923159828618806,{"inputs":[{"Node":{"node_id":1229809699395562135,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"Fill":{"Gradient":{"stops":[[0.0,{"red":0.39215687,"green":0.6392157,"blue":0.4745098,"alpha":1.0}],[0.3267294443765037,{"red":0.45324707,"green":0.734375,"blue":0.5498848,"alpha":1.0}],[0.5703803350862179,{"red":0.72745097,"green":0.7784314,"blue":0.5235294,"alpha":1.0}],[1.0,{"red":1.0,"green":0.84705883,"blue":0.4627451,"alpha":1.0}]],"gradient_type":"Linear","start":[0.4425774215957188,0.8669102822986486],"end":[0.40311512028827146,0.4061330859327766],"transform":[-1171.3007272968916,1.4344296865231056e-13,-2.9954223230091924e-14,733.7843838145138,1307.3912558002485,53.87477268101975]}}},"exposed":false}},{"Value":{"tagged_value":{"OptionalColor":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}},"exposed":false}},{"Value":{"tagged_value":{"Gradient":{"stops":[[0.0,{"red":0.39215687,"green":0.6392157,"blue":0.4745098,"alpha":1.0}],[0.3267294443765037,{"red":0.45324707,"green":0.734375,"blue":0.5498848,"alpha":1.0}],[0.5703803350862179,{"red":0.72745097,"green":0.7784314,"blue":0.5235294,"alpha":1.0}],[1.0,{"red":1.0,"green":0.84705883,"blue":0.4627451,"alpha":1.0}]],"gradient_type":"Linear","start":[0.4425774215957188,0.8669102822986486],"end":[0.40311512028827146,0.4061330859327766],"transform":[-1171.3007272968916,1.4344296865231056e-13,-2.9954223230091924e-14,733.7843838145138,1307.3912558002485,53.87477268101975]}},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::FillNode"}},"visible":true,"skip_deduplication":false}],[1156213189397385283,{"inputs":[{"Value":{"tagged_value":{"VectorData":{"instance":[{"style":{"stroke":{"color":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0},"weight":0.0,"dash_lengths":[],"dash_offset":0.0,"cap":"Butt","join":"Miter","join_miter_limit":4.0,"align":"Center","transform":[1.0,0.0,0.0,1.0,0.0,0.0],"non_scaling":false,"paint_order":"StrokeAbove"},"fill":"None"},"colinear_manipulators":[],"point_domain":{"id":[],"position":[]},"segment_domain":{"id":[],"start_point":[],"end_point":[],"handles":[],"stroke":[]},"region_domain":{"id":[],"segment_range":[],"fill":[]},"upstream_graphic_group":null}],"transform":[[1.0,0.0,0.0,1.0,0.0,0.0]],"alpha_blending":[{"blend_mode":"Normal","opacity":1.0,"fill":1.0,"clip":false}],"source_node_id":[null]}},"exposed":true}},{"Value":{"tagged_value":{"VectorModification":{"points":{"add":[1,2,3,4],"remove":[],"delta":[[2,[65.3108891324556,617.5]],[1,[55.98076211353359,615.0]],[4,[74.64101615137773,610.0]],[3,[83.97114317030051,612.4999999999999]]]},"segments":{"add":[1,2,3,4],"remove":[],"start_point":[[2,2],[4,4],[1,1],[3,3]],"end_point":[[1,2],[4,1],[2,3],[3,4]],"handle_primary":[[1,[0.0,0.0]],[3,[0.0,0.0]],[2,[0.0,0.0]],[4,[0.0,0.0]]],"handle_end":[[2,[0.0,0.0]],[3,[0.0,0.0]],[1,[0.0,0.0]],[4,[0.0,0.0]]],"stroke":[[1,0],[3,0],[4,0],[2,0]]},"regions":{"add":[0],"remove":[],"segment_range":[[0,{"start":1,"end":4}]],"fill":[[0,0]]},"add_g1_continuous":[],"remove_g1_continuous":[]}},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::vector_data::modification::VectorModification","alias":null}},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::vector_data::modification::PathModifyNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[8891726805381758817,{"inputs":[{"Node":{"node_id":17332567356044944766,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"DVec2":[-74.42590421819692,41.71533421869417]},"exposed":false}},{"Value":{"tagged_value":{"F64":0.6752258214141986},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[38.26905454222045,23.541084128981048]},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[0.4371138567686068,0.0]},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[0.5,0.5]},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":1}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":2}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":3}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":4}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":5}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::TransformNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[12998832508553378533,{"inputs":[{"Node":{"node_id":3122972215852775755,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"Fill":{"Gradient":{"stops":[[0.0,{"red":0.46666667,"green":0.7019608,"blue":0.654902,"alpha":1.0}],[0.5,{"red":0.44313726,"green":0.68235296,"blue":0.6313726,"alpha":1.0}],[1.0,{"red":0.40784314,"green":0.627451,"blue":0.6,"alpha":1.0}]],"gradient_type":"Linear","start":[0.0051615000620980345,0.22838569993468072],"end":[0.9899367003601665,0.951087390077165],"transform":[682.3892394899885,0.0,0.0,255.9839039030424,96.4778478979974,545.5369369350916]}}},"exposed":false}},{"Value":{"tagged_value":{"OptionalColor":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}},"exposed":false}},{"Value":{"tagged_value":{"Gradient":{"stops":[[0.0,{"red":0.46666667,"green":0.7019608,"blue":0.654902,"alpha":1.0}],[0.5,{"red":0.44313726,"green":0.68235296,"blue":0.6313726,"alpha":1.0}],[1.0,{"red":0.40784314,"green":0.627451,"blue":0.6,"alpha":1.0}]],"gradient_type":"Linear","start":[0.0051615000620980345,0.22838569993468072],"end":[0.9899367003601665,0.951087390077165],"transform":[682.3892394899885,0.0,0.0,255.9839039030424,96.4778478979974,545.5369369350916]}},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::FillNode"}},"visible":true,"skip_deduplication":false}],[9798215931018813676,{"inputs":[{"Node":{"node_id":10779665858841986661,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"Fill":{"Solid":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}}},"exposed":false}},{"Value":{"tagged_value":{"OptionalColor":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}},"exposed":false}},{"Value":{"tagged_value":{"Gradient":{"stops":[[0.0,{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}],[1.0,{"red":1.0,"green":1.0,"blue":1.0,"alpha":1.0}]],"gradient_type":"Linear","start":[0.0,0.5],"end":[1.0,0.5],"transform":[1.0,0.0,0.0,1.0,0.0,0.0]}},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::FillNode"}},"visible":true,"skip_deduplication":false}],[9210109719406330381,{"inputs":[{"Node":{"node_id":8612613134760093452,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"DVec2":[-261.2435565297001,-64.0]},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[1.0,1.0]},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[0.0,0.0]},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[0.5,0.5]},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":1}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":2}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":3}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":4}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":5}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::TransformNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[9409313765472227540,{"inputs":[{"Node":{"node_id":6821938959315178556,"output_index":0,"lambda":false}},{"Node":{"node_id":8463468388280418154,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[13920465562072008593,{"inputs":[{"Node":{"node_id":3670594928372882885,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"DVec2":[-261.2435565297001,-63.99999999999994]},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[1.0,1.0]},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[0.0,0.0]},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[0.5,0.5]},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":1}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":2}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":3}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":4}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":5}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::TransformNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[3122972215852775755,{"inputs":[{"Node":{"node_id":10431241258085047322,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"DVec2":[-261.2435565297001,-64.0]},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[1.0,1.0]},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[0.0,0.0]},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[0.5,0.5]},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":1}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":2}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":3}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":4}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":5}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::TransformNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[3564067978712674849,{"inputs":[{"Node":{"node_id":6777328619777499144,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"DVec2":[-261.24355652970075,-64.0]},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[1.0,1.0]},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[0.0,0.0]},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[0.5,0.5]},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":1}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":2}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":3}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":4}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":5}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::TransformNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[2189393878093040029,{"inputs":[{"Node":{"node_id":15478704582542175684,"output_index":0,"lambda":false}},{"Node":{"node_id":17533670083736420411,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[10917301734480569398,{"inputs":[{"Node":{"node_id":3455270778005546310,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"DVec2":[-261.2435565297001,-64.0]},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[1.0,1.0]},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[0.0,0.0]},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[0.5,0.5]},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":1}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":2}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":3}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":4}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":5}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::TransformNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[13946577152348504742,{"inputs":[{"Node":{"node_id":3021739385836969518,"output_index":0,"lambda":false}},{"Node":{"node_id":15876464101883822838,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[2510483139353274965,{"inputs":[{"Node":{"node_id":14202574750104046500,"output_index":0,"lambda":false}},{"Node":{"node_id":18128923159828618806,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[16847360882244487081,{"inputs":[{"Node":{"node_id":13817976820605296433,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"Fill":{"Gradient":{"stops":[[0.0,{"red":0.972549,"green":0.87058824,"blue":0.6666667,"alpha":1.0}],[1.0,{"red":0.9490196,"green":0.92156863,"blue":0.7411765,"alpha":1.0}]],"gradient_type":"Linear","start":[0.6476985249926699,0.10666666666666667],"end":[0.9920644403070608,0.4398792234469302],"transform":[1119.6152422706632,0.0,0.0,300.0,555.8268590219807,337.0]}}},"exposed":false}},{"Value":{"tagged_value":{"OptionalColor":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}},"exposed":false}},{"Value":{"tagged_value":{"Gradient":{"stops":[[0.0,{"red":0.972549,"green":0.87058824,"blue":0.6666667,"alpha":1.0}],[1.0,{"red":0.9490196,"green":0.92156863,"blue":0.7411765,"alpha":1.0}]],"gradient_type":"Linear","start":[0.6476985249926699,0.10666666666666667],"end":[0.9920644403070608,0.4398792234469302],"transform":[1119.6152422706632,0.0,0.0,300.0,555.8268590219807,337.0]}},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::FillNode"}},"visible":true,"skip_deduplication":false}],[7671691070850213967,{"inputs":[{"Node":{"node_id":1658032775659237960,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"Fill":{"Gradient":{"stops":[[0.0,{"red":0.22091675,"green":0.4453125,"blue":0.44150904,"alpha":1.0}],[0.6048571201787465,{"red":0.3202623,"green":0.5461857,"blue":0.5423232,"alpha":0.859375}],[0.8131497297124398,{"red":0.41960785,"green":0.64705884,"blue":0.6431373,"alpha":0.71875}],[1.0,{"red":0.43137255,"green":0.61960787,"blue":0.5803922,"alpha":0.3984375}]],"gradient_type":"Radial","start":[0.3691427845059252,-2.109375000000002],"end":[0.05794738050227899,1.089204545454546],"transform":[317.2243186433542,0.0,0.0,109.99999999999989,917.7114317029974,729.0]}}},"exposed":false}},{"Value":{"tagged_value":{"OptionalColor":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}},"exposed":false}},{"Value":{"tagged_value":{"Gradient":{"stops":[[0.0,{"red":0.22091675,"green":0.4453125,"blue":0.44150904,"alpha":1.0}],[0.6048571201787465,{"red":0.3202623,"green":0.5461857,"blue":0.5423232,"alpha":0.859375}],[0.8131497297124398,{"red":0.41960785,"green":0.64705884,"blue":0.6431373,"alpha":0.71875}],[1.0,{"red":0.43137255,"green":0.61960787,"blue":0.5803922,"alpha":0.3984375}]],"gradient_type":"Radial","start":[0.3691427845059252,-2.109375000000002],"end":[0.05794738050227899,1.089204545454546],"transform":[317.2243186433542,0.0,0.0,109.99999999999989,917.7114317029974,729.0]}},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::FillNode"}},"visible":true,"skip_deduplication":false}],[16244305414728361140,{"inputs":[{"Node":{"node_id":11547499603328872398,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"Fill":{"Gradient":{"stops":[[0.0,{"red":0.5294118,"green":0.7490196,"blue":0.65882355,"alpha":1.0}],[1.0,{"red":0.46666667,"green":0.69803923,"blue":0.62352943,"alpha":1.0}]],"gradient_type":"Linear","start":[0.008550171763040293,0.13076923076922986],"end":[0.99103054401049,0.7769230769230764],"transform":[335.8845726811991,0.0,0.0,129.9999999999999,415.12812921102034,414.0000000000001]}}},"exposed":false}},{"Value":{"tagged_value":{"OptionalColor":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}},"exposed":false}},{"Value":{"tagged_value":{"Gradient":{"stops":[[0.0,{"red":0.5294118,"green":0.7490196,"blue":0.65882355,"alpha":1.0}],[1.0,{"red":0.46666667,"green":0.69803923,"blue":0.62352943,"alpha":1.0}]],"gradient_type":"Linear","start":[0.008550171763040293,0.13076923076922986],"end":[0.99103054401049,0.7769230769230764],"transform":[335.8845726811991,0.0,0.0,129.9999999999999,415.12812921102034,414.0000000000001]}},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::FillNode"}},"visible":true,"skip_deduplication":false}],[9724746185253267560,{"inputs":[{"Value":{"tagged_value":{"VectorData":{"instance":[{"style":{"stroke":{"color":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0},"weight":0.0,"dash_lengths":[],"dash_offset":0.0,"cap":"Butt","join":"Miter","join_miter_limit":4.0,"align":"Center","transform":[1.0,0.0,0.0,1.0,0.0,0.0],"non_scaling":false,"paint_order":"StrokeAbove"},"fill":"None"},"colinear_manipulators":[],"point_domain":{"id":[],"position":[]},"segment_domain":{"id":[],"start_point":[],"end_point":[],"handles":[],"stroke":[]},"region_domain":{"id":[],"segment_range":[],"fill":[]},"upstream_graphic_group":null}],"transform":[[1.0,0.0,0.0,1.0,0.0,0.0]],"alpha_blending":[{"blend_mode":"Normal","opacity":1.0,"fill":1.0,"clip":false}],"source_node_id":[null]}},"exposed":true}},{"Value":{"tagged_value":{"VectorModification":{"points":{"add":[1,2,3,4,5,6,7,8,9,10,11],"remove":[],"delta":[[6,[1194.256258422041,458.99999999999994]],[10,[1194.2562584220411,469.00000000000006]],[3,[1044.9742261192855,459.0]],[1,[1091.6248612138966,461.5]],[9,[1222.2466394788075,476.5000000000001]],[4,[1184.9261314031187,496.5]],[2,[1063.63448015713,453.99999999999994]],[8,[1184.9261314031187,486.5]],[11,[1175.5960043841962,474.00000000000006]],[5,[1259.567147554496,476.49999999999994]],[7,[1138.2754963085074,473.99999999999994]]]},"segments":{"add":[1,2,3,4,5,6,7,8,9,10],"remove":[],"start_point":[[3,3],[8,8],[1,1],[4,4],[9,9],[2,2],[10,10],[7,7],[5,5],[6,6]],"end_point":[[1,2],[9,10],[7,8],[5,6],[6,7],[8,9],[2,3],[4,5],[10,11],[3,4]],"handle_primary":[[8,[0.0,0.0]],[4,[0.0,0.0]],[10,[0.0,0.0]],[6,[0.0,0.0]],[7,[0.0,0.0]],[1,[0.0,0.0]],[9,[0.0,0.0]],[2,[0.0,0.0]],[3,[0.0,0.0]],[5,[0.0,0.0]]],"handle_end":[[9,[0.0,0.0]],[6,[0.0,0.0]],[1,[0.0,0.0]],[4,[0.0,0.0]],[3,[0.0,0.0]],[7,[0.0,0.0]],[8,[0.0,0.0]],[2,[0.0,0.0]],[10,[0.0,0.0]],[5,[0.0,0.0]]],"stroke":[[4,0],[2,0],[6,0],[8,0],[9,0],[7,0],[10,0],[1,0],[5,0],[3,0]]},"regions":{"add":[],"remove":[],"segment_range":[],"fill":[]},"add_g1_continuous":[],"remove_g1_continuous":[]}},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::vector_data::modification::VectorModification","alias":null}},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::vector_data::modification::PathModifyNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[1108089904278882840,{"inputs":[{"Node":{"node_id":5317925967883407701,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"Fill":{"Solid":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}}},"exposed":false}},{"Value":{"tagged_value":{"OptionalColor":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}},"exposed":false}},{"Value":{"tagged_value":{"Gradient":{"stops":[[0.0,{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}],[1.0,{"red":1.0,"green":1.0,"blue":1.0,"alpha":1.0}]],"gradient_type":"Linear","start":[0.0,0.5],"end":[1.0,0.5],"transform":[1.0,0.0,0.0,1.0,0.0,0.0]}},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::FillNode"}},"visible":true,"skip_deduplication":false}],[13001069903842109798,{"inputs":[{"Value":{"tagged_value":{"VectorData":{"instance":[{"style":{"stroke":{"color":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0},"weight":0.0,"dash_lengths":[],"dash_offset":0.0,"cap":"Butt","join":"Miter","join_miter_limit":4.0,"align":"Center","transform":[1.0,0.0,0.0,1.0,0.0,0.0],"non_scaling":false,"paint_order":"StrokeAbove"},"fill":"None"},"colinear_manipulators":[],"point_domain":{"id":[],"position":[]},"segment_domain":{"id":[],"start_point":[],"end_point":[],"handles":[],"stroke":[]},"region_domain":{"id":[],"segment_range":[],"fill":[]},"upstream_graphic_group":null}],"transform":[[1.0,0.0,0.0,1.0,0.0,0.0]],"alpha_blending":[{"blend_mode":"Normal","opacity":1.0,"fill":1.0,"clip":false}],"source_node_id":[null]}},"exposed":true}},{"Value":{"tagged_value":{"VectorModification":{"points":{"add":[1,2,3,4],"remove":[],"delta":[[3,[1.0311603768047983,1.0082447817061446]],[4,[0.15793848790232112,1.0756444843098496]],[2,[1.067391838882569,0.5169672994595966]],[1,[0.02964805558748984,0.4451546735104888]]]},"segments":{"add":[1,2,3,4],"remove":[],"start_point":[[1,1],[3,3],[4,4],[2,2]],"end_point":[[2,3],[1,2],[4,1],[3,4]],"handle_primary":[[2,[0.0,0.0]],[4,[0.0,0.0]],[1,[0.0,0.0]],[3,[-0.4856258676143469,-0.19200483651697595]]],"handle_end":[[3,[0.0,0.0]],[4,[0.0,0.0]],[1,[0.0,0.0]],[2,null]],"stroke":[[4,0],[1,0],[2,0],[3,0]]},"regions":{"add":[0],"remove":[],"segment_range":[[0,{"start":1,"end":4}]],"fill":[[0,0]]},"add_g1_continuous":[],"remove_g1_continuous":[]}},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::vector_data::modification::VectorModification","alias":null}},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::vector_data::modification::PathModifyNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[4837219841531371489,{"inputs":[{"Value":{"tagged_value":{"VectorData":{"instance":[{"style":{"stroke":{"color":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0},"weight":0.0,"dash_lengths":[],"dash_offset":0.0,"cap":"Butt","join":"Miter","join_miter_limit":4.0,"align":"Center","transform":[1.0,0.0,0.0,1.0,0.0,0.0],"non_scaling":false,"paint_order":"StrokeAbove"},"fill":"None"},"colinear_manipulators":[],"point_domain":{"id":[],"position":[]},"segment_domain":{"id":[],"start_point":[],"end_point":[],"handles":[],"stroke":[]},"region_domain":{"id":[],"segment_range":[],"fill":[]},"upstream_graphic_group":null}],"transform":[[1.0,0.0,0.0,1.0,0.0,0.0]],"alpha_blending":[{"blend_mode":"Normal","opacity":1.0,"fill":1.0,"clip":false}],"source_node_id":[null]}},"exposed":true}},{"Value":{"tagged_value":{"VectorModification":{"points":{"add":[1,2,3,4],"remove":[],"delta":[[4,[597.1281292110205,340.0000000000001]],[2,[1343.5382907247958,320.00000000000006]],[3,[1007.6537180435968,230.0]],[1,[933.0127018922194,430.0]]]},"segments":{"add":[1,2,3,4],"remove":[],"start_point":[[1,1],[2,2],[4,4],[3,3]],"end_point":[[2,3],[1,2],[3,4],[4,1]],"handle_primary":[[2,[0.0,0.0]],[3,[0.0,0.0]],[4,[0.0,0.0]],[1,[0.0,0.0]]],"handle_end":[[1,[0.0,0.0]],[2,[0.0,0.0]],[4,[0.0,0.0]],[3,[0.0,0.0]]],"stroke":[[1,0],[4,0],[3,0],[2,0]]},"regions":{"add":[0],"remove":[],"segment_range":[[0,{"start":1,"end":4}]],"fill":[[0,0]]},"add_g1_continuous":[],"remove_g1_continuous":[]}},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::vector_data::modification::VectorModification","alias":null}},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::vector_data::modification::PathModifyNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[17785019773455930267,{"inputs":[{"Node":{"node_id":17887542695709892422,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"DVec2":[0.0,-6.0]},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[1.0,1.0]},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[0.0,0.0]},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[0.5,0.5]},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":1}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":2}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":3}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":4}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":5}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::TransformNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[10189927996178548902,{"inputs":[{"Value":{"tagged_value":{"VectorData":{"instance":[{"style":{"stroke":{"color":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0},"weight":0.0,"dash_lengths":[],"dash_offset":0.0,"cap":"Butt","join":"Miter","join_miter_limit":4.0,"align":"Center","transform":[1.0,0.0,0.0,1.0,0.0,0.0],"non_scaling":false,"paint_order":"StrokeAbove"},"fill":"None"},"colinear_manipulators":[],"point_domain":{"id":[],"position":[]},"segment_domain":{"id":[],"start_point":[],"end_point":[],"handles":[],"stroke":[]},"region_domain":{"id":[],"segment_range":[],"fill":[]},"upstream_graphic_group":null}],"transform":[[1.0,0.0,0.0,1.0,0.0,0.0]],"alpha_blending":[{"blend_mode":"Normal","opacity":1.0,"fill":1.0,"clip":false}],"source_node_id":[null]}},"exposed":true}},{"Value":{"tagged_value":{"VectorModification":{"points":{"add":[1,2,3,4,5,6],"remove":[],"delta":[[1,[298.56406460551045,540.0000000000002]],[5,[709.0896534380867,660.0]],[3,[597.1281292110203,649.9999999999999]],[2,[298.5640646055101,570.0000000000006]],[4,[597.1281292110198,630.0]],[6,[709.0896534380864,649.9999999999999]]]},"segments":{"add":[1,2,3,4,5,6],"remove":[],"start_point":[[3,3],[1,1],[4,4],[5,5],[2,2],[6,6]],"end_point":[[5,6],[2,3],[3,4],[1,2],[4,5],[6,1]],"handle_primary":[[6,[0.0,0.0]],[4,[0.0,0.0]],[2,[0.0,0.0]],[5,[-2.273736754432321e-13,-10.000000000000114]],[3,[-5.684341886080801e-13,-19.999999999999886]],[1,[0.0,0.0]]],"handle_end":[[6,[0.0,0.0]],[5,null],[1,[0.0,0.0]],[3,null],[2,null],[4,null]],"stroke":[[3,0],[6,0],[5,0],[2,0],[1,0],[4,0]]},"regions":{"add":[0],"remove":[],"segment_range":[[0,{"start":1,"end":6}]],"fill":[[0,0]]},"add_g1_continuous":[],"remove_g1_continuous":[]}},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::vector_data::modification::VectorModification","alias":null}},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::vector_data::modification::PathModifyNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[13868917743026516656,{"inputs":[{"Node":{"node_id":5258402282444994019,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"Fill":{"Gradient":{"stops":[[0.0,{"red":0.9529412,"green":0.83137256,"blue":0.49411765,"alpha":1.0}],[0.5,{"red":0.6039216,"green":0.77254903,"blue":0.6117647,"alpha":1.0}],[1.0,{"red":0.48010254,"green":0.71875,"blue":0.58451086,"alpha":1.0}]],"gradient_type":"Radial","start":[0.990188567383927,0.031432585832447346],"end":[0.003820820042059303,0.7823921936299838],"transform":[506.9103296893421,0.0,0.0,226.3770224587539,740.0631868527961,262.88438481107136]}}},"exposed":false}},{"Value":{"tagged_value":{"OptionalColor":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}},"exposed":false}},{"Value":{"tagged_value":{"Gradient":{"stops":[[0.0,{"red":0.9529412,"green":0.83137256,"blue":0.49411765,"alpha":1.0}],[0.5,{"red":0.6039216,"green":0.77254903,"blue":0.6117647,"alpha":1.0}],[1.0,{"red":0.48010254,"green":0.71875,"blue":0.58451086,"alpha":1.0}]],"gradient_type":"Radial","start":[0.990188567383927,0.031432585832447346],"end":[0.003820820042059303,0.7823921936299838],"transform":[506.9103296893421,0.0,0.0,226.3770224587539,740.0631868527961,262.88438481107136]}},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::FillNode"}},"visible":true,"skip_deduplication":false}],[9393309733761233513,{"inputs":[{"Node":{"node_id":13946577152348504742,"output_index":0,"lambda":false}},{"Node":{"node_id":11895211316848895241,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[11634802583144606404,{"inputs":[{"Node":{"node_id":9226731772122225003,"output_index":0,"lambda":false}},{"Node":{"node_id":6868877732348460627,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[8165914767449151618,{"inputs":[{"Node":{"node_id":11158238411769751544,"output_index":0,"lambda":false}},{"Node":{"node_id":13942146309185231085,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[14400993470150734626,{"inputs":[{"Node":{"node_id":2088390810384907709,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"DVec2":[-261.2435565297001,-69.0]},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[1.0,1.0]},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[0.0,0.0]},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[0.5,0.5]},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":1}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":2}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":3}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":4}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":5}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::TransformNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[14202574750104046500,{"inputs":[{"Value":{"tagged_value":{"GraphicGroup":{"instance":[],"transform":[],"alpha_blending":[],"source_node_id":[]}},"exposed":true}},{"Node":{"node_id":1831743139584171612,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[15216519480392295991,{"inputs":[{"Node":{"node_id":12019361655085452072,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"Fill":{"Gradient":{"stops":[[0.0,{"red":0.79607844,"green":0.7607843,"blue":0.57254905,"alpha":0.01}],[0.6837652235970189,{"red":0.6666667,"green":0.6666667,"blue":0.6666667,"alpha":0.011764706}],[0.7972664177223364,{"red":0.79607844,"green":0.7607843,"blue":0.57254905,"alpha":0.53515625}],[1.0,{"red":0.9647059,"green":0.7607843,"blue":0.5568628,"alpha":1.0}]],"gradient_type":"Radial","start":[0.5377061694297174,0.1861799653787184],"end":[0.4291107938423666,0.936951921882358],"transform":[-221.0038859407525,2.7065170151646932e-14,-2.629542652075462e-30,-183.8108080683632,1243.8351529382842,529.2218898824021]}}},"exposed":false}},{"Value":{"tagged_value":{"OptionalColor":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}},"exposed":false}},{"Value":{"tagged_value":{"Gradient":{"stops":[[0.0,{"red":0.79607844,"green":0.7607843,"blue":0.57254905,"alpha":0.01}],[0.6837652235970189,{"red":0.6666667,"green":0.6666667,"blue":0.6666667,"alpha":0.011764706}],[0.7972664177223364,{"red":0.79607844,"green":0.7607843,"blue":0.57254905,"alpha":0.53515625}],[1.0,{"red":0.9647059,"green":0.7607843,"blue":0.5568628,"alpha":1.0}]],"gradient_type":"Radial","start":[0.5377061694297174,0.1861799653787184],"end":[0.4291107938423666,0.936951921882358],"transform":[-221.0038859407525,2.7065170151646932e-14,-2.629542652075462e-30,-183.8108080683632,1243.8351529382842,529.2218898824021]}},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::FillNode"}},"visible":true,"skip_deduplication":false}],[1831743139584171612,{"inputs":[{"Node":{"node_id":6569279146800941123,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"Fill":{"Gradient":{"stops":[[0.0,{"red":0.44433594,"green":0.7109375,"blue":0.60144055,"alpha":1.0}],[0.31019165912642926,{"red":0.42991638,"green":0.68359375,"blue":0.5723318,"alpha":0.85546875}],[1.0,{"red":0.41487122,"green":0.66796875,"blue":0.5466929,"alpha":0.3515625}]],"gradient_type":"Radial","start":[0.49564744287268736,0.12680209698558276],"end":[0.6983677910772572,0.8876146788990837],"transform":[340.37037037037106,0.0,0.0,113.03703703703678,837.2962962962961,682.6666666666667]}}},"exposed":false}},{"Value":{"tagged_value":{"OptionalColor":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}},"exposed":false}},{"Value":{"tagged_value":{"Gradient":{"stops":[[0.0,{"red":0.44433594,"green":0.7109375,"blue":0.60144055,"alpha":1.0}],[0.31019165912642926,{"red":0.42991638,"green":0.68359375,"blue":0.5723318,"alpha":0.85546875}],[1.0,{"red":0.41487122,"green":0.66796875,"blue":0.5466929,"alpha":0.3515625}]],"gradient_type":"Radial","start":[0.49564744287268736,0.12680209698558276],"end":[0.6983677910772572,0.8876146788990837],"transform":[340.37037037037106,0.0,0.0,113.03703703703678,837.2962962962961,682.6666666666667]}},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::FillNode"}},"visible":true,"skip_deduplication":false}],[12360435709959435360,{"inputs":[{"Node":{"node_id":15723520455917422372,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"Fill":{"Gradient":{"stops":[[0.0,{"red":0.47843137,"green":0.7294118,"blue":0.5686275,"alpha":1.0}],[1.0,{"red":0.39215687,"green":0.6392157,"blue":0.4745098,"alpha":1.0}]],"gradient_type":"Linear","start":[0.5005723020410011,0.4324498034559026],"end":[0.5007962736667897,0.9150264743070644],"transform":[-992.1891732446936,1.215081295162773e-13,-2.5681507542728992e-14,629.116269946799,1261.8846407334754,149.34195758136912]}}},"exposed":false}},{"Value":{"tagged_value":{"OptionalColor":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}},"exposed":false}},{"Value":{"tagged_value":{"Gradient":{"stops":[[0.0,{"red":0.47843137,"green":0.7294118,"blue":0.5686275,"alpha":1.0}],[1.0,{"red":0.39215687,"green":0.6392157,"blue":0.4745098,"alpha":1.0}]],"gradient_type":"Linear","start":[0.5005723020410011,0.4324498034559026],"end":[0.5007962736667897,0.9150264743070644],"transform":[-992.1891732446936,1.215081295162773e-13,-2.5681507542728992e-14,629.116269946799,1261.8846407334754,149.34195758136912]}},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::FillNode"}},"visible":true,"skip_deduplication":false}],[2077983679740571162,{"inputs":[{"Value":{"tagged_value":{"VectorData":{"instance":[{"style":{"stroke":{"color":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0},"weight":0.0,"dash_lengths":[],"dash_offset":0.0,"cap":"Butt","join":"Miter","join_miter_limit":4.0,"align":"Center","transform":[1.0,0.0,0.0,1.0,0.0,0.0],"non_scaling":false,"paint_order":"StrokeAbove"},"fill":"None"},"colinear_manipulators":[],"point_domain":{"id":[],"position":[]},"segment_domain":{"id":[],"start_point":[],"end_point":[],"handles":[],"stroke":[]},"region_domain":{"id":[],"segment_range":[],"fill":[]},"upstream_graphic_group":null}],"transform":[[1.0,0.0,0.0,1.0,0.0,0.0]],"alpha_blending":[{"blend_mode":"Normal","opacity":1.0,"fill":1.0,"clip":false}],"source_node_id":[null]}},"exposed":true}},{"Value":{"tagged_value":{"VectorModification":{"points":{"add":[1,2,3,4],"remove":[],"delta":[[1,[-137.83320996790803,20.957167389569804]],[4,[-124.49987663457466,76.24680898300153]],[2,[-130.2776544123526,8.793446239014884]],[3,[-119.7591358938339,55.2367451774976]]]},"segments":{"add":[1,2,3,4],"remove":[],"start_point":[[2,2],[1,1],[3,3],[4,4]],"end_point":[[1,2],[2,3],[3,4],[4,1]],"handle_primary":[[4,[0.0,0.0]],[3,[0.0,0.0]],[2,[0.0,0.0]],[1,[0.0,0.0]]],"handle_end":[[3,[0.0,0.0]],[2,[-5.037037037036939,-9.952135486817731]],[1,[0.0,0.0]],[4,[6.814814814814781,36.49116345166567]]],"stroke":[[2,0],[3,0],[1,0],[4,0]]},"regions":{"add":[0],"remove":[],"segment_range":[[0,{"start":1,"end":4}]],"fill":[[0,0]]},"add_g1_continuous":[],"remove_g1_continuous":[]}},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::vector_data::modification::VectorModification","alias":null}},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::vector_data::modification::PathModifyNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[2058192342619930156,{"inputs":[{"Node":{"node_id":2155997486525176376,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"DVec2":[0.0,-5.0]},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[1.0,1.0]},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[0.0,0.0]},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[0.5,0.5]},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":1}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":2}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":3}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":4}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":5}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::TransformNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[10181153433637856462,{"inputs":[{"Node":{"node_id":9150078008481575131,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"DVec2":[187.102540378,187.10254037799996]},"exposed":false}},{"Value":{"tagged_value":{"F64":3.141592653589793},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[373.205080756,373.205080756]},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[-3.2814312084546346e-17,0.0]},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[0.5,0.5]},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":1}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":2}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":3}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":4}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":5}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::TransformNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[11579925754926059876,{"inputs":[{"Node":{"node_id":15670426414376277308,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"DVec2":[1175.596004383839,384.99999999999983]},"exposed":false}},{"Value":{"tagged_value":{"F64":3.141592653589793},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[410.52558883186134,109.99999999999974]},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[-3.2814312084546346e-17,0.0]},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[0.5,0.5]},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":1}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":2}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":3}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":4}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":5}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::TransformNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[9138781233934614517,{"inputs":[{"Node":{"node_id":8073807569018624098,"output_index":0,"lambda":false}},{"Node":{"node_id":4884180935153120645,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[12370676490908282512,{"inputs":[{"Node":{"node_id":9666682009015049330,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"Fill":{"Gradient":{"stops":[[0.0,{"red":0.27058825,"green":0.49411765,"blue":0.5137255,"alpha":1.0}],[0.643741535074667,{"red":0.27450982,"green":0.49411765,"blue":0.5137255,"alpha":0.5019608}],[0.8214781907174007,{"red":0.27450982,"green":0.5019608,"blue":0.52156866,"alpha":0.17254902}],[1.0,{"red":0.0,"green":1.0,"blue":1.0,"alpha":0.003921569}]],"gradient_type":"Linear","start":[0.8142178455184718,0.014814814814815058],"end":[0.8217337510617708,0.33779273207824057],"transform":[1667.7715501019673,0.0,0.0,377.053346257955,-488.4641717793936,466.6341200282825]}}},"exposed":false}},{"Value":{"tagged_value":{"OptionalColor":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}},"exposed":false}},{"Value":{"tagged_value":{"Gradient":{"stops":[[0.0,{"red":0.27058825,"green":0.49411765,"blue":0.5137255,"alpha":1.0}],[0.643741535074667,{"red":0.27450982,"green":0.49411765,"blue":0.5137255,"alpha":0.5019608}],[0.8214781907174007,{"red":0.27450982,"green":0.5019608,"blue":0.52156866,"alpha":0.17254902}],[1.0,{"red":0.0,"green":1.0,"blue":1.0,"alpha":0.003921569}]],"gradient_type":"Linear","start":[0.8142178455184718,0.014814814814815058],"end":[0.8217337510617708,0.33779273207824057],"transform":[1667.7715501019673,0.0,0.0,377.053346257955,-488.4641717793936,466.6341200282825]}},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::FillNode"}},"visible":true,"skip_deduplication":false}],[16261620049358949344,{"inputs":[{"Node":{"node_id":16059265180575745658,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"OptionalColor":{"red":0.9372549,"green":0.90588236,"blue":0.7764706,"alpha":0.7490196}},"exposed":false}},{"Value":{"tagged_value":{"F64":3.0},"exposed":false}},{"Value":{"tagged_value":{"StrokeAlign":"Center"},"exposed":false}},{"Value":{"tagged_value":{"StrokeCap":"Butt"},"exposed":false}},{"Value":{"tagged_value":{"StrokeJoin":"Miter"},"exposed":false}},{"Value":{"tagged_value":{"F64":4.0},"exposed":false}},{"Value":{"tagged_value":{"PaintOrder":"StrokeAbove"},"exposed":false}},{"Value":{"tagged_value":{"VecF64":[]},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::StrokeNode"}},"visible":true,"skip_deduplication":false}],[7340659059180155803,{"inputs":[{"Node":{"node_id":7171713123860587892,"output_index":0,"lambda":false}},{"Node":{"node_id":13531127678140037818,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[6589978257209505606,{"inputs":[{"Value":{"tagged_value":{"VectorData":{"instance":[{"style":{"stroke":{"color":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0},"weight":0.0,"dash_lengths":[],"dash_offset":0.0,"cap":"Butt","join":"Miter","join_miter_limit":4.0,"align":"Center","transform":[1.0,0.0,0.0,1.0,0.0,0.0],"non_scaling":false,"paint_order":"StrokeAbove"},"fill":"None"},"colinear_manipulators":[],"point_domain":{"id":[],"position":[]},"segment_domain":{"id":[],"start_point":[],"end_point":[],"handles":[],"stroke":[]},"region_domain":{"id":[],"segment_range":[],"fill":[]},"upstream_graphic_group":null}],"transform":[[1.0,0.0,0.0,1.0,0.0,0.0]],"alpha_blending":[{"blend_mode":"Normal","opacity":1.0,"fill":1.0,"clip":false}],"source_node_id":[null]}},"exposed":true}},{"Value":{"tagged_value":{"VectorModification":{"points":{"add":[1,2,3],"remove":[],"delta":[[3,[821.0511776651532,440.0000000000001]],[1,[709.0896534380868,410.0000000000001]],[2,[709.0896534380868,470.0]]]},"segments":{"add":[1,2,3],"remove":[],"start_point":[[2,2],[3,3],[1,1]],"end_point":[[2,3],[1,2],[3,1]],"handle_primary":[[2,[0.0,0.0]],[3,[0.0,0.0]],[1,[0.0,0.0]]],"handle_end":[[2,[0.0,0.0]],[3,[0.0,0.0]],[1,[0.0,0.0]]],"stroke":[[2,0],[3,0],[1,0]]},"regions":{"add":[0],"remove":[],"segment_range":[[0,{"start":1,"end":3}]],"fill":[[0,0]]},"add_g1_continuous":[],"remove_g1_continuous":[]}},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::vector_data::modification::VectorModification","alias":null}},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::vector_data::modification::PathModifyNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[16398743435291795904,{"inputs":[{"Node":{"node_id":5574499968250848265,"output_index":0,"lambda":false}},{"Node":{"node_id":4741515246389989284,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[8181290118694677328,{"inputs":[{"Node":{"node_id":5540780316862276409,"output_index":0,"lambda":false}},{"Node":{"node_id":17638504852426495381,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[13837327017498431546,{"inputs":[{"Value":{"tagged_value":{"VectorData":{"instance":[{"style":{"stroke":{"color":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0},"weight":0.0,"dash_lengths":[],"dash_offset":0.0,"cap":"Butt","join":"Miter","join_miter_limit":4.0,"align":"Center","transform":[1.0,0.0,0.0,1.0,0.0,0.0],"non_scaling":false,"paint_order":"StrokeAbove"},"fill":"None"},"colinear_manipulators":[],"point_domain":{"id":[],"position":[]},"segment_domain":{"id":[],"start_point":[],"end_point":[],"handles":[],"stroke":[]},"region_domain":{"id":[],"segment_range":[],"fill":[]},"upstream_graphic_group":null}],"transform":[[1.0,0.0,0.0,1.0,0.0,0.0]],"alpha_blending":[{"blend_mode":"Normal","opacity":1.0,"fill":1.0,"clip":false}],"source_node_id":[null]}},"exposed":true}},{"Value":{"tagged_value":{"VectorModification":{"points":{"add":[1,2,3,4,5,6,7,8,9,10,11,12],"remove":[],"delta":[[9,[1063.63448015713,504.0000000000001]],[5,[802.3909236273088,543.9999999999999]],[8,[727.7499074759312,594.0]],[10,[914.3524478543748,464.0]],[1,[662.4390183434757,536.5]],[12,[1287.5575286112626,593.9999999999999]],[3,[746.4101615137755,574.0]],[2,[774.4005425705421,566.5]],[4,[718.4197804570089,566.5]],[11,[858.3716857408418,479.00000000000006]],[6,[765.0704155516199,533.9999999999999]],[7,[634.4486372867094,569.0000000000001]]]},"segments":{"add":[1,2,3,4,5,6,7,8,9,10,11],"remove":[],"start_point":[[5,5],[8,8],[7,7],[4,4],[1,1],[6,6],[2,2],[9,9],[3,3],[11,11],[10,10]],"end_point":[[11,12],[3,4],[4,5],[9,10],[2,3],[6,7],[7,8],[5,6],[10,11],[1,2],[8,9]],"handle_primary":[[8,[0.0,0.0]],[9,[0.0,0.0]],[6,[0.0,0.0]],[10,[0.0,0.0]],[4,[0.0,0.0]],[2,[0.0,0.0]],[7,[0.0,0.0]],[11,[0.0,0.0]],[5,[0.0,0.0]],[1,[0.0,0.0]],[3,[0.0,0.0]]],"handle_end":[[11,[0.0,0.0]],[5,[0.0,0.0]],[6,[0.0,0.0]],[7,[0.0,0.0]],[1,[0.0,0.0]],[2,[0.0,0.0]],[10,[0.0,0.0]],[3,[0.0,0.0]],[4,[0.0,0.0]],[8,[0.0,0.0]],[9,[0.0,0.0]]],"stroke":[[2,0],[8,0],[9,0],[5,0],[1,0],[4,0],[11,0],[7,0],[3,0],[6,0],[10,0]]},"regions":{"add":[],"remove":[],"segment_range":[],"fill":[]},"add_g1_continuous":[],"remove_g1_continuous":[]}},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::vector_data::modification::VectorModification","alias":null}},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::vector_data::modification::PathModifyNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[183952488591282082,{"inputs":[{"Node":{"node_id":17965270694495451178,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"DVec2":[0.0,-6.0]},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[1.0,1.0]},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[0.0,0.0]},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[0.5,0.5]},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":1}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":2}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":3}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":4}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":5}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::TransformNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[1032659476619711014,{"inputs":[{"Node":{"node_id":3014633976566537110,"output_index":0,"lambda":false}},{"Node":{"node_id":2452294403891427489,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[5670058004691708784,{"inputs":[{"Value":{"tagged_value":{"VectorData":{"instance":[{"style":{"stroke":{"color":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0},"weight":0.0,"dash_lengths":[],"dash_offset":0.0,"cap":"Butt","join":"Miter","join_miter_limit":4.0,"align":"Center","transform":[1.0,0.0,0.0,1.0,0.0,0.0],"non_scaling":false,"paint_order":"StrokeAbove"},"fill":"None"},"colinear_manipulators":[],"point_domain":{"id":[],"position":[]},"segment_domain":{"id":[],"start_point":[],"end_point":[],"handles":[],"stroke":[]},"region_domain":{"id":[],"segment_range":[],"fill":[]},"upstream_graphic_group":null}],"transform":[[1.0,0.0,0.0,1.0,0.0,0.0]],"alpha_blending":[{"blend_mode":"Normal","opacity":1.0,"fill":1.0,"clip":false}],"source_node_id":[null]}},"exposed":true}},{"Value":{"tagged_value":{"VectorModification":{"points":{"add":[1,2,3,4],"remove":[],"delta":[[1,[-109.83320996790816,-37.64985269946783]],[3,[-130.2776544123526,8.793446239014884]],[4,[-115.759135893834,30.3564064604534]],[2,[-117.83320996790816,-58.65991650497199]]]},"segments":{"add":[1,2,3,4],"remove":[],"start_point":[[3,3],[1,1],[2,2],[4,4]],"end_point":[[3,4],[1,2],[4,1],[2,3]],"handle_primary":[[3,[-0.7407407407406481,44.23171327474574]],[1,[0.0,0.0]],[2,[0.0,0.0]],[4,[0.0,0.0]]],"handle_end":[[1,[0.0,0.0]],[2,[0.7407407407406481,-44.23171327474574]],[3,[0.0,0.0]],[4,[-12.740740740740762,23.22164946924204]]],"stroke":[[3,0],[4,0],[1,0],[2,0]]},"regions":{"add":[0],"remove":[],"segment_range":[[0,{"start":1,"end":4}]],"fill":[[0,0]]},"add_g1_continuous":[],"remove_g1_continuous":[]}},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::vector_data::modification::VectorModification","alias":null}},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::vector_data::modification::PathModifyNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[11221222899304956410,{"inputs":[{"Node":{"node_id":5448146793323825465,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"DVec2":[-261.2435565297001,-64.0]},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[1.0,1.0]},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[0.0,0.0]},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[0.5,0.5]},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":1}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":2}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":3}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":4}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":5}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::TransformNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[8242413775403456296,{"inputs":[{"Node":{"node_id":9138781233934614517,"output_index":0,"lambda":false}},{"Node":{"node_id":9115451226763736660,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[15157035456876170143,{"inputs":[{"Node":{"node_id":17059035448296015006,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"DVec2":[-261.2435565297001,-63.99999999999994]},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[1.0,1.0]},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[0.0,0.0]},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[0.5,0.5]},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":1}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":2}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":3}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":4}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":5}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::TransformNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[9150078008481575131,{"inputs":[{"Value":{"tagged_value":{"VectorData":{"instance":[{"style":{"stroke":{"color":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0},"weight":0.0,"dash_lengths":[],"dash_offset":0.0,"cap":"Butt","join":"Miter","join_miter_limit":4.0,"align":"Center","transform":[1.0,0.0,0.0,1.0,0.0,0.0],"non_scaling":false,"paint_order":"StrokeAbove"},"fill":"None"},"colinear_manipulators":[],"point_domain":{"id":[],"position":[]},"segment_domain":{"id":[],"start_point":[],"end_point":[],"handles":[],"stroke":[]},"region_domain":{"id":[],"segment_range":[],"fill":[]},"upstream_graphic_group":null}],"transform":[[1.0,0.0,0.0,1.0,0.0,0.0]],"alpha_blending":[{"blend_mode":"Normal","opacity":1.0,"fill":1.0,"clip":false}],"source_node_id":[null]}},"exposed":true}},{"Value":{"tagged_value":{"VectorModification":{"points":{"add":[1,2,3,4],"remove":[],"delta":[[4,[0.0,0.5]],[3,[0.5,1.0]],[2,[1.0,0.5]],[1,[0.5,0.0]]]},"segments":{"add":[1,2,3,4],"remove":[],"start_point":[[4,4],[3,3],[1,1],[2,2]],"end_point":[[4,1],[2,3],[1,2],[3,4]],"handle_primary":[[4,[0.0,-0.275892388889507]],[2,[0.0,0.27589238888950707]],[3,[-0.275892388889507,0.0]],[1,[0.27589238888950707,0.0]]],"handle_end":[[1,[0.0,-0.275892388889507]],[4,[-0.275892388889507,0.0]],[3,[0.0,0.27589238888950707]],[2,[0.27589238888950707,0.0]]],"stroke":[[1,0],[4,0],[3,0],[2,0]]},"regions":{"add":[0],"remove":[],"segment_range":[[0,{"start":1,"end":4}]],"fill":[[0,0]]},"add_g1_continuous":[],"remove_g1_continuous":[]}},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::vector_data::modification::VectorModification","alias":null}},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::vector_data::modification::PathModifyNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[15775513677915164685,{"inputs":[{"Value":{"tagged_value":{"VectorData":{"instance":[{"style":{"stroke":{"color":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0},"weight":0.0,"dash_lengths":[],"dash_offset":0.0,"cap":"Butt","join":"Miter","join_miter_limit":4.0,"align":"Center","transform":[1.0,0.0,0.0,1.0,0.0,0.0],"non_scaling":false,"paint_order":"StrokeAbove"},"fill":"None"},"colinear_manipulators":[],"point_domain":{"id":[],"position":[]},"segment_domain":{"id":[],"start_point":[],"end_point":[],"handles":[],"stroke":[]},"region_domain":{"id":[],"segment_range":[],"fill":[]},"upstream_graphic_group":null}],"transform":[[1.0,0.0,0.0,1.0,0.0,0.0]],"alpha_blending":[{"blend_mode":"Normal","opacity":1.0,"fill":1.0,"clip":false}],"source_node_id":[null]}},"exposed":true}},{"Value":{"tagged_value":{"VectorModification":{"points":{"add":[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18],"remove":[],"delta":[[11,[713.6278006401462,612.5505258344765]],[4,[682.3593964334707,606.4197530864195]],[18,[725.5089163237311,594.6117969821673]],[15,[763.4567901234569,605.6296296296294]],[1,[699.8518518518516,598.1234567901233]],[2,[667.3909465020577,593.3827160493828]],[9,[709.3552812071331,611.4970278920897]],[12,[721.9094650205761,611.3799725651577]],[17,[749.8271604938273,587.4567901234568]],[7,[692.1871665904588,615.6720012193263]],[3,[699.7421124828531,603.0617283950616]],[6,[695.3964334705074,609.7777777777776]],[16,[726.2990397805214,601.9862825788753]],[5,[662.6063100137173,612.5432098765428]],[8,[701.8247218411828,611.4580094497792]],[10,[709.413808870599,616.4718792866942]],[13,[734.8148148148149,620.9492455418381]],[14,[728.493827160494,609.9753086419753]]]},"segments":{"add":[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18],"remove":[],"start_point":[[17,17],[6,6],[12,12],[4,4],[7,7],[15,15],[3,3],[9,9],[5,5],[11,11],[2,2],[13,13],[10,10],[18,18],[16,16],[14,14],[1,1],[8,8]],"end_point":[[8,9],[11,12],[4,5],[5,6],[9,10],[17,18],[7,8],[13,14],[10,11],[6,7],[15,16],[1,2],[18,1],[3,4],[16,17],[14,15],[2,3],[12,13]],"handle_primary":[[8,[0.0,0.0]],[6,[0.0,0.0]],[7,[0.0,0.0]],[4,[-6.038618148571572,2.2123832635880945]],[5,[0.0,0.0]],[15,[-15.992684042066571,-5.647919524462736]],[12,[0.6886396813392821,0.35058484628291353]],[1,[-13.651577503429507,-4.016460905349504]],[11,[0.9510922553114368,-0.40840938602514143]],[2,[5.399176954732297,6.584362139917744]],[9,[1.0398530837227329,0.17152215813985094]],[13,[-3.101966163694442,-4.096936442615402]],[18,[-0.0877914951989851,0.0]],[16,[0.0,0.0]],[14,[-0.1771601410563335,-2.331086581557088]],[17,[-7.648317030623161,4.388047332817109]],[10,[2.71082158531226,-3.275875783141601]],[3,[0.0,0.0]]],"handle_end":[[3,[6.038618148571345,-2.2123832635879808]],[14,[-22.51851851851859,-0.614540466392441]],[9,null],[1,[8.559670781892919,2.502057613168745]],[12,[-6.90626428898031,-2.3996342021031296]],[16,[-5.977212841894016,7.381559383908893]],[10,null],[18,[0.0,0.0]],[7,[-5.1358024691359105,5.530864197530718]],[17,null],[11,[-1.2025737194898056,-0.6122274594622468]],[5,[-8.69135802469134,3.3580246913579685]],[15,[2.8483462886752022,1.1315348270080676]],[4,[0.0,0.0]],[6,[4.13595488492615,-4.1749733272365575]],[13,[-0.5267489711934559,1.053497942386798]],[2,[0.0,0.0]],[8,[-3.7847889041303233,-0.6242950769699291]]],"stroke":[[12,0],[11,0],[9,0],[17,0],[8,0],[14,0],[1,0],[2,0],[13,0],[5,0],[15,0],[16,0],[4,0],[7,0],[3,0],[10,0],[6,0],[18,0]]},"regions":{"add":[0],"remove":[],"segment_range":[[0,{"start":1,"end":18}]],"fill":[[0,0]]},"add_g1_continuous":[],"remove_g1_continuous":[]}},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::vector_data::modification::VectorModification","alias":null}},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::vector_data::modification::PathModifyNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[6569279146800941123,{"inputs":[{"Node":{"node_id":15775513677915164685,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"DVec2":[0.0,26.66666666666663]},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[1.0,1.0]},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[0.0,0.0]},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[0.5,0.5]},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":1}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":2}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":3}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":4}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":5}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::TransformNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[7799679303995308634,{"inputs":[{"Node":{"node_id":4323461535289334196,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"DVec2":[-261.2435565297001,-64.0]},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[1.0,1.0]},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[0.0,0.0]},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[0.5,0.5]},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":1}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":2}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":3}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":4}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":5}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::TransformNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[2881239077602364410,{"inputs":[{"Node":{"node_id":9641315149170593327,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"Fill":{"Gradient":{"stops":[[0.0,{"red":0.47058824,"green":0.73333335,"blue":0.6117647,"alpha":0.296875}],[0.2777869967086046,{"red":0.46666667,"green":0.72156864,"blue":0.6,"alpha":0.70703125}],[0.36183495566130336,{"red":0.46666667,"green":0.72156864,"blue":0.6039216,"alpha":0.80078125}],[0.6507416725274494,{"red":0.4745098,"green":0.7294118,"blue":0.5921569,"alpha":0.23137255}],[1.0,{"red":0.47058824,"green":0.7176471,"blue":0.6039216,"alpha":0.18359375}]],"gradient_type":"Linear","start":[0.94412535478592,0.7803313772362046],"end":[0.3197649256748516,0.1688059143071423],"transform":[484.7509931080075,0.0,0.0,412.6696147733683,724.2574339293515,434.66666666666674]}}},"exposed":false}},{"Value":{"tagged_value":{"OptionalColor":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}},"exposed":false}},{"Value":{"tagged_value":{"Gradient":{"stops":[[0.0,{"red":0.47058824,"green":0.73333335,"blue":0.6117647,"alpha":0.296875}],[0.2777869967086046,{"red":0.46666667,"green":0.72156864,"blue":0.6,"alpha":0.70703125}],[0.36183495566130336,{"red":0.46666667,"green":0.72156864,"blue":0.6039216,"alpha":0.80078125}],[0.6507416725274494,{"red":0.4745098,"green":0.7294118,"blue":0.5921569,"alpha":0.23137255}],[1.0,{"red":0.47058824,"green":0.7176471,"blue":0.6039216,"alpha":0.18359375}]],"gradient_type":"Linear","start":[0.94412535478592,0.7803313772362046],"end":[0.3197649256748516,0.1688059143071423],"transform":[484.7509931080075,0.0,0.0,412.6696147733683,724.2574339293515,434.66666666666674]}},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::FillNode"}},"visible":true,"skip_deduplication":false}],[2088390810384907709,{"inputs":[{"Node":{"node_id":14341957170885045113,"output_index":0,"lambda":false}},{"Node":{"node_id":9323583246068171750,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[2062662104423219162,{"inputs":[{"Node":{"node_id":10810157408196882043,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"DVec2":[-261.24355652970144,-64.0]},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[1.0,1.0]},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[0.0,0.0]},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[0.5,0.5]},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":1}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":2}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":3}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":4}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":5}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::TransformNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[6556170892691431702,{"inputs":[{"Value":{"tagged_value":{"GraphicGroup":{"instance":[],"transform":[],"alpha_blending":[],"source_node_id":[]}},"exposed":true}},{"Node":{"node_id":3365825508845848745,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[11595529463602678384,{"inputs":[{"Node":{"node_id":4398598693761352299,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"DVec2":[-261.2435565297001,-63.99999999999994]},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[1.0,1.0]},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[0.0,0.0]},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[0.5,0.5]},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":1}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":2}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":3}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":4}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":5}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::TransformNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[10810157408196882043,{"inputs":[{"Value":{"tagged_value":{"VectorData":{"instance":[{"style":{"stroke":{"color":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0},"weight":0.0,"dash_lengths":[],"dash_offset":0.0,"cap":"Butt","join":"Miter","join_miter_limit":4.0,"align":"Center","transform":[1.0,0.0,0.0,1.0,0.0,0.0],"non_scaling":false,"paint_order":"StrokeAbove"},"fill":"None"},"colinear_manipulators":[],"point_domain":{"id":[],"position":[]},"segment_domain":{"id":[],"start_point":[],"end_point":[],"handles":[],"stroke":[]},"region_domain":{"id":[],"segment_range":[],"fill":[]},"upstream_graphic_group":null}],"transform":[[1.0,0.0,0.0,1.0,0.0,0.0]],"alpha_blending":[{"blend_mode":"Normal","opacity":1.0,"fill":1.0,"clip":false}],"source_node_id":[null]}},"exposed":true}},{"Value":{"tagged_value":{"VectorModification":{"points":{"add":[1,2,3,4],"remove":[],"delta":[[4,[1306.2177826491084,530.0000000000023]],[1,[1231.576766497731,510.00000000000233]],[3,[1306.217782649106,559.9999999999999]],[2,[1231.5767664977286,540.0]]]},"segments":{"add":[1,2,3,4],"remove":[],"start_point":[[3,3],[2,2],[4,4],[1,1]],"end_point":[[3,4],[2,3],[1,2],[4,1]],"handle_primary":[[4,[0.0,0.0]],[1,[0.0,0.0]],[3,[0.0,0.0]],[2,[0.0,0.0]]],"handle_end":[[3,[0.0,0.0]],[1,[0.0,0.0]],[2,[0.0,0.0]],[4,[-6.821210263296962e-13,-1.1368683772161605e-13]]],"stroke":[[1,0],[3,0],[4,0],[2,0]]},"regions":{"add":[0],"remove":[],"segment_range":[[0,{"start":1,"end":4}]],"fill":[[0,0]]},"add_g1_continuous":[],"remove_g1_continuous":[]}},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::vector_data::modification::VectorModification","alias":null}},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::vector_data::modification::PathModifyNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[4323461535289334196,{"inputs":[{"Value":{"tagged_value":{"VectorData":{"instance":[{"style":{"stroke":{"color":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0},"weight":0.0,"dash_lengths":[],"dash_offset":0.0,"cap":"Butt","join":"Miter","join_miter_limit":4.0,"align":"Center","transform":[1.0,0.0,0.0,1.0,0.0,0.0],"non_scaling":false,"paint_order":"StrokeAbove"},"fill":"None"},"colinear_manipulators":[],"point_domain":{"id":[],"position":[]},"segment_domain":{"id":[],"start_point":[],"end_point":[],"handles":[],"stroke":[]},"region_domain":{"id":[],"segment_range":[],"fill":[]},"upstream_graphic_group":null}],"transform":[[1.0,0.0,0.0,1.0,0.0,0.0]],"alpha_blending":[{"blend_mode":"Normal","opacity":1.0,"fill":1.0,"clip":false}],"source_node_id":[null]}},"exposed":true}},{"Value":{"tagged_value":{"VectorModification":{"points":{"add":[1,2,3],"remove":[],"delta":[[3,[597.1281292110203,649.9999999999999]],[1,[634.4486372867091,639.9999999999999]],[2,[597.1281292110198,630.0]]]},"segments":{"add":[1,2,3],"remove":[],"start_point":[[2,2],[1,1],[3,3]],"end_point":[[1,2],[2,3],[3,1]],"handle_primary":[[1,[0.0,0.0]],[3,[0.0,0.0]],[2,[0.0,0.0]]],"handle_end":[[3,[0.0,1.1368683772161605e-13]],[1,[0.0,0.0]],[2,[0.0,0.0]]],"stroke":[[1,0],[3,0],[2,0]]},"regions":{"add":[0],"remove":[],"segment_range":[[0,{"start":1,"end":3}]],"fill":[[0,0]]},"add_g1_continuous":[],"remove_g1_continuous":[]}},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::vector_data::modification::VectorModification","alias":null}},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::vector_data::modification::PathModifyNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[16807867745126764195,{"inputs":[{"Value":{"tagged_value":{"VectorData":{"instance":[{"style":{"stroke":{"color":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0},"weight":0.0,"dash_lengths":[],"dash_offset":0.0,"cap":"Butt","join":"Miter","join_miter_limit":4.0,"align":"Center","transform":[1.0,0.0,0.0,1.0,0.0,0.0],"non_scaling":false,"paint_order":"StrokeAbove"},"fill":"None"},"colinear_manipulators":[],"point_domain":{"id":[],"position":[]},"segment_domain":{"id":[],"start_point":[],"end_point":[],"handles":[],"stroke":[]},"region_domain":{"id":[],"segment_range":[],"fill":[]},"upstream_graphic_group":null}],"transform":[[1.0,0.0,0.0,1.0,0.0,0.0]],"alpha_blending":[{"blend_mode":"Normal","opacity":1.0,"fill":1.0,"clip":false}],"source_node_id":[null]}},"exposed":true}},{"Value":{"tagged_value":{"VectorModification":{"points":{"add":[1,2,3,4],"remove":[],"delta":[[3,[0.5,1.0]],[2,[1.0,0.5]],[4,[0.0,0.5]],[1,[0.5,0.0]]]},"segments":{"add":[1,2,3,4],"remove":[],"start_point":[[1,1],[4,4],[3,3],[2,2]],"end_point":[[2,3],[1,2],[4,1],[3,4]],"handle_primary":[[4,[0.0,-0.275892388889507]],[3,[-0.275892388889507,0.0]],[1,[0.27589238888950707,0.0]],[2,[0.0,0.27589238888950707]]],"handle_end":[[4,[-0.275892388889507,0.0]],[2,[0.27589238888950707,0.0]],[1,[0.0,-0.275892388889507]],[3,[0.0,0.27589238888950707]]],"stroke":[[2,0],[3,0],[4,0],[1,0]]},"regions":{"add":[0],"remove":[],"segment_range":[[0,{"start":1,"end":4}]],"fill":[[0,0]]},"add_g1_continuous":[],"remove_g1_continuous":[]}},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::vector_data::modification::VectorModification","alias":null}},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::vector_data::modification::PathModifyNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[17881728913029763313,{"inputs":[{"Node":{"node_id":16793555741218543212,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"DVec2":[-261.2435565297001,-64.0]},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[1.0,1.0]},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[0.0,0.0]},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[0.5,0.5]},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":1}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":2}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":3}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":4}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":5}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::TransformNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[15709488322180832347,{"inputs":[{"Value":{"tagged_value":{"ArtboardGroup":{"instance":[],"transform":[],"alpha_blending":[],"source_node_id":[]}},"exposed":true}},{"Node":{"node_id":7838724497953148309,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"IVec2":[0,0]},"exposed":false}},{"Value":{"tagged_value":{"IVec2":[1270,635]},"exposed":false}},{"Value":{"tagged_value":{"Color":{"red":0.5529412,"green":0.78039217,"blue":0.70980394,"alpha":1.0}},"exposed":false}},{"Value":{"tagged_value":{"Bool":true},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":2,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graph_craft::document::value::TaggedValue","alias":null}},"import_index":1}},{"Value":{"tagged_value":{"String":"Artboard"},"exposed":false}},{"Network":{"import_type":{"Concrete":{"name":"graph_craft::document::value::TaggedValue","alias":null}},"import_index":2}},{"Network":{"import_type":{"Concrete":{"name":"graph_craft::document::value::TaggedValue","alias":null}},"import_index":3}},{"Network":{"import_type":{"Concrete":{"name":"graph_craft::document::value::TaggedValue","alias":null}},"import_index":4}},{"Network":{"import_type":{"Concrete":{"name":"graph_craft::document::value::TaggedValue","alias":null}},"import_index":5}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToArtboardNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Network":{"import_type":{"Fn":[{"Concrete":{"name":"core::option::Option>","alias":null}},{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}}]},"import_index":0}},{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::AppendArtboardNode"}},"visible":true,"skip_deduplication":false}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[14330881008352607546,{"inputs":[{"Node":{"node_id":11595529463602678384,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"Fill":{"Gradient":{"stops":[[0.0,{"red":0.27450982,"green":0.50980395,"blue":0.54509807,"alpha":1.0}],[0.7251131221719457,{"red":0.39215687,"green":0.6156863,"blue":0.5921569,"alpha":0.5019608}],[1.0,{"red":0.5058824,"green":0.7294118,"blue":0.6392157,"alpha":0.0}]],"gradient_type":"Linear","start":[0.3284027974661107,0.17846479235419954],"end":[0.3331499206771569,0.5505113976358942],"transform":[842.6155846750064,0.0,0.0,225.77816544354573,370.28268480418546,448.7065465860055]}}},"exposed":false}},{"Value":{"tagged_value":{"OptionalColor":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}},"exposed":false}},{"Value":{"tagged_value":{"Gradient":{"stops":[[0.0,{"red":0.27450982,"green":0.50980395,"blue":0.54509807,"alpha":1.0}],[0.7251131221719457,{"red":0.39215687,"green":0.6156863,"blue":0.5921569,"alpha":0.5019608}],[1.0,{"red":0.5058824,"green":0.7294118,"blue":0.6392157,"alpha":0.0}]],"gradient_type":"Linear","start":[0.3284027974661107,0.17846479235419954],"end":[0.3331499206771569,0.5505113976358942],"transform":[842.6155846750064,0.0,0.0,225.77816544354573,370.28268480418546,448.7065465860055]}},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::FillNode"}},"visible":true,"skip_deduplication":false}],[70804263053697201,{"inputs":[{"Node":{"node_id":13942787566051910019,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"DVec2":[3.410605131648481e-13,3.410605131648481e-13]},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[1268.999999999999,634.9999999999992]},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[0.0,0.0]},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[0.5,0.5]},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":1}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":2}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":3}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":4}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":5}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::TransformNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[194878846429432339,{"inputs":[{"Value":{"tagged_value":{"VectorData":{"instance":[{"style":{"stroke":{"color":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0},"weight":0.0,"dash_lengths":[],"dash_offset":0.0,"cap":"Butt","join":"Miter","join_miter_limit":4.0,"align":"Center","transform":[1.0,0.0,0.0,1.0,0.0,0.0],"non_scaling":false,"paint_order":"StrokeAbove"},"fill":"None"},"colinear_manipulators":[],"point_domain":{"id":[],"position":[]},"segment_domain":{"id":[],"start_point":[],"end_point":[],"handles":[],"stroke":[]},"region_domain":{"id":[],"segment_range":[],"fill":[]},"upstream_graphic_group":null}],"transform":[[1.0,0.0,0.0,1.0,0.0,0.0]],"alpha_blending":[{"blend_mode":"Normal","opacity":1.0,"fill":1.0,"clip":false}],"source_node_id":[null]}},"exposed":true}},{"Value":{"tagged_value":{"VectorModification":{"points":{"add":[1,2,3,4],"remove":[],"delta":[[1,[671.7691453623979,420.00000000000006]],[2,[559.8076211353317,450.0000000000001]],[4,[522.4871130596428,380.00000000000006]],[3,[410.5255888325765,410.0]]]},"segments":{"add":[1,2,3,4],"remove":[],"start_point":[[1,1],[3,3],[4,4],[2,2]],"end_point":[[4,1],[2,3],[1,2],[3,4]],"handle_primary":[[4,[0.0,0.0]],[3,[0.0,0.0]],[1,[0.0,0.0]],[2,[0.0,0.0]]],"handle_end":[[2,[0.0,0.0]],[1,[0.0,0.0]],[4,[0.0,0.0]],[3,[0.0,0.0]]],"stroke":[[3,0],[4,0],[2,0],[1,0]]},"regions":{"add":[0],"remove":[],"segment_range":[[0,{"start":1,"end":4}]],"fill":[[0,0]]},"add_g1_continuous":[],"remove_g1_continuous":[]}},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::vector_data::modification::VectorModification","alias":null}},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::vector_data::modification::PathModifyNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[3806549994589872867,{"inputs":[{"Node":{"node_id":11429712783984224234,"output_index":0,"lambda":false}},{"Node":{"node_id":11479492521093639512,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[326112971739898070,{"inputs":[{"Value":{"tagged_value":{"VectorData":{"instance":[{"style":{"stroke":{"color":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0},"weight":0.0,"dash_lengths":[],"dash_offset":0.0,"cap":"Butt","join":"Miter","join_miter_limit":4.0,"align":"Center","transform":[1.0,0.0,0.0,1.0,0.0,0.0],"non_scaling":false,"paint_order":"StrokeAbove"},"fill":"None"},"colinear_manipulators":[],"point_domain":{"id":[],"position":[]},"segment_domain":{"id":[],"start_point":[],"end_point":[],"handles":[],"stroke":[]},"region_domain":{"id":[],"segment_range":[],"fill":[]},"upstream_graphic_group":null}],"transform":[[1.0,0.0,0.0,1.0,0.0,0.0]],"alpha_blending":[{"blend_mode":"Normal","opacity":1.0,"fill":1.0,"clip":false}],"source_node_id":[null]}},"exposed":true}},{"Value":{"tagged_value":{"VectorModification":{"points":{"add":[1,2,3,4],"remove":[],"delta":[[1,[559.8076211353317,610.0]],[2,[578.4678751731759,615.0]],[4,[578.4678751731759,605.0]],[3,[597.1281292110207,610.0]]]},"segments":{"add":[1,2,3,4],"remove":[],"start_point":[[4,4],[2,2],[1,1],[3,3]],"end_point":[[4,1],[2,3],[3,4],[1,2]],"handle_primary":[[2,[0.0,0.0]],[3,[0.0,0.0]],[4,[0.0,0.0]],[1,[0.0,0.0]]],"handle_end":[[1,[0.0,0.0]],[4,[-1.1368683772161605e-13,-1.1368683772161605e-13]],[3,[0.0,0.0]],[2,[0.0,0.0]]],"stroke":[[1,0],[2,0],[4,0],[3,0]]},"regions":{"add":[0],"remove":[],"segment_range":[[0,{"start":1,"end":4}]],"fill":[[0,0]]},"add_g1_continuous":[],"remove_g1_continuous":[]}},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::vector_data::modification::VectorModification","alias":null}},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::vector_data::modification::PathModifyNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[4898866541060902381,{"inputs":[{"Node":{"node_id":7799679303995308634,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"Fill":{"Solid":{"red":0.39520264,"green":0.72265625,"blue":0.56068987,"alpha":1.0}}},"exposed":false}},{"Value":{"tagged_value":{"OptionalColor":{"red":0.39520264,"green":0.72265625,"blue":0.56068987,"alpha":1.0}},"exposed":false}},{"Value":{"tagged_value":{"Gradient":{"stops":[[0.0,{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}],[1.0,{"red":1.0,"green":1.0,"blue":1.0,"alpha":1.0}]],"gradient_type":"Linear","start":[0.0,0.5],"end":[1.0,0.5],"transform":[1.0,0.0,0.0,1.0,0.0,0.0]}},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::FillNode"}},"visible":true,"skip_deduplication":false}],[10779665858841986661,{"inputs":[{"Value":{"tagged_value":{"VectorData":{"instance":[{"style":{"stroke":{"color":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0},"weight":0.0,"dash_lengths":[],"dash_offset":0.0,"cap":"Butt","join":"Miter","join_miter_limit":4.0,"align":"Center","transform":[1.0,0.0,0.0,1.0,0.0,0.0],"non_scaling":false,"paint_order":"StrokeAbove"},"fill":"None"},"colinear_manipulators":[],"point_domain":{"id":[],"position":[]},"segment_domain":{"id":[],"start_point":[],"end_point":[],"handles":[],"stroke":[]},"region_domain":{"id":[],"segment_range":[],"fill":[]},"upstream_graphic_group":null}],"transform":[[1.0,0.0,0.0,1.0,0.0,0.0]],"alpha_blending":[{"blend_mode":"Normal","opacity":1.0,"fill":1.0,"clip":false}],"source_node_id":[null]}},"exposed":true}},{"Value":{"tagged_value":{"VectorModification":{"points":{"add":[1,2,3,4],"remove":[],"delta":[[3,[122.7099999086348,-47.60198818628578]],[1,[98.808765340734,-112.29086885060116]],[2,[97.17913571110468,-93.86098831945704]],[4,[127.45074064937567,-74.14101615113282]]]},"segments":{"add":[1,2,3,4],"remove":[],"start_point":[[1,1],[3,3],[2,2],[4,4]],"end_point":[[3,4],[4,1],[2,3],[1,2]],"handle_primary":[[4,[0.0,0.0]],[2,[0.0,0.0]],[3,[0.0,0.0]],[1,[0.0,0.0]]],"handle_end":[[1,[0.0,0.0]],[3,[0.0,0.0]],[4,[0.0,0.0]],[2,[-5.92592592592608,-17.692685309898252]]],"stroke":[[4,0],[1,0],[3,0],[2,0]]},"regions":{"add":[0],"remove":[],"segment_range":[[0,{"start":1,"end":4}]],"fill":[[0,0]]},"add_g1_continuous":[],"remove_g1_continuous":[]}},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::vector_data::modification::VectorModification","alias":null}},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::vector_data::modification::PathModifyNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[7952384394377946257,{"inputs":[{"Node":{"node_id":9935922395919478146,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"Fill":{"Gradient":{"stops":[[0.0,{"red":0.44705883,"green":0.654902,"blue":0.50980395,"alpha":1.0}],[0.15303737473719153,{"red":0.44705883,"green":0.654902,"blue":0.50980395,"alpha":1.0}],[0.45863166412588735,{"red":0.7921569,"green":0.8509804,"blue":0.58431375,"alpha":1.0}],[0.6476150394844262,{"red":0.9764706,"green":0.92941177,"blue":0.54509807,"alpha":1.0}],[1.0,{"red":0.9764706,"green":0.92941177,"blue":0.54509807,"alpha":1.0}]],"gradient_type":"Radial","start":[0.5550432633852689,0.9407795494396834],"end":[0.3799981368712242,0.012217625842737945],"transform":[548.4300072318631,0.0,0.0,524.1079289375543,1123.2642857142864,356.5966454230286]}}},"exposed":false}},{"Value":{"tagged_value":{"OptionalColor":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}},"exposed":false}},{"Value":{"tagged_value":{"Gradient":{"stops":[[0.0,{"red":0.44705883,"green":0.654902,"blue":0.50980395,"alpha":1.0}],[0.15303737473719153,{"red":0.44705883,"green":0.654902,"blue":0.50980395,"alpha":1.0}],[0.45863166412588735,{"red":0.7921569,"green":0.8509804,"blue":0.58431375,"alpha":1.0}],[0.6476150394844262,{"red":0.9764706,"green":0.92941177,"blue":0.54509807,"alpha":1.0}],[1.0,{"red":0.9764706,"green":0.92941177,"blue":0.54509807,"alpha":1.0}]],"gradient_type":"Radial","start":[0.5550432633852689,0.9407795494396834],"end":[0.3799981368712242,0.012217625842737945],"transform":[548.4300072318631,0.0,0.0,524.1079289375543,1123.2642857142864,356.5966454230286]}},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::FillNode"}},"visible":true,"skip_deduplication":false}],[9666682009015049330,{"inputs":[{"Node":{"node_id":2791109467690716388,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"DVec2":[-261.2435565297001,-64.0]},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[1.0,1.0]},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[0.0,0.0]},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[0.5,0.5]},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":1}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":2}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":3}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":4}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":5}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::TransformNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[958845362613832240,{"inputs":[{"Value":{"tagged_value":{"VectorData":{"instance":[{"style":{"stroke":{"color":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0},"weight":0.0,"dash_lengths":[],"dash_offset":0.0,"cap":"Butt","join":"Miter","join_miter_limit":4.0,"align":"Center","transform":[1.0,0.0,0.0,1.0,0.0,0.0],"non_scaling":false,"paint_order":"StrokeAbove"},"fill":"None"},"colinear_manipulators":[],"point_domain":{"id":[],"position":[]},"segment_domain":{"id":[],"start_point":[],"end_point":[],"handles":[],"stroke":[]},"region_domain":{"id":[],"segment_range":[],"fill":[]},"upstream_graphic_group":null}],"transform":[[1.0,0.0,0.0,1.0,0.0,0.0]],"alpha_blending":[{"blend_mode":"Normal","opacity":1.0,"fill":1.0,"clip":false}],"source_node_id":[null]}},"exposed":true}},{"Value":{"tagged_value":{"VectorModification":{"points":{"add":[1,2,3,4,5,6],"remove":[],"delta":[[2,[971.7488173182714,480.37931084632993]],[1,[971.7488173182716,440.37931084632993]],[4,[1195.671865772399,520.3793108463286]],[6,[1382.2744061508486,330.3793108463298]],[3,[1195.6718657723986,420.3793108463287]],[5,[1382.2744061508483,470.3793108463301]]]},"segments":{"add":[1,2,3,4,5,6],"remove":[],"start_point":[[6,6],[4,4],[5,5],[2,2],[3,3],[1,1]],"end_point":[[3,4],[1,2],[2,3],[6,1],[5,6],[4,5]],"handle_primary":[[6,[0.0,0.0]],[3,[0.0,0.0]],[5,[0.0,0.0]],[2,[0.0,0.0]],[1,[0.0,0.0]],[4,[0.0,0.0]]],"handle_end":[[1,[0.0,0.0]],[2,[0.0,0.0]],[5,[0.0,0.0]],[3,[0.0,0.0]],[6,[0.0,0.0]],[4,[0.0,0.0]]],"stroke":[[2,0],[1,0],[5,0],[4,0],[6,0],[3,0]]},"regions":{"add":[0],"remove":[],"segment_range":[[0,{"start":1,"end":6}]],"fill":[[0,0]]},"add_g1_continuous":[],"remove_g1_continuous":[]}},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::vector_data::modification::VectorModification","alias":null}},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::vector_data::modification::PathModifyNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[13817976820605296433,{"inputs":[{"Node":{"node_id":4837219841531371489,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"DVec2":[-261.24355652969996,-64.0]},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[1.0,1.0]},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[0.0,0.0]},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[0.5,0.5]},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":1}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":2}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":3}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":4}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":5}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::TransformNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[15595689026000825531,{"inputs":[{"Node":{"node_id":2785423879796980286,"output_index":0,"lambda":false}},{"Node":{"node_id":12172015233077238737,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[17433098630591807963,{"inputs":[{"Node":{"node_id":11490835759023283071,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"Fill":{"Solid":{"red":0.49019608,"green":0.69411767,"blue":0.627451,"alpha":1.0}}},"exposed":false}},{"Value":{"tagged_value":{"OptionalColor":{"red":0.49019608,"green":0.69411767,"blue":0.627451,"alpha":1.0}},"exposed":false}},{"Value":{"tagged_value":{"Gradient":{"stops":[[0.0,{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}],[1.0,{"red":1.0,"green":1.0,"blue":1.0,"alpha":1.0}]],"gradient_type":"Linear","start":[0.0,0.5],"end":[1.0,0.5],"transform":[1.0,0.0,0.0,1.0,0.0,0.0]}},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::FillNode"}},"visible":true,"skip_deduplication":false}],[3670594928372882885,{"inputs":[{"Value":{"tagged_value":{"VectorData":{"instance":[{"style":{"stroke":{"color":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0},"weight":0.0,"dash_lengths":[],"dash_offset":0.0,"cap":"Butt","join":"Miter","join_miter_limit":4.0,"align":"Center","transform":[1.0,0.0,0.0,1.0,0.0,0.0],"non_scaling":false,"paint_order":"StrokeAbove"},"fill":"None"},"colinear_manipulators":[],"point_domain":{"id":[],"position":[]},"segment_domain":{"id":[],"start_point":[],"end_point":[],"handles":[],"stroke":[]},"region_domain":{"id":[],"segment_range":[],"fill":[]},"upstream_graphic_group":null}],"transform":[[1.0,0.0,0.0,1.0,0.0,0.0]],"alpha_blending":[{"blend_mode":"Normal","opacity":1.0,"fill":1.0,"clip":false}],"source_node_id":[null]}},"exposed":true}},{"Value":{"tagged_value":{"VectorModification":{"points":{"add":[1,2,3,4],"remove":[],"delta":[[2,[671.7691453623979,420.00000000000006]],[1,[671.7691453623979,459.99999999999994]],[4,[559.8076211353317,490.00000000000006]],[3,[559.8076211353316,450.00000000000006]]]},"segments":{"add":[1,2,3,4],"remove":[],"start_point":[[2,2],[1,1],[4,4],[3,3]],"end_point":[[3,4],[2,3],[4,1],[1,2]],"handle_primary":[[1,[0.0,0.0]],[2,[0.0,0.0]],[3,[0.0,0.0]],[4,[0.0,0.0]]],"handle_end":[[2,[0.0,0.0]],[3,[0.0,0.0]],[4,[0.0,0.0]],[1,[0.0,0.0]]],"stroke":[[3,0],[1,0],[2,0],[4,0]]},"regions":{"add":[0],"remove":[],"segment_range":[[0,{"start":1,"end":4}]],"fill":[[0,0]]},"add_g1_continuous":[],"remove_g1_continuous":[]}},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::vector_data::modification::VectorModification","alias":null}},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::vector_data::modification::PathModifyNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[15723520455917422372,{"inputs":[{"Node":{"node_id":4187349759243468746,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"DVec2":[55.4066256813212,75.48692492726542]},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[1.093432966432927,1.093432966432927]},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[0.0,0.0]},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[0.5,0.5]},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":1}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":2}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":3}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":4}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":5}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::TransformNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[13743495762122910279,{"inputs":[{"Node":{"node_id":322234583139821148,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"Fill":{"Gradient":{"stops":[[0.0,{"red":0.30980393,"green":0.54901963,"blue":0.5568628,"alpha":1.0}],[1.0,{"red":0.27450982,"green":0.50980395,"blue":0.54509807,"alpha":1.0}]],"gradient_type":"Linear","start":[0.0487255567160787,0.14016773560900295],"end":[0.9275384787415986,0.5063561479050618],"transform":[117.20355654603016,0.0,0.0,62.809196653128225,646.2891914581903,455.19617712971046]}}},"exposed":false}},{"Value":{"tagged_value":{"OptionalColor":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}},"exposed":false}},{"Value":{"tagged_value":{"Gradient":{"stops":[[0.0,{"red":0.30980393,"green":0.54901963,"blue":0.5568628,"alpha":1.0}],[1.0,{"red":0.27450982,"green":0.50980395,"blue":0.54509807,"alpha":1.0}]],"gradient_type":"Linear","start":[0.0487255567160787,0.14016773560900295],"end":[0.9275384787415986,0.5063561479050618],"transform":[117.20355654603016,0.0,0.0,62.809196653128225,646.2891914581903,455.19617712971046]}},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::FillNode"}},"visible":true,"skip_deduplication":false}],[17250040304106119844,{"inputs":[{"Node":{"node_id":6142412830271644616,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"DVec2":[0.0,16.0]},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[1.0,1.0]},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[0.0,0.0]},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[0.5,0.5]},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":1}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":2}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":3}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":4}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":5}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::TransformNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[12548387328300782726,{"inputs":[{"Node":{"node_id":764189229787475993,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"Fill":{"Gradient":{"stops":[[0.0,{"red":0.972549,"green":0.87058824,"blue":0.6666667,"alpha":1.0}],[1.0,{"red":0.98039216,"green":0.94509804,"blue":0.7058824,"alpha":1.0}]],"gradient_type":"Radial","start":[0.7883568080179962,0.844472024944475],"end":[0.14631144508187544,0.21558322991428724],"transform":[468.8142261841201,0.0,0.0,125.61839330625676,23.40711309206017,381.9187810343939]}}},"exposed":false}},{"Value":{"tagged_value":{"OptionalColor":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}},"exposed":false}},{"Value":{"tagged_value":{"Gradient":{"stops":[[0.0,{"red":0.972549,"green":0.87058824,"blue":0.6666667,"alpha":1.0}],[1.0,{"red":0.98039216,"green":0.94509804,"blue":0.7058824,"alpha":1.0}]],"gradient_type":"Radial","start":[0.7883568080179962,0.844472024944475],"end":[0.14631144508187544,0.21558322991428724],"transform":[468.8142261841201,0.0,0.0,125.61839330625676,23.40711309206017,381.9187810343939]}},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::FillNode"}},"visible":true,"skip_deduplication":false}],[7339104629465306715,{"inputs":[{"Node":{"node_id":16229837691656808412,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"Fill":{"Solid":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}}},"exposed":false}},{"Value":{"tagged_value":{"OptionalColor":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}},"exposed":false}},{"Value":{"tagged_value":{"Gradient":{"stops":[[0.0,{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}],[1.0,{"red":1.0,"green":1.0,"blue":1.0,"alpha":1.0}]],"gradient_type":"Linear","start":[0.0,0.5],"end":[1.0,0.5],"transform":[1.0,0.0,0.0,1.0,0.0,0.0]}},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::FillNode"}},"visible":true,"skip_deduplication":false}],[9226731772122225003,{"inputs":[{"Node":{"node_id":8884703330021429739,"output_index":0,"lambda":false}},{"Node":{"node_id":9695624216919732577,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[10188337730058049439,{"inputs":[{"Node":{"node_id":1268775104597510914,"output_index":0,"lambda":false}},{"Node":{"node_id":11076863066321508991,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[15898396405528650339,{"inputs":[{"Node":{"node_id":16807867745126764195,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"DVec2":[1156.935750346027,389.9999999999999]},"exposed":false}},{"Value":{"tagged_value":{"F64":3.141592653589793},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[373.2050807562376,99.99999999999976]},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[-3.2814312084546346e-17,0.0]},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[0.5,0.5]},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":1}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":2}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":3}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":4}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":5}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::TransformNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[4046495708656778502,{"inputs":[{"Value":{"tagged_value":{"VectorData":{"instance":[{"style":{"stroke":{"color":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0},"weight":0.0,"dash_lengths":[],"dash_offset":0.0,"cap":"Butt","join":"Miter","join_miter_limit":4.0,"align":"Center","transform":[1.0,0.0,0.0,1.0,0.0,0.0],"non_scaling":false,"paint_order":"StrokeAbove"},"fill":"None"},"colinear_manipulators":[],"point_domain":{"id":[],"position":[]},"segment_domain":{"id":[],"start_point":[],"end_point":[],"handles":[],"stroke":[]},"region_domain":{"id":[],"segment_range":[],"fill":[]},"upstream_graphic_group":null}],"transform":[[1.0,0.0,0.0,1.0,0.0,0.0]],"alpha_blending":[{"blend_mode":"Normal","opacity":1.0,"fill":1.0,"clip":false}],"source_node_id":[null]}},"exposed":true}},{"Value":{"tagged_value":{"VectorModification":{"points":{"add":[1,2,3,4],"remove":[],"delta":[[1,[106.87778599676416,75.02595252015249]],[2,[111.05567892098054,93.44803081206965]],[4,[122.38078180163905,40.36997488237489]],[3,[130.0186418839436,64.45168544306966]]]},"segments":{"add":[1,2,3,4],"remove":[],"start_point":[[1,1],[4,4],[2,2],[3,3]],"end_point":[[4,1],[1,2],[2,3],[3,4]],"handle_primary":[[3,[0.0,0.0]],[4,[0.0,0.0]],[2,[0.0,0.0]],[1,[0.0,0.0]]],"handle_end":[[1,[0.0,0.0]],[2,[0.0,0.0]],[3,[0.0,0.0]],[4,[0.0,0.0]]],"stroke":[[2,0],[4,0],[1,0],[3,0]]},"regions":{"add":[0],"remove":[],"segment_range":[[0,{"start":1,"end":4}]],"fill":[[0,0]]},"add_g1_continuous":[],"remove_g1_continuous":[]}},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::vector_data::modification::VectorModification","alias":null}},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::vector_data::modification::PathModifyNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[9771562518763748677,{"inputs":[{"Node":{"node_id":14234384001010789008,"output_index":0,"lambda":false}},{"Node":{"node_id":12554549497938935061,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[11479492521093639512,{"inputs":[{"Node":{"node_id":15216519480392295991,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"BlendMode":"Lighten"},"exposed":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::blending_nodes::BlendModeNode"}},"visible":true,"skip_deduplication":false}],[15300421479077882117,{"inputs":[{"Node":{"node_id":7030585744407664630,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"Fill":{"Solid":{"red":0.98039216,"green":0.94509804,"blue":0.7058824,"alpha":1.0}}},"exposed":false}},{"Value":{"tagged_value":{"OptionalColor":{"red":0.98039216,"green":0.94509804,"blue":0.7058824,"alpha":1.0}},"exposed":false}},{"Value":{"tagged_value":{"Gradient":{"stops":[[0.0,{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}],[1.0,{"red":1.0,"green":1.0,"blue":1.0,"alpha":1.0}]],"gradient_type":"Linear","start":[0.0,0.5],"end":[1.0,0.5],"transform":[1.0,0.0,0.0,1.0,0.0,0.0]}},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::FillNode"}},"visible":true,"skip_deduplication":false}],[4887570735033124574,{"inputs":[{"Node":{"node_id":9210109719406330381,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"Fill":{"Gradient":{"stops":[[0.0,{"red":0.39607844,"green":0.57322305,"blue":0.627451,"alpha":0.6313726}],[1.0,{"red":0.5882353,"green":0.627451,"blue":0.39607844,"alpha":0.0}]],"gradient_type":"Linear","start":[0.7128143377734406,-0.305555555555558],"end":[0.6180751590210081,0.944444444444442],"transform":[348.32474203976165,0.0,0.0,120.0,901.7091296728228,809.666666666667]}}},"exposed":false}},{"Value":{"tagged_value":{"OptionalColor":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}},"exposed":false}},{"Value":{"tagged_value":{"Gradient":{"stops":[[0.0,{"red":0.39607844,"green":0.57322305,"blue":0.627451,"alpha":0.6313726}],[1.0,{"red":0.5882353,"green":0.627451,"blue":0.39607844,"alpha":0.0}]],"gradient_type":"Linear","start":[0.7128143377734406,-0.305555555555558],"end":[0.6180751590210081,0.944444444444442],"transform":[348.32474203976165,0.0,0.0,120.0,901.7091296728228,809.666666666667]}},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::FillNode"}},"visible":true,"skip_deduplication":false}],[5365849201631468915,{"inputs":[{"Node":{"node_id":10849502918952703647,"output_index":0,"lambda":false}},{"Node":{"node_id":2310170068575553369,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[14483299526002574058,{"inputs":[{"Value":{"tagged_value":{"VectorData":{"instance":[{"style":{"stroke":{"color":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0},"weight":0.0,"dash_lengths":[],"dash_offset":0.0,"cap":"Butt","join":"Miter","join_miter_limit":4.0,"align":"Center","transform":[1.0,0.0,0.0,1.0,0.0,0.0],"non_scaling":false,"paint_order":"StrokeAbove"},"fill":"None"},"colinear_manipulators":[],"point_domain":{"id":[],"position":[]},"segment_domain":{"id":[],"start_point":[],"end_point":[],"handles":[],"stroke":[]},"region_domain":{"id":[],"segment_range":[],"fill":[]},"upstream_graphic_group":null}],"transform":[[1.0,0.0,0.0,1.0,0.0,0.0]],"alpha_blending":[{"blend_mode":"Normal","opacity":1.0,"fill":1.0,"clip":false}],"source_node_id":[null]}},"exposed":true}},{"Value":{"tagged_value":{"VectorModification":{"points":{"add":[1,2,3,4],"remove":[],"delta":[[3,[933.0127018922192,649.9999999999999]],[4,[839.7114317029976,625.0000000000001]],[1,[1156.9357503463516,540.0]],[2,[1156.9357503463518,589.9999999999999]]]},"segments":{"add":[1,2,3,4],"remove":[],"start_point":[[4,4],[1,1],[2,2],[3,3]],"end_point":[[2,3],[4,1],[1,2],[3,4]],"handle_primary":[[3,[0.0,0.0]],[1,[0.0,0.0]],[4,[0.0,0.0]],[2,[0.0,0.0]]],"handle_end":[[2,[0.0,0.0]],[3,[0.0,0.0]],[1,[0.0,0.0]],[4,[2.273736754432321e-13,0.0]]],"stroke":[[4,0],[2,0],[1,0],[3,0]]},"regions":{"add":[0],"remove":[],"segment_range":[[0,{"start":1,"end":4}]],"fill":[[0,0]]},"add_g1_continuous":[],"remove_g1_continuous":[]}},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::vector_data::modification::VectorModification","alias":null}},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::vector_data::modification::PathModifyNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[14234384001010789008,{"inputs":[{"Node":{"node_id":4757672276235057645,"output_index":0,"lambda":false}},{"Node":{"node_id":8863202447825570192,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[16793555741218543212,{"inputs":[{"Value":{"tagged_value":{"VectorData":{"instance":[{"style":{"stroke":{"color":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0},"weight":0.0,"dash_lengths":[],"dash_offset":0.0,"cap":"Butt","join":"Miter","join_miter_limit":4.0,"align":"Center","transform":[1.0,0.0,0.0,1.0,0.0,0.0],"non_scaling":false,"paint_order":"StrokeAbove"},"fill":"None"},"colinear_manipulators":[],"point_domain":{"id":[],"position":[]},"segment_domain":{"id":[],"start_point":[],"end_point":[],"handles":[],"stroke":[]},"region_domain":{"id":[],"segment_range":[],"fill":[]},"upstream_graphic_group":null}],"transform":[[1.0,0.0,0.0,1.0,0.0,0.0]],"alpha_blending":[{"blend_mode":"Normal","opacity":1.0,"fill":1.0,"clip":false}],"source_node_id":[null]}},"exposed":true}},{"Value":{"tagged_value":{"VectorModification":{"points":{"add":[1,2,3,4,5,6],"remove":[],"delta":[[1,[559.7618537735666,489.9877366723751]],[6,[410.5255888325765,450.0000000000001]],[3,[783.7306695894638,509.9999999999999]],[2,[634.4486372867091,470.00000000000006]],[4,[597.1281292110201,559.9999999999999]],[5,[298.56406460551005,480.00000000000006]]]},"segments":{"add":[1,2,3,4,5,6],"remove":[],"start_point":[[2,2],[3,3],[6,6],[1,1],[5,5],[4,4]],"end_point":[[2,3],[6,1],[4,5],[1,2],[3,4],[5,6]],"handle_primary":[[6,[0.0,0.0]],[2,[149.28203230275471,39.99999999999983]],[5,[0.0,0.0]],[1,[0.0,0.0]],[4,[0.0,0.0]],[3,[0.0,0.0]]],"handle_end":[[3,[0.0,0.0]],[6,[0.0,0.0]],[5,[0.0,0.0]],[1,null],[4,[0.0,0.0]],[2,null]],"stroke":[[2,0],[3,0],[1,0],[5,0],[4,0],[6,0]]},"regions":{"add":[0],"remove":[],"segment_range":[[0,{"start":1,"end":6}]],"fill":[[0,0]]},"add_g1_continuous":[],"remove_g1_continuous":[]}},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::vector_data::modification::VectorModification","alias":null}},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::vector_data::modification::PathModifyNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[2209276411833629008,{"inputs":[{"Value":{"tagged_value":{"VectorData":{"instance":[{"style":{"stroke":{"color":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0},"weight":0.0,"dash_lengths":[],"dash_offset":0.0,"cap":"Butt","join":"Miter","join_miter_limit":4.0,"align":"Center","transform":[1.0,0.0,0.0,1.0,0.0,0.0],"non_scaling":false,"paint_order":"StrokeAbove"},"fill":"None"},"colinear_manipulators":[],"point_domain":{"id":[],"position":[]},"segment_domain":{"id":[],"start_point":[],"end_point":[],"handles":[],"stroke":[]},"region_domain":{"id":[],"segment_range":[],"fill":[]},"upstream_graphic_group":null}],"transform":[[1.0,0.0,0.0,1.0,0.0,0.0]],"alpha_blending":[{"blend_mode":"Normal","opacity":1.0,"fill":1.0,"clip":false}],"source_node_id":[null]}},"exposed":true}},{"Value":{"tagged_value":{"VectorModification":{"points":{"add":[1,2,3,4,5,6],"remove":[],"delta":[[5,[0.1274934116812796,0.166664669692703]],[4,[0.0,0.5]],[1,[0.8725092774641316,0.16666767219504575]],[6,[0.5000000000000018,0.10816199860278752]],[2,[1.0,0.5]],[3,[0.5,1.0]]]},"segments":{"add":[1,2,3,4,5,6],"remove":[],"start_point":[[2,2],[5,5],[3,3],[1,1],[6,6],[4,4]],"end_point":[[2,3],[3,4],[5,6],[1,2],[6,1],[4,5]],"handle_primary":[[5,[0.14548887396141374,-0.05850358027814341]],[1,[0.07925873631249913,0.08849560350574948]],[3,[-0.275892388889507,0.0]],[6,[0.22701785858837376,9.09188805575667e-7]],[2,[0.0,0.27589238888950707]],[4,[0.0,-0.12799231715991943]]],"handle_end":[[2,[0.27589238888950707,0.0]],[6,null],[4,[-0.07926033448372466,0.08849596308181285]],[5,null],[1,[0.0,-0.12799086965193351]],[3,[0.0,0.27589238888950707]]],"stroke":[[4,0],[3,0],[1,0],[2,0],[6,0],[5,0]]},"regions":{"add":[0],"remove":[],"segment_range":[[0,{"start":1,"end":6}]],"fill":[[0,0]]},"add_g1_continuous":[],"remove_g1_continuous":[]}},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::vector_data::modification::VectorModification","alias":null}},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::vector_data::modification::PathModifyNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[5434119356821575534,{"inputs":[{"Node":{"node_id":1490537476612110327,"output_index":0,"lambda":false}},{"Node":{"node_id":16261620049358949344,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[2032185045476767535,{"inputs":[{"Value":{"tagged_value":{"GraphicGroup":{"instance":[],"transform":[],"alpha_blending":[],"source_node_id":[]}},"exposed":true}},{"Node":{"node_id":7340659059180155803,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[15261165353096835967,{"inputs":[{"Value":{"tagged_value":{"VectorData":{"instance":[{"style":{"stroke":{"color":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0},"weight":0.0,"dash_lengths":[],"dash_offset":0.0,"cap":"Butt","join":"Miter","join_miter_limit":4.0,"align":"Center","transform":[1.0,0.0,0.0,1.0,0.0,0.0],"non_scaling":false,"paint_order":"StrokeAbove"},"fill":"None"},"colinear_manipulators":[],"point_domain":{"id":[],"position":[]},"segment_domain":{"id":[],"start_point":[],"end_point":[],"handles":[],"stroke":[]},"region_domain":{"id":[],"segment_range":[],"fill":[]},"upstream_graphic_group":null}],"transform":[[1.0,0.0,0.0,1.0,0.0,0.0]],"alpha_blending":[{"blend_mode":"Normal","opacity":1.0,"fill":1.0,"clip":false}],"source_node_id":[null]}},"exposed":true}},{"Value":{"tagged_value":{"VectorModification":{"points":{"add":[1,2,3,4,5,6],"remove":[],"delta":[[6,[1044.9742261192855,480.0]],[1,[1156.9357503463468,509.9999999999987]],[4,[615.7883832488644,605.0000000000001]],[2,[877.0319397786863,584.9999999999998]],[5,[597.1281292110198,599.9999999999999]],[3,[783.7306695894646,560.0]]]},"segments":{"add":[1,2,3,4,5,6],"remove":[],"start_point":[[1,1],[5,5],[3,3],[2,2],[4,4],[6,6]],"end_point":[[3,4],[4,5],[5,6],[1,2],[6,1],[2,3]],"handle_primary":[[2,[0.0,0.0]],[5,[447.84609690826574,-119.99999999999989]],[6,[0.0,0.0]],[4,null],[1,[0.0,0.0]],[3,null]],"handle_end":[[1,[0.0,0.0]],[3,null],[2,null],[6,[0.0,0.0]],[4,null],[5,null]],"stroke":[[6,0],[3,0],[4,0],[5,0],[2,0],[1,0]]},"regions":{"add":[0],"remove":[],"segment_range":[[0,{"start":1,"end":6}]],"fill":[[0,0]]},"add_g1_continuous":[],"remove_g1_continuous":[]}},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::vector_data::modification::VectorModification","alias":null}},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::vector_data::modification::PathModifyNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[1658032775659237960,{"inputs":[{"Node":{"node_id":14483299526002574058,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"DVec2":[-261.2435565297003,-64.0]},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[1.0,1.0]},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[0.0,0.0]},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[0.5,0.5]},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":1}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":2}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":3}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":4}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":5}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::TransformNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[18185020559178852986,{"inputs":[{"Value":{"tagged_value":{"GraphicGroup":{"instance":[],"transform":[],"alpha_blending":[],"source_node_id":[]}},"exposed":true}},{"Node":{"node_id":4847316728405535983,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[6785205785632793666,{"inputs":[{"Node":{"node_id":10917301734480569398,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"Fill":{"Solid":{"red":0.49803922,"green":0.73333335,"blue":0.6666667,"alpha":1.0}}},"exposed":false}},{"Value":{"tagged_value":{"OptionalColor":{"red":0.49803922,"green":0.73333335,"blue":0.6666667,"alpha":1.0}},"exposed":false}},{"Value":{"tagged_value":{"Gradient":{"stops":[[0.0,{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}],[1.0,{"red":1.0,"green":1.0,"blue":1.0,"alpha":1.0}]],"gradient_type":"Linear","start":[0.0,0.5],"end":[1.0,0.5],"transform":[1.0,0.0,0.0,1.0,0.0,0.0]}},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::FillNode"}},"visible":true,"skip_deduplication":false}],[4884180935153120645,{"inputs":[{"Node":{"node_id":11221222899304956410,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"Fill":{"Gradient":{"stops":[[0.0,{"red":0.972549,"green":0.87058824,"blue":0.6666667,"alpha":1.0}],[1.0,{"red":0.98039216,"green":0.94509804,"blue":0.7058824,"alpha":1.0}]],"gradient_type":"Radial","start":[0.4094933109340779,0.6607209771464397],"end":[0.921423168424672,0.39536705519277415],"transform":[351.6106696380906,0.0,0.0,94.21379497969252,533.0177827301501,601.7509693203432]}}},"exposed":false}},{"Value":{"tagged_value":{"OptionalColor":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}},"exposed":false}},{"Value":{"tagged_value":{"Gradient":{"stops":[[0.0,{"red":0.972549,"green":0.87058824,"blue":0.6666667,"alpha":1.0}],[1.0,{"red":0.98039216,"green":0.94509804,"blue":0.7058824,"alpha":1.0}]],"gradient_type":"Radial","start":[0.4094933109340779,0.6607209771464397],"end":[0.921423168424672,0.39536705519277415],"transform":[351.6106696380906,0.0,0.0,94.21379497969252,533.0177827301501,601.7509693203432]}},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::FillNode"}},"visible":true,"skip_deduplication":false}],[7838724497953148309,{"inputs":[{"Node":{"node_id":9771562518763748677,"output_index":0,"lambda":false}},{"Node":{"node_id":2058192342619930156,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[17873337220577786871,{"inputs":[{"Value":{"tagged_value":{"VectorData":{"instance":[{"style":{"stroke":{"color":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0},"weight":0.0,"dash_lengths":[],"dash_offset":0.0,"cap":"Butt","join":"Miter","join_miter_limit":4.0,"align":"Center","transform":[1.0,0.0,0.0,1.0,0.0,0.0],"non_scaling":false,"paint_order":"StrokeAbove"},"fill":"None"},"colinear_manipulators":[],"point_domain":{"id":[],"position":[]},"segment_domain":{"id":[],"start_point":[],"end_point":[],"handles":[],"stroke":[]},"region_domain":{"id":[],"segment_range":[],"fill":[]},"upstream_graphic_group":null}],"transform":[[1.0,0.0,0.0,1.0,0.0,0.0]],"alpha_blending":[{"blend_mode":"Normal","opacity":1.0,"fill":1.0,"clip":false}],"source_node_id":[null]}},"exposed":true}},{"Value":{"tagged_value":{"VectorModification":{"points":{"add":[1,2,3,4,5,6],"remove":[],"delta":[[6,[1044.9742261192855,480.0]],[5,[597.1281292110198,599.9999999999999]],[2,[877.0319397786863,584.9999999999998]],[3,[783.7306695894646,560.0]],[4,[615.7883832488646,605.0000000000001]],[1,[1156.9357503463468,509.9999999999987]]]},"segments":{"add":[1,2,3,4,5,6],"remove":[],"start_point":[[5,5],[6,6],[2,2],[1,1],[4,4],[3,3]],"end_point":[[1,2],[6,1],[5,6],[4,5],[2,3],[3,4]],"handle_primary":[[5,[447.84609690826574,-119.99999999999989]],[2,[0.0,0.0]],[3,null],[1,[0.0,0.0]],[6,[0.0,0.0]],[4,null]],"handle_end":[[4,null],[6,[0.0,0.0]],[1,[0.0,0.0]],[2,null],[5,null],[3,null]],"stroke":[[4,0],[6,0],[1,0],[3,0],[2,0],[5,0]]},"regions":{"add":[0],"remove":[],"segment_range":[[0,{"start":1,"end":6}]],"fill":[[0,0]]},"add_g1_continuous":[],"remove_g1_continuous":[]}},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::vector_data::modification::VectorModification","alias":null}},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::vector_data::modification::PathModifyNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[7861616450605235840,{"inputs":[{"Value":{"tagged_value":{"VectorData":{"instance":[{"style":{"stroke":{"color":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0},"weight":0.0,"dash_lengths":[],"dash_offset":0.0,"cap":"Butt","join":"Miter","join_miter_limit":4.0,"align":"Center","transform":[1.0,0.0,0.0,1.0,0.0,0.0],"non_scaling":false,"paint_order":"StrokeAbove"},"fill":"None"},"colinear_manipulators":[],"point_domain":{"id":[],"position":[]},"segment_domain":{"id":[],"start_point":[],"end_point":[],"handles":[],"stroke":[]},"region_domain":{"id":[],"segment_range":[],"fill":[]},"upstream_graphic_group":null}],"transform":[[1.0,0.0,0.0,1.0,0.0,0.0]],"alpha_blending":[{"blend_mode":"Normal","opacity":1.0,"fill":1.0,"clip":false}],"source_node_id":[null]}},"exposed":true}},{"Value":{"tagged_value":{"VectorModification":{"points":{"add":[1,2,3,4],"remove":[],"delta":[[1,[1343.3813269975649,420.0420583039525]],[3,[1268.8972745734186,460.00000000000233]],[4,[1231.5767664977302,450.00000000000233]],[2,[1343.5382907247954,439.792314581573]]]},"segments":{"add":[1,2,3,4],"remove":[],"start_point":[[2,2],[1,1],[4,4],[3,3]],"end_point":[[2,3],[4,1],[3,4],[1,2]],"handle_primary":[[1,[0.0,0.0]],[2,[0.0,0.0]],[3,[0.0,0.0]],[4,[0.0,0.0]]],"handle_end":[[1,[0.0,0.0]],[3,[0.0,0.0]],[2,[0.0,0.0]],[4,[0.0,0.0]]],"stroke":[[3,0],[4,0],[2,0],[1,0]]},"regions":{"add":[0],"remove":[],"segment_range":[[0,{"start":1,"end":4}]],"fill":[[0,0]]},"add_g1_continuous":[],"remove_g1_continuous":[]}},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::vector_data::modification::VectorModification","alias":null}},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::vector_data::modification::PathModifyNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[8463468388280418154,{"inputs":[{"Node":{"node_id":9993538712344947860,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"F64":74.5472},"exposed":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::blending_nodes::OpacityNode"}},"visible":true,"skip_deduplication":false}],[15670426414376277308,{"inputs":[{"Value":{"tagged_value":{"VectorData":{"instance":[{"style":{"stroke":{"color":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0},"weight":0.0,"dash_lengths":[],"dash_offset":0.0,"cap":"Butt","join":"Miter","join_miter_limit":4.0,"align":"Center","transform":[1.0,0.0,0.0,1.0,0.0,0.0],"non_scaling":false,"paint_order":"StrokeAbove"},"fill":"None"},"colinear_manipulators":[],"point_domain":{"id":[],"position":[]},"segment_domain":{"id":[],"start_point":[],"end_point":[],"handles":[],"stroke":[]},"region_domain":{"id":[],"segment_range":[],"fill":[]},"upstream_graphic_group":null}],"transform":[[1.0,0.0,0.0,1.0,0.0,0.0]],"alpha_blending":[{"blend_mode":"Normal","opacity":1.0,"fill":1.0,"clip":false}],"source_node_id":[null]}},"exposed":true}},{"Value":{"tagged_value":{"VectorModification":{"points":{"add":[1,2,3,4],"remove":[],"delta":[[3,[0.5,1.0]],[4,[0.0,0.5]],[2,[1.0,0.5]],[1,[0.5,0.0]]]},"segments":{"add":[1,2,3,4],"remove":[],"start_point":[[1,1],[4,4],[3,3],[2,2]],"end_point":[[1,2],[2,3],[4,1],[3,4]],"handle_primary":[[2,[0.0,0.27589238888950707]],[3,[-0.275892388889507,0.0]],[4,[0.0,-0.275892388889507]],[1,[0.27589238888950707,0.0]]],"handle_end":[[3,[0.0,0.27589238888950707]],[4,[-0.275892388889507,0.0]],[1,[0.0,-0.275892388889507]],[2,[0.27589238888950707,0.0]]],"stroke":[[2,0],[1,0],[4,0],[3,0]]},"regions":{"add":[0],"remove":[],"segment_range":[[0,{"start":1,"end":4}]],"fill":[[0,0]]},"add_g1_continuous":[],"remove_g1_continuous":[]}},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::vector_data::modification::VectorModification","alias":null}},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::vector_data::modification::PathModifyNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[2292399603649738346,{"inputs":[{"Node":{"node_id":16510804133693080967,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"Fill":{"Gradient":{"stops":[[0.0,{"red":0.27058825,"green":0.49411765,"blue":0.5137255,"alpha":1.0}],[0.9127081032507663,{"red":0.27058825,"green":0.49411765,"blue":0.5137255,"alpha":1.0}],[1.0,{"red":0.27058825,"green":0.49411765,"blue":0.5137255,"alpha":0.0}]],"gradient_type":"Radial","start":[0.6216293634586009,-3.518518518518513],"end":[0.4157051295501385,0.32812296023903675],"transform":[1332.3243231154509,0.0,0.0,297.49602202927537,-250.85405534350912,609.3847245924164]}}},"exposed":false}},{"Value":{"tagged_value":{"OptionalColor":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}},"exposed":false}},{"Value":{"tagged_value":{"Gradient":{"stops":[[0.0,{"red":0.27058825,"green":0.49411765,"blue":0.5137255,"alpha":1.0}],[0.9127081032507663,{"red":0.27058825,"green":0.49411765,"blue":0.5137255,"alpha":1.0}],[1.0,{"red":0.27058825,"green":0.49411765,"blue":0.5137255,"alpha":0.0}]],"gradient_type":"Radial","start":[0.6216293634586009,-3.518518518518513],"end":[0.4157051295501385,0.32812296023903675],"transform":[1332.3243231154509,0.0,0.0,297.49602202927537,-250.85405534350912,609.3847245924164]}},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::FillNode"}},"visible":true,"skip_deduplication":false}],[4069478660487729695,{"inputs":[{"Value":{"tagged_value":{"VectorData":{"instance":[{"style":{"stroke":{"color":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0},"weight":0.0,"dash_lengths":[],"dash_offset":0.0,"cap":"Butt","join":"Miter","join_miter_limit":4.0,"align":"Center","transform":[1.0,0.0,0.0,1.0,0.0,0.0],"non_scaling":false,"paint_order":"StrokeAbove"},"fill":"None"},"colinear_manipulators":[],"point_domain":{"id":[],"position":[]},"segment_domain":{"id":[],"start_point":[],"end_point":[],"handles":[],"stroke":[]},"region_domain":{"id":[],"segment_range":[],"fill":[]},"upstream_graphic_group":null}],"transform":[[1.0,0.0,0.0,1.0,0.0,0.0]],"alpha_blending":[{"blend_mode":"Normal","opacity":1.0,"fill":1.0,"clip":false}],"source_node_id":[null]}},"exposed":true}},{"Value":{"tagged_value":{"VectorModification":{"points":{"add":[1,2,3,4],"remove":[],"delta":[[1,[-22.15328312748764,98.9633432080564]],[2,[-23.148253406408465,116.21917209054972]],[4,[55.822325899541134,88.0419325229343]],[3,[59.855160808698834,104.19217420861494]]]},"segments":{"add":[1,2,3,4],"remove":[],"start_point":[[3,3],[1,1],[2,2],[4,4]],"end_point":[[3,4],[1,2],[2,3],[4,1]],"handle_primary":[[4,[0.0,0.0]],[1,[0.0,0.0]],[3,[0.0,0.0]],[2,[0.0,0.0]]],"handle_end":[[2,[-27.645547736903644,17.139482007743737]],[4,[24.844120782255654,5.22590107758802]],[1,[0.0,0.0]],[3,[0.0,0.0]]],"stroke":[[3,0],[1,0],[2,0],[4,0]]},"regions":{"add":[0],"remove":[],"segment_range":[[0,{"start":1,"end":4}]],"fill":[[0,0]]},"add_g1_continuous":[],"remove_g1_continuous":[]}},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::vector_data::modification::VectorModification","alias":null}},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::vector_data::modification::PathModifyNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[5326013268137833446,{"inputs":[{"Node":{"node_id":12875121980058869686,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"Fill":{"Gradient":{"stops":[[0.0,{"red":0.48235294,"green":0.69803923,"blue":0.69411767,"alpha":1.0}],[0.5005297191519419,{"red":0.48235294,"green":0.69803923,"blue":0.69411767,"alpha":1.0}],[0.8104119804726813,{"red":0.5686275,"green":0.69411767,"blue":0.5372549,"alpha":0.87890625}],[1.0,{"red":0.3529412,"green":0.5647059,"blue":0.57254905,"alpha":0.296875}]],"gradient_type":"Radial","start":[0.0015840517590797742,0.9627709247339196],"end":[1.0370671897237005,-1.554312234475219e-14],"transform":[2645.364887303592,0.0,0.0,759.3749999999876,-1035.2336294696888,690.8750000000118]}}},"exposed":false}},{"Value":{"tagged_value":{"OptionalColor":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}},"exposed":false}},{"Value":{"tagged_value":{"Gradient":{"stops":[[0.0,{"red":0.48235294,"green":0.69803923,"blue":0.69411767,"alpha":1.0}],[0.5005297191519419,{"red":0.48235294,"green":0.69803923,"blue":0.69411767,"alpha":1.0}],[0.8104119804726813,{"red":0.5686275,"green":0.69411767,"blue":0.5372549,"alpha":0.87890625}],[1.0,{"red":0.3529412,"green":0.5647059,"blue":0.57254905,"alpha":0.296875}]],"gradient_type":"Radial","start":[0.0015840517590797742,0.9627709247339196],"end":[1.0370671897237005,-1.554312234475219e-14],"transform":[2645.364887303592,0.0,0.0,759.3749999999876,-1035.2336294696888,690.8750000000118]}},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::FillNode"}},"visible":true,"skip_deduplication":false}],[12537712543904859919,{"inputs":[{"Node":{"node_id":4968550668755026811,"output_index":0,"lambda":false}},{"Node":{"node_id":8508454285877707748,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[12469956387875933942,{"inputs":[{"Value":{"tagged_value":{"GraphicGroup":{"instance":[],"transform":[],"alpha_blending":[],"source_node_id":[]}},"exposed":true}},{"Node":{"node_id":2881239077602364410,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[13207576193421440093,{"inputs":[{"Node":{"node_id":12930243402848966353,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"Fill":{"Solid":{"red":0.5686275,"green":0.7411765,"blue":0.654902,"alpha":1.0}}},"exposed":false}},{"Value":{"tagged_value":{"OptionalColor":{"red":0.5686275,"green":0.7411765,"blue":0.654902,"alpha":1.0}},"exposed":false}},{"Value":{"tagged_value":{"Gradient":{"stops":[[0.0,{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}],[1.0,{"red":1.0,"green":1.0,"blue":1.0,"alpha":1.0}]],"gradient_type":"Linear","start":[0.0,0.5],"end":[1.0,0.5],"transform":[1.0,0.0,0.0,1.0,0.0,0.0]}},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::FillNode"}},"visible":true,"skip_deduplication":false}],[5574499968250848265,{"inputs":[{"Node":{"node_id":11776939455674933130,"output_index":0,"lambda":false}},{"Node":{"node_id":5925268772265373737,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[18371793711669837037,{"inputs":[{"Node":{"node_id":7861616450605235840,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"DVec2":[-261.2435565297001,-64.00000000000006]},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[1.0,1.0]},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[0.0,0.0]},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[0.5,0.5]},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":1}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":2}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":3}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":4}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":5}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::TransformNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[10742991645899166287,{"inputs":[{"Node":{"node_id":1104068854328504126,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"DVec2":[-298.5640646053887,-114.0000000000026]},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[0.9999999999999996,0.9999999999999996]},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[0.0,0.0]},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[0.5,0.5]},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":1}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":2}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":3}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":4}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":5}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::TransformNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[18085100003956405261,{"inputs":[{"Value":{"tagged_value":{"VectorData":{"instance":[{"style":{"stroke":{"color":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0},"weight":0.0,"dash_lengths":[],"dash_offset":0.0,"cap":"Butt","join":"Miter","join_miter_limit":4.0,"align":"Center","transform":[1.0,0.0,0.0,1.0,0.0,0.0],"non_scaling":false,"paint_order":"StrokeAbove"},"fill":"None"},"colinear_manipulators":[],"point_domain":{"id":[],"position":[]},"segment_domain":{"id":[],"start_point":[],"end_point":[],"handles":[],"stroke":[]},"region_domain":{"id":[],"segment_range":[],"fill":[]},"upstream_graphic_group":null}],"transform":[[1.0,0.0,0.0,1.0,0.0,0.0]],"alpha_blending":[{"blend_mode":"Normal","opacity":1.0,"fill":1.0,"clip":false}],"source_node_id":[null]}},"exposed":true}},{"Value":{"tagged_value":{"VectorModification":{"points":{"add":[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19],"remove":[],"delta":[[19,[530.7654320987656,499.55555555555566]],[8,[502.0960349862431,417.9179038759178]],[2,[476.9512618480758,444.1904085078117]],[10,[524.0493827160495,487.1111111111112]],[14,[552.9705625612692,418.19081042008474]],[6,[499.77650172698026,445.9388618767647]],[13,[526.0246913580248,490.07407407407413]],[1,[510.41975308641986,500.1481481481481]],[17,[565.2914244954804,444.3855996237166]],[15,[556.7578325004595,420.13017723423656]],[18,[568.2339832275112,446.0155371619765]],[5,[497.38271604938257,447.60493827160496]],[3,[480.5925925925926,440.2962962962962]],[12,[533.8924329970387,433.46495092641567]],[4,[511.55555555555554,490.2222222222222]],[9,[505.311372421164,416.4524664944526]],[16,[530.3703703703702,486.71604938271594]],[7,[515.1604938271604,486.716049382716]],[11,[531.5890484844431,432.90541944395505]]]},"segments":{"add":[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19],"remove":[],"start_point":[[3,3],[15,15],[6,6],[5,5],[10,10],[11,11],[4,4],[16,16],[7,7],[12,12],[13,13],[17,17],[14,14],[9,9],[19,19],[18,18],[8,8],[2,2],[1,1]],"end_point":[[6,7],[5,6],[4,5],[11,12],[7,8],[9,10],[13,14],[18,19],[1,2],[12,13],[14,15],[2,3],[15,16],[3,4],[16,17],[17,18],[8,9],[10,11],[19,1]],"handle_primary":[[10,[0.0,0.0]],[5,[-10.016557406305251,-15.024836109457851]],[1,[-9.283950617284065,-12.246913580246884]],[15,[-11.459519915000214,23.15277176924241]],[4,[0.0,0.0]],[3,[21.32824309569804,17.329197515254634]],[18,[-19.30865594294653,18.299752742610902]],[6,[3.9272019767233246,4.629039357803151]],[12,[-5.082537215847424,18.7049831985629]],[9,[11.197015798182122,18.39034937970939]],[7,[0.0,0.0]],[17,[27.324497401397252,-21.15032331824051]],[19,[-1.5204271954055455,4.429070525747022]],[2,[-17.16805625160663,-20.28383937076643]],[16,[0.0,0.0]],[14,[15.260998855532309,-21.888591759537466]],[13,[0.0,0.0]],[11,[7.784237194372736,-22.222909722529664]],[8,[-8.936088730151937,-20.93774746663439]]],"handle_end":[[19,[2.7053847913285836,3.5688054694122116]],[5,[-12.032856371187677,-14.183269935989983]],[11,[5.082537215847424,-18.704983198562843]],[6,[0.7901234567898427,-16.197530864197745]],[10,[-7.784237194372736,22.22290972252955]],[4,[13.03703703703701,19.555555555555543]],[18,[4.54320987654296,-13.23456790123464]],[8,[-11.197015798182008,-18.39034937970939]],[15,[4.54320987654296,-11.851851851852018]],[17,[19.435079545528083,-18.419570542198244]],[14,[11.286699158099054,-22.803605349427187]],[7,[18.59187624528363,43.5617887769169]],[16,[-28.402535606591755,21.984770746653737]],[3,[-3.111111111111086,-12.0]],[13,[-15.260998855532534,21.888591759537743]],[12,[3.7530864197531177,-16.59259259259261]],[2,[-22.123456790123555,-17.97530864197529]],[9,[0.7901234567898427,-21.135802469135857]],[1,[28.522359190346833,33.698803394714844]]],"stroke":[[10,0],[1,0],[9,0],[7,0],[4,0],[16,0],[19,0],[18,0],[3,0],[13,0],[15,0],[8,0],[11,0],[12,0],[17,0],[14,0],[5,0],[2,0],[6,0]]},"regions":{"add":[0],"remove":[],"segment_range":[[0,{"start":1,"end":19}]],"fill":[[0,0]]},"add_g1_continuous":[],"remove_g1_continuous":[]}},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::vector_data::modification::VectorModification","alias":null}},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::vector_data::modification::PathModifyNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[8612613134760093452,{"inputs":[{"Value":{"tagged_value":{"VectorData":{"instance":[{"style":{"stroke":{"color":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0},"weight":0.0,"dash_lengths":[],"dash_offset":0.0,"cap":"Butt","join":"Miter","join_miter_limit":4.0,"align":"Center","transform":[1.0,0.0,0.0,1.0,0.0,0.0],"non_scaling":false,"paint_order":"StrokeAbove"},"fill":"None"},"colinear_manipulators":[],"point_domain":{"id":[],"position":[]},"segment_domain":{"id":[],"start_point":[],"end_point":[],"handles":[],"stroke":[]},"region_domain":{"id":[],"segment_range":[],"fill":[]},"upstream_graphic_group":null}],"transform":[[1.0,0.0,0.0,1.0,0.0,0.0]],"alpha_blending":[{"blend_mode":"Normal","opacity":1.0,"fill":1.0,"clip":false}],"source_node_id":[null]}},"exposed":true}},{"Value":{"tagged_value":{"VectorModification":{"points":{"add":[1,2,3,4],"remove":[],"delta":[[2,[839.7114317029974,625.0000000000001]],[4,[933.0127018922192,670.0000000000001]],[1,[933.0127018922192,650.0]],[3,[802.3909236273086,635.0000000000001]]]},"segments":{"add":[1,2,3,4],"remove":[],"start_point":[[1,1],[4,4],[3,3],[2,2]],"end_point":[[1,2],[3,4],[4,1],[2,3]],"handle_primary":[[4,[0.0,0.0]],[1,[0.0,0.0]],[2,[0.0,0.0]],[3,[0.0,0.0]]],"handle_end":[[4,[0.0,0.0]],[3,[0.0,0.0]],[1,[0.0,0.0]],[2,[0.0,0.0]]],"stroke":[[1,0],[3,0],[2,0],[4,0]]},"regions":{"add":[0],"remove":[],"segment_range":[[0,{"start":1,"end":4}]],"fill":[[0,0]]},"add_g1_continuous":[],"remove_g1_continuous":[]}},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::vector_data::modification::VectorModification","alias":null}},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::vector_data::modification::PathModifyNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[12931264630175648107,{"inputs":[{"Value":{"tagged_value":{"VectorData":{"instance":[{"style":{"stroke":{"color":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0},"weight":0.0,"dash_lengths":[],"dash_offset":0.0,"cap":"Butt","join":"Miter","join_miter_limit":4.0,"align":"Center","transform":[1.0,0.0,0.0,1.0,0.0,0.0],"non_scaling":false,"paint_order":"StrokeAbove"},"fill":"None"},"colinear_manipulators":[],"point_domain":{"id":[],"position":[]},"segment_domain":{"id":[],"start_point":[],"end_point":[],"handles":[],"stroke":[]},"region_domain":{"id":[],"segment_range":[],"fill":[]},"upstream_graphic_group":null}],"transform":[[1.0,0.0,0.0,1.0,0.0,0.0]],"alpha_blending":[{"blend_mode":"Normal","opacity":1.0,"fill":1.0,"clip":false}],"source_node_id":[null]}},"exposed":true}},{"Value":{"tagged_value":{"VectorModification":{"points":{"add":[1,2,3,4,5,6,7,8,9,10,11],"remove":[],"delta":[[3,[1531.243556529699,704.9999999999997]],[9,[1231.576766497731,510.0000000000024]],[7,[298.56406460551045,540.0000000000001]],[8,[709.0896534380863,649.9999999999999]],[5,[261.2435565296994,530.0000000000001]],[11,[1492.8203230275508,480.0000000000001]],[6,[298.56406460551034,520.0000000000002]],[1,[1492.820323027551,460.0000000000025]],[4,[261.24355652969956,704.9999999999997]],[2,[1531.2435565296985,470.3]],[10,[1306.2177826491086,530.0000000000023]]]},"segments":{"add":[1,2,3,4,5,6,7,8,9,10,11],"remove":[],"start_point":[[11,11],[8,8],[10,10],[5,5],[4,4],[3,3],[6,6],[7,7],[2,2],[1,1],[9,9]],"end_point":[[6,7],[8,9],[10,11],[3,4],[9,10],[5,6],[1,2],[4,5],[11,1],[7,8],[2,3]],"handle_primary":[[3,[0.0,0.0]],[4,[0.0,0.0]],[10,[0.0,0.0]],[7,[0.0,0.0]],[1,[0.0,0.0]],[8,[0.0,0.0]],[2,[0.0,0.0]],[5,[0.0,0.0]],[9,[0.0,0.0]],[11,[0.0,0.0]],[6,[0.0,0.0]]],"handle_end":[[10,[0.0,0.0]],[6,[0.0,0.0]],[7,[0.0,0.0]],[11,[0.0,0.0]],[1,[0.0,0.0]],[8,[0.0,0.0]],[2,[0.0,0.0]],[5,[0.0,0.0]],[3,[0.0,0.0]],[4,[0.0,0.0]],[9,[0.0,0.0]]],"stroke":[[7,0],[2,0],[5,0],[9,0],[11,0],[8,0],[1,0],[6,0],[10,0],[4,0],[3,0]]},"regions":{"add":[0],"remove":[],"segment_range":[[0,{"start":1,"end":11}]],"fill":[[0,0]]},"add_g1_continuous":[],"remove_g1_continuous":[]}},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::vector_data::modification::VectorModification","alias":null}},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::vector_data::modification::PathModifyNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[4757672276235057645,{"inputs":[{"Node":{"node_id":4924169570021915606,"output_index":0,"lambda":false}},{"Node":{"node_id":14400993470150734626,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[15134939288287905620,{"inputs":[{"Node":{"node_id":8958782938691501404,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"DVec2":[-261.2435565297001,-64.0]},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[1.0,1.0]},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[0.0,0.0]},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[0.5,0.5]},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":1}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":2}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":3}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":4}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":5}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::TransformNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[10989897386232385465,{"inputs":[{"Node":{"node_id":10507084483235320484,"output_index":0,"lambda":false}},{"Node":{"node_id":7339104629465306715,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[5540780316862276409,{"inputs":[{"Node":{"node_id":1032659476619711014,"output_index":0,"lambda":false}},{"Node":{"node_id":13743495762122910279,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[9695624216919732577,{"inputs":[{"Node":{"node_id":1156213189397385283,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"OptionalColor":{"red":0.9372549,"green":0.90588236,"blue":0.7764706,"alpha":0.7490196}},"exposed":false}},{"Value":{"tagged_value":{"F64":3.0},"exposed":false}},{"Value":{"tagged_value":{"StrokeAlign":"Center"},"exposed":false}},{"Value":{"tagged_value":{"StrokeCap":"Butt"},"exposed":false}},{"Value":{"tagged_value":{"StrokeJoin":"Miter"},"exposed":false}},{"Value":{"tagged_value":{"F64":4.0},"exposed":false}},{"Value":{"tagged_value":{"PaintOrder":"StrokeAbove"},"exposed":false}},{"Value":{"tagged_value":{"VecF64":[]},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::StrokeNode"}},"visible":true,"skip_deduplication":false}],[16852951849051795674,{"inputs":[{"Value":{"tagged_value":{"VectorData":{"instance":[{"style":{"stroke":{"color":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0},"weight":0.0,"dash_lengths":[],"dash_offset":0.0,"cap":"Butt","join":"Miter","join_miter_limit":4.0,"align":"Center","transform":[1.0,0.0,0.0,1.0,0.0,0.0],"non_scaling":false,"paint_order":"StrokeAbove"},"fill":"None"},"colinear_manipulators":[],"point_domain":{"id":[],"position":[]},"segment_domain":{"id":[],"start_point":[],"end_point":[],"handles":[],"stroke":[]},"region_domain":{"id":[],"segment_range":[],"fill":[]},"upstream_graphic_group":null}],"transform":[[1.0,0.0,0.0,1.0,0.0,0.0]],"alpha_blending":[{"blend_mode":"Normal","opacity":1.0,"fill":1.0,"clip":false}],"source_node_id":[null]}},"exposed":true}},{"Value":{"tagged_value":{"VectorModification":{"points":{"add":[1,2,3,4,5,6,7,8],"remove":[],"delta":[[2,[1156.9357503463518,590.0]],[5,[1343.5382907247958,560.0]],[3,[933.0127018922192,650.0]],[1,[1156.9357503463525,530.0]],[8,[1231.576766497731,510.0000000000022]],[4,[933.0127018922192,670.0]],[6,[1343.5382907247958,520.0]],[7,[1306.2177826491068,529.9999999999972]]]},"segments":{"add":[1,2,3,4,5,6,7,8],"remove":[],"start_point":[[4,4],[3,3],[5,5],[2,2],[1,1],[7,7],[8,8],[6,6]],"end_point":[[5,6],[4,5],[6,7],[7,8],[3,4],[1,2],[2,3],[8,1]],"handle_primary":[[2,null],[1,[0.0,0.0]],[6,null],[7,[-74.64101615137588,-19.99999999999494]],[3,[0.0,20.0]],[4,[0.0,0.0]],[5,null],[8,[0.0,0.0]]],"handle_end":[[7,null],[3,null],[5,null],[6,null],[2,null],[8,[0.0,0.0]],[1,null],[4,null]],"stroke":[[2,0],[7,0],[5,0],[1,0],[8,0],[6,0],[4,0],[3,0]]},"regions":{"add":[0],"remove":[],"segment_range":[[0,{"start":1,"end":8}]],"fill":[[0,0]]},"add_g1_continuous":[],"remove_g1_continuous":[]}},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::vector_data::modification::VectorModification","alias":null}},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::vector_data::modification::PathModifyNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[14124486712683868036,{"inputs":[{"Node":{"node_id":14449527838292182035,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"Fill":{"Gradient":{"stops":[[0.0,{"red":0.44433594,"green":0.7109375,"blue":0.60144055,"alpha":1.0}],[0.31019165912642926,{"red":0.42991638,"green":0.68359375,"blue":0.5723318,"alpha":0.85546875}],[1.0,{"red":0.41487122,"green":0.66796875,"blue":0.5466929,"alpha":0.3515625}]],"gradient_type":"Radial","start":[0.49564744287268736,0.12680209698558276],"end":[0.6983677910772572,0.8876146788990837],"transform":[340.37037037037106,0.0,0.0,113.03703703703678,837.2962962962961,682.6666666666667]}}},"exposed":false}},{"Value":{"tagged_value":{"OptionalColor":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}},"exposed":false}},{"Value":{"tagged_value":{"Gradient":{"stops":[[0.0,{"red":0.44433594,"green":0.7109375,"blue":0.60144055,"alpha":1.0}],[0.31019165912642926,{"red":0.42991638,"green":0.68359375,"blue":0.5723318,"alpha":0.85546875}],[1.0,{"red":0.41487122,"green":0.66796875,"blue":0.5466929,"alpha":0.3515625}]],"gradient_type":"Radial","start":[0.49564744287268736,0.12680209698558276],"end":[0.6983677910772572,0.8876146788990837],"transform":[340.37037037037106,0.0,0.0,113.03703703703678,837.2962962962961,682.6666666666667]}},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::FillNode"}},"visible":true,"skip_deduplication":false}],[11450962621506425680,{"inputs":[{"Node":{"node_id":514222872092587805,"output_index":0,"lambda":false}},{"Node":{"node_id":6006052038693767172,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[11158238411769751544,{"inputs":[{"Value":{"tagged_value":{"GraphicGroup":{"instance":[],"transform":[],"alpha_blending":[],"source_node_id":[]}},"exposed":true}},{"Node":{"node_id":14124486712683868036,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[2310170068575553369,{"inputs":[{"Node":{"node_id":3564067978712674849,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"Fill":{"Gradient":{"stops":[[0.0,{"red":0.94921875,"green":0.8861847,"blue":0.5710144,"alpha":1.0}],[1.0,{"red":0.6594621,"green":0.859375,"blue":0.62438965,"alpha":1.0}]],"gradient_type":"Radial","start":[0.9615262104062824,0.1999999999999842],"end":[0.047819464216158014,0.809999999999961],"transform":[373.20508075688934,0.0,0.0,100.00000000000384,799.1535329954577,376.0000000000008]}}},"exposed":false}},{"Value":{"tagged_value":{"OptionalColor":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}},"exposed":false}},{"Value":{"tagged_value":{"Gradient":{"stops":[[0.0,{"red":0.94921875,"green":0.8861847,"blue":0.5710144,"alpha":1.0}],[1.0,{"red":0.6594621,"green":0.859375,"blue":0.62438965,"alpha":1.0}]],"gradient_type":"Radial","start":[0.9615262104062824,0.1999999999999842],"end":[0.047819464216158014,0.809999999999961],"transform":[373.20508075688934,0.0,0.0,100.00000000000384,799.1535329954577,376.0000000000008]}},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::FillNode"}},"visible":true,"skip_deduplication":false}],[6868877732348460627,{"inputs":[{"Node":{"node_id":7884283658260267478,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"OptionalColor":{"red":0.9372549,"green":0.90588236,"blue":0.7764706,"alpha":0.7490196}},"exposed":false}},{"Value":{"tagged_value":{"F64":3.0},"exposed":false}},{"Value":{"tagged_value":{"StrokeAlign":"Center"},"exposed":false}},{"Value":{"tagged_value":{"StrokeCap":"Butt"},"exposed":false}},{"Value":{"tagged_value":{"StrokeJoin":"Miter"},"exposed":false}},{"Value":{"tagged_value":{"F64":4.0},"exposed":false}},{"Value":{"tagged_value":{"PaintOrder":"StrokeAbove"},"exposed":false}},{"Value":{"tagged_value":{"VecF64":[]},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::StrokeNode"}},"visible":true,"skip_deduplication":false}],[4191887059541031673,{"inputs":[{"Node":{"node_id":4046495708656778502,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"Fill":{"Solid":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}}},"exposed":false}},{"Value":{"tagged_value":{"OptionalColor":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}},"exposed":false}},{"Value":{"tagged_value":{"Gradient":{"stops":[[0.0,{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}],[1.0,{"red":1.0,"green":1.0,"blue":1.0,"alpha":1.0}]],"gradient_type":"Linear","start":[0.0,0.5],"end":[1.0,0.5],"transform":[1.0,0.0,0.0,1.0,0.0,0.0]}},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::FillNode"}},"visible":true,"skip_deduplication":false}],[13287180494862716983,{"inputs":[{"Value":{"tagged_value":{"VectorData":{"instance":[{"style":{"stroke":{"color":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0},"weight":0.0,"dash_lengths":[],"dash_offset":0.0,"cap":"Butt","join":"Miter","join_miter_limit":4.0,"align":"Center","transform":[1.0,0.0,0.0,1.0,0.0,0.0],"non_scaling":false,"paint_order":"StrokeAbove"},"fill":"None"},"colinear_manipulators":[],"point_domain":{"id":[],"position":[]},"segment_domain":{"id":[],"start_point":[],"end_point":[],"handles":[],"stroke":[]},"region_domain":{"id":[],"segment_range":[],"fill":[]},"upstream_graphic_group":null}],"transform":[[1.0,0.0,0.0,1.0,0.0,0.0]],"alpha_blending":[{"blend_mode":"Normal","opacity":1.0,"fill":1.0,"clip":false}],"source_node_id":[null]}},"exposed":true}},{"Value":{"tagged_value":{"VectorModification":{"points":{"add":[1,2,3,4],"remove":[],"delta":[[4,[830.3813046840752,527.5]],[2,[783.7306695894644,525.0]],[3,[811.7210506462309,532.5]],[1,[765.0704155516202,530.0]]]},"segments":{"add":[1,2,3],"remove":[],"start_point":[[2,2],[3,3],[1,1]],"end_point":[[1,2],[2,3],[3,4]],"handle_primary":[[1,[0.0,0.0]],[3,[0.0,0.0]],[2,[0.0,0.0]]],"handle_end":[[3,[0.0,0.0]],[1,[0.0,0.0]],[2,[0.0,0.0]]],"stroke":[[1,0],[2,0],[3,0]]},"regions":{"add":[],"remove":[],"segment_range":[],"fill":[]},"add_g1_continuous":[],"remove_g1_continuous":[]}},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::vector_data::modification::VectorModification","alias":null}},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::vector_data::modification::PathModifyNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[1396768435017101055,{"inputs":[{"Node":{"node_id":15914878146223026034,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"Fill":{"Solid":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}}},"exposed":false}},{"Value":{"tagged_value":{"OptionalColor":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}},"exposed":false}},{"Value":{"tagged_value":{"Gradient":{"stops":[[0.0,{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}],[1.0,{"red":1.0,"green":1.0,"blue":1.0,"alpha":1.0}]],"gradient_type":"Linear","start":[0.0,0.5],"end":[1.0,0.5],"transform":[1.0,0.0,0.0,1.0,0.0,0.0]}},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::FillNode"}},"visible":true,"skip_deduplication":false}],[16727310898641763441,{"inputs":[{"Node":{"node_id":13920465562072008593,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"Fill":{"Solid":{"red":0.4117647,"green":0.6392157,"blue":0.6117647,"alpha":1.0}}},"exposed":false}},{"Value":{"tagged_value":{"OptionalColor":{"red":0.4117647,"green":0.6392157,"blue":0.6117647,"alpha":1.0}},"exposed":false}},{"Value":{"tagged_value":{"Gradient":{"stops":[[0.0,{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}],[1.0,{"red":1.0,"green":1.0,"blue":1.0,"alpha":1.0}]],"gradient_type":"Linear","start":[0.0,0.5],"end":[1.0,0.5],"transform":[1.0,0.0,0.0,1.0,0.0,0.0]}},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::FillNode"}},"visible":true,"skip_deduplication":false}],[9278774434958175105,{"inputs":[{"Node":{"node_id":3927358878935116440,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"DVec2":[-298.5640646053914,-74.00000000000011]},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[0.9999999999999972,0.9999999999999972]},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[0.0,0.0]},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[0.5,0.5]},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":1}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":2}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":3}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":4}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":5}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::TransformNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[12930243402848966353,{"inputs":[{"Node":{"node_id":7948029953091985757,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"DVec2":[895.6921938163274,315.9999999999998]},"exposed":false}},{"Value":{"tagged_value":{"F64":3.141592653589793},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[373.2050807562376,99.99999999999976]},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[-3.2814312084546346e-17,0.0]},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[0.5,0.5]},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":1}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":2}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":3}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":4}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":5}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::TransformNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[14805036488257720752,{"inputs":[{"Value":{"tagged_value":{"VectorData":{"instance":[{"style":{"stroke":{"color":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0},"weight":0.0,"dash_lengths":[],"dash_offset":0.0,"cap":"Butt","join":"Miter","join_miter_limit":4.0,"align":"Center","transform":[1.0,0.0,0.0,1.0,0.0,0.0],"non_scaling":false,"paint_order":"StrokeAbove"},"fill":"None"},"colinear_manipulators":[],"point_domain":{"id":[],"position":[]},"segment_domain":{"id":[],"start_point":[],"end_point":[],"handles":[],"stroke":[]},"region_domain":{"id":[],"segment_range":[],"fill":[]},"upstream_graphic_group":null}],"transform":[[1.0,0.0,0.0,1.0,0.0,0.0]],"alpha_blending":[{"blend_mode":"Normal","opacity":1.0,"fill":1.0,"clip":false}],"source_node_id":[null]}},"exposed":true}},{"Value":{"tagged_value":{"VectorModification":{"points":{"add":[1,2,3,4],"remove":[],"delta":[[3,[895.6921938165302,595.0]],[1,[849.0415587219195,597.5000000000001]],[2,[877.0319397786858,590.0]],[4,[942.3428289111416,582.5]]]},"segments":{"add":[1,2,3],"remove":[],"start_point":[[2,2],[3,3],[1,1]],"end_point":[[3,4],[1,2],[2,3]],"handle_primary":[[2,[0.0,0.0]],[1,[0.0,0.0]],[3,[0.0,0.0]]],"handle_end":[[1,[0.0,0.0]],[3,[0.0,0.0]],[2,[0.0,0.0]]],"stroke":[[3,0],[1,0],[2,0]]},"regions":{"add":[],"remove":[],"segment_range":[],"fill":[]},"add_g1_continuous":[],"remove_g1_continuous":[]}},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::vector_data::modification::VectorModification","alias":null}},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::vector_data::modification::PathModifyNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[18011777376689315137,{"inputs":[{"Node":{"node_id":10564228200140683112,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"Fill":{"Solid":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}}},"exposed":false}},{"Value":{"tagged_value":{"OptionalColor":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}},"exposed":false}},{"Value":{"tagged_value":{"Gradient":{"stops":[[0.0,{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}],[1.0,{"red":1.0,"green":1.0,"blue":1.0,"alpha":1.0}]],"gradient_type":"Linear","start":[0.0,0.5],"end":[1.0,0.5],"transform":[1.0,0.0,0.0,1.0,0.0,0.0]}},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::FillNode"}},"visible":true,"skip_deduplication":false}],[8343201730608263656,{"inputs":[{"Value":{"tagged_value":{"VectorData":{"instance":[{"style":{"stroke":{"color":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0},"weight":0.0,"dash_lengths":[],"dash_offset":0.0,"cap":"Butt","join":"Miter","join_miter_limit":4.0,"align":"Center","transform":[1.0,0.0,0.0,1.0,0.0,0.0],"non_scaling":false,"paint_order":"StrokeAbove"},"fill":"None"},"colinear_manipulators":[],"point_domain":{"id":[],"position":[]},"segment_domain":{"id":[],"start_point":[],"end_point":[],"handles":[],"stroke":[]},"region_domain":{"id":[],"segment_range":[],"fill":[]},"upstream_graphic_group":null}],"transform":[[1.0,0.0,0.0,1.0,0.0,0.0]],"alpha_blending":[{"blend_mode":"Normal","opacity":1.0,"fill":1.0,"clip":false}],"source_node_id":[null]}},"exposed":true}},{"Value":{"tagged_value":{"VectorModification":{"points":{"add":[1,2,3,4,5,6],"remove":[],"delta":[[1,[933.0127018922194,430.0]],[4,[709.0896534380868,470.0]],[5,[597.1281292110203,439.99999999999994]],[6,[597.1281292110205,340.0000000000001]],[2,[933.0127018922194,470.0]],[3,[709.0896534380868,410.0000000000001]]]},"segments":{"add":[1,2,3,4,5,6],"remove":[],"start_point":[[1,1],[4,4],[5,5],[6,6],[3,3],[2,2]],"end_point":[[6,1],[4,5],[3,4],[5,6],[1,2],[2,3]],"handle_primary":[[5,[0.0,0.0]],[1,[0.0,0.0]],[6,[0.0,0.0]],[3,[0.0,0.0]],[4,[0.0,0.0]],[2,[0.0,0.0]]],"handle_end":[[5,[0.0,0.0]],[2,[0.0,0.0]],[6,[0.0,0.0]],[3,[0.0,0.0]],[4,[0.0,0.0]],[1,[0.0,0.0]]],"stroke":[[2,0],[3,0],[5,0],[1,0],[6,0],[4,0]]},"regions":{"add":[0],"remove":[],"segment_range":[[0,{"start":1,"end":6}]],"fill":[[0,0]]},"add_g1_continuous":[],"remove_g1_continuous":[]}},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::vector_data::modification::VectorModification","alias":null}},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::vector_data::modification::PathModifyNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[9935922395919478146,{"inputs":[{"Value":{"tagged_value":{"VectorData":{"instance":[{"style":{"stroke":{"color":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0},"weight":0.0,"dash_lengths":[],"dash_offset":0.0,"cap":"Butt","join":"Miter","join_miter_limit":4.0,"align":"Center","transform":[1.0,0.0,0.0,1.0,0.0,0.0],"non_scaling":false,"paint_order":"StrokeAbove"},"fill":"None"},"colinear_manipulators":[],"point_domain":{"id":[],"position":[]},"segment_domain":{"id":[],"start_point":[],"end_point":[],"handles":[],"stroke":[]},"region_domain":{"id":[],"segment_range":[],"fill":[]},"upstream_graphic_group":null}],"transform":[[1.0,0.0,0.0,1.0,0.0,0.0]],"alpha_blending":[{"blend_mode":"Normal","opacity":1.0,"fill":1.0,"clip":false}],"source_node_id":[null]}},"exposed":true}},{"Value":{"tagged_value":{"VectorModification":{"points":{"add":[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20],"remove":[],"delta":[[3,[1276.181069958848,406.51851851851853]],[13,[1334.9135802469134,382.9465020576131]],[6,[1283.8189300411525,381.6296296296296]],[16,[1349.7942386831278,385.3168724279836]],[18,[1353.2181069958854,390.3209876543211]],[19,[1353.7448559670786,395.8518518518519]],[17,[1331.2263374485594,418.633744855967]],[1,[1317.9649443682358,445.9417771681145]],[14,[1320.9547325102878,428.11522633744846]],[4,[1281.3168724279838,402.0411522633745]],[8,[1311.341563786008,420.872427983539]],[5,[1303.7037037037037,419.6872427983538]],[11,[1318.5843621399176,404.93827160493817]],[12,[1330.9629629629628,378.8641975308641]],[15,[1346.7654320987656,379.522633744856]],[20,[1325.5637860082302,441.9423868312756]],[10,[1307.9176954732511,360.6913580246913]],[2,[1309.8491083676272,442.3520804755373]],[9,[1303.5720164609054,369.51440329218104]],[7,[1291.19341563786,379.78600823045264]]]},"segments":{"add":[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20],"remove":[],"start_point":[[6,6],[19,19],[20,20],[13,13],[16,16],[12,12],[7,7],[17,17],[18,18],[3,3],[5,5],[10,10],[8,8],[1,1],[2,2],[14,14],[9,9],[15,15],[11,11],[4,4]],"end_point":[[3,4],[15,16],[7,8],[11,12],[1,2],[18,19],[14,15],[20,1],[8,9],[16,17],[2,3],[9,10],[17,18],[6,7],[5,6],[19,20],[10,11],[12,13],[4,5],[13,14]],"handle_primary":[[4,[11.934313314187648,6.04743230718924]],[6,[-13.958847736625785,-23.967078189300366]],[19,[-17.792694511774243,22.05806648377495]],[18,[14.617283950616866,-16.32921810699594]],[7,[13.958847736626012,18.304526748971227]],[10,[10.930041152263357,24.88888888888891]],[17,[0.0,0.0]],[16,[-13.168724279835487,17.382716049382793]],[3,[-25.9423868312756,-18.304526748971227]],[5,[0.0,0.0]],[2,[-1.1927104603494172,-1.8387619597050957]],[12,[8.691358024691226,-13.168724279835374]],[15,[17.514403292181214,-18.96296296296299]],[9,[-8.427983539094384,-34.502057613168745]],[8,[0.0,0.0]],[14,[0.0,0.0]],[11,[0.0,0.0]],[1,[-5.73075474332677,0.190602104454058]],[20,[-0.8876695625660886,2.750800182899013]],[13,[-7.506172839506235,20.67489711934155]]],"handle_end":[[4,[0.0,0.0]],[3,[-29.366255144032948,-14.880658436213992]],[14,[-16.17829033097064,17.51634441849427]],[19,[2.149866795831258,-6.662224576095184]],[18,[19.22633744855989,-23.835390946502]],[16,[0.0,0.0]],[7,[0.0,0.0]],[10,[0.0,0.0]],[15,[22.902000000470935,-30.23064000062169]],[2,[21.160177959832257,14.930277849830986]],[9,[-11.24897964853426,-25.61514642859032]],[1,[1.8728852309102424,2.887364730986178]],[13,[0.0,0.0]],[20,[6.571889866311722,-0.218577847920983]],[6,[-21.35436745259517,-28.00242524443996]],[12,[7.506172839506235,-20.67489711934155]],[11,[-8.691358024691226,13.168724279835374]],[5,[8.275699533270199,14.209219953350214]],[17,[-11.234881916731185,12.550678897970386]],[8,[7.512329871725342,30.753600412376215]]],"stroke":[[5,0],[2,0],[17,0],[9,0],[4,0],[16,0],[14,0],[11,0],[8,0],[12,0],[1,0],[3,0],[10,0],[6,0],[15,0],[20,0],[13,0],[19,0],[7,0],[18,0]]},"regions":{"add":[0],"remove":[],"segment_range":[[0,{"start":1,"end":20}]],"fill":[[0,0]]},"add_g1_continuous":[],"remove_g1_continuous":[]}},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::vector_data::modification::VectorModification","alias":null}},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::vector_data::modification::PathModifyNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[8073807569018624098,{"inputs":[{"Node":{"node_id":8028812053913481975,"output_index":0,"lambda":false}},{"Node":{"node_id":12998832508553378533,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[12875121980058869686,{"inputs":[{"Node":{"node_id":13747030364552895864,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"DVec2":[-261.2435565297001,-64.0]},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[1.0,1.0]},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[0.0,0.0]},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[0.5,0.5]},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":1}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":2}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":3}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":4}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":5}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::TransformNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[14341957170885045113,{"inputs":[{"Node":{"node_id":12469956387875933942,"output_index":0,"lambda":false}},{"Node":{"node_id":7952384394377946257,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[514222872092587805,{"inputs":[{"Node":{"node_id":5434119356821575534,"output_index":0,"lambda":false}},{"Node":{"node_id":3679103217373457623,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[9908869573449854874,{"inputs":[{"Node":{"node_id":16416441286881083283,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"DVec2":[-261.2435565297001,-64.0]},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[1.0,1.0]},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[0.0,0.0]},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[0.5,0.5]},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":1}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":2}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":3}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":4}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":5}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::TransformNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[17059035448296015006,{"inputs":[{"Value":{"tagged_value":{"VectorData":{"instance":[{"style":{"stroke":{"color":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0},"weight":0.0,"dash_lengths":[],"dash_offset":0.0,"cap":"Butt","join":"Miter","join_miter_limit":4.0,"align":"Center","transform":[1.0,0.0,0.0,1.0,0.0,0.0],"non_scaling":false,"paint_order":"StrokeAbove"},"fill":"None"},"colinear_manipulators":[],"point_domain":{"id":[],"position":[]},"segment_domain":{"id":[],"start_point":[],"end_point":[],"handles":[],"stroke":[]},"region_domain":{"id":[],"segment_range":[],"fill":[]},"upstream_graphic_group":null}],"transform":[[1.0,0.0,0.0,1.0,0.0,0.0]],"alpha_blending":[{"blend_mode":"Normal","opacity":1.0,"fill":1.0,"clip":false}],"source_node_id":[null]}},"exposed":true}},{"Value":{"tagged_value":{"VectorModification":{"points":{"add":[1,2,3,4],"remove":[],"delta":[[4,[821.0511776651532,440.0000000000001]],[2,[821.0511776651531,500.0]],[1,[709.0896534380867,469.99999999999994]],[3,[933.0127018922194,470.0]]]},"segments":{"add":[1,2,3,4],"remove":[],"start_point":[[4,4],[3,3],[2,2],[1,1]],"end_point":[[1,2],[3,4],[2,3],[4,1]],"handle_primary":[[1,[0.0,0.0]],[3,[0.0,0.0]],[2,[0.0,0.0]],[4,[0.0,0.0]]],"handle_end":[[2,[0.0,0.0]],[1,[0.0,0.0]],[3,[0.0,0.0]],[4,[0.0,5.684341886080804e-14]]],"stroke":[[1,0],[3,0],[2,0],[4,0]]},"regions":{"add":[0],"remove":[],"segment_range":[[0,{"start":1,"end":4}]],"fill":[[0,0]]},"add_g1_continuous":[],"remove_g1_continuous":[]}},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::vector_data::modification::VectorModification","alias":null}},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::vector_data::modification::PathModifyNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[8028812053913481975,{"inputs":[{"Node":{"node_id":15517065353723874205,"output_index":0,"lambda":false}},{"Node":{"node_id":6785205785632793666,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[9993538712344947860,{"inputs":[{"Node":{"node_id":15134939288287905620,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"Fill":{"Gradient":{"stops":[[0.0,{"red":0.38039216,"green":0.58431375,"blue":0.57254905,"alpha":1.0}],[1.0,{"red":0.38039216,"green":0.58431375,"blue":0.5764706,"alpha":0.0}]],"gradient_type":"Radial","start":[0.9375072552322194,-0.022211489741806645],"end":[0.8621391458239049,0.9748376053312908],"transform":[252.09601447033225,0.0,0.0,101.29892349242375,1209.6581574189368,708.250000000008]}}},"exposed":false}},{"Value":{"tagged_value":{"OptionalColor":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}},"exposed":false}},{"Value":{"tagged_value":{"Gradient":{"stops":[[0.0,{"red":0.38039216,"green":0.58431375,"blue":0.57254905,"alpha":1.0}],[1.0,{"red":0.38039216,"green":0.58431375,"blue":0.5764706,"alpha":0.0}]],"gradient_type":"Radial","start":[0.9375072552322194,-0.022211489741806645],"end":[0.8621391458239049,0.9748376053312908],"transform":[252.09601447033225,0.0,0.0,101.29892349242375,1209.6581574189368,708.250000000008]}},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::FillNode"}},"visible":true,"skip_deduplication":false}],[456239140723765386,{"inputs":[{"Value":{"tagged_value":{"VectorData":{"instance":[{"style":{"stroke":{"color":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0},"weight":0.0,"dash_lengths":[],"dash_offset":0.0,"cap":"Butt","join":"Miter","join_miter_limit":4.0,"align":"Center","transform":[1.0,0.0,0.0,1.0,0.0,0.0],"non_scaling":false,"paint_order":"StrokeAbove"},"fill":"None"},"colinear_manipulators":[],"point_domain":{"id":[],"position":[]},"segment_domain":{"id":[],"start_point":[],"end_point":[],"handles":[],"stroke":[]},"region_domain":{"id":[],"segment_range":[],"fill":[]},"upstream_graphic_group":null}],"transform":[[1.0,0.0,0.0,1.0,0.0,0.0]],"alpha_blending":[{"blend_mode":"Normal","opacity":1.0,"fill":1.0,"clip":false}],"source_node_id":[null]}},"exposed":true}},{"Value":{"tagged_value":{"VectorModification":{"points":{"add":[1,2,3,4],"remove":[],"delta":[[2,[1.0,0.5]],[4,[0.0,0.5]],[3,[0.5,1.0]],[1,[0.5,0.0]]]},"segments":{"add":[1,2,3,4],"remove":[],"start_point":[[4,4],[3,3],[1,1],[2,2]],"end_point":[[2,3],[1,2],[3,4],[4,1]],"handle_primary":[[2,[0.0,0.27589238888950707]],[1,[0.27589238888950707,0.0]],[3,[-0.275892388889507,0.0]],[4,[0.0,-0.275892388889507]]],"handle_end":[[3,[0.0,0.27589238888950707]],[2,[0.27589238888950707,0.0]],[4,[-0.275892388889507,0.0]],[1,[0.0,-0.275892388889507]]],"stroke":[[3,0],[1,0],[2,0],[4,0]]},"regions":{"add":[0],"remove":[],"segment_range":[[0,{"start":1,"end":4}]],"fill":[[0,0]]},"add_g1_continuous":[],"remove_g1_continuous":[]}},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::vector_data::modification::VectorModification","alias":null}},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::vector_data::modification::PathModifyNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[2465823993152870948,{"inputs":[{"Node":{"node_id":15898396405528650339,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"Fill":{"Gradient":{"stops":[[0.0,{"red":0.3778839,"green":0.76171875,"blue":0.72573423,"alpha":1.0}],[1.0,{"red":0.7411765,"green":0.87058824,"blue":0.7372549,"alpha":1.0}]],"gradient_type":"Radial","start":[0.4840260278337376,0.5459259284371654],"end":[-0.00035013139300899,0.5459259284371651],"transform":[-1259.5671475523018,1.5425248755610888e-13,0.0,-337.4999999999992,1616.6581574178408,781.2499999999995]}}},"exposed":false}},{"Value":{"tagged_value":{"OptionalColor":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}},"exposed":false}},{"Value":{"tagged_value":{"Gradient":{"stops":[[0.0,{"red":0.3778839,"green":0.76171875,"blue":0.72573423,"alpha":1.0}],[1.0,{"red":0.7411765,"green":0.87058824,"blue":0.7372549,"alpha":1.0}]],"gradient_type":"Radial","start":[0.4840260278337376,0.5459259284371654],"end":[-0.00035013139300899,0.5459259284371651],"transform":[-1259.5671475523018,1.5425248755610888e-13,0.0,-337.4999999999992,1616.6581574178408,781.2499999999995]}},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::FillNode"}},"visible":true,"skip_deduplication":false}],[14161755104759532162,{"inputs":[{"Node":{"node_id":13837327017498431546,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"DVec2":[0.0,16.0]},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[1.0,1.0]},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[0.0,0.0]},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[0.5,0.5]},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":1}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":2}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":3}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":4}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":5}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::TransformNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[3021739385836969518,{"inputs":[{"Node":{"node_id":6556170892691431702,"output_index":0,"lambda":false}},{"Node":{"node_id":13868917743026516656,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[11547499603328872398,{"inputs":[{"Node":{"node_id":8343201730608263656,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"DVec2":[-261.2435565297001,-64.0]},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[1.0,1.0]},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[0.0,0.0]},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[0.5,0.5]},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":1}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":2}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":3}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":4}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":5}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::TransformNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[6777328619777499144,{"inputs":[{"Value":{"tagged_value":{"VectorData":{"instance":[{"style":{"stroke":{"color":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0},"weight":0.0,"dash_lengths":[],"dash_offset":0.0,"cap":"Butt","join":"Miter","join_miter_limit":4.0,"align":"Center","transform":[1.0,0.0,0.0,1.0,0.0,0.0],"non_scaling":false,"paint_order":"StrokeAbove"},"fill":"None"},"colinear_manipulators":[],"point_domain":{"id":[],"position":[]},"segment_domain":{"id":[],"start_point":[],"end_point":[],"handles":[],"stroke":[]},"region_domain":{"id":[],"segment_range":[],"fill":[]},"upstream_graphic_group":null}],"transform":[[1.0,0.0,0.0,1.0,0.0,0.0]],"alpha_blending":[{"blend_mode":"Normal","opacity":1.0,"fill":1.0,"clip":false}],"source_node_id":[null]}},"exposed":true}},{"Value":{"tagged_value":{"VectorModification":{"points":{"add":[1,2,3,4],"remove":[],"delta":[[4,[1231.5767664977295,450.0]],[3,[1268.8972745734193,460.0000000000024]],[1,[1343.5382907246749,419.99978273075953]],[2,[1380.8587988003642,430.0]]]},"segments":{"add":[1,2,3,4],"remove":[],"start_point":[[4,4],[2,2],[1,1],[3,3]],"end_point":[[1,2],[3,4],[2,3],[4,1]],"handle_primary":[[2,[0.0,0.0]],[4,[0.0,0.0]],[3,[0.0,0.0]],[1,[0.0,0.0]]],"handle_end":[[3,[0.0,0.0]],[2,[0.0,0.0]],[1,[0.0,0.0]],[4,[-6.821210263296962e-13,-5.684341886080804e-14]]],"stroke":[[1,0],[4,0],[2,0],[3,0]]},"regions":{"add":[0],"remove":[],"segment_range":[[0,{"start":1,"end":4}]],"fill":[[0,0]]},"add_g1_continuous":[],"remove_g1_continuous":[]}},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::vector_data::modification::VectorModification","alias":null}},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::vector_data::modification::PathModifyNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[3455270778005546310,{"inputs":[{"Value":{"tagged_value":{"VectorData":{"instance":[{"style":{"stroke":{"color":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0},"weight":0.0,"dash_lengths":[],"dash_offset":0.0,"cap":"Butt","join":"Miter","join_miter_limit":4.0,"align":"Center","transform":[1.0,0.0,0.0,1.0,0.0,0.0],"non_scaling":false,"paint_order":"StrokeAbove"},"fill":"None"},"colinear_manipulators":[],"point_domain":{"id":[],"position":[]},"segment_domain":{"id":[],"start_point":[],"end_point":[],"handles":[],"stroke":[]},"region_domain":{"id":[],"segment_range":[],"fill":[]},"upstream_graphic_group":null}],"transform":[[1.0,0.0,0.0,1.0,0.0,0.0]],"alpha_blending":[{"blend_mode":"Normal","opacity":1.0,"fill":1.0,"clip":false}],"source_node_id":[null]}},"exposed":true}},{"Value":{"tagged_value":{"VectorModification":{"points":{"add":[1,2,3,4],"remove":[],"delta":[[3,[410.5255888325765,450.0000000000001]],[4,[410.5255888325765,410.0]],[1,[559.8076211353316,449.99999999999994]],[2,[559.7618537735666,489.9877366723752]]]},"segments":{"add":[1,2,3,4],"remove":[],"start_point":[[2,2],[1,1],[3,3],[4,4]],"end_point":[[3,4],[2,3],[4,1],[1,2]],"handle_primary":[[1,[0.0,0.0]],[3,[0.0,0.0]],[2,[0.0,0.0]],[4,[0.0,0.0]]],"handle_end":[[1,[0.0,0.0]],[3,[0.0,0.0]],[4,[0.0,5.684341886080804e-14]],[2,[0.0,0.0]]],"stroke":[[1,0],[3,0],[4,0],[2,0]]},"regions":{"add":[0],"remove":[],"segment_range":[[0,{"start":1,"end":4}]],"fill":[[0,0]]},"add_g1_continuous":[],"remove_g1_continuous":[]}},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::vector_data::modification::VectorModification","alias":null}},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::vector_data::modification::PathModifyNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[11076863066321508991,{"inputs":[{"Node":{"node_id":8891726805381758817,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"Fill":{"Solid":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}}},"exposed":false}},{"Value":{"tagged_value":{"OptionalColor":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}},"exposed":false}},{"Value":{"tagged_value":{"Gradient":{"stops":[[0.0,{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}],[1.0,{"red":1.0,"green":1.0,"blue":1.0,"alpha":1.0}]],"gradient_type":"Linear","start":[0.0,0.5],"end":[1.0,0.5],"transform":[1.0,0.0,0.0,1.0,0.0,0.0]}},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::FillNode"}},"visible":true,"skip_deduplication":false}],[5925268772265373737,{"inputs":[{"Node":{"node_id":4105329493214975815,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"Fill":{"Solid":{"red":0.49019608,"green":0.7882353,"blue":0.75686276,"alpha":1.0}}},"exposed":false}},{"Value":{"tagged_value":{"OptionalColor":{"red":0.49019608,"green":0.7882353,"blue":0.75686276,"alpha":1.0}},"exposed":false}},{"Value":{"tagged_value":{"Gradient":{"stops":[[0.0,{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}],[1.0,{"red":1.0,"green":1.0,"blue":1.0,"alpha":1.0}]],"gradient_type":"Linear","start":[0.0,0.5],"end":[1.0,0.5],"transform":[1.0,0.0,0.0,1.0,0.0,0.0]}},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::FillNode"}},"visible":true,"skip_deduplication":false}],[11895211316848895241,{"inputs":[{"Node":{"node_id":10742991645899166287,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"Fill":{"Solid":{"red":0.5019608,"green":0.72156864,"blue":0.62352943,"alpha":1.0}}},"exposed":false}},{"Value":{"tagged_value":{"OptionalColor":{"red":0.5019608,"green":0.72156864,"blue":0.62352943,"alpha":1.0}},"exposed":false}},{"Value":{"tagged_value":{"Gradient":{"stops":[[0.0,{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}],[1.0,{"red":1.0,"green":1.0,"blue":1.0,"alpha":1.0}]],"gradient_type":"Linear","start":[0.0,0.5],"end":[1.0,0.5],"transform":[1.0,0.0,0.0,1.0,0.0,0.0]}},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::FillNode"}},"visible":true,"skip_deduplication":false}],[7639490284239357347,{"inputs":[{"Node":{"node_id":14805036488257720752,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"OptionalColor":{"red":0.9372549,"green":0.90588236,"blue":0.7764706,"alpha":0.7490196}},"exposed":false}},{"Value":{"tagged_value":{"F64":3.0},"exposed":false}},{"Value":{"tagged_value":{"StrokeAlign":"Center"},"exposed":false}},{"Value":{"tagged_value":{"StrokeCap":"Round"},"exposed":false}},{"Value":{"tagged_value":{"StrokeJoin":"Miter"},"exposed":false}},{"Value":{"tagged_value":{"F64":4.0},"exposed":false}},{"Value":{"tagged_value":{"PaintOrder":"StrokeAbove"},"exposed":false}},{"Value":{"tagged_value":{"VecF64":[]},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::StrokeNode"}},"visible":true,"skip_deduplication":false}],[7259756719760382667,{"inputs":[{"Node":{"node_id":15157035456876170143,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"Fill":{"Gradient":{"stops":[[0.0,{"red":0.27450982,"green":0.50980395,"blue":0.54509807,"alpha":1.0}],[1.0,{"red":0.27450982,"green":0.50980395,"blue":0.54509807,"alpha":0.0}]],"gradient_type":"Linear","start":[0.4803107402195895,-0.1138575403671318],"end":[0.41147745365941946,0.9225580029175888],"transform":[842.6155846750064,0.0,0.0,225.77816544354573,370.28268480418546,448.7065465860055]}}},"exposed":false}},{"Value":{"tagged_value":{"OptionalColor":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}},"exposed":false}},{"Value":{"tagged_value":{"Gradient":{"stops":[[0.0,{"red":0.27450982,"green":0.50980395,"blue":0.54509807,"alpha":1.0}],[1.0,{"red":0.27450982,"green":0.50980395,"blue":0.54509807,"alpha":0.0}]],"gradient_type":"Linear","start":[0.4803107402195895,-0.1138575403671318],"end":[0.41147745365941946,0.9225580029175888],"transform":[842.6155846750064,0.0,0.0,225.77816544354573,370.28268480418546,448.7065465860055]}},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::FillNode"}},"visible":true,"skip_deduplication":false}],[2036609094647228373,{"inputs":[{"Value":{"tagged_value":{"VectorData":{"instance":[{"style":{"stroke":{"color":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0},"weight":0.0,"dash_lengths":[],"dash_offset":0.0,"cap":"Butt","join":"Miter","join_miter_limit":4.0,"align":"Center","transform":[1.0,0.0,0.0,1.0,0.0,0.0],"non_scaling":false,"paint_order":"StrokeAbove"},"fill":"None"},"colinear_manipulators":[],"point_domain":{"id":[],"position":[]},"segment_domain":{"id":[],"start_point":[],"end_point":[],"handles":[],"stroke":[]},"region_domain":{"id":[],"segment_range":[],"fill":[]},"upstream_graphic_group":null}],"transform":[[1.0,0.0,0.0,1.0,0.0,0.0]],"alpha_blending":[{"blend_mode":"Normal","opacity":1.0,"fill":1.0,"clip":false}],"source_node_id":[null]}},"exposed":true}},{"Value":{"tagged_value":{"VectorModification":{"points":{"add":[1,2,3,4,5],"remove":[],"delta":[[3,[0.5,1.0]],[1,[0.8725092774628217,0.1666676721950458]],[5,[0.12749341167028605,0.1666646696927025]],[4,[0.0,0.5]],[2,[1.0,0.5]]]},"segments":{"add":[1,2,3,4,5],"remove":[],"start_point":[[4,4],[3,3],[5,5],[1,1],[2,2]],"end_point":[[2,3],[3,4],[4,5],[5,1],[1,2]],"handle_primary":[[1,[0.07925873631249913,0.08849560350574948]],[4,[0.0,-0.12799231715991943]],[2,[0.0,0.27589238888950707]],[5,null],[3,[-0.275892388889507,0.0]]],"handle_end":[[4,[-0.07926033448372466,0.0884959630818129]],[1,[0.0,-0.12799086965193351]],[3,[0.0,0.27589238888950707]],[5,null],[2,[0.27589238888950707,0.0]]],"stroke":[[1,0],[5,0],[3,0],[4,0],[2,0]]},"regions":{"add":[0],"remove":[],"segment_range":[[0,{"start":1,"end":5}]],"fill":[[0,0]]},"add_g1_continuous":[],"remove_g1_continuous":[]}},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::vector_data::modification::VectorModification","alias":null}},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::vector_data::modification::PathModifyNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[14842592386831797498,{"inputs":[{"Node":{"node_id":664587514588499648,"output_index":0,"lambda":false}},{"Node":{"node_id":14330881008352607546,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[4243146970185091100,{"inputs":[{"Value":{"tagged_value":{"VectorData":{"instance":[{"style":{"stroke":{"color":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0},"weight":0.0,"dash_lengths":[],"dash_offset":0.0,"cap":"Butt","join":"Miter","join_miter_limit":4.0,"align":"Center","transform":[1.0,0.0,0.0,1.0,0.0,0.0],"non_scaling":false,"paint_order":"StrokeAbove"},"fill":"None"},"colinear_manipulators":[],"point_domain":{"id":[],"position":[]},"segment_domain":{"id":[],"start_point":[],"end_point":[],"handles":[],"stroke":[]},"region_domain":{"id":[],"segment_range":[],"fill":[]},"upstream_graphic_group":null}],"transform":[[1.0,0.0,0.0,1.0,0.0,0.0]],"alpha_blending":[{"blend_mode":"Normal","opacity":1.0,"fill":1.0,"clip":false}],"source_node_id":[null]}},"exposed":true}},{"Value":{"tagged_value":{"VectorModification":{"points":{"add":[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18],"remove":[],"delta":[[7,[596.3676268861453,491.9835390946502]],[17,[668.3566529492455,433.2510288065844]],[8,[580.9382716049382,401.9753086419752]],[5,[574.0246913580246,440.2962962962963]],[12,[609.0096021947874,496.4609053497942]],[1,[583.5500685871057,499.53360768175577]],[3,[589.8710562414265,497.0754458161865]],[4,[591.18792866941,498.3045267489712]],[18,[618.4910836762688,499.9725651577503]],[9,[606.0246913580247,486.803840877915]],[15,[615.4183813443072,491.19341563786]],[13,[609.7997256515774,497.6899862825788]],[16,[616.0751917898693,491.077444156548]],[14,[650.6666666666667,398.2222222222223]],[6,[594.4362139917694,493.6515775034293]],[10,[607.8683127572016,488.3840877914952]],[11,[615.6378600823045,431.5390946502058]],[2,[533.9259259259258,420.7407407407407]]]},"segments":{"add":[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18],"remove":[],"start_point":[[18,18],[7,7],[13,13],[6,6],[15,15],[9,9],[3,3],[16,16],[12,12],[17,17],[4,4],[2,2],[1,1],[14,14],[5,5],[8,8],[10,10],[11,11]],"end_point":[[6,7],[16,17],[18,1],[5,6],[1,2],[11,12],[10,11],[14,15],[15,16],[13,14],[2,3],[7,8],[8,9],[12,13],[9,10],[3,4],[4,5],[17,18]],"handle_primary":[[17,[-38.27709190672158,34.5020576131688]],[2,[44.005486968450214,35.16049382716062]],[18,[-7.386678859929702,8.10852004267656]],[9,[0.0,0.0]],[13,[0.0,0.0]],[14,[-18.3045267489714,37.31138545953348]],[12,[0.0,0.0]],[16,[0.0,0.0]],[4,[0.0,0.0]],[15,[0.0,0.0]],[3,[0.0,0.0]],[1,[0.0,0.0]],[6,[0.0,0.0]],[11,[-3.906721536351256,29.62962962962956]],[8,[22.10150891632361,44.44444444444463]],[5,[18.392318244170156,23.769547325102906]],[10,[0.0,0.0]],[7,[0.0,0.0]]],"handle_end":[[18,[3.2434080170708057,6.03566529492457]],[7,[25.964334705075316,61.47599451303165]],[1,[48.21947873799752,48.855967078189394]],[11,[0.0,0.0]],[10,[-6.189300411522709,26.732510288065782]],[13,[-23.747599451303245,35.4677640603565]],[6,[0.0,0.0]],[2,null],[9,[0.0,0.0]],[14,null],[3,[0.0,0.0]],[16,[-35.29218106995893,26.337448559670804]],[12,[0.0,0.0]],[5,null],[15,[0.0,0.0]],[8,null],[17,null],[4,[21.113854595336193,37.201646090535064]]],"stroke":[[15,0],[17,0],[2,0],[16,0],[8,0],[12,0],[13,0],[6,0],[14,0],[9,0],[5,0],[11,0],[18,0],[10,0],[4,0],[7,0],[3,0],[1,0]]},"regions":{"add":[0],"remove":[],"segment_range":[[0,{"start":1,"end":18}]],"fill":[[0,0]]},"add_g1_continuous":[],"remove_g1_continuous":[]}},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::vector_data::modification::VectorModification","alias":null}},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::vector_data::modification::PathModifyNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[17965270694495451178,{"inputs":[{"Node":{"node_id":9409313765472227540,"output_index":0,"lambda":false}},{"Node":{"node_id":4887570735033124574,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[15167880819976070791,{"inputs":[{"Node":{"node_id":4898866541060902381,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"F64":33.0},"exposed":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::blending_nodes::OpacityNode"}},"visible":true,"skip_deduplication":false}],[16069762220015310717,{"inputs":[{"Node":{"node_id":16398743435291795904,"output_index":0,"lambda":false}},{"Node":{"node_id":14791465604033956302,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[16510804133693080967,{"inputs":[{"Node":{"node_id":3966971396176820223,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"DVec2":[-261.24355652969996,-64.0]},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[1.0,1.0]},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[0.0,0.0]},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[0.5,0.5]},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":1}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":2}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":3}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":4}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":5}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::TransformNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[2785423879796980286,{"inputs":[{"Node":{"node_id":11634802583144606404,"output_index":0,"lambda":false}},{"Node":{"node_id":16591255610014418910,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[2921219300441868542,{"inputs":[{"Node":{"node_id":11506204916439878896,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"Fill":{"Solid":{"red":0.49019608,"green":0.69411767,"blue":0.627451,"alpha":1.0}}},"exposed":false}},{"Value":{"tagged_value":{"OptionalColor":{"red":0.49019608,"green":0.69411767,"blue":0.627451,"alpha":1.0}},"exposed":false}},{"Value":{"tagged_value":{"Gradient":{"stops":[[0.0,{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}],[1.0,{"red":1.0,"green":1.0,"blue":1.0,"alpha":1.0}]],"gradient_type":"Linear","start":[0.0,0.5],"end":[1.0,0.5],"transform":[1.0,0.0,0.0,1.0,0.0,0.0]}},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::FillNode"}},"visible":true,"skip_deduplication":false}],[7067047867039575315,{"inputs":[{"Node":{"node_id":15261165353096835967,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"DVec2":[-261.24355652969996,-64.0]},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[1.0,1.0]},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[0.0,0.0]},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[0.5,0.5]},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":1}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":2}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":3}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":4}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":5}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::TransformNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[5261200785298607501,{"inputs":[{"Node":{"node_id":2465823993152870948,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"BlendMode":"Lighten"},"exposed":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::blending_nodes::BlendModeNode"}},"visible":true,"skip_deduplication":false}],[12554549497938935061,{"inputs":[{"Node":{"node_id":14055195208113082127,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"DVec2":[833.274364370262,-33.56362500933909]},"exposed":false}},{"Value":{"tagged_value":{"F64":3.141592653589793},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[0.8,-0.6]},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[1.2246467991473532e-16,0.0]},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[0.5,0.5]},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":1}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":2}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":3}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":4}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":5}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::TransformNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[8256712316698018135,{"inputs":[{"Value":{"tagged_value":{"VectorData":{"instance":[{"style":{"stroke":{"color":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0},"weight":0.0,"dash_lengths":[],"dash_offset":0.0,"cap":"Butt","join":"Miter","join_miter_limit":4.0,"align":"Center","transform":[1.0,0.0,0.0,1.0,0.0,0.0],"non_scaling":false,"paint_order":"StrokeAbove"},"fill":"None"},"colinear_manipulators":[],"point_domain":{"id":[],"position":[]},"segment_domain":{"id":[],"start_point":[],"end_point":[],"handles":[],"stroke":[]},"region_domain":{"id":[],"segment_range":[],"fill":[]},"upstream_graphic_group":null}],"transform":[[1.0,0.0,0.0,1.0,0.0,0.0]],"alpha_blending":[{"blend_mode":"Normal","opacity":1.0,"fill":1.0,"clip":false}],"source_node_id":[null]}},"exposed":true}},{"Value":{"tagged_value":{"VectorModification":{"points":{"add":[1,2,3,4],"remove":[],"delta":[[1,[1268.897274573418,500.00000000000006]],[2,[1268.8972745734184,559.9999999999999]],[4,[1343.5382907247958,520.0]],[3,[1343.538290724796,579.9999999999998]]]},"segments":{"add":[1,2,3,4],"remove":[],"start_point":[[4,4],[2,2],[3,3],[1,1]],"end_point":[[3,4],[2,3],[1,2],[4,1]],"handle_primary":[[2,[0.0,0.0]],[3,[0.0,0.0]],[4,[0.0,0.0]],[1,[0.0,0.0]]],"handle_end":[[1,[0.0,0.0]],[3,[0.0,0.0]],[4,[0.0,0.0]],[2,[0.0,0.0]]],"stroke":[[1,0],[3,0],[4,0],[2,0]]},"regions":{"add":[0],"remove":[],"segment_range":[[0,{"start":1,"end":4}]],"fill":[[0,0]]},"add_g1_continuous":[],"remove_g1_continuous":[]}},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::vector_data::modification::VectorModification","alias":null}},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::vector_data::modification::PathModifyNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[18046677540207938977,{"inputs":[{"Node":{"node_id":2189393878093040029,"output_index":0,"lambda":false}},{"Node":{"node_id":2292399603649738346,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[4134257789770357215,{"inputs":[{"Node":{"node_id":9640215309187299519,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"DVec2":[-298.5640646053945,-71.86019325256757]},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[0.9999999999999948,0.9999999999999948]},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[0.0,0.0]},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[0.5,0.5]},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":1}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":2}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":3}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":4}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":5}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::TransformNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[15914878146223026034,{"inputs":[{"Node":{"node_id":4069478660487729695,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"DVec2":[39.06014871394696,-80.31594690033606]},"exposed":false}},{"Value":{"tagged_value":{"F64":-0.44070994426773896},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[0.7021527212517815,1.4014617956106905]},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[-0.8600612888523491,0.0]},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[0.5,0.5]},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":1}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":2}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":3}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":4}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":5}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::TransformNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[2640491057355360805,{"inputs":[{"Value":{"tagged_value":{"VectorData":{"instance":[{"style":{"stroke":{"color":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0},"weight":0.0,"dash_lengths":[],"dash_offset":0.0,"cap":"Butt","join":"Miter","join_miter_limit":4.0,"align":"Center","transform":[1.0,0.0,0.0,1.0,0.0,0.0],"non_scaling":false,"paint_order":"StrokeAbove"},"fill":"None"},"colinear_manipulators":[],"point_domain":{"id":[],"position":[]},"segment_domain":{"id":[],"start_point":[],"end_point":[],"handles":[],"stroke":[]},"region_domain":{"id":[],"segment_range":[],"fill":[]},"upstream_graphic_group":null}],"transform":[[1.0,0.0,0.0,1.0,0.0,0.0]],"alpha_blending":[{"blend_mode":"Normal","opacity":1.0,"fill":1.0,"clip":false}],"source_node_id":[null]}},"exposed":true}},{"Value":{"tagged_value":{"VectorModification":{"points":{"add":[1,2,3,4,5,6,7,8,9,10],"remove":[],"delta":[[9,[821.0511776651531,440.00000000000006]],[5,[410.5255888325765,450.0000000000001]],[3,[559.8076211353318,500.00000000000017]],[4,[410.5255888325763,460.0]],[6,[559.7618537735666,489.9877366723752]],[7,[671.7691453623979,459.99999999999994]],[10,[933.0127018922194,470.0]],[2,[653.1088913245535,475.0]],[8,[709.0896534380868,470.00000000000006]],[1,[783.7306695894642,510.0]]]},"segments":{"add":[1,2,3,4,5,6,7,8,9,10],"remove":[],"start_point":[[9,9],[1,1],[4,4],[7,7],[2,2],[3,3],[10,10],[6,6],[8,8],[5,5]],"end_point":[[9,10],[8,9],[7,8],[1,2],[5,6],[6,7],[10,1],[2,3],[3,4],[4,5]],"handle_primary":[[5,null],[10,[0.0,0.0]],[6,null],[3,[-149.2820323027555,-40.00000000000017]],[1,null],[2,null],[8,[0.0,0.0]],[7,[37.32050807568885,10.000000000000114]],[9,[0.0,0.0]],[4,[0.0,0.0]]],"handle_end":[[4,null],[7,null],[6,null],[9,[0.0,0.0]],[1,null],[2,null],[3,null],[5,null],[8,[0.0,0.0]],[10,null]],"stroke":[[9,0],[6,0],[2,0],[5,0],[4,0],[10,0],[7,0],[3,0],[8,0],[1,0]]},"regions":{"add":[0],"remove":[],"segment_range":[[0,{"start":1,"end":10}]],"fill":[[0,0]]},"add_g1_continuous":[],"remove_g1_continuous":[]}},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::vector_data::modification::VectorModification","alias":null}},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::vector_data::modification::PathModifyNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[3680957604830907751,{"inputs":[{"Value":{"tagged_value":{"VectorData":{"instance":[{"style":{"stroke":{"color":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0},"weight":0.0,"dash_lengths":[],"dash_offset":0.0,"cap":"Butt","join":"Miter","join_miter_limit":4.0,"align":"Center","transform":[1.0,0.0,0.0,1.0,0.0,0.0],"non_scaling":false,"paint_order":"StrokeAbove"},"fill":"None"},"colinear_manipulators":[],"point_domain":{"id":[],"position":[]},"segment_domain":{"id":[],"start_point":[],"end_point":[],"handles":[],"stroke":[]},"region_domain":{"id":[],"segment_range":[],"fill":[]},"upstream_graphic_group":null}],"transform":[[1.0,0.0,0.0,1.0,0.0,0.0]],"alpha_blending":[{"blend_mode":"Normal","opacity":1.0,"fill":1.0,"clip":false}],"source_node_id":[null]}},"exposed":true}},{"Value":{"tagged_value":{"VectorModification":{"points":{"add":[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15],"remove":[],"delta":[[7,[1336.2743484224964,374.25514403292175]],[11,[1325.124828532236,431.14403292181055]],[10,[1354.710562414266,375.5720164609054]],[6,[1317.750342935528,414.37585733882025]],[13,[1322.315500685871,442.4691358024692]],[15,[1264.5486968449932,395.9981710105167]],[4,[1311.6049382716046,423.2427983539094]],[1,[1304.1133973479657,421.12604785855825]],[14,[1313.0096021947877,442.29355281207137]],[2,[1304.6986739826243,420.69684499314127]],[5,[1301.1577503429353,350.639231824417]],[9,[1321.5253772290812,429.56378600823047]],[3,[1278.0100594421583,366.7343392775492]],[12,[1360.3292181069958,385.0534979423868]],[8,[1319.9451303155006,428.8614540466391]]]},"segments":{"add":[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15],"remove":[],"start_point":[[14,14],[9,9],[6,6],[10,10],[8,8],[1,1],[13,13],[7,7],[15,15],[4,4],[5,5],[11,11],[2,2],[3,3],[12,12]],"end_point":[[2,3],[4,5],[8,9],[11,12],[9,10],[5,6],[6,7],[13,14],[14,15],[15,1],[7,8],[3,4],[1,2],[12,13],[10,11]],"handle_primary":[[14,[-1.4013919408635047,-1.0754868383370422]],[3,[22.884316415180592,29.146776406035656]],[7,[-16.182898948331285,35.4677640603565]],[13,[-1.0925163846973192,0.8063811410860922]],[15,[30.375857338820197,15.10013717421117]],[2,[0.0,0.0]],[12,[-18.78737997256485,20.455418381344316]],[10,[-22.650205761316556,26.60082304526742]],[8,[0.0,0.0]],[1,[0.0,0.0]],[11,[6.190926179952385,-9.64405832444237]],[4,[0.0,0.0]],[6,[0.0,0.0]],[9,[0.0,0.0]],[5,[15.978052126200282,30.375857338820197]]],"handle_end":[[15,[0.0,0.0]],[4,[16.153635116598025,62.683127572016474]],[13,[0.8337588052027058,0.639861408644208]],[10,null],[5,[0.0,0.0]],[2,[26.044810242340873,43.48605395518973]],[9,[-20.894375857338673,18.52400548696835]],[6,[-20.484682213077576,38.013717421124625]],[7,[0.0,0.0]],[1,[0.0,0.0]],[12,[1.2603823499284772,-0.9302822106615168]],[14,[36.34567901234527,22.650205761316897]],[3,[0.0,0.0]],[11,[-18.34842249657072,19.13854595336079]],[8,[0.0,0.0]]],"stroke":[[3,0],[8,0],[11,0],[13,0],[4,0],[15,0],[9,0],[1,0],[5,0],[2,0],[14,0],[7,0],[10,0],[6,0],[12,0]]},"regions":{"add":[0],"remove":[],"segment_range":[[0,{"start":1,"end":15}]],"fill":[[0,0]]},"add_g1_continuous":[],"remove_g1_continuous":[]}},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::vector_data::modification::VectorModification","alias":null}},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::vector_data::modification::PathModifyNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[7910743362843097140,{"inputs":[{"Value":{"tagged_value":{"VectorData":{"instance":[{"style":{"stroke":{"color":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0},"weight":0.0,"dash_lengths":[],"dash_offset":0.0,"cap":"Butt","join":"Miter","join_miter_limit":4.0,"align":"Center","transform":[1.0,0.0,0.0,1.0,0.0,0.0],"non_scaling":false,"paint_order":"StrokeAbove"},"fill":"None"},"colinear_manipulators":[],"point_domain":{"id":[],"position":[]},"segment_domain":{"id":[],"start_point":[],"end_point":[],"handles":[],"stroke":[]},"region_domain":{"id":[],"segment_range":[],"fill":[]},"upstream_graphic_group":null}],"transform":[[1.0,0.0,0.0,1.0,0.0,0.0]],"alpha_blending":[{"blend_mode":"Normal","opacity":1.0,"fill":1.0,"clip":false}],"source_node_id":[null]}},"exposed":true}},{"Value":{"tagged_value":{"VectorModification":{"points":{"add":[1,2,3,4,5,6,7,8,9,10,11],"remove":[],"delta":[[8,[261.24355652982126,545.0]],[11,[18.66025403784454,515.0]],[7,[93.30127018922188,590.0]],[2,[121.29165124598823,557.5000000000001]],[6,[130.62177826491063,599.9999999999999]],[3,[83.97114317030001,547.5]],[1,[-9.33012701892199,592.5]],[10,[261.2435565298214,580.0]],[4,[55.98076211353338,555.0000000000001]],[9,[326.55444566227675,562.5]],[5,[177.2724133595217,587.5]]]},"segments":{"add":[1,2,3,4,5,6,7,8,9,10],"remove":[],"start_point":[[6,6],[8,8],[5,5],[4,4],[3,3],[1,1],[10,10],[2,2],[9,9],[7,7]],"end_point":[[7,8],[5,6],[3,4],[9,10],[1,2],[2,3],[4,5],[10,11],[6,7],[8,9]],"handle_primary":[[9,[0.0,0.0]],[5,[0.0,0.0]],[10,[0.0,0.0]],[6,[0.0,0.0]],[3,[0.0,0.0]],[4,[0.0,0.0]],[1,[0.0,0.0]],[2,[0.0,0.0]],[7,[0.0,0.0]],[8,[0.0,0.0]]],"handle_end":[[2,[0.0,0.0]],[5,[0.0,0.0]],[4,[0.0,0.0]],[3,[0.0,0.0]],[7,[0.0,0.0]],[6,[0.0,0.0]],[10,[0.0,0.0]],[1,[0.0,0.0]],[9,[0.0,0.0]],[8,[0.0,0.0]]],"stroke":[[4,0],[6,0],[8,0],[7,0],[10,0],[1,0],[9,0],[3,0],[5,0],[2,0]]},"regions":{"add":[],"remove":[],"segment_range":[],"fill":[]},"add_g1_continuous":[],"remove_g1_continuous":[]}},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::vector_data::modification::VectorModification","alias":null}},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::vector_data::modification::PathModifyNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[17887542695709892422,{"inputs":[{"Node":{"node_id":14842592386831797498,"output_index":0,"lambda":false}},{"Node":{"node_id":7259756719760382667,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[10564228200140683112,{"inputs":[{"Node":{"node_id":13001069903842109798,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"DVec2":[-140.23409378379097,-66.17529531267506]},"exposed":false}},{"Value":{"tagged_value":{"F64":-1.1549250908208777},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[61.12160376625298,24.813625019997943]},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[-0.6236723178991973,0.0]},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[0.5,0.5]},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":1}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":2}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":3}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":4}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":5}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::TransformNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[11634445349252640936,{"inputs":[{"Node":{"node_id":2032185045476767535,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"DVec2":[708.5896534382083,269.5]},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[1.0,0.267949192432]},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[-3.2814312084546346e-17,0.0]},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[0.5,0.5]},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":1}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":2}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":3}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":4}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":5}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::TransformNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[3966971396176820223,{"inputs":[{"Value":{"tagged_value":{"VectorData":{"instance":[{"style":{"stroke":{"color":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0},"weight":0.0,"dash_lengths":[],"dash_offset":0.0,"cap":"Butt","join":"Miter","join_miter_limit":4.0,"align":"Center","transform":[1.0,0.0,0.0,1.0,0.0,0.0],"non_scaling":false,"paint_order":"StrokeAbove"},"fill":"None"},"colinear_manipulators":[],"point_domain":{"id":[],"position":[]},"segment_domain":{"id":[],"start_point":[],"end_point":[],"handles":[],"stroke":[]},"region_domain":{"id":[],"segment_range":[],"fill":[]},"upstream_graphic_group":null}],"transform":[[1.0,0.0,0.0,1.0,0.0,0.0]],"alpha_blending":[{"blend_mode":"Normal","opacity":1.0,"fill":1.0,"clip":false}],"source_node_id":[null]}},"exposed":true}},{"Value":{"tagged_value":{"VectorModification":{"points":{"add":[1,2,3,4,5,6],"remove":[],"delta":[[5,[597.1281292110198,599.9999999999999]],[4,[615.7883832488646,605.0000000000001]],[1,[1156.9357503463468,509.9999999999987]],[3,[783.7306695894646,560.0]],[2,[877.0319397786863,584.9999999999998]],[6,[1044.9742261192855,480.0]]]},"segments":{"add":[1,2,3,4,5,6],"remove":[],"start_point":[[4,4],[3,3],[6,6],[1,1],[2,2],[5,5]],"end_point":[[1,2],[6,1],[4,5],[2,3],[5,6],[3,4]],"handle_primary":[[3,null],[2,[0.0,0.0]],[4,null],[1,[0.0,0.0]],[6,[0.0,0.0]],[5,[447.84609690826574,-119.99999999999989]]],"handle_end":[[4,null],[1,[0.0,0.0]],[6,[0.0,0.0]],[5,null],[3,null],[2,null]],"stroke":[[6,0],[5,0],[4,0],[3,0],[1,0],[2,0]]},"regions":{"add":[0],"remove":[],"segment_range":[[0,{"start":1,"end":6}]],"fill":[[0,0]]},"add_g1_continuous":[],"remove_g1_continuous":[]}},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::vector_data::modification::VectorModification","alias":null}},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::vector_data::modification::PathModifyNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[2900504420179573771,{"inputs":[{"Node":{"node_id":3185536512640676801,"output_index":0,"lambda":false}},{"Node":{"node_id":10852750245702849075,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[2843751023378786714,{"inputs":[{"Value":{"tagged_value":{"VectorData":{"instance":[{"style":{"stroke":{"color":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0},"weight":0.0,"dash_lengths":[],"dash_offset":0.0,"cap":"Butt","join":"Miter","join_miter_limit":4.0,"align":"Center","transform":[1.0,0.0,0.0,1.0,0.0,0.0],"non_scaling":false,"paint_order":"StrokeAbove"},"fill":"None"},"colinear_manipulators":[],"point_domain":{"id":[],"position":[]},"segment_domain":{"id":[],"start_point":[],"end_point":[],"handles":[],"stroke":[]},"region_domain":{"id":[],"segment_range":[],"fill":[]},"upstream_graphic_group":null}],"transform":[[1.0,0.0,0.0,1.0,0.0,0.0]],"alpha_blending":[{"blend_mode":"Normal","opacity":1.0,"fill":1.0,"clip":false}],"source_node_id":[null]}},"exposed":true}},{"Value":{"tagged_value":{"VectorModification":{"points":{"add":[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19],"remove":[],"delta":[[5,[497.38271604938257,447.60493827160496]],[14,[552.9705625612692,418.19081042008474]],[13,[526.0246913580248,490.07407407407413]],[8,[502.0960349862431,417.9179038759178]],[1,[510.41975308641986,500.1481481481481]],[15,[556.7578325004595,420.13017723423656]],[10,[524.0493827160495,487.1111111111112]],[7,[515.1604938271604,486.716049382716]],[16,[530.3703703703702,486.71604938271594]],[19,[530.7654320987656,499.55555555555566]],[18,[568.2339832275112,446.0155371619765]],[4,[511.55555555555554,490.2222222222222]],[12,[533.8924329970387,433.46495092641567]],[17,[565.2914244954804,444.3855996237166]],[6,[499.77650172698026,445.9388618767647]],[11,[531.5890484844431,432.90541944395505]],[3,[480.5925925925926,440.2962962962962]],[9,[505.311372421164,416.4524664944526]],[2,[476.9512618480758,444.1904085078117]]]},"segments":{"add":[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19],"remove":[],"start_point":[[6,6],[7,7],[18,18],[2,2],[4,4],[19,19],[15,15],[5,5],[16,16],[12,12],[11,11],[17,17],[13,13],[10,10],[14,14],[3,3],[1,1],[9,9],[8,8]],"end_point":[[1,2],[13,14],[6,7],[2,3],[8,9],[16,17],[3,4],[11,12],[15,16],[19,1],[4,5],[12,13],[5,6],[14,15],[7,8],[18,19],[17,18],[9,10],[10,11]],"handle_primary":[[5,[-10.016557406305251,-15.024836109457851]],[11,[7.784237194372736,-22.222909722529664]],[10,[0.0,0.0]],[9,[11.197015798182122,18.39034937970939]],[1,[-9.283950617284065,-12.246913580246884]],[8,[-8.936088730151937,-20.93774746663439]],[12,[-5.082537215847424,18.7049831985629]],[3,[21.32824309569804,17.329197515254634]],[15,[-11.459519915000214,23.15277176924241]],[13,[0.0,0.0]],[2,[-17.16805625160663,-20.28383937076643]],[4,[0.0,0.0]],[16,[0.0,0.0]],[7,[0.0,0.0]],[6,[3.9272019767233246,4.629039357803151]],[14,[15.260998855532309,-21.888591759537466]],[18,[-19.30865594294653,18.299752742610902]],[17,[27.324497401397252,-21.15032331824051]],[19,[-1.5204271954055455,4.429070525747022]]],"handle_end":[[18,[4.54320987654296,-13.23456790123464]],[3,[-3.111111111111086,-12.0]],[15,[4.54320987654296,-11.851851851852018]],[12,[3.7530864197531177,-16.59259259259261]],[11,[5.082537215847424,-18.704983198562843]],[10,[-7.784237194372736,22.22290972252955]],[16,[-28.402535606591755,21.984770746653737]],[14,[11.286699158099054,-22.803605349427187]],[7,[18.59187624528363,43.5617887769169]],[17,[19.435079545528083,-18.419570542198244]],[13,[-15.260998855532534,21.888591759537743]],[19,[2.7053847913285836,3.5688054694122116]],[9,[0.7901234567898427,-21.135802469135857]],[5,[-12.032856371187677,-14.183269935989983]],[6,[0.7901234567898427,-16.197530864197745]],[2,[-22.123456790123555,-17.97530864197529]],[8,[-11.197015798182008,-18.39034937970939]],[4,[13.03703703703701,19.555555555555543]],[1,[28.522359190346833,33.698803394714844]]],"stroke":[[18,0],[10,0],[4,0],[19,0],[6,0],[9,0],[17,0],[11,0],[1,0],[14,0],[3,0],[16,0],[2,0],[5,0],[7,0],[12,0],[8,0],[15,0],[13,0]]},"regions":{"add":[0],"remove":[],"segment_range":[[0,{"start":1,"end":19}]],"fill":[[0,0]]},"add_g1_continuous":[],"remove_g1_continuous":[]}},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::vector_data::modification::VectorModification","alias":null}},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::vector_data::modification::PathModifyNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[7637119583909417127,{"inputs":[{"Node":{"node_id":4740496570730418920,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"OptionalColor":{"red":0.9372549,"green":0.90588236,"blue":0.7764706,"alpha":0.7490196}},"exposed":false}},{"Value":{"tagged_value":{"F64":3.0},"exposed":false}},{"Value":{"tagged_value":{"StrokeAlign":"Center"},"exposed":false}},{"Value":{"tagged_value":{"StrokeCap":"Butt"},"exposed":false}},{"Value":{"tagged_value":{"StrokeJoin":"Miter"},"exposed":false}},{"Value":{"tagged_value":{"F64":4.0},"exposed":false}},{"Value":{"tagged_value":{"PaintOrder":"StrokeAbove"},"exposed":false}},{"Value":{"tagged_value":{"VecF64":[]},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::StrokeNode"}},"visible":true,"skip_deduplication":false}],[8166796652234334001,{"inputs":[{"Node":{"node_id":8034980397175569257,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"Fill":{"Gradient":{"stops":[[0.0,{"red":0.47937012,"green":0.73046875,"blue":0.56778514,"alpha":1.0}],[1.0,{"red":0.36862746,"green":0.57254905,"blue":0.45490196,"alpha":1.0}]],"gradient_type":"Linear","start":[0.4830458531002497,0.18799510852727777],"end":[0.5102584056336581,0.7583861422837161],"transform":[330.72972441489793,0.0,0.0,262.97748583483383,694.2423781243951,620.5615190102498]}}},"exposed":false}},{"Value":{"tagged_value":{"OptionalColor":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}},"exposed":false}},{"Value":{"tagged_value":{"Gradient":{"stops":[[0.0,{"red":0.47937012,"green":0.73046875,"blue":0.56778514,"alpha":1.0}],[1.0,{"red":0.36862746,"green":0.57254905,"blue":0.45490196,"alpha":1.0}]],"gradient_type":"Linear","start":[0.4830458531002497,0.18799510852727777],"end":[0.5102584056336581,0.7583861422837161],"transform":[330.72972441489793,0.0,0.0,262.97748583483383,694.2423781243951,620.5615190102498]}},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::FillNode"}},"visible":true,"skip_deduplication":false}],[16591255610014418910,{"inputs":[{"Node":{"node_id":2225749123534781340,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"OptionalColor":{"red":0.9372549,"green":0.90588236,"blue":0.7764706,"alpha":0.7490196}},"exposed":false}},{"Value":{"tagged_value":{"F64":3.0},"exposed":false}},{"Value":{"tagged_value":{"StrokeAlign":"Center"},"exposed":false}},{"Value":{"tagged_value":{"StrokeCap":"Butt"},"exposed":false}},{"Value":{"tagged_value":{"StrokeJoin":"Miter"},"exposed":false}},{"Value":{"tagged_value":{"F64":4.0},"exposed":false}},{"Value":{"tagged_value":{"PaintOrder":"StrokeAbove"},"exposed":false}},{"Value":{"tagged_value":{"VecF64":[]},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::StrokeNode"}},"visible":true,"skip_deduplication":false}],[5891705401441266824,{"inputs":[{"Node":{"node_id":5670058004691708784,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"Fill":{"Solid":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}}},"exposed":false}},{"Value":{"tagged_value":{"OptionalColor":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}},"exposed":false}},{"Value":{"tagged_value":{"Gradient":{"stops":[[0.0,{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}],[1.0,{"red":1.0,"green":1.0,"blue":1.0,"alpha":1.0}]],"gradient_type":"Linear","start":[0.0,0.5],"end":[1.0,0.5],"transform":[1.0,0.0,0.0,1.0,0.0,0.0]}},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::FillNode"}},"visible":true,"skip_deduplication":false}],[17332567356044944766,{"inputs":[{"Value":{"tagged_value":{"VectorData":{"instance":[{"style":{"stroke":{"color":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0},"weight":0.0,"dash_lengths":[],"dash_offset":0.0,"cap":"Butt","join":"Miter","join_miter_limit":4.0,"align":"Center","transform":[1.0,0.0,0.0,1.0,0.0,0.0],"non_scaling":false,"paint_order":"StrokeAbove"},"fill":"None"},"colinear_manipulators":[],"point_domain":{"id":[],"position":[]},"segment_domain":{"id":[],"start_point":[],"end_point":[],"handles":[],"stroke":[]},"region_domain":{"id":[],"segment_range":[],"fill":[]},"upstream_graphic_group":null}],"transform":[[1.0,0.0,0.0,1.0,0.0,0.0]],"alpha_blending":[{"blend_mode":"Normal","opacity":1.0,"fill":1.0,"clip":false}],"source_node_id":[null]}},"exposed":true}},{"Value":{"tagged_value":{"VectorModification":{"points":{"add":[1,2,3,4],"remove":[],"delta":[[4,[-0.10921713655450987,1.0126086768123077]],[2,[1.0,0.0]],[3,[1.0,1.0]],[1,[0.0,0.0]]]},"segments":{"add":[1,2,3,4],"remove":[],"start_point":[[2,2],[4,4],[3,3],[1,1]],"end_point":[[1,2],[3,4],[4,1],[2,3]],"handle_primary":[[1,[0.0,0.0]],[3,[0.0,0.0]],[4,[0.0,0.0]],[2,[0.0,0.0]]],"handle_end":[[3,[0.0,0.0]],[2,[0.0,0.0]],[4,[0.0,0.0]],[1,[0.0,0.0]]],"stroke":[[1,0],[3,0],[2,0],[4,0]]},"regions":{"add":[0],"remove":[],"segment_range":[[0,{"start":1,"end":4}]],"fill":[[0,0]]},"add_g1_continuous":[],"remove_g1_continuous":[]}},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::vector_data::modification::VectorModification","alias":null}},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::vector_data::modification::PathModifyNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[429913874753911073,{"inputs":[{"Node":{"node_id":11236872744106223256,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"OptionalColor":{"red":0.9372549,"green":0.9098039,"blue":0.7764706,"alpha":0.75}},"exposed":false}},{"Value":{"tagged_value":{"F64":3.0},"exposed":false}},{"Value":{"tagged_value":{"StrokeAlign":"Center"},"exposed":false}},{"Value":{"tagged_value":{"StrokeCap":"Round"},"exposed":false}},{"Value":{"tagged_value":{"StrokeJoin":"Miter"},"exposed":false}},{"Value":{"tagged_value":{"F64":4.0},"exposed":false}},{"Value":{"tagged_value":{"PaintOrder":"StrokeAbove"},"exposed":false}},{"Value":{"tagged_value":{"VecF64":[]},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::StrokeNode"}},"visible":true,"skip_deduplication":false}],[13701442050580061197,{"inputs":[{"Value":{"tagged_value":{"VectorData":{"instance":[{"style":{"stroke":{"color":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0},"weight":0.0,"dash_lengths":[],"dash_offset":0.0,"cap":"Butt","join":"Miter","join_miter_limit":4.0,"align":"Center","transform":[1.0,0.0,0.0,1.0,0.0,0.0],"non_scaling":false,"paint_order":"StrokeAbove"},"fill":"None"},"colinear_manipulators":[],"point_domain":{"id":[],"position":[]},"segment_domain":{"id":[],"start_point":[],"end_point":[],"handles":[],"stroke":[]},"region_domain":{"id":[],"segment_range":[],"fill":[]},"upstream_graphic_group":null}],"transform":[[1.0,0.0,0.0,1.0,0.0,0.0]],"alpha_blending":[{"blend_mode":"Normal","opacity":1.0,"fill":1.0,"clip":false}],"source_node_id":[null]}},"exposed":true}},{"Value":{"tagged_value":{"VectorModification":{"points":{"add":[1,2,3,4,5,6],"remove":[],"delta":[[2,[1343.5382907247958,520.0000000000001]],[1,[1268.897274573418,500.00000000000006]],[4,[1380.8587988003635,429.9999999999991]],[6,[1380.8587988003635,469.9999999999993]],[3,[1530.14083110324,469.9999999999986]],[5,[1380.8587988003635,469.9997827307588]]]},"segments":{"add":[1,2,3,4,5,6],"remove":[],"start_point":[[2,2],[3,3],[5,5],[1,1],[6,6],[4,4]],"end_point":[[3,4],[6,1],[4,5],[5,6],[1,2],[2,3]],"handle_primary":[[4,[0.0,0.0]],[6,[0.0,0.0]],[3,[0.0,0.0]],[2,[0.0,0.0]],[1,[0.0,0.0]],[5,[0.0,0.0002172692405224552]]],"handle_end":[[4,null],[6,[4.547473508864641e-13,5.684341886080804e-14]],[1,[0.0,0.0]],[3,[0.0,0.0]],[2,[0.0,0.0]],[5,null]],"stroke":[[6,0],[1,0],[5,0],[3,0],[2,0],[4,0]]},"regions":{"add":[0],"remove":[],"segment_range":[[0,{"start":1,"end":6}]],"fill":[[0,0]]},"add_g1_continuous":[],"remove_g1_continuous":[]}},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::vector_data::modification::VectorModification","alias":null}},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::vector_data::modification::PathModifyNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[16059265180575745658,{"inputs":[{"Value":{"tagged_value":{"VectorData":{"instance":[{"style":{"stroke":{"color":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0},"weight":0.0,"dash_lengths":[],"dash_offset":0.0,"cap":"Butt","join":"Miter","join_miter_limit":4.0,"align":"Center","transform":[1.0,0.0,0.0,1.0,0.0,0.0],"non_scaling":false,"paint_order":"StrokeAbove"},"fill":"None"},"colinear_manipulators":[],"point_domain":{"id":[],"position":[]},"segment_domain":{"id":[],"start_point":[],"end_point":[],"handles":[],"stroke":[]},"region_domain":{"id":[],"segment_range":[],"fill":[]},"upstream_graphic_group":null}],"transform":[[1.0,0.0,0.0,1.0,0.0,0.0]],"alpha_blending":[{"blend_mode":"Normal","opacity":1.0,"fill":1.0,"clip":false}],"source_node_id":[null]}},"exposed":true}},{"Value":{"tagged_value":{"VectorModification":{"points":{"add":[1,2,3,4,5],"remove":[],"delta":[[4,[1082.2947341949744,580.0]],[2,[1044.9742261192855,599.9999999999999]],[5,[839.7114317029976,645.0]],[1,[1194.256258422041,640.0]],[3,[1100.9549882328188,585.0]]]},"segments":{"add":[1,2,3,4],"remove":[],"start_point":[[4,4],[2,2],[3,3],[1,1]],"end_point":[[4,5],[1,2],[2,3],[3,4]],"handle_primary":[[2,[0.0,0.0]],[3,[0.0,0.0]],[4,[0.0,0.0]],[1,[0.0,0.0]]],"handle_end":[[2,[0.0,0.0]],[3,[0.0,0.0]],[1,[0.0,0.0]],[4,[0.0,0.0]]],"stroke":[[1,0],[4,0],[3,0],[2,0]]},"regions":{"add":[],"remove":[],"segment_range":[],"fill":[]},"add_g1_continuous":[],"remove_g1_continuous":[]}},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::vector_data::modification::VectorModification","alias":null}},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::vector_data::modification::PathModifyNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[5882319123081134737,{"inputs":[{"Node":{"node_id":14102693648424950146,"output_index":0,"lambda":false}},{"Node":{"node_id":13207576193421440093,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[7030585744407664630,{"inputs":[{"Node":{"node_id":13701442050580061197,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"DVec2":[-298.5640646053887,-113.99999999999903]},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[0.9999999999999996,0.9999999999999996]},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[0.0,0.0]},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[0.5,0.5]},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":1}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":2}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":3}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":4}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":5}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::TransformNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[4740496570730418920,{"inputs":[{"Value":{"tagged_value":{"VectorData":{"instance":[{"style":{"stroke":{"color":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0},"weight":0.0,"dash_lengths":[],"dash_offset":0.0,"cap":"Butt","join":"Miter","join_miter_limit":4.0,"align":"Center","transform":[1.0,0.0,0.0,1.0,0.0,0.0],"non_scaling":false,"paint_order":"StrokeAbove"},"fill":"None"},"colinear_manipulators":[],"point_domain":{"id":[],"position":[]},"segment_domain":{"id":[],"start_point":[],"end_point":[],"handles":[],"stroke":[]},"region_domain":{"id":[],"segment_range":[],"fill":[]},"upstream_graphic_group":null}],"transform":[[1.0,0.0,0.0,1.0,0.0,0.0]],"alpha_blending":[{"blend_mode":"Normal","opacity":1.0,"fill":1.0,"clip":false}],"source_node_id":[null]}},"exposed":true}},{"Value":{"tagged_value":{"VectorModification":{"points":{"add":[1,2,3,4],"remove":[],"delta":[[1,[279.9038105676662,605.0000000000001]],[3,[261.24355652982155,620.0]],[4,[298.56406460551034,610.0]],[2,[242.58330249197704,615.0]]]},"segments":{"add":[1,2,3,4],"remove":[],"start_point":[[1,1],[4,4],[3,3],[2,2]],"end_point":[[2,3],[3,4],[4,1],[1,2]],"handle_primary":[[1,[0.0,0.0]],[4,[0.0,0.0]],[3,[0.0,0.0]],[2,[0.0,0.0]]],"handle_end":[[1,[0.0,0.0]],[2,[0.0,0.0]],[3,[0.0,0.0]],[4,[0.0,0.0]]],"stroke":[[1,0],[3,0],[2,0],[4,0]]},"regions":{"add":[0],"remove":[],"segment_range":[[0,{"start":1,"end":4}]],"fill":[[0,0]]},"add_g1_continuous":[],"remove_g1_continuous":[]}},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::vector_data::modification::VectorModification","alias":null}},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::vector_data::modification::PathModifyNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[10651614176902312108,{"inputs":[{"Node":{"node_id":4134257789770357215,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"Fill":{"Gradient":{"stops":[[0.0,{"red":0.41568628,"green":0.6313726,"blue":0.6039216,"alpha":1.0}],[0.869076264787314,{"red":0.46666667,"green":0.69803923,"blue":0.6313726,"alpha":1.0}],[0.9670173672287944,{"red":0.39215687,"green":0.6117647,"blue":0.6,"alpha":1.0}],[1.0,{"red":0.37254903,"green":0.5647059,"blue":0.5529412,"alpha":1.0}]],"gradient_type":"Radial","start":[0.004591093221745557,0.9549938856995572],"end":[1.0010898078090742,0.23229219555707512],"transform":[682.3892394899896,0.0,0.0,255.98390390304277,553.867087387986,415.53693693509086]}}},"exposed":false}},{"Value":{"tagged_value":{"OptionalColor":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}},"exposed":false}},{"Value":{"tagged_value":{"Gradient":{"stops":[[0.0,{"red":0.41568628,"green":0.6313726,"blue":0.6039216,"alpha":1.0}],[0.869076264787314,{"red":0.46666667,"green":0.69803923,"blue":0.6313726,"alpha":1.0}],[0.9670173672287944,{"red":0.39215687,"green":0.6117647,"blue":0.6,"alpha":1.0}],[1.0,{"red":0.37254903,"green":0.5647059,"blue":0.5529412,"alpha":1.0}]],"gradient_type":"Radial","start":[0.004591093221745557,0.9549938856995572],"end":[1.0010898078090742,0.23229219555707512],"transform":[682.3892394899896,0.0,0.0,255.98390390304277,553.867087387986,415.53693693509086]}},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::FillNode"}},"visible":true,"skip_deduplication":false}],[18431382379595272672,{"inputs":[{"Node":{"node_id":10989897386232385465,"output_index":0,"lambda":false}},{"Node":{"node_id":4191887059541031673,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[13609749019463823009,{"inputs":[{"Node":{"node_id":2062662104423219162,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"Fill":{"Gradient":{"stops":[[0.0,{"red":0.34901962,"green":0.5647059,"blue":0.5686275,"alpha":1.0}],[1.0,{"red":0.34901962,"green":0.5647059,"blue":0.5686275,"alpha":0.0}]],"gradient_type":"Linear","start":[0.6190188337031772,0.2673182752249348],"end":[0.4910887633661796,0.9800526827918484],"transform":[244.87384707744465,0.0,0.0,164.03437392974598,690.4184767777101,515.1506140834983]}}},"exposed":false}},{"Value":{"tagged_value":{"OptionalColor":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}},"exposed":false}},{"Value":{"tagged_value":{"Gradient":{"stops":[[0.0,{"red":0.34901962,"green":0.5647059,"blue":0.5686275,"alpha":1.0}],[1.0,{"red":0.34901962,"green":0.5647059,"blue":0.5686275,"alpha":0.0}]],"gradient_type":"Linear","start":[0.6190188337031772,0.2673182752249348],"end":[0.4910887633661796,0.9800526827918484],"transform":[244.87384707744465,0.0,0.0,164.03437392974598,690.4184767777101,515.1506140834983]}},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::FillNode"}},"visible":true,"skip_deduplication":false}],[4847316728405535983,{"inputs":[{"Node":{"node_id":11579925754926059876,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"Fill":{"Solid":{"red":0.5686275,"green":0.7411765,"blue":0.654902,"alpha":1.0}}},"exposed":false}},{"Value":{"tagged_value":{"OptionalColor":{"red":0.5686275,"green":0.7411765,"blue":0.654902,"alpha":1.0}},"exposed":false}},{"Value":{"tagged_value":{"Gradient":{"stops":[[0.0,{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}],[1.0,{"red":1.0,"green":1.0,"blue":1.0,"alpha":1.0}]],"gradient_type":"Linear","start":[0.0,0.5],"end":[1.0,0.5],"transform":[1.0,0.0,0.0,1.0,0.0,0.0]}},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::FillNode"}},"visible":true,"skip_deduplication":false}],[10431241258085047322,{"inputs":[{"Value":{"tagged_value":{"VectorData":{"instance":[{"style":{"stroke":{"color":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0},"weight":0.0,"dash_lengths":[],"dash_offset":0.0,"cap":"Butt","join":"Miter","join_miter_limit":4.0,"align":"Center","transform":[1.0,0.0,0.0,1.0,0.0,0.0],"non_scaling":false,"paint_order":"StrokeAbove"},"fill":"None"},"colinear_manipulators":[],"point_domain":{"id":[],"position":[]},"segment_domain":{"id":[],"start_point":[],"end_point":[],"handles":[],"stroke":[]},"region_domain":{"id":[],"segment_range":[],"fill":[]},"upstream_graphic_group":null}],"transform":[[1.0,0.0,0.0,1.0,0.0,0.0]],"alpha_blending":[{"blend_mode":"Normal","opacity":1.0,"fill":1.0,"clip":false}],"source_node_id":[null]}},"exposed":true}},{"Value":{"tagged_value":{"VectorModification":{"points":{"add":[1,2,3,4,5,6],"remove":[],"delta":[[3,[597.1281292110202,599.9999999999999]],[1,[298.56406460551034,479.99999999999983]],[6,[298.56406460551045,540.0000000000001]],[4,[709.0896534380863,630.0]],[5,[709.0896534380863,649.9999999999999]],[2,[597.1281292110192,559.9999999999998]]]},"segments":{"add":[1,2,3,4,5,6],"remove":[],"start_point":[[1,1],[5,5],[4,4],[6,6],[3,3],[2,2]],"end_point":[[3,4],[5,6],[2,3],[6,1],[1,2],[4,5]],"handle_primary":[[6,[0.0,0.0]],[4,[0.0,0.0]],[3,[0.0,0.0]],[1,[0.0,0.0]],[2,[0.0,0.0]],[5,[0.0,0.0]]],"handle_end":[[5,[0.0,0.0]],[1,[0.0,0.0]],[4,[0.0,0.0]],[6,[0.0,0.0]],[2,[0.0,0.0]],[3,[0.0,0.0]]],"stroke":[[2,0],[6,0],[5,0],[4,0],[1,0],[3,0]]},"regions":{"add":[0],"remove":[],"segment_range":[[0,{"start":1,"end":6}]],"fill":[[0,0]]},"add_g1_continuous":[],"remove_g1_continuous":[]}},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::vector_data::modification::VectorModification","alias":null}},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::vector_data::modification::PathModifyNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[5346759588580719138,{"inputs":[{"Node":{"node_id":57904581517036791,"output_index":0,"lambda":false}},{"Node":{"node_id":16244305414728361140,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[8508454285877707748,{"inputs":[{"Node":{"node_id":9908869573449854874,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"Fill":{"Gradient":{"stops":[[0.0,{"red":0.5137255,"green":0.7294118,"blue":0.68235296,"alpha":1.0}],[1.0,{"red":0.49019608,"green":0.7882353,"blue":0.75686276,"alpha":1.0}]],"gradient_type":"Linear","start":[0.0033697141397510677,0.6230645063687077],"end":[0.058070316242295306,1.09924019568288],"transform":[593.4286164571708,0.0,0.0,254.41394967234703,831.0003152001923,405.4836980340858]}}},"exposed":false}},{"Value":{"tagged_value":{"OptionalColor":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}},"exposed":false}},{"Value":{"tagged_value":{"Gradient":{"stops":[[0.0,{"red":0.5137255,"green":0.7294118,"blue":0.68235296,"alpha":1.0}],[1.0,{"red":0.49019608,"green":0.7882353,"blue":0.75686276,"alpha":1.0}]],"gradient_type":"Linear","start":[0.0033697141397510677,0.6230645063687077],"end":[0.058070316242295306,1.09924019568288],"transform":[593.4286164571708,0.0,0.0,254.41394967234703,831.0003152001923,405.4836980340858]}},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::FillNode"}},"visible":true,"skip_deduplication":false}],[11236872744106223256,{"inputs":[{"Node":{"node_id":9724746185253267560,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"DVec2":[0.0,16.0]},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[1.0,1.0]},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[0.0,0.0]},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[0.5,0.5]},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":1}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":2}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":3}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":4}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":5}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::TransformNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[14102693648424950146,{"inputs":[{"Value":{"tagged_value":{"GraphicGroup":{"instance":[],"transform":[],"alpha_blending":[],"source_node_id":[]}},"exposed":true}},{"Node":{"node_id":16847360882244487081,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[6142412830271644616,{"inputs":[{"Value":{"tagged_value":{"VectorData":{"instance":[{"style":{"stroke":{"color":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0},"weight":0.0,"dash_lengths":[],"dash_offset":0.0,"cap":"Butt","join":"Miter","join_miter_limit":4.0,"align":"Center","transform":[1.0,0.0,0.0,1.0,0.0,0.0],"non_scaling":false,"paint_order":"StrokeAbove"},"fill":"None"},"colinear_manipulators":[],"point_domain":{"id":[],"position":[]},"segment_domain":{"id":[],"start_point":[],"end_point":[],"handles":[],"stroke":[]},"region_domain":{"id":[],"segment_range":[],"fill":[]},"upstream_graphic_group":null}],"transform":[[1.0,0.0,0.0,1.0,0.0,0.0]],"alpha_blending":[{"blend_mode":"Normal","opacity":1.0,"fill":1.0,"clip":false}],"source_node_id":[null]}},"exposed":true}},{"Value":{"tagged_value":{"VectorModification":{"points":{"add":[1,2,3,4],"remove":[],"delta":[[3,[1203.586385440963,436.5]],[2,[1175.5960043841962,429.0]],[1,[1278.2274015923404,401.49999999999994]],[4,[1250.2370205355735,424.00000000000006]]]},"segments":{"add":[1,2,3],"remove":[],"start_point":[[1,1],[3,3],[2,2]],"end_point":[[2,3],[3,4],[1,2]],"handle_primary":[[1,[0.0,0.0]],[2,[0.0,0.0]],[3,[0.0,0.0]]],"handle_end":[[3,[0.0,0.0]],[2,[0.0,0.0]],[1,[0.0,0.0]]],"stroke":[[3,0],[2,0],[1,0]]},"regions":{"add":[],"remove":[],"segment_range":[],"fill":[]},"add_g1_continuous":[],"remove_g1_continuous":[]}},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::vector_data::modification::VectorModification","alias":null}},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::vector_data::modification::PathModifyNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[57904581517036791,{"inputs":[{"Node":{"node_id":9393309733761233513,"output_index":0,"lambda":false}},{"Node":{"node_id":15300421479077882117,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[10852750245702849075,{"inputs":[{"Node":{"node_id":17250040304106119844,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"OptionalColor":{"red":0.9372549,"green":0.90588236,"blue":0.77254903,"alpha":0.75}},"exposed":false}},{"Value":{"tagged_value":{"F64":3.0},"exposed":false}},{"Value":{"tagged_value":{"StrokeAlign":"Center"},"exposed":false}},{"Value":{"tagged_value":{"StrokeCap":"Round"},"exposed":false}},{"Value":{"tagged_value":{"StrokeJoin":"Miter"},"exposed":false}},{"Value":{"tagged_value":{"F64":4.0},"exposed":false}},{"Value":{"tagged_value":{"PaintOrder":"StrokeAbove"},"exposed":false}},{"Value":{"tagged_value":{"VecF64":[]},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::StrokeNode"}},"visible":true,"skip_deduplication":false}],[14449710315388146362,{"inputs":[{"Node":{"node_id":7671691070850213967,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"F64":81.1788},"exposed":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::blending_nodes::OpacityNode"}},"visible":true,"skip_deduplication":false}],[6006052038693767172,{"inputs":[{"Node":{"node_id":4197544064668946479,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"OptionalColor":{"red":0.9372549,"green":0.90588236,"blue":0.7764706,"alpha":0.7490196}},"exposed":false}},{"Value":{"tagged_value":{"F64":3.0},"exposed":false}},{"Value":{"tagged_value":{"StrokeAlign":"Center"},"exposed":false}},{"Value":{"tagged_value":{"StrokeCap":"Round"},"exposed":false}},{"Value":{"tagged_value":{"StrokeJoin":"Miter"},"exposed":false}},{"Value":{"tagged_value":{"F64":4.0},"exposed":false}},{"Value":{"tagged_value":{"PaintOrder":"StrokeAbove"},"exposed":false}},{"Value":{"tagged_value":{"VecF64":[]},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::StrokeNode"}},"visible":true,"skip_deduplication":false}],[16923062582661131268,{"inputs":[{"Value":{"tagged_value":{"VectorData":{"instance":[{"style":{"stroke":{"color":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0},"weight":0.0,"dash_lengths":[],"dash_offset":0.0,"cap":"Butt","join":"Miter","join_miter_limit":4.0,"align":"Center","transform":[1.0,0.0,0.0,1.0,0.0,0.0],"non_scaling":false,"paint_order":"StrokeAbove"},"fill":"None"},"colinear_manipulators":[],"point_domain":{"id":[],"position":[]},"segment_domain":{"id":[],"start_point":[],"end_point":[],"handles":[],"stroke":[]},"region_domain":{"id":[],"segment_range":[],"fill":[]},"upstream_graphic_group":null}],"transform":[[1.0,0.0,0.0,1.0,0.0,0.0]],"alpha_blending":[{"blend_mode":"Normal","opacity":1.0,"fill":1.0,"clip":false}],"source_node_id":[null]}},"exposed":true}},{"Value":{"tagged_value":{"VectorModification":{"points":{"add":[1,2,3,4],"remove":[],"delta":[[4,[671.769145362398,420.0000000000001]],[1,[597.1281292110202,399.9999999999999]],[3,[653.1088913245534,424.99999999999994]],[2,[597.1281292110202,409.99999999999994]]]},"segments":{"add":[1,2,3,4],"remove":[],"start_point":[[4,4],[3,3],[1,1],[2,2]],"end_point":[[1,2],[2,3],[4,1],[3,4]],"handle_primary":[[4,[0.0,0.0]],[3,[0.0,0.0]],[1,[0.0,0.0]],[2,[0.0,0.0]]],"handle_end":[[2,[0.0,0.0]],[4,[0.0,0.0]],[1,[0.0,0.0]],[3,[0.0,0.0]]],"stroke":[[2,0],[4,0],[1,0],[3,0]]},"regions":{"add":[0],"remove":[],"segment_range":[[0,{"start":1,"end":4}]],"fill":[[0,0]]},"add_g1_continuous":[],"remove_g1_continuous":[]}},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::vector_data::modification::VectorModification","alias":null}},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::vector_data::modification::PathModifyNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[8958782938691501404,{"inputs":[{"Value":{"tagged_value":{"VectorData":{"instance":[{"style":{"stroke":{"color":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0},"weight":0.0,"dash_lengths":[],"dash_offset":0.0,"cap":"Butt","join":"Miter","join_miter_limit":4.0,"align":"Center","transform":[1.0,0.0,0.0,1.0,0.0,0.0],"non_scaling":false,"paint_order":"StrokeAbove"},"fill":"None"},"colinear_manipulators":[],"point_domain":{"id":[],"position":[]},"segment_domain":{"id":[],"start_point":[],"end_point":[],"handles":[],"stroke":[]},"region_domain":{"id":[],"segment_range":[],"fill":[]},"upstream_graphic_group":null}],"transform":[[1.0,0.0,0.0,1.0,0.0,0.0]],"alpha_blending":[{"blend_mode":"Normal","opacity":1.0,"fill":1.0,"clip":false}],"source_node_id":[null]}},"exposed":true}},{"Value":{"tagged_value":{"VectorModification":{"points":{"add":[1,2,3,4],"remove":[],"delta":[[4,[1156.9357503463516,540.0]],[2,[1231.576766497729,510.00000000000233]],[3,[1231.6308657449686,540.0144958496094]],[1,[1156.9357503463525,530.0]]]},"segments":{"add":[1,2,3,4],"remove":[],"start_point":[[2,2],[1,1],[4,4],[3,3]],"end_point":[[1,2],[2,3],[3,4],[4,1]],"handle_primary":[[3,[-74.69511539861696,-0.014495849609375]],[2,[0.0,0.0]],[4,[0.0,0.0]],[1,[0.0,0.0]]],"handle_end":[[1,[0.0,0.0]],[4,[0.0,-2.273736754432321e-13]],[2,null],[3,null]],"stroke":[[3,0],[4,0],[2,0],[1,0]]},"regions":{"add":[0],"remove":[],"segment_range":[[0,{"start":1,"end":4}]],"fill":[[0,0]]},"add_g1_continuous":[],"remove_g1_continuous":[]}},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::vector_data::modification::VectorModification","alias":null}},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::vector_data::modification::PathModifyNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[15478704582542175684,{"inputs":[{"Node":{"node_id":8242413775403456296,"output_index":0,"lambda":false}},{"Node":{"node_id":13696921450692276893,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[532055960192543062,{"inputs":[{"Node":{"node_id":326112971739898070,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"OptionalColor":{"red":0.9372549,"green":0.90588236,"blue":0.7764706,"alpha":0.7490196}},"exposed":false}},{"Value":{"tagged_value":{"F64":3.0},"exposed":false}},{"Value":{"tagged_value":{"StrokeAlign":"Center"},"exposed":false}},{"Value":{"tagged_value":{"StrokeCap":"Butt"},"exposed":false}},{"Value":{"tagged_value":{"StrokeJoin":"Miter"},"exposed":false}},{"Value":{"tagged_value":{"F64":4.0},"exposed":false}},{"Value":{"tagged_value":{"PaintOrder":"StrokeAbove"},"exposed":false}},{"Value":{"tagged_value":{"VecF64":[]},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::StrokeNode"}},"visible":true,"skip_deduplication":false}],[13942787566051910019,{"inputs":[{"Value":{"tagged_value":{"VectorData":{"instance":[{"style":{"stroke":{"color":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0},"weight":0.0,"dash_lengths":[],"dash_offset":0.0,"cap":"Butt","join":"Miter","join_miter_limit":4.0,"align":"Center","transform":[1.0,0.0,0.0,1.0,0.0,0.0],"non_scaling":false,"paint_order":"StrokeAbove"},"fill":"None"},"colinear_manipulators":[],"point_domain":{"id":[],"position":[]},"segment_domain":{"id":[],"start_point":[],"end_point":[],"handles":[],"stroke":[]},"region_domain":{"id":[],"segment_range":[],"fill":[]},"upstream_graphic_group":null}],"transform":[[1.0,0.0,0.0,1.0,0.0,0.0]],"alpha_blending":[{"blend_mode":"Normal","opacity":1.0,"fill":1.0,"clip":false}],"source_node_id":[null]}},"exposed":true}},{"Value":{"tagged_value":{"VectorModification":{"points":{"add":[1,2,3,4],"remove":[],"delta":[[2,[1.000788022064618,-6.266203653947348e-16]],[3,[1.000788022064618,1.0000000000000009]],[4,[0.0,1.0]],[1,[0.0,0.0]]]},"segments":{"add":[1,2,3,4],"remove":[],"start_point":[[4,4],[1,1],[3,3],[2,2]],"end_point":[[4,1],[1,2],[3,4],[2,3]],"handle_primary":[[4,[0.0,0.0]],[1,[0.0,0.0]],[2,[0.0,0.0]],[3,[0.0,0.0]]],"handle_end":[[3,[0.0,0.0]],[1,[0.0,0.0]],[4,[0.0,0.0]],[2,[0.0,0.0]]],"stroke":[[2,0],[3,0],[4,0],[1,0]]},"regions":{"add":[0],"remove":[],"segment_range":[[0,{"start":1,"end":4}]],"fill":[[0,0]]},"add_g1_continuous":[],"remove_g1_continuous":[]}},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::vector_data::modification::VectorModification","alias":null}},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::vector_data::modification::PathModifyNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[13852123721901366011,{"inputs":[{"Node":{"node_id":456239140723765386,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"DVec2":[819.6941583984747,299.6363877833991]},"exposed":false}},{"Value":{"tagged_value":{"F64":3.141592653589793},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[221.20900992053447,59.27277556679853]},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[-3.2814312084546346e-17,0.0]},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[0.5,0.5]},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":1}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":2}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":3}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":4}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":5}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::TransformNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[7171713123860587892,{"inputs":[{"Node":{"node_id":18431382379595272672,"output_index":0,"lambda":false}},{"Node":{"node_id":9798215931018813676,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[7884283658260267478,{"inputs":[{"Value":{"tagged_value":{"VectorData":{"instance":[{"style":{"stroke":{"color":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0},"weight":0.0,"dash_lengths":[],"dash_offset":0.0,"cap":"Butt","join":"Miter","join_miter_limit":4.0,"align":"Center","transform":[1.0,0.0,0.0,1.0,0.0,0.0],"non_scaling":false,"paint_order":"StrokeAbove"},"fill":"None"},"colinear_manipulators":[],"point_domain":{"id":[],"position":[]},"segment_domain":{"id":[],"start_point":[],"end_point":[],"handles":[],"stroke":[]},"region_domain":{"id":[],"segment_range":[],"fill":[]},"upstream_graphic_group":null}],"transform":[[1.0,0.0,0.0,1.0,0.0,0.0]],"alpha_blending":[{"blend_mode":"Normal","opacity":1.0,"fill":1.0,"clip":false}],"source_node_id":[null]}},"exposed":true}},{"Value":{"tagged_value":{"VectorModification":{"points":{"add":[1,2,3,4],"remove":[],"delta":[[3,[1250.2370205355735,545.0000000000001]],[4,[1203.5863854409629,557.4999999999999]],[1,[1184.9261314031187,552.5]],[2,[1231.5767664977295,540.0000000000001]]]},"segments":{"add":[1,2,3,4],"remove":[],"start_point":[[4,4],[1,1],[2,2],[3,3]],"end_point":[[1,2],[2,3],[3,4],[4,1]],"handle_primary":[[2,[0.0,0.0]],[1,[0.0,0.0]],[4,[0.0,0.0]],[3,[0.0,0.0]]],"handle_end":[[2,[0.0,0.0]],[3,[0.0,0.0]],[4,[0.0,0.0]],[1,[0.0,0.0]]],"stroke":[[4,0],[3,0],[2,0],[1,0]]},"regions":{"add":[0],"remove":[],"segment_range":[[0,{"start":1,"end":4}]],"fill":[[0,0]]},"add_g1_continuous":[],"remove_g1_continuous":[]}},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::vector_data::modification::VectorModification","alias":null}},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::vector_data::modification::PathModifyNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[16564941800301062922,{"inputs":[{"Node":{"node_id":18371793711669837037,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"Fill":{"Solid":{"red":0.0,"green":0.0,"blue":0.0,"alpha":0.03}}},"exposed":false}},{"Value":{"tagged_value":{"OptionalColor":{"red":0.0,"green":0.0,"blue":0.0,"alpha":0.03}},"exposed":false}},{"Value":{"tagged_value":{"Gradient":{"stops":[[0.0,{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}],[1.0,{"red":1.0,"green":1.0,"blue":1.0,"alpha":1.0}]],"gradient_type":"Linear","start":[0.0,0.5],"end":[1.0,0.5],"transform":[1.0,0.0,0.0,1.0,0.0,0.0]}},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::FillNode"}},"visible":true,"skip_deduplication":false}],[3616319631707471648,{"inputs":[{"Node":{"node_id":12852312236973354891,"output_index":0,"lambda":false}},{"Node":{"node_id":16727310898641763441,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[1104068854328504126,{"inputs":[{"Value":{"tagged_value":{"VectorData":{"instance":[{"style":{"stroke":{"color":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0},"weight":0.0,"dash_lengths":[],"dash_offset":0.0,"cap":"Butt","join":"Miter","join_miter_limit":4.0,"align":"Center","transform":[1.0,0.0,0.0,1.0,0.0,0.0],"non_scaling":false,"paint_order":"StrokeAbove"},"fill":"None"},"colinear_manipulators":[],"point_domain":{"id":[],"position":[]},"segment_domain":{"id":[],"start_point":[],"end_point":[],"handles":[],"stroke":[]},"region_domain":{"id":[],"segment_range":[],"fill":[]},"upstream_graphic_group":null}],"transform":[[1.0,0.0,0.0,1.0,0.0,0.0]],"alpha_blending":[{"blend_mode":"Normal","opacity":1.0,"fill":1.0,"clip":false}],"source_node_id":[null]}},"exposed":true}},{"Value":{"tagged_value":{"VectorModification":{"points":{"add":[1,2,3,4],"remove":[],"delta":[[4,[1343.5382907247958,520.0]],[2,[1530.14083110324,530.000000000003]],[1,[1343.538290724796,580.0000000000001]],[3,[1530.14083110324,470.00000000000216]]]},"segments":{"add":[1,2,3,4],"remove":[],"start_point":[[2,2],[3,3],[4,4],[1,1]],"end_point":[[1,2],[2,3],[3,4],[4,1]],"handle_primary":[[2,[0.0,0.0]],[4,[0.0,0.0]],[1,[0.0,0.0]],[3,[0.0,0.0]]],"handle_end":[[1,[0.0,0.0]],[4,[0.0,0.0]],[3,[0.0,0.0]],[2,[0.0,0.0]]],"stroke":[[4,0],[3,0],[1,0],[2,0]]},"regions":{"add":[0],"remove":[],"segment_range":[[0,{"start":1,"end":4}]],"fill":[[0,0]]},"add_g1_continuous":[],"remove_g1_continuous":[]}},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::vector_data::modification::VectorModification","alias":null}},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::vector_data::modification::PathModifyNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[13942146309185231085,{"inputs":[{"Node":{"node_id":15166516760575860563,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"Fill":{"Gradient":{"stops":[[0.0,{"red":0.36862746,"green":0.57254905,"blue":0.45490196,"alpha":1.0}],[0.2134053325596848,{"red":0.45490196,"green":0.70980394,"blue":0.58431375,"alpha":1.0}],[1.0,{"red":1.0,"green":0.84705883,"blue":0.4627451,"alpha":1.0}]],"gradient_type":"Linear","start":[0.4417705336480124,0.7894513882255817],"end":[0.4000315611112892,0.37243515464306],"transform":[1317.713318209003,0.0,0.0,1100.6765757217709,406.8730842197156,-30.930650690931543]}}},"exposed":false}},{"Value":{"tagged_value":{"OptionalColor":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}},"exposed":false}},{"Value":{"tagged_value":{"Gradient":{"stops":[[0.0,{"red":0.36862746,"green":0.57254905,"blue":0.45490196,"alpha":1.0}],[0.2134053325596848,{"red":0.45490196,"green":0.70980394,"blue":0.58431375,"alpha":1.0}],[1.0,{"red":1.0,"green":0.84705883,"blue":0.4627451,"alpha":1.0}]],"gradient_type":"Linear","start":[0.4417705336480124,0.7894513882255817],"end":[0.4000315611112892,0.37243515464306],"transform":[1317.713318209003,0.0,0.0,1100.6765757217709,406.8730842197156,-30.930650690931543]}},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::FillNode"}},"visible":true,"skip_deduplication":false}],[14449527838292182035,{"inputs":[{"Value":{"tagged_value":{"VectorData":{"instance":[{"style":{"stroke":{"color":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0},"weight":0.0,"dash_lengths":[],"dash_offset":0.0,"cap":"Butt","join":"Miter","join_miter_limit":4.0,"align":"Center","transform":[1.0,0.0,0.0,1.0,0.0,0.0],"non_scaling":false,"paint_order":"StrokeAbove"},"fill":"None"},"colinear_manipulators":[],"point_domain":{"id":[],"position":[]},"segment_domain":{"id":[],"start_point":[],"end_point":[],"handles":[],"stroke":[]},"region_domain":{"id":[],"segment_range":[],"fill":[]},"upstream_graphic_group":null}],"transform":[[1.0,0.0,0.0,1.0,0.0,0.0]],"alpha_blending":[{"blend_mode":"Normal","opacity":1.0,"fill":1.0,"clip":false}],"source_node_id":[null]}},"exposed":true}},{"Value":{"tagged_value":{"VectorModification":{"points":{"add":[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18],"remove":[],"delta":[[4,[682.3593964334707,606.4197530864195]],[7,[692.1871665904588,615.6720012193263]],[10,[709.413808870599,616.4718792866942]],[11,[713.6278006401462,612.5505258344765]],[1,[699.8518518518516,598.1234567901233]],[13,[734.8148148148149,620.9492455418381]],[8,[701.8247218411828,611.4580094497792]],[17,[749.8271604938273,587.4567901234568]],[5,[662.6063100137173,612.5432098765428]],[3,[699.7421124828531,603.0617283950616]],[18,[725.5089163237311,594.6117969821673]],[15,[763.4567901234569,605.6296296296294]],[6,[695.3964334705074,609.7777777777776]],[14,[728.493827160494,609.9753086419753]],[9,[709.3552812071331,611.4970278920897]],[12,[721.9094650205761,611.3799725651577]],[16,[726.2990397805214,601.9862825788753]],[2,[667.3909465020577,593.3827160493828]]]},"segments":{"add":[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18],"remove":[],"start_point":[[17,17],[8,8],[5,5],[16,16],[3,3],[12,12],[2,2],[4,4],[13,13],[18,18],[1,1],[9,9],[15,15],[11,11],[7,7],[10,10],[14,14],[6,6]],"end_point":[[10,11],[15,16],[3,4],[18,1],[13,14],[14,15],[2,3],[6,7],[12,13],[7,8],[9,10],[17,18],[1,2],[16,17],[11,12],[5,6],[4,5],[8,9]],"handle_primary":[[10,[2.71082158531226,-3.275875783141601]],[3,[0.0,0.0]],[6,[0.0,0.0]],[5,[0.0,0.0]],[9,[1.0398530837227329,0.17152215813985094]],[14,[-0.1771601410563335,-2.331086581557088]],[18,[-0.0877914951989851,0.0]],[16,[0.0,0.0]],[17,[-7.648317030623161,4.388047332817109]],[8,[0.0,0.0]],[12,[0.6886396813392821,0.35058484628291353]],[11,[0.9510922553114368,-0.40840938602514143]],[4,[-6.038618148571572,2.2123832635880945]],[2,[5.399176954732297,6.584362139917744]],[15,[-15.992684042066571,-5.647919524462736]],[1,[-13.651577503429507,-4.016460905349504]],[7,[0.0,0.0]],[13,[-3.101966163694442,-4.096936442615402]]],"handle_end":[[10,null],[6,[4.13595488492615,-4.1749733272365575]],[18,[0.0,0.0]],[5,[-8.69135802469134,3.3580246913579685]],[12,[-6.90626428898031,-2.3996342021031296]],[16,[-5.977212841894016,7.381559383908893]],[3,[6.038618148571345,-2.2123832635879808]],[14,[-22.51851851851859,-0.614540466392441]],[4,[0.0,0.0]],[17,null],[7,[-5.1358024691359105,5.530864197530718]],[15,[2.8483462886752022,1.1315348270080676]],[8,[-3.7847889041303233,-0.6242950769699291]],[9,null],[13,[-0.5267489711934559,1.053497942386798]],[2,[0.0,0.0]],[11,[-1.2025737194898056,-0.6122274594622468]],[1,[8.559670781892919,2.502057613168745]]],"stroke":[[13,0],[9,0],[8,0],[7,0],[12,0],[11,0],[3,0],[4,0],[10,0],[14,0],[15,0],[17,0],[6,0],[5,0],[18,0],[2,0],[1,0],[16,0]]},"regions":{"add":[0],"remove":[],"segment_range":[[0,{"start":1,"end":18}]],"fill":[[0,0]]},"add_g1_continuous":[],"remove_g1_continuous":[]}},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::vector_data::modification::VectorModification","alias":null}},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::vector_data::modification::PathModifyNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[13861850149743924125,{"inputs":[{"Node":{"node_id":13442128106088307772,"output_index":0,"lambda":false}},{"Node":{"node_id":5891705401441266824,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[4398598693761352299,{"inputs":[{"Value":{"tagged_value":{"VectorData":{"instance":[{"style":{"stroke":{"color":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0},"weight":0.0,"dash_lengths":[],"dash_offset":0.0,"cap":"Butt","join":"Miter","join_miter_limit":4.0,"align":"Center","transform":[1.0,0.0,0.0,1.0,0.0,0.0],"non_scaling":false,"paint_order":"StrokeAbove"},"fill":"None"},"colinear_manipulators":[],"point_domain":{"id":[],"position":[]},"segment_domain":{"id":[],"start_point":[],"end_point":[],"handles":[],"stroke":[]},"region_domain":{"id":[],"segment_range":[],"fill":[]},"upstream_graphic_group":null}],"transform":[[1.0,0.0,0.0,1.0,0.0,0.0]],"alpha_blending":[{"blend_mode":"Normal","opacity":1.0,"fill":1.0,"clip":false}],"source_node_id":[null]}},"exposed":true}},{"Value":{"tagged_value":{"VectorModification":{"points":{"add":[1,2,3,4],"remove":[],"delta":[[3,[933.0127018922194,470.0]],[4,[821.0511776651532,440.0000000000001]],[2,[821.0511776651531,500.0]],[1,[709.0896534380867,469.99999999999994]]]},"segments":{"add":[1,2,3,4],"remove":[],"start_point":[[2,2],[3,3],[1,1],[4,4]],"end_point":[[2,3],[1,2],[4,1],[3,4]],"handle_primary":[[4,[0.0,0.0]],[1,[0.0,0.0]],[2,[0.0,0.0]],[3,[0.0,0.0]]],"handle_end":[[3,[0.0,0.0]],[1,[0.0,0.0]],[4,[0.0,5.684341886080804e-14]],[2,[0.0,0.0]]],"stroke":[[4,0],[3,0],[1,0],[2,0]]},"regions":{"add":[0],"remove":[],"segment_range":[[0,{"start":1,"end":4}]],"fill":[[0,0]]},"add_g1_continuous":[],"remove_g1_continuous":[]}},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::vector_data::modification::VectorModification","alias":null}},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::vector_data::modification::PathModifyNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[16732345645494316637,{"inputs":[{"Node":{"node_id":11450962621506425680,"output_index":0,"lambda":false}},{"Node":{"node_id":7637119583909417127,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[938033825024582130,{"inputs":[{"Node":{"node_id":10477328336261010694,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"Fill":{"Gradient":{"stops":[[0.0,{"red":0.5019608,"green":0.72156864,"blue":0.70980394,"alpha":1.0}],[1.0,{"red":0.5019608,"green":0.72156864,"blue":0.70980394,"alpha":0.0}]],"gradient_type":"Linear","start":[0.44995556068938913,0.40889389103747775],"end":[0.42763248011625454,0.6979899795516591],"transform":[861.8034829475831,0.0,0.0,248.35202392783896,117.22673062625182,378.4503745891131]}}},"exposed":false}},{"Value":{"tagged_value":{"OptionalColor":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}},"exposed":false}},{"Value":{"tagged_value":{"Gradient":{"stops":[[0.0,{"red":0.5019608,"green":0.72156864,"blue":0.70980394,"alpha":1.0}],[1.0,{"red":0.5019608,"green":0.72156864,"blue":0.70980394,"alpha":0.0}]],"gradient_type":"Linear","start":[0.44995556068938913,0.40889389103747775],"end":[0.42763248011625454,0.6979899795516591],"transform":[861.8034829475831,0.0,0.0,248.35202392783896,117.22673062625182,378.4503745891131]}},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::FillNode"}},"visible":true,"skip_deduplication":false}],[12019361655085452072,{"inputs":[{"Node":{"node_id":2036609094647228373,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"DVec2":[1080.8351529382842,378.98352292316827]},"exposed":false}},{"Value":{"tagged_value":{"F64":3.141592653589793},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[221.0038859407525,220.57244110912933]},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[-1.2222560378726955e-16,0.0]},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[0.5,0.5]},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":1}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":2}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":3}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":4}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":5}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::TransformNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[585709295659496998,{"inputs":[{"Node":{"node_id":11990662272042254522,"output_index":0,"lambda":false}},{"Node":{"node_id":12331680982485935376,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[15347111149235590492,{"inputs":[{"Node":{"node_id":2209276411833629008,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"DVec2":[1080.8351529382842,378.9835229231682]},"exposed":false}},{"Value":{"tagged_value":{"F64":3.141592653589793},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[221.0038859407525,220.57244110912933]},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[-1.2222560378726955e-16,0.0]},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[0.5,0.5]},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":1}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":2}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":3}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":4}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":5}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::TransformNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[14752203606937854133,{"inputs":[{"Value":{"tagged_value":{"VectorData":{"instance":[{"style":{"stroke":{"color":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0},"weight":0.0,"dash_lengths":[],"dash_offset":0.0,"cap":"Butt","join":"Miter","join_miter_limit":4.0,"align":"Center","transform":[1.0,0.0,0.0,1.0,0.0,0.0],"non_scaling":false,"paint_order":"StrokeAbove"},"fill":"None"},"colinear_manipulators":[],"point_domain":{"id":[],"position":[]},"segment_domain":{"id":[],"start_point":[],"end_point":[],"handles":[],"stroke":[]},"region_domain":{"id":[],"segment_range":[],"fill":[]},"upstream_graphic_group":null}],"transform":[[1.0,0.0,0.0,1.0,0.0,0.0]],"alpha_blending":[{"blend_mode":"Normal","opacity":1.0,"fill":1.0,"clip":false}],"source_node_id":[null]}},"exposed":true}},{"Value":{"tagged_value":{"VectorModification":{"points":{"add":[1,2,3,4],"remove":[],"delta":[[4,[1044.9742261192855,480.0]],[3,[1044.9742261192855,439.99999999999994]],[1,[597.1281292110193,599.9999999999997]],[2,[597.1281292110197,559.9999999999997]]]},"segments":{"add":[1,2,3,4],"remove":[],"start_point":[[2,2],[3,3],[1,1],[4,4]],"end_point":[[1,2],[4,1],[2,3],[3,4]],"handle_primary":[[3,[0.0,0.0]],[2,[0.0,0.0]],[1,[0.0,0.0]],[4,[0.0,0.0]]],"handle_end":[[2,[0.0,0.0]],[4,[0.0,0.0]],[1,[0.0,0.0]],[3,[0.0,0.0]]],"stroke":[[1,0],[4,0],[3,0],[2,0]]},"regions":{"add":[0],"remove":[],"segment_range":[[0,{"start":1,"end":4}]],"fill":[[0,0]]},"add_g1_continuous":[],"remove_g1_continuous":[]}},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::vector_data::modification::VectorModification","alias":null}},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::vector_data::modification::PathModifyNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[10849502918952703647,{"inputs":[{"Node":{"node_id":9663740787529879916,"output_index":0,"lambda":false}},{"Node":{"node_id":17433098630591807963,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[11506204916439878896,{"inputs":[{"Node":{"node_id":2640491057355360805,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"DVec2":[-261.2435565297001,-64.0]},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[1.0,1.0]},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[0.0,0.0]},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[0.5,0.5]},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":1}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":2}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":3}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":4}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":5}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::TransformNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[7005645574203740491,{"inputs":[{"Node":{"node_id":17873337220577786871,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"DVec2":[-261.24355652969996,-64.0]},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[1.0,1.0]},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[0.0,0.0]},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[0.5,0.5]},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":1}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":2}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":3}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":4}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":5}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::TransformNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[2452294403891427489,{"inputs":[{"Node":{"node_id":9278774434958175105,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"Fill":{"Gradient":{"stops":[[0.0,{"red":0.27058825,"green":0.49411765,"blue":0.5137255,"alpha":1.0}],[1.0,{"red":0.3372549,"green":0.5647059,"blue":0.5529412,"alpha":1.0}]],"gradient_type":"Linear","start":[0.027025122260555538,0.6600000000000135],"end":[0.9916422150126412,0.04000000000001247],"transform":[111.96152422706125,0.0,0.0,99.99999999999976,862.9742261192855,483.9999999999988]}}},"exposed":false}},{"Value":{"tagged_value":{"OptionalColor":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}},"exposed":false}},{"Value":{"tagged_value":{"Gradient":{"stops":[[0.0,{"red":0.27058825,"green":0.49411765,"blue":0.5137255,"alpha":1.0}],[1.0,{"red":0.3372549,"green":0.5647059,"blue":0.5529412,"alpha":1.0}]],"gradient_type":"Linear","start":[0.027025122260555538,0.6600000000000135],"end":[0.9916422150126412,0.04000000000001247],"transform":[111.96152422706125,0.0,0.0,99.99999999999976,862.9742261192855,483.9999999999988]}},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::FillNode"}},"visible":true,"skip_deduplication":false}],[17638504852426495381,{"inputs":[{"Node":{"node_id":17881728913029763313,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"Fill":{"Gradient":{"stops":[[0.0,{"red":0.972549,"green":0.87058824,"blue":0.6666667,"alpha":1.0}],[1.0,{"red":0.98039216,"green":0.94509804,"blue":0.7058824,"alpha":1.0}]],"gradient_type":"Radial","start":[0.7363207208514658,0.8045676758185962],"end":[0.02104094774655124,0.19319223963735063],"transform":[703.2213392761797,0.0,0.0,157.02299163282092,64.20355654603011,465.66437657189834]}}},"exposed":false}},{"Value":{"tagged_value":{"OptionalColor":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}},"exposed":false}},{"Value":{"tagged_value":{"Gradient":{"stops":[[0.0,{"red":0.972549,"green":0.87058824,"blue":0.6666667,"alpha":1.0}],[1.0,{"red":0.98039216,"green":0.94509804,"blue":0.7058824,"alpha":1.0}]],"gradient_type":"Radial","start":[0.7363207208514658,0.8045676758185962],"end":[0.02104094774655124,0.19319223963735063],"transform":[703.2213392761797,0.0,0.0,157.02299163282092,64.20355654603011,465.66437657189834]}},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::FillNode"}},"visible":true,"skip_deduplication":false}],[13696921450692276893,{"inputs":[{"Node":{"node_id":729026403095264425,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"Fill":{"Gradient":{"stops":[[0.0,{"red":0.27058825,"green":0.49411765,"blue":0.5137255,"alpha":1.0}],[0.9059757781988896,{"red":0.27058825,"green":0.49411765,"blue":0.5137255,"alpha":1.0}],[1.0,{"red":0.27058825,"green":0.49411765,"blue":0.5137255,"alpha":0.0}]],"gradient_type":"Radial","start":[0.8930663763318565,-1.4466906873466163],"end":[1.0003976000579349,0.2239198862330611],"transform":[1332.3243231154509,0.0,0.0,297.49602202927537,-250.85405534350912,609.3847245924164]}}},"exposed":false}},{"Value":{"tagged_value":{"OptionalColor":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}},"exposed":false}},{"Value":{"tagged_value":{"Gradient":{"stops":[[0.0,{"red":0.27058825,"green":0.49411765,"blue":0.5137255,"alpha":1.0}],[0.9059757781988896,{"red":0.27058825,"green":0.49411765,"blue":0.5137255,"alpha":1.0}],[1.0,{"red":0.27058825,"green":0.49411765,"blue":0.5137255,"alpha":0.0}]],"gradient_type":"Radial","start":[0.8930663763318565,-1.4466906873466163],"end":[1.0003976000579349,0.2239198862330611],"transform":[1332.3243231154509,0.0,0.0,297.49602202927537,-250.85405534350912,609.3847245924164]}},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::FillNode"}},"visible":true,"skip_deduplication":false}],[764189229787475993,{"inputs":[{"Node":{"node_id":194878846429432339,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"DVec2":[-261.2435565297001,-64.0]},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[1.0,1.0]},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[0.0,0.0]},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[0.5,0.5]},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":1}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":2}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":3}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":4}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":5}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::TransformNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[664587514588499648,{"inputs":[{"Node":{"node_id":5365849201631468915,"output_index":0,"lambda":false}},{"Node":{"node_id":16564941800301062922,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[4924169570021915606,{"inputs":[{"Node":{"node_id":972153153989181918,"output_index":0,"lambda":false}},{"Node":{"node_id":8015732980153557800,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[13853529851208960143,{"inputs":[{"Value":{"tagged_value":{"VectorData":{"instance":[{"style":{"stroke":{"color":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0},"weight":0.0,"dash_lengths":[],"dash_offset":0.0,"cap":"Butt","join":"Miter","join_miter_limit":4.0,"align":"Center","transform":[1.0,0.0,0.0,1.0,0.0,0.0],"non_scaling":false,"paint_order":"StrokeAbove"},"fill":"None"},"colinear_manipulators":[],"point_domain":{"id":[],"position":[]},"segment_domain":{"id":[],"start_point":[],"end_point":[],"handles":[],"stroke":[]},"region_domain":{"id":[],"segment_range":[],"fill":[]},"upstream_graphic_group":null}],"transform":[[1.0,0.0,0.0,1.0,0.0,0.0]],"alpha_blending":[{"blend_mode":"Normal","opacity":1.0,"fill":1.0,"clip":false}],"source_node_id":[null]}},"exposed":true}},{"Value":{"tagged_value":{"VectorModification":{"points":{"add":[1,2,3,4],"remove":[],"delta":[[4,[-40.648024782723304,138.90840278889075]],[3,[29.146213900404632,142.10291541428978]],[2,[28.09271595801783,129.8163283935271]],[1,[-39.199465111941095,125.88462054688308]]]},"segments":{"add":[1,2,3,4],"remove":[],"start_point":[[4,4],[1,1],[2,2],[3,3]],"end_point":[[4,1],[3,4],[2,3],[1,2]],"handle_primary":[[2,[0.0,0.0]],[3,[0.0,0.0]],[1,[0.0,0.0]],[4,[0.0,0.0]]],"handle_end":[[3,[27.65672806576993,9.286366023261053]],[4,[0.0,0.0]],[2,[0.0,0.0]],[1,[-37.794238683127446,8.35487917411865]]],"stroke":[[3,0],[4,0],[1,0],[2,0]]},"regions":{"add":[0],"remove":[],"segment_range":[[0,{"start":1,"end":4}]],"fill":[[0,0]]},"add_g1_continuous":[],"remove_g1_continuous":[]}},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::vector_data::modification::VectorModification","alias":null}},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::vector_data::modification::PathModifyNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[16416441286881083283,{"inputs":[{"Value":{"tagged_value":{"VectorData":{"instance":[{"style":{"stroke":{"color":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0},"weight":0.0,"dash_lengths":[],"dash_offset":0.0,"cap":"Butt","join":"Miter","join_miter_limit":4.0,"align":"Center","transform":[1.0,0.0,0.0,1.0,0.0,0.0],"non_scaling":false,"paint_order":"StrokeAbove"},"fill":"None"},"colinear_manipulators":[],"point_domain":{"id":[],"position":[]},"segment_domain":{"id":[],"start_point":[],"end_point":[],"handles":[],"stroke":[]},"region_domain":{"id":[],"segment_range":[],"fill":[]},"upstream_graphic_group":null}],"transform":[[1.0,0.0,0.0,1.0,0.0,0.0]],"alpha_blending":[{"blend_mode":"Normal","opacity":1.0,"fill":1.0,"clip":false}],"source_node_id":[null]}},"exposed":true}},{"Value":{"tagged_value":{"VectorModification":{"points":{"add":[1,2,3,4],"remove":[],"delta":[[3,[1492.8203230275506,480.00000000000006]],[1,[1306.217782649107,559.9999999999999]],[2,[1492.8203230275508,509.99999999999994]],[4,[1306.2177826491068,529.9999999999972]]]},"segments":{"add":[1,2,3,4],"remove":[],"start_point":[[2,2],[4,4],[1,1],[3,3]],"end_point":[[1,2],[4,1],[3,4],[2,3]],"handle_primary":[[2,[0.0,0.0]],[1,[0.0,0.0]],[3,[0.0,0.0]],[4,[0.0,0.0]]],"handle_end":[[2,[0.0,0.0]],[3,[0.0,0.0]],[4,[0.0,0.0]],[1,[0.0,0.0]]],"stroke":[[4,0],[3,0],[2,0],[1,0]]},"regions":{"add":[0],"remove":[],"segment_range":[[0,{"start":1,"end":4}]],"fill":[[0,0]]},"add_g1_continuous":[],"remove_g1_continuous":[]}},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::vector_data::modification::VectorModification","alias":null}},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::vector_data::modification::PathModifyNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[7948029953091985757,{"inputs":[{"Value":{"tagged_value":{"VectorData":{"instance":[{"style":{"stroke":{"color":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0},"weight":0.0,"dash_lengths":[],"dash_offset":0.0,"cap":"Butt","join":"Miter","join_miter_limit":4.0,"align":"Center","transform":[1.0,0.0,0.0,1.0,0.0,0.0],"non_scaling":false,"paint_order":"StrokeAbove"},"fill":"None"},"colinear_manipulators":[],"point_domain":{"id":[],"position":[]},"segment_domain":{"id":[],"start_point":[],"end_point":[],"handles":[],"stroke":[]},"region_domain":{"id":[],"segment_range":[],"fill":[]},"upstream_graphic_group":null}],"transform":[[1.0,0.0,0.0,1.0,0.0,0.0]],"alpha_blending":[{"blend_mode":"Normal","opacity":1.0,"fill":1.0,"clip":false}],"source_node_id":[null]}},"exposed":true}},{"Value":{"tagged_value":{"VectorModification":{"points":{"add":[1,2,3,4],"remove":[],"delta":[[1,[0.5,0.0]],[3,[0.5,1.0]],[2,[1.0,0.5]],[4,[0.0,0.5]]]},"segments":{"add":[1,2,3,4],"remove":[],"start_point":[[3,3],[2,2],[1,1],[4,4]],"end_point":[[3,4],[4,1],[1,2],[2,3]],"handle_primary":[[4,[0.0,-0.275892388889507]],[2,[0.0,0.27589238888950707]],[1,[0.27589238888950707,0.0]],[3,[-0.275892388889507,0.0]]],"handle_end":[[1,[0.0,-0.275892388889507]],[3,[0.0,0.27589238888950707]],[2,[0.27589238888950707,0.0]],[4,[-0.275892388889507,0.0]]],"stroke":[[4,0],[1,0],[2,0],[3,0]]},"regions":{"add":[0],"remove":[],"segment_range":[[0,{"start":1,"end":4}]],"fill":[[0,0]]},"add_g1_continuous":[],"remove_g1_continuous":[]}},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::vector_data::modification::VectorModification","alias":null}},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::vector_data::modification::PathModifyNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[9663740787529879916,{"inputs":[{"Node":{"node_id":14633096010607565334,"output_index":0,"lambda":false}},{"Node":{"node_id":10651614176902312108,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[9323583246068171750,{"inputs":[{"Node":{"node_id":3680957604830907751,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"Fill":{"Gradient":{"stops":[[0.0,{"red":0.54901963,"green":0.7372549,"blue":0.654902,"alpha":1.0}],[1.0,{"red":0.44705883,"green":0.654902,"blue":0.50980395,"alpha":1.0}]],"gradient_type":"Linear","start":[0.481496333638864,0.31809715494984925],"end":[0.5186182401466546,0.7659061379880119],"transform":[215.50617283950584,0.0,0.0,207.67783479697297,1364.2345679012346,470.9382716049381]}}},"exposed":false}},{"Value":{"tagged_value":{"OptionalColor":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}},"exposed":false}},{"Value":{"tagged_value":{"Gradient":{"stops":[[0.0,{"red":0.54901963,"green":0.7372549,"blue":0.654902,"alpha":1.0}],[1.0,{"red":0.44705883,"green":0.654902,"blue":0.50980395,"alpha":1.0}]],"gradient_type":"Linear","start":[0.481496333638864,0.31809715494984925],"end":[0.5186182401466546,0.7659061379880119],"transform":[215.50617283950584,0.0,0.0,207.67783479697297,1364.2345679012346,470.9382716049381]}},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::FillNode"}},"visible":true,"skip_deduplication":false}],[15876464101883822838,{"inputs":[{"Node":{"node_id":3227544593834141716,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"Fill":{"Solid":{"red":0.33333334,"green":0.5647059,"blue":0.5529412,"alpha":1.0}}},"exposed":false}},{"Value":{"tagged_value":{"OptionalColor":{"red":0.33333334,"green":0.5647059,"blue":0.5529412,"alpha":1.0}},"exposed":false}},{"Value":{"tagged_value":{"Gradient":{"stops":[[0.0,{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}],[1.0,{"red":1.0,"green":1.0,"blue":1.0,"alpha":1.0}]],"gradient_type":"Linear","start":[0.0,0.5],"end":[1.0,0.5],"transform":[1.0,0.0,0.0,1.0,0.0,0.0]}},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::FillNode"}},"visible":true,"skip_deduplication":false}],[5317925967883407701,{"inputs":[{"Node":{"node_id":13853529851208960143,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"DVec2":[0.0,2.0]},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[1.0,1.0]},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[0.0,0.0]},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[0.5,0.5]},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":1}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":2}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":3}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":4}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":5}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::TransformNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[729026403095264425,{"inputs":[{"Node":{"node_id":9392462024456293097,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"DVec2":[-261.24355652969996,-64.0]},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[1.0,1.0]},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[0.0,0.0]},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[0.5,0.5]},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":1}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":2}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":3}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":4}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":5}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::TransformNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[972153153989181918,{"inputs":[{"Node":{"node_id":15488533792651297821,"output_index":0,"lambda":false}},{"Node":{"node_id":9981992739451603109,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[12852312236973354891,{"inputs":[{"Node":{"node_id":8181290118694677328,"output_index":0,"lambda":false}},{"Node":{"node_id":2921219300441868542,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[5017082804473894058,{"inputs":[{"Node":{"node_id":8165914767449151618,"output_index":0,"lambda":false}},{"Node":{"node_id":8166796652234334001,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[1268775104597510914,{"inputs":[{"Node":{"node_id":13861850149743924125,"output_index":0,"lambda":false}},{"Node":{"node_id":18011777376689315137,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[9641315149170593327,{"inputs":[{"Value":{"tagged_value":{"VectorData":{"instance":[{"style":{"stroke":{"color":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0},"weight":0.0,"dash_lengths":[],"dash_offset":0.0,"cap":"Butt","join":"Miter","join_miter_limit":4.0,"align":"Center","transform":[1.0,0.0,0.0,1.0,0.0,0.0],"non_scaling":false,"paint_order":"StrokeAbove"},"fill":"None"},"colinear_manipulators":[],"point_domain":{"id":[],"position":[]},"segment_domain":{"id":[],"start_point":[],"end_point":[],"handles":[],"stroke":[]},"region_domain":{"id":[],"segment_range":[],"fill":[]},"upstream_graphic_group":null}],"transform":[[1.0,0.0,0.0,1.0,0.0,0.0]],"alpha_blending":[{"blend_mode":"Normal","opacity":1.0,"fill":1.0,"clip":false}],"source_node_id":[null]}},"exposed":true}},{"Value":{"tagged_value":{"VectorModification":{"points":{"add":[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20],"remove":[],"delta":[[19,[1353.7580246913572,440.1251028806582]],[2,[1297.047751590237,432.45710241679353]],[17,[1343.538290724795,449.4814814814814]],[6,[1286.7160493827164,380.04205830395256]],[20,[1326.2661179698216,436.1481481481482]],[7,[1284.082304526749,376.2304526748971]],[1,[1313.111111111111,440.66666666666663]],[9,[1269.113854595336,397.6954732510288]],[14,[1325.5637860082304,455.6378600823044]],[12,[1302.7379972565157,443.9615912208504]],[18,[1327.484998303753,444.1384489176408]],[16,[1323.5884773662551,445.96633567616453]],[5,[1280.0,432.79012345679007]],[3,[1311.0123456790122,389.1358024691358]],[8,[1270.5185185185182,430.0]],[10,[1267.5056400134067,396.48371220183463]],[13,[1312.9218106995884,446.85871056241416]],[4,[1309.432098765432,385.3827160493827]],[11,[1259.4489801206926,442.53166286845914]],[15,[1319.4403292181073,447.7366255144034]]]},"segments":{"add":[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20],"remove":[],"start_point":[[6,6],[15,15],[12,12],[9,9],[18,18],[8,8],[11,11],[4,4],[14,14],[7,7],[16,16],[1,1],[19,19],[2,2],[17,17],[20,20],[5,5],[3,3],[13,13],[10,10]],"end_point":[[6,7],[10,11],[7,8],[1,2],[5,6],[16,17],[17,18],[14,15],[13,14],[18,19],[12,13],[2,3],[20,1],[19,20],[8,9],[15,16],[9,10],[11,12],[4,5],[3,4]],"handle_primary":[[3,null],[16,[19.75931834024595,4.512540664093933]],[10,[-0.14088374697121253,12.961503560065635]],[15,[0.05852766346606586,-1.7558299039780536]],[5,[0.0,-30.09785939152056]],[9,[0.0,0.0]],[7,[-10.798353909464822,37.53086419753089]],[19,[-0.162851070793522,-0.9241759662677964]],[8,[-2.1728395061727497,-5.1111111111111995]],[6,null],[2,[-7.975963753017595,-5.0295761250696955]],[20,null],[4,[-16.197530864197688,14.61728395061732]],[14,[0.7997581306144639,-0.5767761645364544]],[12,[9.763281342613707,0.018425375535628064]],[18,[26.44161668001243,-3.0566001241026584]],[17,[0.17673990847697496,-0.9253757795596016]],[11,[14.00629256044499,3.614815506799175]],[1,[-1.6922078070856514,-5.274941522376082]],[13,[0.0,0.0]]],"handle_end":[[6,null],[7,null],[15,null],[5,null],[12,[0.0,0.0]],[11,[-11.251577773519555,-0.02123410547835647]],[9,null],[8,[0.0,0.0]],[14,[-0.022878726643284608,0.6863617992941045]],[16,null],[19,[1.229080932784882,6.672153635116501]],[1,[3.0857646420445235,-0.2303077208630384]],[13,[-0.8413105648451165,0.6067432917530482]],[3,null],[4,null],[18,null],[10,[-4.337869009581482,-9.544008547471435]],[20,null],[17,null],[2,null]],"stroke":[[13,0],[14,0],[16,0],[5,0],[15,0],[9,0],[10,0],[19,0],[18,0],[11,0],[2,0],[17,0],[8,0],[1,0],[6,0],[20,0],[12,0],[3,0],[7,0],[4,0]]},"regions":{"add":[0],"remove":[],"segment_range":[[0,{"start":1,"end":20}]],"fill":[[0,0]]},"add_g1_continuous":[],"remove_g1_continuous":[]}},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::vector_data::modification::VectorModification","alias":null}},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::vector_data::modification::PathModifyNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[3927358878935116440,{"inputs":[{"Value":{"tagged_value":{"VectorData":{"instance":[{"style":{"stroke":{"color":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0},"weight":0.0,"dash_lengths":[],"dash_offset":0.0,"cap":"Butt","join":"Miter","join_miter_limit":4.0,"align":"Center","transform":[1.0,0.0,0.0,1.0,0.0,0.0],"non_scaling":false,"paint_order":"StrokeAbove"},"fill":"None"},"colinear_manipulators":[],"point_domain":{"id":[],"position":[]},"segment_domain":{"id":[],"start_point":[],"end_point":[],"handles":[],"stroke":[]},"region_domain":{"id":[],"segment_range":[],"fill":[]},"upstream_graphic_group":null}],"transform":[[1.0,0.0,0.0,1.0,0.0,0.0]],"alpha_blending":[{"blend_mode":"Normal","opacity":1.0,"fill":1.0,"clip":false}],"source_node_id":[null]}},"exposed":true}},{"Value":{"tagged_value":{"VectorModification":{"points":{"add":[1,2,3,4],"remove":[],"delta":[[4,[1194.2562584220411,420.00000000000006]],[2,[1082.2947341949798,490.0000000000013]],[3,[1082.2947341949805,450.0000000000013]],[1,[1194.2562584220414,520.0000000000001]]]},"segments":{"add":[1,2,3,4],"remove":[],"start_point":[[2,2],[3,3],[1,1],[4,4]],"end_point":[[1,2],[4,1],[3,4],[2,3]],"handle_primary":[[2,[6.821210263296962e-13,-40.0]],[4,[0.0,0.0]],[1,[0.0,0.0]],[3,[0.0,0.0]]],"handle_end":[[3,[0.0,0.0]],[1,null],[4,[0.0,-1.1368683772161605e-13]],[2,null]],"stroke":[[2,0],[1,0],[3,0],[4,0]]},"regions":{"add":[0],"remove":[],"segment_range":[[0,{"start":1,"end":4}]],"fill":[[0,0]]},"add_g1_continuous":[],"remove_g1_continuous":[]}},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::vector_data::modification::VectorModification","alias":null}},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::vector_data::modification::PathModifyNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[14255588039347536657,{"inputs":[{"Node":{"node_id":18185020559178852986,"output_index":0,"lambda":false}},{"Node":{"node_id":5261200785298607501,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[9640215309187299519,{"inputs":[{"Value":{"tagged_value":{"VectorData":{"instance":[{"style":{"stroke":{"color":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0},"weight":0.0,"dash_lengths":[],"dash_offset":0.0,"cap":"Butt","join":"Miter","join_miter_limit":4.0,"align":"Center","transform":[1.0,0.0,0.0,1.0,0.0,0.0],"non_scaling":false,"paint_order":"StrokeAbove"},"fill":"None"},"colinear_manipulators":[],"point_domain":{"id":[],"position":[]},"segment_domain":{"id":[],"start_point":[],"end_point":[],"handles":[],"stroke":[]},"region_domain":{"id":[],"segment_range":[],"fill":[]},"upstream_graphic_group":null}],"transform":[[1.0,0.0,0.0,1.0,0.0,0.0]],"alpha_blending":[{"blend_mode":"Normal","opacity":1.0,"fill":1.0,"clip":false}],"source_node_id":[null]}},"exposed":true}},{"Value":{"tagged_value":{"VectorModification":{"points":{"add":[1,2,3,4,5],"remove":[],"delta":[[3,[746.4101615137856,637.8601932525706]],[5,[1268.8972745734306,517.8601932525701]],[4,[746.4101615137852,657.8601932525711]],[2,[1194.2562584220475,517.8601932525687]],[1,[1268.8972745734306,457.8601932525698]]]},"segments":{"add":[1,2,3,4,5],"remove":[],"start_point":[[3,3],[4,4],[2,2],[1,1],[5,5]],"end_point":[[4,5],[3,4],[5,1],[2,3],[1,2]],"handle_primary":[[4,[0.0,0.0]],[5,[0.0,-60.00000000000029]],[2,[-447.8460969082618,120.00000000000192]],[1,[0.0,0.0]],[3,[0.0,0.0]]],"handle_end":[[1,null],[3,[0.0,0.0]],[5,null],[4,null],[2,null]],"stroke":[[2,0],[3,0],[5,0],[4,0],[1,0]]},"regions":{"add":[0],"remove":[],"segment_range":[[0,{"start":1,"end":5}]],"fill":[[0,0]]},"add_g1_continuous":[],"remove_g1_continuous":[]}},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::vector_data::modification::VectorModification","alias":null}},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::vector_data::modification::PathModifyNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[4101813853952238986,{"inputs":[{"Node":{"node_id":14161755104759532162,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"OptionalColor":{"red":0.9372549,"green":0.90588236,"blue":0.7764706,"alpha":0.7490196}},"exposed":false}},{"Value":{"tagged_value":{"F64":3.0},"exposed":false}},{"Value":{"tagged_value":{"StrokeAlign":"Center"},"exposed":false}},{"Value":{"tagged_value":{"StrokeCap":"Round"},"exposed":false}},{"Value":{"tagged_value":{"StrokeJoin":"Miter"},"exposed":false}},{"Value":{"tagged_value":{"F64":4.0},"exposed":false}},{"Value":{"tagged_value":{"PaintOrder":"StrokeAbove"},"exposed":false}},{"Value":{"tagged_value":{"VecF64":[]},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::StrokeNode"}},"visible":true,"skip_deduplication":false}],[8884703330021429739,{"inputs":[{"Node":{"node_id":16732345645494316637,"output_index":0,"lambda":false}},{"Node":{"node_id":532055960192543062,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[2155997486525176376,{"inputs":[{"Node":{"node_id":15595689026000825531,"output_index":0,"lambda":false}},{"Node":{"node_id":7639490284239357347,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[13700218159488557234,{"inputs":[{"Node":{"node_id":10181153433637856462,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"Fill":{"Gradient":{"stops":[[0.0,{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}],[0.4831746395427087,{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}],[0.49908141270537343,{"red":1.0,"green":1.0,"blue":1.0,"alpha":1.0}],[0.5160486374122156,{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}],[0.65708869278784,{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}],[0.6729954659505047,{"red":1.0,"green":1.0,"blue":1.0,"alpha":1.0}],[0.6899626906573468,{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}],[0.7291993977919214,{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}],[0.7440457194104085,{"red":1.0,"green":1.0,"blue":1.0,"alpha":1.0}],[0.7588920410288952,{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}],[1.0,{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}]],"gradient_type":"Radial","start":[0.5008896367526079,0.4999999999999998],"end":[1.0,0.5],"transform":[-1889.35072132725,6.199774420689026e-14,-1.0738324292042565e-13,-506.25000000045327,2021.9872361261616,956.3750000002264]}}},"exposed":false}},{"Value":{"tagged_value":{"OptionalColor":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}},"exposed":false}},{"Value":{"tagged_value":{"Gradient":{"stops":[[0.0,{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}],[0.4831746395427087,{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}],[0.49908141270537343,{"red":1.0,"green":1.0,"blue":1.0,"alpha":1.0}],[0.5160486374122156,{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}],[0.65708869278784,{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}],[0.6729954659505047,{"red":1.0,"green":1.0,"blue":1.0,"alpha":1.0}],[0.6899626906573468,{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}],[0.7291993977919214,{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}],[0.7440457194104085,{"red":1.0,"green":1.0,"blue":1.0,"alpha":1.0}],[0.7588920410288952,{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}],[1.0,{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}]],"gradient_type":"Radial","start":[0.5008896367526079,0.4999999999999998],"end":[1.0,0.5],"transform":[-1889.35072132725,6.199774420689026e-14,-1.0738324292042565e-13,-506.25000000045327,2021.9872361261616,956.3750000002264]}},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::FillNode"}},"visible":true,"skip_deduplication":false}],[8863202447825570192,{"inputs":[{"Node":{"node_id":5017082804473894058,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"DVec2":[-299.38891648776223,-111.69072674057747]},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[1.0616145921394244,1.0616145921394244]},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[0.0,0.0]},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[0.5,0.5]},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":1}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":2}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":3}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":4}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":5}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::TransformNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[7156963182187517674,{"inputs":[{"Node":{"node_id":14752203606937854133,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"DVec2":[-261.2435565296996,-63.99999999999977]},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[1.0,1.0]},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[0.0,0.0]},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[0.5,0.5]},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":1}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":2}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":3}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":4}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":5}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::TransformNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[322234583139821148,{"inputs":[{"Node":{"node_id":6589978257209505606,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"DVec2":[-261.2435565297001,-63.99999999999994]},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[1.0,1.0]},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[0.0,0.0]},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[0.5,0.5]},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":1}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":2}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":3}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":4}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":5}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::TransformNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[11990662272042254522,{"inputs":[{"Node":{"node_id":1147521068928676110,"output_index":0,"lambda":false}},{"Node":{"node_id":15167880819976070791,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[14633096010607565334,{"inputs":[{"Node":{"node_id":18046677540207938977,"output_index":0,"lambda":false}},{"Node":{"node_id":12370676490908282512,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[3227544593834141716,{"inputs":[{"Node":{"node_id":8256712316698018135,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"DVec2":[-298.5640646053871,-113.9999999999974]},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[0.9999999999999996,0.9999999999999996]},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[0.0,0.0]},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[0.5,0.5]},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":1}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":2}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":3}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":4}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":5}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::TransformNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[2183401450260403525,{"inputs":[{"Node":{"node_id":16852951849051795674,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"DVec2":[-261.2435565297001,-64.0]},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[1.0,1.0]},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[0.0,0.0]},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[0.5,0.5]},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":1}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":2}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":3}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":4}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":5}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::TransformNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[11429712783984224234,{"inputs":[{"Value":{"tagged_value":{"GraphicGroup":{"instance":[],"transform":[],"alpha_blending":[],"source_node_id":[]}},"exposed":true}},{"Node":{"node_id":12302362769310895852,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[9392462024456293097,{"inputs":[{"Value":{"tagged_value":{"VectorData":{"instance":[{"style":{"stroke":{"color":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0},"weight":0.0,"dash_lengths":[],"dash_offset":0.0,"cap":"Butt","join":"Miter","join_miter_limit":4.0,"align":"Center","transform":[1.0,0.0,0.0,1.0,0.0,0.0],"non_scaling":false,"paint_order":"StrokeAbove"},"fill":"None"},"colinear_manipulators":[],"point_domain":{"id":[],"position":[]},"segment_domain":{"id":[],"start_point":[],"end_point":[],"handles":[],"stroke":[]},"region_domain":{"id":[],"segment_range":[],"fill":[]},"upstream_graphic_group":null}],"transform":[[1.0,0.0,0.0,1.0,0.0,0.0]],"alpha_blending":[{"blend_mode":"Normal","opacity":1.0,"fill":1.0,"clip":false}],"source_node_id":[null]}},"exposed":true}},{"Value":{"tagged_value":{"VectorModification":{"points":{"add":[1,2,3,4,5,6],"remove":[],"delta":[[3,[783.7306695894646,560.0]],[1,[1156.9357503463468,509.9999999999987]],[6,[1044.9742261192855,480.0]],[2,[877.0319397786863,584.9999999999998]],[4,[615.7883832488646,605.0000000000001]],[5,[597.1281292110198,599.9999999999999]]]},"segments":{"add":[1,2,3,4,5,6],"remove":[],"start_point":[[2,2],[6,6],[1,1],[4,4],[5,5],[3,3]],"end_point":[[5,6],[1,2],[3,4],[2,3],[6,1],[4,5]],"handle_primary":[[2,[0.0,0.0]],[6,[0.0,0.0]],[1,[0.0,0.0]],[3,null],[5,[447.84609690826574,-119.99999999999989]],[4,null]],"handle_end":[[6,[0.0,0.0]],[3,null],[5,null],[4,null],[1,[0.0,0.0]],[2,null]],"stroke":[[2,0],[1,0],[5,0],[6,0],[3,0],[4,0]]},"regions":{"add":[0],"remove":[],"segment_range":[[0,{"start":1,"end":6}]],"fill":[[0,0]]},"add_g1_continuous":[],"remove_g1_continuous":[]}},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::vector_data::modification::VectorModification","alias":null}},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::vector_data::modification::PathModifyNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[12331680982485935376,{"inputs":[{"Node":{"node_id":2183401450260403525,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"Fill":{"Gradient":{"stops":[[0.0,{"red":0.5882353,"green":0.627451,"blue":0.39607844,"alpha":0.6313726}],[1.0,{"red":0.5882353,"green":0.627451,"blue":0.39607844,"alpha":0.0}]],"gradient_type":"Linear","start":[0.7293479177394283,-0.000903965337796908],"end":[0.7877909957441462,0.5587258938108439],"transform":[508.0879347267641,0.0,0.0,198.0243662458641,767.745306197191,484.2026674087032]}}},"exposed":false}},{"Value":{"tagged_value":{"OptionalColor":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}},"exposed":false}},{"Value":{"tagged_value":{"Gradient":{"stops":[[0.0,{"red":0.5882353,"green":0.627451,"blue":0.39607844,"alpha":0.6313726}],[1.0,{"red":0.5882353,"green":0.627451,"blue":0.39607844,"alpha":0.0}]],"gradient_type":"Linear","start":[0.7293479177394283,-0.000903965337796908],"end":[0.7877909957441462,0.5587258938108439],"transform":[508.0879347267641,0.0,0.0,198.0243662458641,767.745306197191,484.2026674087032]}},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::FillNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]},"network_metadata":{"persistent_metadata":{"node_metadata":[[2088390810384907709,{"persistent_metadata":{"reference":"Merge","display_name":"","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Absolute":[-22,72]}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[3014633976566537110,{"persistent_metadata":{"reference":"Merge","display_name":"Boolean Cut","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":["Out"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":0}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[5434119356821575534,{"persistent_metadata":{"reference":"Merge","display_name":"","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":0}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[4105329493214975815,{"persistent_metadata":{"reference":"Transform","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"unit":" px","input_name":"Translation","x":"X","y":"Y"},"widget_override":"vec2"},{"input_data":{"input_name":"Rotation"},"widget_override":"transform_rotation"},{"input_data":{"x":"W","y":"H","input_name":"Scale","unit":"x"},"widget_override":"vec2"},{"input_data":{"input_name":"Skew"},"widget_override":"hidden"},{"input_data":{"input_name":"Pivot"},"widget_override":"hidden"}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"Transform","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[18046677540207938977,{"persistent_metadata":{"reference":"Merge","display_name":"","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":0}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[17433098630591807963,{"persistent_metadata":{"reference":"Fill","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Fill"},"widget_override":null},{"input_data":{"input_name":"Backup Color"},"widget_override":null},{"input_data":{"input_name":"Backup Gradient"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[12331680982485935376,{"persistent_metadata":{"reference":"Fill","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Fill"},"widget_override":null},{"input_data":{"input_name":"Backup Color"},"widget_override":null},{"input_data":{"input_name":"Backup Gradient"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[12852312236973354891,{"persistent_metadata":{"reference":"Merge","display_name":"","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":0}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[9771562518763748677,{"persistent_metadata":{"reference":"Merge","display_name":"Plant (Upper Left)","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":39}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[11479492521093639512,{"persistent_metadata":{"reference":"Blend Mode","display_name":"","input_properties":[{"input_data":{"input_name":"Value"},"widget_override":null},{"input_data":{"input_name":"Blend Mode"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[11547499603328872398,{"persistent_metadata":{"reference":"Transform","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"y":"Y","input_name":"Translation","unit":" px","x":"X"},"widget_override":"vec2"},{"input_data":{"input_name":"Rotation"},"widget_override":"transform_rotation"},{"input_data":{"x":"W","input_name":"Scale","unit":"x","y":"H"},"widget_override":"vec2"},{"input_data":{"input_name":"Skew"},"widget_override":"hidden"},{"input_data":{"input_name":"Pivot"},"widget_override":"hidden"}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"Transform","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[10849502918952703647,{"persistent_metadata":{"reference":"Merge","display_name":"","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":0}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[4741515246389989284,{"persistent_metadata":{"reference":"Transform","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"y":"Y","input_name":"Translation","x":"X","unit":" px"},"widget_override":"vec2"},{"input_data":{"input_name":"Rotation"},"widget_override":"transform_rotation"},{"input_data":{"x":"W","y":"H","input_name":"Scale","unit":"x"},"widget_override":"vec2"},{"input_data":{"input_name":"Skew"},"widget_override":"hidden"},{"input_data":{"input_name":"Pivot"},"widget_override":"hidden"}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"Transform","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[3970872207068447290,{"persistent_metadata":{"reference":"Transform","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"y":"Y","unit":" px","x":"X","input_name":"Translation"},"widget_override":"vec2"},{"input_data":{"input_name":"Rotation"},"widget_override":"transform_rotation"},{"input_data":{"y":"H","x":"W","unit":"x","input_name":"Scale"},"widget_override":"vec2"},{"input_data":{"input_name":"Skew"},"widget_override":"hidden"},{"input_data":{"input_name":"Pivot"},"widget_override":"hidden"}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"Transform","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[3927358878935116440,{"persistent_metadata":{"reference":"Path","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Modification"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"Path Modify","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[9695624216919732577,{"persistent_metadata":{"reference":"Stroke","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Color"},"widget_override":null},{"input_data":{"input_name":"Weight"},"widget_override":null},{"input_data":{"input_name":"Dash Lengths"},"widget_override":null},{"input_data":{"input_name":"Dash Offset"},"widget_override":null},{"input_data":{"input_name":"Line Cap"},"widget_override":null},{"input_data":{"input_name":"Line Join"},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{"input_name":"Miter Limit"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[4924169570021915606,{"persistent_metadata":{"reference":"Merge","display_name":"Sphere","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":9}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[14805036488257720752,{"persistent_metadata":{"reference":"Path","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Modification"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-43,6]}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"Path Modify","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[15300421479077882117,{"persistent_metadata":{"reference":"Fill","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Fill"},"widget_override":null},{"input_data":{"input_name":"Backup Color"},"widget_override":null},{"input_data":{"input_name":"Backup Gradient"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[16416441286881083283,{"persistent_metadata":{"reference":"Path","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Modification"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"Path Modify","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[2921219300441868542,{"persistent_metadata":{"reference":"Fill","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Fill"},"widget_override":null},{"input_data":{"input_name":"Backup Color"},"widget_override":null},{"input_data":{"input_name":"Backup Gradient"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[16732345645494316637,{"persistent_metadata":{"reference":"Merge","display_name":"","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":0}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[15167880819976070791,{"persistent_metadata":{"reference":"Opacity","display_name":"","input_properties":[{"input_data":{"input_name":"Value"},"widget_override":null},{"input_data":{"input_name":"Factor"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[4134257789770357215,{"persistent_metadata":{"reference":"Transform","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Translation","x":"X","unit":" px","y":"Y"},"widget_override":"vec2"},{"input_data":{"input_name":"Rotation"},"widget_override":"transform_rotation"},{"input_data":{"x":"W","y":"H","unit":"x","input_name":"Scale"},"widget_override":"vec2"},{"input_data":{"input_name":"Skew"},"widget_override":"hidden"},{"input_data":{"input_name":"Pivot"},"widget_override":"hidden"}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"Transform","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[16510804133693080967,{"persistent_metadata":{"reference":"Transform","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Translation","x":"X","y":"Y","unit":" px"},"widget_override":"vec2"},{"input_data":{"input_name":"Rotation"},"widget_override":"transform_rotation"},{"input_data":{"input_name":"Scale","unit":"x","x":"W","y":"H"},"widget_override":"vec2"},{"input_data":{"input_name":"Skew"},"widget_override":"hidden"},{"input_data":{"input_name":"Pivot"},"widget_override":"hidden"}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"Transform","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[14330881008352607546,{"persistent_metadata":{"reference":"Fill","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Fill"},"widget_override":null},{"input_data":{"input_name":"Backup Color"},"widget_override":null},{"input_data":{"input_name":"Backup Gradient"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[3021739385836969518,{"persistent_metadata":{"reference":"Merge","display_name":"","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":0}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[5017082804473894058,{"persistent_metadata":{"reference":"Merge","display_name":"","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Absolute":[-22,60]}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[12683405703338263457,{"persistent_metadata":{"reference":"Merge","display_name":"","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":0}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[5317925967883407701,{"persistent_metadata":{"reference":"Transform","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"y":"Y","input_name":"Translation","unit":" px","x":"X"},"widget_override":"vec2"},{"input_data":{"input_name":"Rotation"},"widget_override":"transform_rotation"},{"input_data":{"y":"H","x":"W","unit":"x","input_name":"Scale"},"widget_override":"vec2"},{"input_data":{"input_name":"Skew"},"widget_override":"hidden"},{"input_data":{"input_name":"Pivot"},"widget_override":"hidden"}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"Transform","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[9278774434958175105,{"persistent_metadata":{"reference":"Transform","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Translation","y":"Y","unit":" px","x":"X"},"widget_override":"vec2"},{"input_data":{"input_name":"Rotation"},"widget_override":"transform_rotation"},{"input_data":{"unit":"x","input_name":"Scale","y":"H","x":"W"},"widget_override":"vec2"},{"input_data":{"input_name":"Skew"},"widget_override":"hidden"},{"input_data":{"input_name":"Pivot"},"widget_override":"hidden"}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"Transform","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[8181290118694677328,{"persistent_metadata":{"reference":"Merge","display_name":"","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":0}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[8863202447825570192,{"persistent_metadata":{"reference":"Transform","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"unit":" px","input_name":"Translation","x":"X","y":"Y"},"widget_override":"vec2"},{"input_data":{"input_name":"Rotation"},"widget_override":"transform_rotation"},{"input_data":{"y":"H","unit":"x","input_name":"Scale","x":"W"},"widget_override":"vec2"},{"input_data":{"input_name":"Skew"},"widget_override":"hidden"},{"input_data":{"input_name":"Pivot"},"widget_override":"hidden"}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"Transform","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[3122972215852775755,{"persistent_metadata":{"reference":"Transform","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Translation","y":"Y","x":"X","unit":" px"},"widget_override":"vec2"},{"input_data":{"input_name":"Rotation"},"widget_override":"transform_rotation"},{"input_data":{"unit":"x","input_name":"Scale","x":"W","y":"H"},"widget_override":"vec2"},{"input_data":{"input_name":"Skew"},"widget_override":"hidden"},{"input_data":{"input_name":"Pivot"},"widget_override":"hidden"}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"Transform","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[15216519480392295991,{"persistent_metadata":{"reference":"Fill","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Fill"},"widget_override":null},{"input_data":{"input_name":"Backup Color"},"widget_override":null},{"input_data":{"input_name":"Backup Gradient"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[8028812053913481975,{"persistent_metadata":{"reference":"Merge","display_name":"","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":0}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[7639490284239357347,{"persistent_metadata":{"reference":"Stroke","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Color"},"widget_override":null},{"input_data":{"input_name":"Weight"},"widget_override":null},{"input_data":{"input_name":"Dash Lengths"},"widget_override":null},{"input_data":{"input_name":"Dash Offset"},"widget_override":null},{"input_data":{"input_name":"Line Cap"},"widget_override":null},{"input_data":{"input_name":"Line Join"},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{"input_name":"Miter Limit"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[7799679303995308634,{"persistent_metadata":{"reference":"Transform","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"x":"X","y":"Y","input_name":"Translation","unit":" px"},"widget_override":"vec2"},{"input_data":{"input_name":"Rotation"},"widget_override":"transform_rotation"},{"input_data":{"y":"H","unit":"x","input_name":"Scale","x":"W"},"widget_override":"vec2"},{"input_data":{"input_name":"Skew"},"widget_override":"hidden"},{"input_data":{"input_name":"Pivot"},"widget_override":"hidden"}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"Transform","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[8884703330021429739,{"persistent_metadata":{"reference":"Merge","display_name":"","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":0}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[3680957604830907751,{"persistent_metadata":{"reference":"Path","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Modification"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"Path Modify","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[16261620049358949344,{"persistent_metadata":{"reference":"Stroke","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Color"},"widget_override":null},{"input_data":{"input_name":"Weight"},"widget_override":null},{"input_data":{"input_name":"Dash Lengths"},"widget_override":null},{"input_data":{"input_name":"Dash Offset"},"widget_override":null},{"input_data":{"input_name":"Line Cap"},"widget_override":null},{"input_data":{"input_name":"Line Join"},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{"input_name":"Miter Limit"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[15347111149235590492,{"persistent_metadata":{"reference":"Transform","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"unit":" px","input_name":"Translation","x":"X","y":"Y"},"widget_override":"vec2"},{"input_data":{"input_name":"Rotation"},"widget_override":"transform_rotation"},{"input_data":{"y":"H","input_name":"Scale","unit":"x","x":"W"},"widget_override":"vec2"},{"input_data":{"input_name":"Skew"},"widget_override":"hidden"},{"input_data":{"input_name":"Pivot"},"widget_override":"hidden"}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"Transform","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[7952384394377946257,{"persistent_metadata":{"reference":"Fill","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Fill"},"widget_override":null},{"input_data":{"input_name":"Backup Color"},"widget_override":null},{"input_data":{"input_name":"Backup Gradient"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[5261200785298607501,{"persistent_metadata":{"reference":"Blend Mode","display_name":"","input_properties":[{"input_data":{"input_name":"Value"},"widget_override":null},{"input_data":{"input_name":"Blend Mode"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[18185020559178852986,{"persistent_metadata":{"reference":"Merge","display_name":"","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":0}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[17881728913029763313,{"persistent_metadata":{"reference":"Transform","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Translation","x":"X","y":"Y","unit":" px"},"widget_override":"vec2"},{"input_data":{"input_name":"Rotation"},"widget_override":"transform_rotation"},{"input_data":{"y":"H","input_name":"Scale","unit":"x","x":"W"},"widget_override":"vec2"},{"input_data":{"input_name":"Skew"},"widget_override":"hidden"},{"input_data":{"input_name":"Pivot"},"widget_override":"hidden"}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"Transform","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[16847360882244487081,{"persistent_metadata":{"reference":"Fill","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Fill"},"widget_override":null},{"input_data":{"input_name":"Backup Color"},"widget_override":null},{"input_data":{"input_name":"Backup Gradient"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[9392462024456293097,{"persistent_metadata":{"reference":"Path","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Modification"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"Path Modify","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[15898396405528650339,{"persistent_metadata":{"reference":"Transform","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"x":"X","y":"Y","input_name":"Translation","unit":" px"},"widget_override":"vec2"},{"input_data":{"input_name":"Rotation"},"widget_override":"transform_rotation"},{"input_data":{"unit":"x","input_name":"Scale","x":"W","y":"H"},"widget_override":"vec2"},{"input_data":{"input_name":"Skew"},"widget_override":"hidden"},{"input_data":{"input_name":"Pivot"},"widget_override":"hidden"}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"Transform","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[17250040304106119844,{"persistent_metadata":{"reference":"Transform","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"unit":" px","x":"X","y":"Y","input_name":"Translation"},"widget_override":"vec2"},{"input_data":{"input_name":"Rotation"},"widget_override":"transform_rotation"},{"input_data":{"unit":"x","input_name":"Scale","x":"W","y":"H"},"widget_override":"vec2"},{"input_data":{"input_name":"Skew"},"widget_override":"hidden"},{"input_data":{"input_name":"Pivot"},"widget_override":"hidden"}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-50,39]}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"Transform","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[585709295659496998,{"persistent_metadata":{"reference":"Merge","display_name":"","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":0}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[2209276411833629008,{"persistent_metadata":{"reference":"Path","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Modification"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"Path Modify","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[10564228200140683112,{"persistent_metadata":{"reference":"Transform","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"unit":" px","input_name":"Translation","y":"Y","x":"X"},"widget_override":"vec2"},{"input_data":{"input_name":"Rotation"},"widget_override":"transform_rotation"},{"input_data":{"y":"H","input_name":"Scale","x":"W","unit":"x"},"widget_override":"vec2"},{"input_data":{"input_name":"Skew"},"widget_override":"hidden"},{"input_data":{"input_name":"Pivot"},"widget_override":"hidden"}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"Transform","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[7861616450605235840,{"persistent_metadata":{"reference":"Path","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Modification"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"Path Modify","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[12537712543904859919,{"persistent_metadata":{"reference":"Merge","display_name":"","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":0}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[10779665858841986661,{"persistent_metadata":{"reference":"Path","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Modification"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"Path Modify","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[15709488322180832347,{"persistent_metadata":{"reference":"Artboard","display_name":"","input_properties":[{"input_data":{"input_name":"Artboards"},"widget_override":null},{"input_data":{"input_name":"Contents"},"widget_override":"hidden"},{"input_data":{"x":"X","unit":" px","y":"Y","input_name":"Location"},"widget_override":"vec2"},{"input_data":{"input_name":"Dimensions","unit":" px","x":"W","y":"H"},"widget_override":"vec2"},{"input_data":{"input_name":"Background"},"widget_override":"artboard_background"},{"input_data":{"input_name":"Clip"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Absolute":[-5,0]}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-2,-3]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"To Artboard","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-10,-3]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Append Artboards","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[6,-4]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[8166796652234334001,{"persistent_metadata":{"reference":"Fill","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Fill"},"widget_override":null},{"input_data":{"input_name":"Backup Color"},"widget_override":null},{"input_data":{"input_name":"Backup Gradient"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[13817976820605296433,{"persistent_metadata":{"reference":"Transform","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"x":"X","y":"Y","input_name":"Translation","unit":" px"},"widget_override":"vec2"},{"input_data":{"input_name":"Rotation"},"widget_override":"transform_rotation"},{"input_data":{"x":"W","input_name":"Scale","unit":"x","y":"H"},"widget_override":"vec2"},{"input_data":{"input_name":"Skew"},"widget_override":"hidden"},{"input_data":{"input_name":"Pivot"},"widget_override":"hidden"}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"Transform","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[14791465604033956302,{"persistent_metadata":{"reference":"Opacity","display_name":"","input_properties":[{"input_data":{"input_name":"Value"},"widget_override":null},{"input_data":{"input_name":"Factor"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[14842592386831797498,{"persistent_metadata":{"reference":"Merge","display_name":"","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":0}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[7910743362843097140,{"persistent_metadata":{"reference":"Path","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Modification"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-43,30]}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"Path Modify","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[2189393878093040029,{"persistent_metadata":{"reference":"Merge","display_name":"","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":0}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[8612613134760093452,{"persistent_metadata":{"reference":"Path","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Modification"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"Path Modify","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[9663740787529879916,{"persistent_metadata":{"reference":"Merge","display_name":"","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":0}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[11579925754926059876,{"persistent_metadata":{"reference":"Transform","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Translation","unit":" px","x":"X","y":"Y"},"widget_override":"vec2"},{"input_data":{"input_name":"Rotation"},"widget_override":"transform_rotation"},{"input_data":{"y":"H","input_name":"Scale","unit":"x","x":"W"},"widget_override":"vec2"},{"input_data":{"input_name":"Skew"},"widget_override":"hidden"},{"input_data":{"input_name":"Pivot"},"widget_override":"hidden"}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"Transform","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[8891726805381758817,{"persistent_metadata":{"reference":"Transform","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"y":"Y","unit":" px","x":"X","input_name":"Translation"},"widget_override":"vec2"},{"input_data":{"input_name":"Rotation"},"widget_override":"transform_rotation"},{"input_data":{"input_name":"Scale","unit":"x","x":"W","y":"H"},"widget_override":"vec2"},{"input_data":{"input_name":"Skew"},"widget_override":"hidden"},{"input_data":{"input_name":"Pivot"},"widget_override":"hidden"}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"Transform","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[7067047867039575315,{"persistent_metadata":{"reference":"Transform","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Translation","x":"X","y":"Y","unit":" px"},"widget_override":"vec2"},{"input_data":{"input_name":"Rotation"},"widget_override":"transform_rotation"},{"input_data":{"input_name":"Scale","x":"W","y":"H","unit":"x"},"widget_override":"vec2"},{"input_data":{"input_name":"Skew"},"widget_override":"hidden"},{"input_data":{"input_name":"Pivot"},"widget_override":"hidden"}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"Transform","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[10989897386232385465,{"persistent_metadata":{"reference":"Merge","display_name":"","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":0}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[11595529463602678384,{"persistent_metadata":{"reference":"Transform","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"y":"Y","x":"X","unit":" px","input_name":"Translation"},"widget_override":"vec2"},{"input_data":{"input_name":"Rotation"},"widget_override":"transform_rotation"},{"input_data":{"input_name":"Scale","x":"W","y":"H","unit":"x"},"widget_override":"vec2"},{"input_data":{"input_name":"Skew"},"widget_override":"hidden"},{"input_data":{"input_name":"Pivot"},"widget_override":"hidden"}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"Transform","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[764189229787475993,{"persistent_metadata":{"reference":"Transform","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"y":"Y","unit":" px","input_name":"Translation","x":"X"},"widget_override":"vec2"},{"input_data":{"input_name":"Rotation"},"widget_override":"transform_rotation"},{"input_data":{"y":"H","unit":"x","x":"W","input_name":"Scale"},"widget_override":"vec2"},{"input_data":{"input_name":"Skew"},"widget_override":"hidden"},{"input_data":{"input_name":"Pivot"},"widget_override":"hidden"}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"Transform","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[12875121980058869686,{"persistent_metadata":{"reference":"Transform","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"y":"Y","unit":" px","x":"X","input_name":"Translation"},"widget_override":"vec2"},{"input_data":{"input_name":"Rotation"},"widget_override":"transform_rotation"},{"input_data":{"x":"W","unit":"x","y":"H","input_name":"Scale"},"widget_override":"vec2"},{"input_data":{"input_name":"Skew"},"widget_override":"hidden"},{"input_data":{"input_name":"Pivot"},"widget_override":"hidden"}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"Transform","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[13837327017498431546,{"persistent_metadata":{"reference":"Path","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Modification"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"Path Modify","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[7005645574203740491,{"persistent_metadata":{"reference":"Transform","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Translation","y":"Y","unit":" px","x":"X"},"widget_override":"vec2"},{"input_data":{"input_name":"Rotation"},"widget_override":"transform_rotation"},{"input_data":{"x":"W","input_name":"Scale","unit":"x","y":"H"},"widget_override":"vec2"},{"input_data":{"input_name":"Skew"},"widget_override":"hidden"},{"input_data":{"input_name":"Pivot"},"widget_override":"hidden"}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"Transform","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[5448146793323825465,{"persistent_metadata":{"reference":"Path","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Modification"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"Path Modify","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[3670594928372882885,{"persistent_metadata":{"reference":"Path","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Modification"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"Path Modify","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[7948029953091985757,{"persistent_metadata":{"reference":"Path","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Modification"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"Path Modify","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[4191887059541031673,{"persistent_metadata":{"reference":"Fill","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Fill"},"widget_override":null},{"input_data":{"input_name":"Backup Color"},"widget_override":null},{"input_data":{"input_name":"Backup Gradient"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[2640491057355360805,{"persistent_metadata":{"reference":"Path","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Modification"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"Path Modify","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[15517065353723874205,{"persistent_metadata":{"reference":"Merge","display_name":"","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":0}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[17059035448296015006,{"persistent_metadata":{"reference":"Path","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Modification"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"Path Modify","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[4187349759243468746,{"persistent_metadata":{"reference":"Path","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Modification"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"Path Modify","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[9409313765472227540,{"persistent_metadata":{"reference":"Merge","display_name":"","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":0}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[7171713123860587892,{"persistent_metadata":{"reference":"Merge","display_name":"","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":0}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[11860177410232537211,{"persistent_metadata":{"reference":"Boolean Operation","display_name":"","input_properties":[{"input_data":{"input_name":"Group of Paths"},"widget_override":null},{"input_data":{"input_name":"Operation"},"widget_override":null}],"output_names":["Vector"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"Boolean Operation","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Boundless Footprint","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[14,0]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"Freeze Real Time","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[456239140723765386,{"persistent_metadata":{"reference":"Path","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Modification"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"Path Modify","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[4398598693761352299,{"persistent_metadata":{"reference":"Path","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Modification"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"Path Modify","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[4740496570730418920,{"persistent_metadata":{"reference":"Path","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Modification"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-43,24]}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"Path Modify","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[16793555741218543212,{"persistent_metadata":{"reference":"Path","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Modification"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"Path Modify","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[11634445349252640936,{"persistent_metadata":{"reference":"Transform","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"y":"Y","input_name":"Translation","unit":" px","x":"X"},"widget_override":"vec2"},{"input_data":{"input_name":"Rotation"},"widget_override":"transform_rotation"},{"input_data":{"unit":"x","y":"H","x":"W","input_name":"Scale"},"widget_override":"vec2"},{"input_data":{"input_name":"Skew"},"widget_override":"hidden"},{"input_data":{"input_name":"Pivot"},"widget_override":"hidden"}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"Transform","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[9981992739451603109,{"persistent_metadata":{"reference":"Fill","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Fill"},"widget_override":null},{"input_data":{"input_name":"Backup Color"},"widget_override":null},{"input_data":{"input_name":"Backup Gradient"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[11990662272042254522,{"persistent_metadata":{"reference":"Merge","display_name":"","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":0}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[10507084483235320484,{"persistent_metadata":{"reference":"Merge","display_name":"","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":0}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[16852951849051795674,{"persistent_metadata":{"reference":"Path","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Modification"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"Path Modify","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[2881239077602364410,{"persistent_metadata":{"reference":"Fill","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Fill"},"widget_override":null},{"input_data":{"input_name":"Backup Color"},"widget_override":null},{"input_data":{"input_name":"Backup Gradient"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[5326013268137833446,{"persistent_metadata":{"reference":"Fill","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Fill"},"widget_override":null},{"input_data":{"input_name":"Backup Color"},"widget_override":null},{"input_data":{"input_name":"Backup Gradient"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[8463468388280418154,{"persistent_metadata":{"reference":"Opacity","display_name":"","input_properties":[{"input_data":{"input_name":"Value"},"widget_override":null},{"input_data":{"input_name":"Factor"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[7030585744407664630,{"persistent_metadata":{"reference":"Transform","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Translation","x":"X","y":"Y","unit":" px"},"widget_override":"vec2"},{"input_data":{"input_name":"Rotation"},"widget_override":"transform_rotation"},{"input_data":{"x":"W","input_name":"Scale","y":"H","unit":"x"},"widget_override":"vec2"},{"input_data":{"input_name":"Skew"},"widget_override":"hidden"},{"input_data":{"input_name":"Pivot"},"widget_override":"hidden"}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"Transform","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[4046495708656778502,{"persistent_metadata":{"reference":"Path","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Modification"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"Path Modify","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[9210109719406330381,{"persistent_metadata":{"reference":"Transform","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Translation","unit":" px","x":"X","y":"Y"},"widget_override":"vec2"},{"input_data":{"input_name":"Rotation"},"widget_override":"transform_rotation"},{"input_data":{"x":"W","y":"H","unit":"x","input_name":"Scale"},"widget_override":"vec2"},{"input_data":{"input_name":"Skew"},"widget_override":"hidden"},{"input_data":{"input_name":"Pivot"},"widget_override":"hidden"}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"Transform","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[13852123721901366011,{"persistent_metadata":{"reference":"Transform","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"x":"X","y":"Y","input_name":"Translation","unit":" px"},"widget_override":"vec2"},{"input_data":{"input_name":"Rotation"},"widget_override":"transform_rotation"},{"input_data":{"y":"H","input_name":"Scale","unit":"x","x":"W"},"widget_override":"vec2"},{"input_data":{"input_name":"Skew"},"widget_override":"hidden"},{"input_data":{"input_name":"Pivot"},"widget_override":"hidden"}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"Transform","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[8242413775403456296,{"persistent_metadata":{"reference":"Merge","display_name":"","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":0}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[7884283658260267478,{"persistent_metadata":{"reference":"Path","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Modification"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-43,15]}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"Path Modify","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[12931264630175648107,{"persistent_metadata":{"reference":"Path","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Modification"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"Path Modify","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[7671691070850213967,{"persistent_metadata":{"reference":"Fill","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Fill"},"widget_override":null},{"input_data":{"input_name":"Backup Color"},"widget_override":null},{"input_data":{"input_name":"Backup Gradient"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[16069762220015310717,{"persistent_metadata":{"reference":"Merge","display_name":"Fountain Water Ripples","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":87}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[11506204916439878896,{"persistent_metadata":{"reference":"Transform","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"unit":" px","x":"X","y":"Y","input_name":"Translation"},"widget_override":"vec2"},{"input_data":{"input_name":"Rotation"},"widget_override":"transform_rotation"},{"input_data":{"x":"W","input_name":"Scale","y":"H","unit":"x"},"widget_override":"vec2"},{"input_data":{"input_name":"Skew"},"widget_override":"hidden"},{"input_data":{"input_name":"Pivot"},"widget_override":"hidden"}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"Transform","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[1396768435017101055,{"persistent_metadata":{"reference":"Fill","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Fill"},"widget_override":null},{"input_data":{"input_name":"Backup Color"},"widget_override":null},{"input_data":{"input_name":"Backup Gradient"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[6556170892691431702,{"persistent_metadata":{"reference":"Merge","display_name":"","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":0}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[14234384001010789008,{"persistent_metadata":{"reference":"Merge","display_name":"Plant (Lower Left)","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":9}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[3679103217373457623,{"persistent_metadata":{"reference":"Stroke","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Color"},"widget_override":null},{"input_data":{"input_name":"Weight"},"widget_override":null},{"input_data":{"input_name":"Dash Lengths"},"widget_override":null},{"input_data":{"input_name":"Dash Offset"},"widget_override":null},{"input_data":{"input_name":"Line Cap"},"widget_override":null},{"input_data":{"input_name":"Line Join"},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{"input_name":"Miter Limit"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[2292399603649738346,{"persistent_metadata":{"reference":"Fill","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Fill"},"widget_override":null},{"input_data":{"input_name":"Backup Color"},"widget_override":null},{"input_data":{"input_name":"Backup Gradient"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[57904581517036791,{"persistent_metadata":{"reference":"Merge","display_name":"","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":0}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[9724746185253267560,{"persistent_metadata":{"reference":"Path","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Modification"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-43,36]}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"Path Modify","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[938033825024582130,{"persistent_metadata":{"reference":"Fill","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Fill"},"widget_override":null},{"input_data":{"input_name":"Backup Color"},"widget_override":null},{"input_data":{"input_name":"Backup Gradient"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[1147521068928676110,{"persistent_metadata":{"reference":"Merge","display_name":"","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":0}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[18187802220803838247,{"persistent_metadata":{"reference":"Blend Mode","display_name":"","input_properties":[{"input_data":{"input_name":"Value"},"widget_override":null},{"input_data":{"input_name":"Blend Mode"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[13868917743026516656,{"persistent_metadata":{"reference":"Fill","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Fill"},"widget_override":null},{"input_data":{"input_name":"Backup Color"},"widget_override":null},{"input_data":{"input_name":"Backup Gradient"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[13287180494862716983,{"persistent_metadata":{"reference":"Path","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Modification"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-43,9]}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"Path Modify","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[9935922395919478146,{"persistent_metadata":{"reference":"Path","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Modification"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"Path Modify","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[2077983679740571162,{"persistent_metadata":{"reference":"Path","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Modification"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"Path Modify","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[3455270778005546310,{"persistent_metadata":{"reference":"Path","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Modification"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"Path Modify","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[2225749123534781340,{"persistent_metadata":{"reference":"Path","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Modification"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-43,12]}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"Path Modify","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[13442128106088307772,{"persistent_metadata":{"reference":"Merge","display_name":"","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":0}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[2900504420179573771,{"persistent_metadata":{"reference":"Merge","display_name":"","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":0}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[972153153989181918,{"persistent_metadata":{"reference":"Merge","display_name":"Sphere Shadow","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":6}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[14341957170885045113,{"persistent_metadata":{"reference":"Merge","display_name":"","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":0}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[2062662104423219162,{"persistent_metadata":{"reference":"Transform","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Translation","unit":" px","x":"X","y":"Y"},"widget_override":"vec2"},{"input_data":{"input_name":"Rotation"},"widget_override":"transform_rotation"},{"input_data":{"input_name":"Scale","unit":"x","y":"H","x":"W"},"widget_override":"vec2"},{"input_data":{"input_name":"Skew"},"widget_override":"hidden"},{"input_data":{"input_name":"Pivot"},"widget_override":"hidden"}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"Transform","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[4101813853952238986,{"persistent_metadata":{"reference":"Stroke","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Color"},"widget_override":null},{"input_data":{"input_name":"Weight"},"widget_override":null},{"input_data":{"input_name":"Dash Lengths"},"widget_override":null},{"input_data":{"input_name":"Dash Offset"},"widget_override":null},{"input_data":{"input_name":"Line Cap"},"widget_override":null},{"input_data":{"input_name":"Line Join"},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{"input_name":"Miter Limit"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[14255588039347536657,{"persistent_metadata":{"reference":"Merge","display_name":"","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Absolute":[-22,255]}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[12302362769310895852,{"persistent_metadata":{"reference":"Fill","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Fill"},"widget_override":null},{"input_data":{"input_name":"Backup Color"},"widget_override":null},{"input_data":{"input_name":"Backup Gradient"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[5346759588580719138,{"persistent_metadata":{"reference":"Merge","display_name":"","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":6}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[1658032775659237960,{"persistent_metadata":{"reference":"Transform","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"y":"Y","unit":" px","input_name":"Translation","x":"X"},"widget_override":"vec2"},{"input_data":{"input_name":"Rotation"},"widget_override":"transform_rotation"},{"input_data":{"unit":"x","y":"H","x":"W","input_name":"Scale"},"widget_override":"vec2"},{"input_data":{"input_name":"Skew"},"widget_override":"hidden"},{"input_data":{"input_name":"Pivot"},"widget_override":"hidden"}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"Transform","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[1108089904278882840,{"persistent_metadata":{"reference":"Fill","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Fill"},"widget_override":null},{"input_data":{"input_name":"Backup Color"},"widget_override":null},{"input_data":{"input_name":"Backup Gradient"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[13001069903842109798,{"persistent_metadata":{"reference":"Path","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Modification"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"Path Modify","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[3564067978712674849,{"persistent_metadata":{"reference":"Transform","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Translation","unit":" px","y":"Y","x":"X"},"widget_override":"vec2"},{"input_data":{"input_name":"Rotation"},"widget_override":"transform_rotation"},{"input_data":{"unit":"x","x":"W","input_name":"Scale","y":"H"},"widget_override":"vec2"},{"input_data":{"input_name":"Skew"},"widget_override":"hidden"},{"input_data":{"input_name":"Pivot"},"widget_override":"hidden"}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"Transform","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[3616319631707471648,{"persistent_metadata":{"reference":"Merge","display_name":"","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":0}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[194878846429432339,{"persistent_metadata":{"reference":"Path","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Modification"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"Path Modify","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[15914878146223026034,{"persistent_metadata":{"reference":"Transform","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Translation","x":"X","unit":" px","y":"Y"},"widget_override":"vec2"},{"input_data":{"input_name":"Rotation"},"widget_override":"transform_rotation"},{"input_data":{"input_name":"Scale","x":"W","unit":"x","y":"H"},"widget_override":"vec2"},{"input_data":{"input_name":"Skew"},"widget_override":"hidden"},{"input_data":{"input_name":"Pivot"},"widget_override":"hidden"}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"Transform","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[10431241258085047322,{"persistent_metadata":{"reference":"Path","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Modification"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"Path Modify","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[18128923159828618806,{"persistent_metadata":{"reference":"Fill","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Fill"},"widget_override":null},{"input_data":{"input_name":"Backup Color"},"widget_override":null},{"input_data":{"input_name":"Backup Gradient"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[4757672276235057645,{"persistent_metadata":{"reference":"Merge","display_name":"Plant (Right)","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":9}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[13207576193421440093,{"persistent_metadata":{"reference":"Fill","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Fill"},"widget_override":null},{"input_data":{"input_name":"Backup Color"},"widget_override":null},{"input_data":{"input_name":"Backup Gradient"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[9226731772122225003,{"persistent_metadata":{"reference":"Merge","display_name":"","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":0}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[17965270694495451178,{"persistent_metadata":{"reference":"Merge","display_name":"","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Absolute":[-22,96]}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[13531127678140037818,{"persistent_metadata":{"reference":"Fill","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Fill"},"widget_override":null},{"input_data":{"input_name":"Backup Color"},"widget_override":null},{"input_data":{"input_name":"Backup Gradient"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[7259756719760382667,{"persistent_metadata":{"reference":"Fill","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Fill"},"widget_override":null},{"input_data":{"input_name":"Backup Color"},"widget_override":null},{"input_data":{"input_name":"Backup Gradient"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[532055960192543062,{"persistent_metadata":{"reference":"Stroke","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Color"},"widget_override":null},{"input_data":{"input_name":"Weight"},"widget_override":null},{"input_data":{"input_name":"Dash Lengths"},"widget_override":null},{"input_data":{"input_name":"Dash Offset"},"widget_override":null},{"input_data":{"input_name":"Line Cap"},"widget_override":null},{"input_data":{"input_name":"Line Join"},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{"input_name":"Miter Limit"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[15134939288287905620,{"persistent_metadata":{"reference":"Transform","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"x":"X","unit":" px","input_name":"Translation","y":"Y"},"widget_override":"vec2"},{"input_data":{"input_name":"Rotation"},"widget_override":"transform_rotation"},{"input_data":{"x":"W","unit":"x","input_name":"Scale","y":"H"},"widget_override":"vec2"},{"input_data":{"input_name":"Skew"},"widget_override":"hidden"},{"input_data":{"input_name":"Pivot"},"widget_override":"hidden"}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"Transform","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[11221222899304956410,{"persistent_metadata":{"reference":"Transform","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"x":"X","y":"Y","unit":" px","input_name":"Translation"},"widget_override":"vec2"},{"input_data":{"input_name":"Rotation"},"widget_override":"transform_rotation"},{"input_data":{"input_name":"Scale","x":"W","y":"H","unit":"x"},"widget_override":"vec2"},{"input_data":{"input_name":"Skew"},"widget_override":"hidden"},{"input_data":{"input_name":"Pivot"},"widget_override":"hidden"}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"Transform","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[4968550668755026811,{"persistent_metadata":{"reference":"Merge","display_name":"","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":0}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[18371793711669837037,{"persistent_metadata":{"reference":"Transform","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"y":"Y","input_name":"Translation","x":"X","unit":" px"},"widget_override":"vec2"},{"input_data":{"input_name":"Rotation"},"widget_override":"transform_rotation"},{"input_data":{"y":"H","x":"W","unit":"x","input_name":"Scale"},"widget_override":"vec2"},{"input_data":{"input_name":"Skew"},"widget_override":"hidden"},{"input_data":{"input_name":"Pivot"},"widget_override":"hidden"}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"Transform","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[5891705401441266824,{"persistent_metadata":{"reference":"Fill","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Fill"},"widget_override":null},{"input_data":{"input_name":"Backup Color"},"widget_override":null},{"input_data":{"input_name":"Backup Gradient"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[15775513677915164685,{"persistent_metadata":{"reference":"Path","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Modification"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"Path Modify","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[958845362613832240,{"persistent_metadata":{"reference":"Path","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Modification"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"Path Modify","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[7637119583909417127,{"persistent_metadata":{"reference":"Stroke","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Color"},"widget_override":null},{"input_data":{"input_name":"Weight"},"widget_override":null},{"input_data":{"input_name":"Dash Lengths"},"widget_override":null},{"input_data":{"input_name":"Dash Offset"},"widget_override":null},{"input_data":{"input_name":"Line Cap"},"widget_override":null},{"input_data":{"input_name":"Line Join"},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{"input_name":"Miter Limit"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[6589978257209505606,{"persistent_metadata":{"reference":"Path","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Modification"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"Path Modify","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[12469956387875933942,{"persistent_metadata":{"reference":"Merge","display_name":"","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":0}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[11490835759023283071,{"persistent_metadata":{"reference":"Transform","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"unit":" px","x":"X","input_name":"Translation","y":"Y"},"widget_override":"vec2"},{"input_data":{"input_name":"Rotation"},"widget_override":"transform_rotation"},{"input_data":{"input_name":"Scale","y":"H","x":"W","unit":"x"},"widget_override":"vec2"},{"input_data":{"input_name":"Skew"},"widget_override":"hidden"},{"input_data":{"input_name":"Pivot"},"widget_override":"hidden"}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"Transform","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[2036609094647228373,{"persistent_metadata":{"reference":"Path","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Modification"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"Path Modify","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[10651614176902312108,{"persistent_metadata":{"reference":"Fill","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Fill"},"widget_override":null},{"input_data":{"input_name":"Backup Color"},"widget_override":null},{"input_data":{"input_name":"Backup Gradient"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[326112971739898070,{"persistent_metadata":{"reference":"Path","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Modification"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-43,21]}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"Path Modify","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[1229809699395562135,{"persistent_metadata":{"reference":"Transform","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"unit":" px","x":"X","y":"Y","input_name":"Translation"},"widget_override":"vec2"},{"input_data":{"input_name":"Rotation"},"widget_override":"transform_rotation"},{"input_data":{"x":"W","unit":"x","y":"H","input_name":"Scale"},"widget_override":"vec2"},{"input_data":{"input_name":"Skew"},"widget_override":"hidden"},{"input_data":{"input_name":"Pivot"},"widget_override":"hidden"}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"Transform","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[9993538712344947860,{"persistent_metadata":{"reference":"Fill","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Fill"},"widget_override":null},{"input_data":{"input_name":"Backup Color"},"widget_override":null},{"input_data":{"input_name":"Backup Gradient"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[18085100003956405261,{"persistent_metadata":{"reference":"Path","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Modification"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"Path Modify","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[16059265180575745658,{"persistent_metadata":{"reference":"Path","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Modification"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-43,33]}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"Path Modify","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[7156963182187517674,{"persistent_metadata":{"reference":"Transform","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"unit":" px","y":"Y","input_name":"Translation","x":"X"},"widget_override":"vec2"},{"input_data":{"input_name":"Rotation"},"widget_override":"transform_rotation"},{"input_data":{"input_name":"Scale","unit":"x","y":"H","x":"W"},"widget_override":"vec2"},{"input_data":{"input_name":"Skew"},"widget_override":"hidden"},{"input_data":{"input_name":"Pivot"},"widget_override":"hidden"}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"Transform","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[6142412830271644616,{"persistent_metadata":{"reference":"Path","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Modification"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-43,39]}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"Path Modify","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[13696921450692276893,{"persistent_metadata":{"reference":"Fill","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Fill"},"widget_override":null},{"input_data":{"input_name":"Backup Color"},"widget_override":null},{"input_data":{"input_name":"Backup Gradient"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[14102693648424950146,{"persistent_metadata":{"reference":"Merge","display_name":"","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":0}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[3227544593834141716,{"persistent_metadata":{"reference":"Transform","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Translation","unit":" px","x":"X","y":"Y"},"widget_override":"vec2"},{"input_data":{"input_name":"Rotation"},"widget_override":"transform_rotation"},{"input_data":{"x":"W","y":"H","input_name":"Scale","unit":"x"},"widget_override":"vec2"},{"input_data":{"input_name":"Skew"},"widget_override":"hidden"},{"input_data":{"input_name":"Pivot"},"widget_override":"hidden"}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"Transform","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[11236872744106223256,{"persistent_metadata":{"reference":"Transform","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"y":"Y","input_name":"Translation","unit":" px","x":"X"},"widget_override":"vec2"},{"input_data":{"input_name":"Rotation"},"widget_override":"transform_rotation"},{"input_data":{"input_name":"Scale","y":"H","unit":"x","x":"W"},"widget_override":"vec2"},{"input_data":{"input_name":"Skew"},"widget_override":"hidden"},{"input_data":{"input_name":"Pivot"},"widget_override":"hidden"}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-50,36]}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"Transform","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[322234583139821148,{"persistent_metadata":{"reference":"Transform","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Translation","y":"Y","x":"X","unit":" px"},"widget_override":"vec2"},{"input_data":{"input_name":"Rotation"},"widget_override":"transform_rotation"},{"input_data":{"unit":"x","x":"W","input_name":"Scale","y":"H"},"widget_override":"vec2"},{"input_data":{"input_name":"Skew"},"widget_override":"hidden"},{"input_data":{"input_name":"Pivot"},"widget_override":"hidden"}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"Transform","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[10742991645899166287,{"persistent_metadata":{"reference":"Transform","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"unit":" px","y":"Y","input_name":"Translation","x":"X"},"widget_override":"vec2"},{"input_data":{"input_name":"Rotation"},"widget_override":"transform_rotation"},{"input_data":{"input_name":"Scale","y":"H","x":"W","unit":"x"},"widget_override":"vec2"},{"input_data":{"input_name":"Skew"},"widget_override":"hidden"},{"input_data":{"input_name":"Pivot"},"widget_override":"hidden"}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"Transform","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[15166516760575860563,{"persistent_metadata":{"reference":"Transform","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Translation","x":"X","y":"Y","unit":" px"},"widget_override":"vec2"},{"input_data":{"input_name":"Rotation"},"widget_override":"transform_rotation"},{"input_data":{"unit":"x","y":"H","input_name":"Scale","x":"W"},"widget_override":"vec2"},{"input_data":{"input_name":"Skew"},"widget_override":"hidden"},{"input_data":{"input_name":"Pivot"},"widget_override":"hidden"}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"Transform","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[15595689026000825531,{"persistent_metadata":{"reference":"Merge","display_name":"","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":0}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[12930243402848966353,{"persistent_metadata":{"reference":"Transform","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"y":"Y","unit":" px","input_name":"Translation","x":"X"},"widget_override":"vec2"},{"input_data":{"input_name":"Rotation"},"widget_override":"transform_rotation"},{"input_data":{"unit":"x","x":"W","y":"H","input_name":"Scale"},"widget_override":"vec2"},{"input_data":{"input_name":"Skew"},"widget_override":"hidden"},{"input_data":{"input_name":"Pivot"},"widget_override":"hidden"}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"Transform","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[9641315149170593327,{"persistent_metadata":{"reference":"Path","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Modification"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"Path Modify","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[7340659059180155803,{"persistent_metadata":{"reference":"Merge","display_name":"","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Absolute":[-44,219]}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[10477328336261010694,{"persistent_metadata":{"reference":"Transform","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"unit":" px","x":"X","input_name":"Translation","y":"Y"},"widget_override":"vec2"},{"input_data":{"input_name":"Rotation"},"widget_override":"transform_rotation"},{"input_data":{"input_name":"Scale","unit":"x","x":"W","y":"H"},"widget_override":"vec2"},{"input_data":{"input_name":"Skew"},"widget_override":"hidden"},{"input_data":{"input_name":"Pivot"},"widget_override":"hidden"}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"Transform","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[17887542695709892422,{"persistent_metadata":{"reference":"Merge","display_name":"","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Absolute":[-22,126]}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[10852750245702849075,{"persistent_metadata":{"reference":"Stroke","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Color"},"widget_override":null},{"input_data":{"input_name":"Weight"},"widget_override":null},{"input_data":{"input_name":"Dash Lengths"},"widget_override":null},{"input_data":{"input_name":"Dash Offset"},"widget_override":null},{"input_data":{"input_name":"Line Cap"},"widget_override":null},{"input_data":{"input_name":"Line Join"},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{"input_name":"Miter Limit"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[4197544064668946479,{"persistent_metadata":{"reference":"Path","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Modification"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-43,27]}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"Path Modify","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[12019361655085452072,{"persistent_metadata":{"reference":"Transform","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"x":"X","input_name":"Translation","unit":" px","y":"Y"},"widget_override":"vec2"},{"input_data":{"input_name":"Rotation"},"widget_override":"transform_rotation"},{"input_data":{"y":"H","unit":"x","input_name":"Scale","x":"W"},"widget_override":"vec2"},{"input_data":{"input_name":"Skew"},"widget_override":"hidden"},{"input_data":{"input_name":"Pivot"},"widget_override":"hidden"}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"Transform","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[13853529851208960143,{"persistent_metadata":{"reference":"Path","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Modification"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"Path Modify","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[7838724497953148309,{"persistent_metadata":{"reference":"Merge","display_name":"Geometric Ripples","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Absolute":[-9,3]}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[4323461535289334196,{"persistent_metadata":{"reference":"Path","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Modification"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"Path Modify","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[13701442050580061197,{"persistent_metadata":{"reference":"Path","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Modification"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"Path Modify","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[4847316728405535983,{"persistent_metadata":{"reference":"Fill","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Fill"},"widget_override":null},{"input_data":{"input_name":"Backup Color"},"widget_override":null},{"input_data":{"input_name":"Backup Gradient"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[8958782938691501404,{"persistent_metadata":{"reference":"Path","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Modification"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"Path Modify","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[16807867745126764195,{"persistent_metadata":{"reference":"Path","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Modification"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"Path Modify","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[9138781233934614517,{"persistent_metadata":{"reference":"Merge","display_name":"","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":0}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[6868877732348460627,{"persistent_metadata":{"reference":"Stroke","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Color"},"widget_override":null},{"input_data":{"input_name":"Weight"},"widget_override":null},{"input_data":{"input_name":"Dash Lengths"},"widget_override":null},{"input_data":{"input_name":"Dash Offset"},"widget_override":null},{"input_data":{"input_name":"Line Cap"},"widget_override":null},{"input_data":{"input_name":"Line Join"},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{"input_name":"Miter Limit"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[9157963288496356916,{"persistent_metadata":{"reference":"Merge","display_name":"","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":0}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[16727310898641763441,{"persistent_metadata":{"reference":"Fill","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Fill"},"widget_override":null},{"input_data":{"input_name":"Backup Color"},"widget_override":null},{"input_data":{"input_name":"Backup Gradient"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[1156213189397385283,{"persistent_metadata":{"reference":"Path","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Modification"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-43,18]}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"Path Modify","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[18011777376689315137,{"persistent_metadata":{"reference":"Fill","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Fill"},"widget_override":null},{"input_data":{"input_name":"Backup Color"},"widget_override":null},{"input_data":{"input_name":"Backup Gradient"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[14449710315388146362,{"persistent_metadata":{"reference":"Opacity","display_name":"","input_properties":[{"input_data":{"input_name":"Value"},"widget_override":null},{"input_data":{"input_name":"Factor"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[9908869573449854874,{"persistent_metadata":{"reference":"Transform","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"x":"X","unit":" px","y":"Y","input_name":"Translation"},"widget_override":"vec2"},{"input_data":{"input_name":"Rotation"},"widget_override":"transform_rotation"},{"input_data":{"y":"H","input_name":"Scale","unit":"x","x":"W"},"widget_override":"vec2"},{"input_data":{"input_name":"Skew"},"widget_override":"hidden"},{"input_data":{"input_name":"Pivot"},"widget_override":"hidden"}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"Transform","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[9393309733761233513,{"persistent_metadata":{"reference":"Merge","display_name":"","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":0}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[13747030364552895864,{"persistent_metadata":{"reference":"Path","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Modification"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"Path Modify","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[14055195208113082127,{"persistent_metadata":{"reference":"Merge","display_name":"","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Absolute":[-22,48]}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[10188337730058049439,{"persistent_metadata":{"reference":"Merge","display_name":"","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":0}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[13942146309185231085,{"persistent_metadata":{"reference":"Fill","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Fill"},"widget_override":null},{"input_data":{"input_name":"Backup Color"},"widget_override":null},{"input_data":{"input_name":"Backup Gradient"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[16564941800301062922,{"persistent_metadata":{"reference":"Fill","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Fill"},"widget_override":null},{"input_data":{"input_name":"Backup Color"},"widget_override":null},{"input_data":{"input_name":"Backup Gradient"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[4243146970185091100,{"persistent_metadata":{"reference":"Path","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Modification"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"Path Modify","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[70804263053697201,{"persistent_metadata":{"reference":"Transform","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"unit":" px","y":"Y","input_name":"Translation","x":"X"},"widget_override":"vec2"},{"input_data":{"input_name":"Rotation"},"widget_override":"transform_rotation"},{"input_data":{"x":"W","unit":"x","input_name":"Scale","y":"H"},"widget_override":"vec2"},{"input_data":{"input_name":"Skew"},"widget_override":"hidden"},{"input_data":{"input_name":"Pivot"},"widget_override":"hidden"}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"Transform","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[11158238411769751544,{"persistent_metadata":{"reference":"Merge","display_name":"","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":0}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[2843751023378786714,{"persistent_metadata":{"reference":"Path","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Modification"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"Path Modify","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[14124486712683868036,{"persistent_metadata":{"reference":"Fill","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Fill"},"widget_override":null},{"input_data":{"input_name":"Backup Color"},"widget_override":null},{"input_data":{"input_name":"Backup Gradient"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[16398743435291795904,{"persistent_metadata":{"reference":"Merge","display_name":"Fountain Water","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":36}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[13700218159488557234,{"persistent_metadata":{"reference":"Fill","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Fill"},"widget_override":null},{"input_data":{"input_name":"Backup Color"},"widget_override":null},{"input_data":{"input_name":"Backup Gradient"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[729026403095264425,{"persistent_metadata":{"reference":"Transform","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Translation","x":"X","y":"Y","unit":" px"},"widget_override":"vec2"},{"input_data":{"input_name":"Rotation"},"widget_override":"transform_rotation"},{"input_data":{"input_name":"Scale","unit":"x","x":"W","y":"H"},"widget_override":"vec2"},{"input_data":{"input_name":"Skew"},"widget_override":"hidden"},{"input_data":{"input_name":"Pivot"},"widget_override":"hidden"}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"Transform","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[5925268772265373737,{"persistent_metadata":{"reference":"Fill","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Fill"},"widget_override":null},{"input_data":{"input_name":"Backup Color"},"widget_override":null},{"input_data":{"input_name":"Backup Gradient"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[15488533792651297821,{"persistent_metadata":{"reference":"Merge","display_name":"Structure Reflection","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":0}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[5540780316862276409,{"persistent_metadata":{"reference":"Merge","display_name":"","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":0}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[2032185045476767535,{"persistent_metadata":{"reference":"Merge","display_name":"","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":["Out"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Absolute":[-36,216]}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[11776939455674933130,{"persistent_metadata":{"reference":"Merge","display_name":"Backdrop Gradient","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":0}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[7339104629465306715,{"persistent_metadata":{"reference":"Fill","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Fill"},"widget_override":null},{"input_data":{"input_name":"Backup Color"},"widget_override":null},{"input_data":{"input_name":"Backup Gradient"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[13920465562072008593,{"persistent_metadata":{"reference":"Transform","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Translation","y":"Y","unit":" px","x":"X"},"widget_override":"vec2"},{"input_data":{"input_name":"Rotation"},"widget_override":"transform_rotation"},{"input_data":{"unit":"x","input_name":"Scale","x":"W","y":"H"},"widget_override":"vec2"},{"input_data":{"input_name":"Skew"},"widget_override":"hidden"},{"input_data":{"input_name":"Pivot"},"widget_override":"hidden"}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"Transform","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[2785423879796980286,{"persistent_metadata":{"reference":"Merge","display_name":"","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":0}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[15261165353096835967,{"persistent_metadata":{"reference":"Path","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Modification"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"Path Modify","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[14400993470150734626,{"persistent_metadata":{"reference":"Transform","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"y":"Y","unit":" px","x":"X","input_name":"Translation"},"widget_override":"vec2"},{"input_data":{"input_name":"Rotation"},"widget_override":"transform_rotation"},{"input_data":{"y":"H","x":"W","input_name":"Scale","unit":"x"},"widget_override":"vec2"},{"input_data":{"input_name":"Skew"},"widget_override":"hidden"},{"input_data":{"input_name":"Pivot"},"widget_override":"hidden"}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"Transform","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[12548387328300782726,{"persistent_metadata":{"reference":"Fill","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Fill"},"widget_override":null},{"input_data":{"input_name":"Backup Color"},"widget_override":null},{"input_data":{"input_name":"Backup Gradient"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[17638504852426495381,{"persistent_metadata":{"reference":"Fill","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Fill"},"widget_override":null},{"input_data":{"input_name":"Backup Color"},"widget_override":null},{"input_data":{"input_name":"Backup Gradient"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[11429712783984224234,{"persistent_metadata":{"reference":"Merge","display_name":"","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":0}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[664587514588499648,{"persistent_metadata":{"reference":"Merge","display_name":"","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":0}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[11634802583144606404,{"persistent_metadata":{"reference":"Merge","display_name":"","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":0}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[11076863066321508991,{"persistent_metadata":{"reference":"Fill","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Fill"},"widget_override":null},{"input_data":{"input_name":"Backup Color"},"widget_override":null},{"input_data":{"input_name":"Backup Gradient"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[2791109467690716388,{"persistent_metadata":{"reference":"Path","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Modification"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"Path Modify","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[3185536512640676801,{"persistent_metadata":{"reference":"Merge","display_name":"","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":0}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[9684750473849891261,{"persistent_metadata":{"reference":"Fill","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Fill"},"widget_override":null},{"input_data":{"input_name":"Backup Color"},"widget_override":null},{"input_data":{"input_name":"Backup Gradient"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[2183401450260403525,{"persistent_metadata":{"reference":"Transform","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"y":"Y","unit":" px","x":"X","input_name":"Translation"},"widget_override":"vec2"},{"input_data":{"input_name":"Rotation"},"widget_override":"transform_rotation"},{"input_data":{"y":"H","x":"W","unit":"x","input_name":"Scale"},"widget_override":"vec2"},{"input_data":{"input_name":"Skew"},"widget_override":"hidden"},{"input_data":{"input_name":"Pivot"},"widget_override":"hidden"}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"Transform","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[14483299526002574058,{"persistent_metadata":{"reference":"Path","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Modification"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"Path Modify","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[14449527838292182035,{"persistent_metadata":{"reference":"Path","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Modification"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"Path Modify","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[5882319123081134737,{"persistent_metadata":{"reference":"Merge","display_name":"","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Absolute":[-35,189]}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[1490537476612110327,{"persistent_metadata":{"reference":"Merge","display_name":"","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":0}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[2310170068575553369,{"persistent_metadata":{"reference":"Fill","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Fill"},"widget_override":null},{"input_data":{"input_name":"Backup Color"},"widget_override":null},{"input_data":{"input_name":"Backup Gradient"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[16229837691656808412,{"persistent_metadata":{"reference":"Path","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Modification"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"Path Modify","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[183952488591282082,{"persistent_metadata":{"reference":"Transform","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Translation","x":"X","y":"Y","unit":" px"},"widget_override":"vec2"},{"input_data":{"input_name":"Rotation"},"widget_override":"transform_rotation"},{"input_data":{"x":"W","unit":"x","input_name":"Scale","y":"H"},"widget_override":"vec2"},{"input_data":{"input_name":"Skew"},"widget_override":"hidden"},{"input_data":{"input_name":"Pivot"},"widget_override":"hidden"}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"Transform","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[2510483139353274965,{"persistent_metadata":{"reference":"Merge","display_name":"","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":0}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[5258402282444994019,{"persistent_metadata":{"reference":"Transform","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"y":"Y","input_name":"Translation","x":"X","unit":" px"},"widget_override":"vec2"},{"input_data":{"input_name":"Rotation"},"widget_override":"transform_rotation"},{"input_data":{"y":"H","x":"W","input_name":"Scale","unit":"x"},"widget_override":"vec2"},{"input_data":{"input_name":"Skew"},"widget_override":"hidden"},{"input_data":{"input_name":"Pivot"},"widget_override":"hidden"}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"Transform","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[8165914767449151618,{"persistent_metadata":{"reference":"Merge","display_name":"","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":0}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[15876464101883822838,{"persistent_metadata":{"reference":"Fill","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Fill"},"widget_override":null},{"input_data":{"input_name":"Backup Color"},"widget_override":null},{"input_data":{"input_name":"Backup Gradient"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[3806549994589872867,{"persistent_metadata":{"reference":"Merge","display_name":"","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Absolute":[-22,84]}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[16591255610014418910,{"persistent_metadata":{"reference":"Stroke","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Color"},"widget_override":null},{"input_data":{"input_name":"Weight"},"widget_override":null},{"input_data":{"input_name":"Dash Lengths"},"widget_override":null},{"input_data":{"input_name":"Dash Offset"},"widget_override":null},{"input_data":{"input_name":"Line Cap"},"widget_override":null},{"input_data":{"input_name":"Line Join"},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{"input_name":"Miter Limit"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[14161755104759532162,{"persistent_metadata":{"reference":"Transform","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"x":"X","input_name":"Translation","y":"Y","unit":" px"},"widget_override":"vec2"},{"input_data":{"input_name":"Rotation"},"widget_override":"transform_rotation"},{"input_data":{"unit":"x","input_name":"Scale","x":"W","y":"H"},"widget_override":"vec2"},{"input_data":{"input_name":"Skew"},"widget_override":"hidden"},{"input_data":{"input_name":"Pivot"},"widget_override":"hidden"}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"Transform","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[6785205785632793666,{"persistent_metadata":{"reference":"Fill","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Fill"},"widget_override":null},{"input_data":{"input_name":"Backup Color"},"widget_override":null},{"input_data":{"input_name":"Backup Gradient"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[14633096010607565334,{"persistent_metadata":{"reference":"Merge","display_name":"","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":0}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[13743495762122910279,{"persistent_metadata":{"reference":"Fill","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Fill"},"widget_override":null},{"input_data":{"input_name":"Backup Color"},"widget_override":null},{"input_data":{"input_name":"Backup Gradient"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[12172015233077238737,{"persistent_metadata":{"reference":"Stroke","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Color"},"widget_override":null},{"input_data":{"input_name":"Weight"},"widget_override":null},{"input_data":{"input_name":"Dash Lengths"},"widget_override":null},{"input_data":{"input_name":"Dash Offset"},"widget_override":null},{"input_data":{"input_name":"Line Cap"},"widget_override":null},{"input_data":{"input_name":"Line Join"},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{"input_name":"Miter Limit"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[9150078008481575131,{"persistent_metadata":{"reference":"Path","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Modification"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"Path Modify","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[9798215931018813676,{"persistent_metadata":{"reference":"Fill","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Fill"},"widget_override":null},{"input_data":{"input_name":"Backup Color"},"widget_override":null},{"input_data":{"input_name":"Backup Gradient"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[9115451226763736660,{"persistent_metadata":{"reference":"Fill","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Fill"},"widget_override":null},{"input_data":{"input_name":"Backup Color"},"widget_override":null},{"input_data":{"input_name":"Backup Gradient"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[16244305414728361140,{"persistent_metadata":{"reference":"Fill","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Fill"},"widget_override":null},{"input_data":{"input_name":"Backup Color"},"widget_override":null},{"input_data":{"input_name":"Backup Gradient"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[8034980397175569257,{"persistent_metadata":{"reference":"Transform","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Translation","unit":" px","x":"X","y":"Y"},"widget_override":"vec2"},{"input_data":{"input_name":"Rotation"},"widget_override":"transform_rotation"},{"input_data":{"input_name":"Scale","y":"H","unit":"x","x":"W"},"widget_override":"vec2"},{"input_data":{"input_name":"Skew"},"widget_override":"hidden"},{"input_data":{"input_name":"Pivot"},"widget_override":"hidden"}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"Transform","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[13861850149743924125,{"persistent_metadata":{"reference":"Merge","display_name":"","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":0}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[14202574750104046500,{"persistent_metadata":{"reference":"Merge","display_name":"","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":0}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[15157035456876170143,{"persistent_metadata":{"reference":"Transform","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Translation","x":"X","y":"Y","unit":" px"},"widget_override":"vec2"},{"input_data":{"input_name":"Rotation"},"widget_override":"transform_rotation"},{"input_data":{"y":"H","x":"W","unit":"x","input_name":"Scale"},"widget_override":"vec2"},{"input_data":{"input_name":"Skew"},"widget_override":"hidden"},{"input_data":{"input_name":"Pivot"},"widget_override":"hidden"}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"Transform","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[5365849201631468915,{"persistent_metadata":{"reference":"Merge","display_name":"","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":0}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[1104068854328504126,{"persistent_metadata":{"reference":"Path","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Modification"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"Path Modify","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[10810157408196882043,{"persistent_metadata":{"reference":"Path","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Modification"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"Path Modify","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[10917301734480569398,{"persistent_metadata":{"reference":"Transform","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"x":"X","y":"Y","unit":" px","input_name":"Translation"},"widget_override":"vec2"},{"input_data":{"input_name":"Rotation"},"widget_override":"transform_rotation"},{"input_data":{"x":"W","unit":"x","input_name":"Scale","y":"H"},"widget_override":"vec2"},{"input_data":{"input_name":"Skew"},"widget_override":"hidden"},{"input_data":{"input_name":"Pivot"},"widget_override":"hidden"}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"Transform","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[10181153433637856462,{"persistent_metadata":{"reference":"Transform","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Translation","unit":" px","x":"X","y":"Y"},"widget_override":"vec2"},{"input_data":{"input_name":"Rotation"},"widget_override":"transform_rotation"},{"input_data":{"input_name":"Scale","y":"H","x":"W","unit":"x"},"widget_override":"vec2"},{"input_data":{"input_name":"Skew"},"widget_override":"hidden"},{"input_data":{"input_name":"Pivot"},"widget_override":"hidden"}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"Transform","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[4898866541060902381,{"persistent_metadata":{"reference":"Fill","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Fill"},"widget_override":null},{"input_data":{"input_name":"Backup Color"},"widget_override":null},{"input_data":{"input_name":"Backup Gradient"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[12554549497938935061,{"persistent_metadata":{"reference":"Transform","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"x":"X","y":"Y","unit":" px","input_name":"Translation"},"widget_override":"vec2"},{"input_data":{"input_name":"Rotation"},"widget_override":"transform_rotation"},{"input_data":{"input_name":"Scale","y":"H","unit":"x","x":"W"},"widget_override":"vec2"},{"input_data":{"input_name":"Skew"},"widget_override":"hidden"},{"input_data":{"input_name":"Pivot"},"widget_override":"hidden"}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"Transform","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[5574499968250848265,{"persistent_metadata":{"reference":"Merge","display_name":"Water","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":6}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[18431382379595272672,{"persistent_metadata":{"reference":"Merge","display_name":"","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":0}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[12360435709959435360,{"persistent_metadata":{"reference":"Fill","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Fill"},"widget_override":null},{"input_data":{"input_name":"Backup Color"},"widget_override":null},{"input_data":{"input_name":"Backup Gradient"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[11450962621506425680,{"persistent_metadata":{"reference":"Merge","display_name":"","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":0}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[6006052038693767172,{"persistent_metadata":{"reference":"Stroke","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Color"},"widget_override":null},{"input_data":{"input_name":"Weight"},"widget_override":null},{"input_data":{"input_name":"Dash Lengths"},"widget_override":null},{"input_data":{"input_name":"Dash Offset"},"widget_override":null},{"input_data":{"input_name":"Line Cap"},"widget_override":null},{"input_data":{"input_name":"Line Join"},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{"input_name":"Miter Limit"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[9666682009015049330,{"persistent_metadata":{"reference":"Transform","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"x":"X","y":"Y","unit":" px","input_name":"Translation"},"widget_override":"vec2"},{"input_data":{"input_name":"Rotation"},"widget_override":"transform_rotation"},{"input_data":{"y":"H","input_name":"Scale","unit":"x","x":"W"},"widget_override":"vec2"},{"input_data":{"input_name":"Skew"},"widget_override":"hidden"},{"input_data":{"input_name":"Pivot"},"widget_override":"hidden"}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"Transform","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[10189927996178548902,{"persistent_metadata":{"reference":"Path","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Modification"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"Path Modify","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[15723520455917422372,{"persistent_metadata":{"reference":"Transform","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Translation","y":"Y","x":"X","unit":" px"},"widget_override":"vec2"},{"input_data":{"input_name":"Rotation"},"widget_override":"transform_rotation"},{"input_data":{"input_name":"Scale","unit":"x","x":"W","y":"H"},"widget_override":"vec2"},{"input_data":{"input_name":"Skew"},"widget_override":"hidden"},{"input_data":{"input_name":"Pivot"},"widget_override":"hidden"}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"Transform","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[2465823993152870948,{"persistent_metadata":{"reference":"Fill","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Fill"},"widget_override":null},{"input_data":{"input_name":"Backup Color"},"widget_override":null},{"input_data":{"input_name":"Backup Gradient"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[17873337220577786871,{"persistent_metadata":{"reference":"Path","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Modification"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"Path Modify","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[3365825508845848745,{"persistent_metadata":{"reference":"Fill","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Fill"},"widget_override":null},{"input_data":{"input_name":"Backup Color"},"widget_override":null},{"input_data":{"input_name":"Backup Gradient"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[12370676490908282512,{"persistent_metadata":{"reference":"Fill","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Fill"},"widget_override":null},{"input_data":{"input_name":"Backup Color"},"widget_override":null},{"input_data":{"input_name":"Backup Gradient"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[9323583246068171750,{"persistent_metadata":{"reference":"Fill","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Fill"},"widget_override":null},{"input_data":{"input_name":"Backup Color"},"widget_override":null},{"input_data":{"input_name":"Backup Gradient"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[4884180935153120645,{"persistent_metadata":{"reference":"Fill","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Fill"},"widget_override":null},{"input_data":{"input_name":"Backup Color"},"widget_override":null},{"input_data":{"input_name":"Backup Gradient"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[429913874753911073,{"persistent_metadata":{"reference":"Stroke","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Color"},"widget_override":null},{"input_data":{"input_name":"Weight"},"widget_override":null},{"input_data":{"input_name":"Dash Lengths"},"widget_override":null},{"input_data":{"input_name":"Dash Offset"},"widget_override":null},{"input_data":{"input_name":"Line Cap"},"widget_override":null},{"input_data":{"input_name":"Line Join"},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{"input_name":"Miter Limit"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[1032659476619711014,{"persistent_metadata":{"reference":"Merge","display_name":"","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":0}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[11895211316848895241,{"persistent_metadata":{"reference":"Fill","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Fill"},"widget_override":null},{"input_data":{"input_name":"Backup Color"},"widget_override":null},{"input_data":{"input_name":"Backup Gradient"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[8256712316698018135,{"persistent_metadata":{"reference":"Path","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Modification"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"Path Modify","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[514222872092587805,{"persistent_metadata":{"reference":"Merge","display_name":"","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":0}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[17785019773455930267,{"persistent_metadata":{"reference":"Transform","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Translation","unit":" px","y":"Y","x":"X"},"widget_override":"vec2"},{"input_data":{"input_name":"Rotation"},"widget_override":"transform_rotation"},{"input_data":{"x":"W","input_name":"Scale","y":"H","unit":"x"},"widget_override":"vec2"},{"input_data":{"input_name":"Skew"},"widget_override":"hidden"},{"input_data":{"input_name":"Pivot"},"widget_override":"hidden"}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"Transform","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[5670058004691708784,{"persistent_metadata":{"reference":"Path","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Modification"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"Path Modify","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[1831743139584171612,{"persistent_metadata":{"reference":"Fill","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Fill"},"widget_override":null},{"input_data":{"input_name":"Backup Color"},"widget_override":null},{"input_data":{"input_name":"Backup Gradient"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[9640215309187299519,{"persistent_metadata":{"reference":"Path","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Modification"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"Path Modify","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[6777328619777499144,{"persistent_metadata":{"reference":"Path","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Modification"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"Path Modify","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[2058192342619930156,{"persistent_metadata":{"reference":"Transform","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Translation","x":"X","unit":" px","y":"Y"},"widget_override":"vec2"},{"input_data":{"input_name":"Rotation"},"widget_override":"transform_rotation"},{"input_data":{"x":"W","unit":"x","input_name":"Scale","y":"H"},"widget_override":"vec2"},{"input_data":{"input_name":"Skew"},"widget_override":"hidden"},{"input_data":{"input_name":"Pivot"},"widget_override":"hidden"}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"Transform","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[8073807569018624098,{"persistent_metadata":{"reference":"Merge","display_name":"","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":0}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[12998832508553378533,{"persistent_metadata":{"reference":"Fill","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Fill"},"widget_override":null},{"input_data":{"input_name":"Backup Color"},"widget_override":null},{"input_data":{"input_name":"Backup Gradient"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[13942787566051910019,{"persistent_metadata":{"reference":"Path","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Modification"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"Path Modify","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[17533670083736420411,{"persistent_metadata":{"reference":"Fill","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Fill"},"widget_override":null},{"input_data":{"input_name":"Backup Color"},"widget_override":null},{"input_data":{"input_name":"Backup Gradient"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[4837219841531371489,{"persistent_metadata":{"reference":"Path","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Modification"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"Path Modify","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[4069478660487729695,{"persistent_metadata":{"reference":"Path","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Modification"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"Path Modify","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[14019233912018234740,{"persistent_metadata":{"reference":"Merge","display_name":"Structure","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":27}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[17332567356044944766,{"persistent_metadata":{"reference":"Path","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Modification"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"Path Modify","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[3966971396176820223,{"persistent_metadata":{"reference":"Path","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Modification"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"Path Modify","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[14752203606937854133,{"persistent_metadata":{"reference":"Path","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Modification"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"Path Modify","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[2452294403891427489,{"persistent_metadata":{"reference":"Fill","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Fill"},"widget_override":null},{"input_data":{"input_name":"Backup Color"},"widget_override":null},{"input_data":{"input_name":"Backup Gradient"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[13946577152348504742,{"persistent_metadata":{"reference":"Merge","display_name":"","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":0}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[15478704582542175684,{"persistent_metadata":{"reference":"Merge","display_name":"","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":0}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[15670426414376277308,{"persistent_metadata":{"reference":"Path","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Modification"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"Path Modify","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[13609749019463823009,{"persistent_metadata":{"reference":"Fill","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Fill"},"widget_override":null},{"input_data":{"input_name":"Backup Color"},"widget_override":null},{"input_data":{"input_name":"Backup Gradient"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[6569279146800941123,{"persistent_metadata":{"reference":"Transform","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"y":"Y","input_name":"Translation","unit":" px","x":"X"},"widget_override":"vec2"},{"input_data":{"input_name":"Rotation"},"widget_override":"transform_rotation"},{"input_data":{"x":"W","y":"H","input_name":"Scale","unit":"x"},"widget_override":"vec2"},{"input_data":{"input_name":"Skew"},"widget_override":"hidden"},{"input_data":{"input_name":"Pivot"},"widget_override":"hidden"}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"Transform","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[8508454285877707748,{"persistent_metadata":{"reference":"Fill","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Fill"},"widget_override":null},{"input_data":{"input_name":"Backup Color"},"widget_override":null},{"input_data":{"input_name":"Backup Gradient"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[8015732980153557800,{"persistent_metadata":{"reference":"Transform","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"unit":" px","input_name":"Translation","y":"Y","x":"X"},"widget_override":"vec2"},{"input_data":{"input_name":"Rotation"},"widget_override":"transform_rotation"},{"input_data":{"x":"W","y":"H","unit":"x","input_name":"Scale"},"widget_override":"vec2"},{"input_data":{"input_name":"Skew"},"widget_override":"hidden"},{"input_data":{"input_name":"Pivot"},"widget_override":"hidden"}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"Transform","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[2155997486525176376,{"persistent_metadata":{"reference":"Merge","display_name":"","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Absolute":[-22,6]}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[4887570735033124574,{"persistent_metadata":{"reference":"Fill","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Fill"},"widget_override":null},{"input_data":{"input_name":"Backup Color"},"widget_override":null},{"input_data":{"input_name":"Backup Gradient"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[16923062582661131268,{"persistent_metadata":{"reference":"Path","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Modification"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"Path Modify","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[6821938959315178556,{"persistent_metadata":{"reference":"Merge","display_name":"","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":0}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[8343201730608263656,{"persistent_metadata":{"reference":"Path","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Modification"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"Path Modify","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[1268775104597510914,{"persistent_metadata":{"reference":"Merge","display_name":"","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":0}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[693.0,-4081.136664739667],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,693.0,-4081.0],"node_graph_top_right":[1468.796875,0.0]},"selection_undo_history":[[],[],[],[],[],[15517065353723874205],[7340659059180155803],[7340659059180155803,13442128106088307772,7171713123860587892,18431382379595272672,10989897386232385465,10507084483235320484,9157963288496356916,10188337730058049439,1268775104597510914,13861850149743924125],[7340659059180155803,7171713123860587892,18431382379595272672,10989897386232385465,10507084483235320484,9157963288496356916,10188337730058049439,1268775104597510914,13861850149743924125,13442128106088307772],[7340659059180155803],[7340659059180155803,7171713123860587892,18431382379595272672,10989897386232385465,10507084483235320484,9157963288496356916,10188337730058049439,1268775104597510914,13861850149743924125,13442128106088307772],[16398743435291795904,4741515246389989284,14255588039347536657,5261200785298607501,2465823993152870948,15898396405528650339,16807867745126764195,18185020559178852986,4847316728405535983,11579925754926059876,15670426414376277308,5574499968250848265,5925268772265373737,4105329493214975815,12931264630175648107,11776939455674933130,9684750473849891261,70804263053697201,13942787566051910019],[7340659059180155803,7171713123860587892,18431382379595272672,10989897386232385465,10507084483235320484,9157963288496356916,10188337730058049439,1268775104597510914,13861850149743924125,13442128106088307772],[7340659059180155803],[7340659059180155803,7171713123860587892,18431382379595272672,10989897386232385465,10507084483235320484,9157963288496356916,10188337730058049439,1268775104597510914,13861850149743924125,13442128106088307772],[16398743435291795904,4741515246389989284,14255588039347536657,5261200785298607501,2465823993152870948,15898396405528650339,16807867745126764195,18185020559178852986,4847316728405535983,11579925754926059876,15670426414376277308,5574499968250848265,5925268772265373737,4105329493214975815,12931264630175648107,11776939455674933130,9684750473849891261,70804263053697201,13942787566051910019],[7340659059180155803,7171713123860587892,18431382379595272672,10989897386232385465,10507084483235320484,9157963288496356916,10188337730058049439,1268775104597510914,13861850149743924125,13442128106088307772],[7340659059180155803,13531127678140037818,3970872207068447290,2077983679740571162,7171713123860587892,9798215931018813676,10779665858841986661,18431382379595272672,4191887059541031673,4046495708656778502,10989897386232385465,7339104629465306715,16229837691656808412,10507084483235320484,1396768435017101055,15914878146223026034,4069478660487729695,9157963288496356916,1108089904278882840,5317925967883407701,13853529851208960143,10188337730058049439,11076863066321508991,8891726805381758817,17332567356044944766,1268775104597510914,18011777376689315137,10564228200140683112,13001069903842109798,13861850149743924125,5891705401441266824,5670058004691708784],[7340659059180155803,7171713123860587892,18431382379595272672,10989897386232385465,10507084483235320484,9157963288496356916,10188337730058049439,1268775104597510914,13861850149743924125,13442128106088307772],[13442128106088307772],[7340659059180155803,7171713123860587892,18431382379595272672,10989897386232385465,10507084483235320484,9157963288496356916,10188337730058049439,1268775104597510914,13861850149743924125,13442128106088307772],[7340659059180155803,13531127678140037818,3970872207068447290,2077983679740571162,7171713123860587892,9798215931018813676,10779665858841986661,18431382379595272672,4191887059541031673,4046495708656778502,10989897386232385465,7339104629465306715,16229837691656808412,10507084483235320484,1396768435017101055,15914878146223026034,4069478660487729695,9157963288496356916,1108089904278882840,5317925967883407701,13853529851208960143,10188337730058049439,11076863066321508991,8891726805381758817,17332567356044944766,1268775104597510914,18011777376689315137,10564228200140683112,13001069903842109798],[7340659059180155803,7171713123860587892,18431382379595272672,10989897386232385465,10507084483235320484,9157963288496356916,10188337730058049439,1268775104597510914,13861850149743924125,13442128106088307772],[13861850149743924125],[7340659059180155803,7171713123860587892,18431382379595272672,10989897386232385465,10507084483235320484,9157963288496356916,10188337730058049439,1268775104597510914,13861850149743924125,13442128106088307772],[7340659059180155803,13531127678140037818,3970872207068447290,2077983679740571162,7171713123860587892,9798215931018813676,10779665858841986661,18431382379595272672,4191887059541031673,4046495708656778502,10989897386232385465,7339104629465306715,16229837691656808412,10507084483235320484,1396768435017101055,15914878146223026034,4069478660487729695,9157963288496356916,1108089904278882840,5317925967883407701,13853529851208960143,10188337730058049439,11076863066321508991,8891726805381758817,17332567356044944766],[7340659059180155803,7171713123860587892,18431382379595272672,10989897386232385465,10507084483235320484,9157963288496356916,10188337730058049439,1268775104597510914,13861850149743924125,13442128106088307772],[1268775104597510914],[7340659059180155803,7171713123860587892,18431382379595272672,10989897386232385465,10507084483235320484,9157963288496356916,10188337730058049439,1268775104597510914,13861850149743924125,13442128106088307772],[7340659059180155803,13531127678140037818,3970872207068447290,2077983679740571162,7171713123860587892,9798215931018813676,10779665858841986661,18431382379595272672,4191887059541031673,4046495708656778502,10989897386232385465,7339104629465306715,16229837691656808412,10507084483235320484,1396768435017101055,15914878146223026034,4069478660487729695,9157963288496356916,1108089904278882840,5317925967883407701,13853529851208960143],[7340659059180155803,7171713123860587892,18431382379595272672,10989897386232385465,10507084483235320484,9157963288496356916,10188337730058049439,1268775104597510914,13861850149743924125,13442128106088307772],[10188337730058049439],[7340659059180155803,7171713123860587892,18431382379595272672,10989897386232385465,10507084483235320484,9157963288496356916,10188337730058049439,1268775104597510914,13861850149743924125,13442128106088307772],[7340659059180155803,13531127678140037818,3970872207068447290,2077983679740571162,7171713123860587892,9798215931018813676,10779665858841986661,18431382379595272672,4191887059541031673,4046495708656778502,10989897386232385465,7339104629465306715,16229837691656808412,10507084483235320484,1396768435017101055,15914878146223026034,4069478660487729695],[7340659059180155803,7171713123860587892,18431382379595272672,10989897386232385465,10507084483235320484,9157963288496356916,10188337730058049439,1268775104597510914,13861850149743924125,13442128106088307772],[9157963288496356916],[7340659059180155803,7171713123860587892,18431382379595272672,10989897386232385465,10507084483235320484,9157963288496356916,10188337730058049439,1268775104597510914,13861850149743924125,13442128106088307772],[7340659059180155803,13531127678140037818,3970872207068447290,2077983679740571162,7171713123860587892,9798215931018813676,10779665858841986661,18431382379595272672,4191887059541031673,4046495708656778502,10989897386232385465,7339104629465306715,16229837691656808412],[7340659059180155803,7171713123860587892,18431382379595272672,10989897386232385465,10507084483235320484,9157963288496356916,10188337730058049439,1268775104597510914,13861850149743924125,13442128106088307772],[10507084483235320484],[7340659059180155803,7171713123860587892,18431382379595272672,10989897386232385465,10507084483235320484,9157963288496356916,10188337730058049439,1268775104597510914,13861850149743924125,13442128106088307772],[7340659059180155803,13531127678140037818,3970872207068447290,2077983679740571162,7171713123860587892,9798215931018813676,10779665858841986661,18431382379595272672,4191887059541031673,4046495708656778502],[7340659059180155803,7171713123860587892,18431382379595272672,10989897386232385465,10507084483235320484,9157963288496356916,10188337730058049439,1268775104597510914,13861850149743924125,13442128106088307772],[10989897386232385465],[7340659059180155803,7171713123860587892,18431382379595272672,10989897386232385465,10507084483235320484,9157963288496356916,10188337730058049439,1268775104597510914,13861850149743924125,13442128106088307772],[7340659059180155803,13531127678140037818,3970872207068447290,2077983679740571162,7171713123860587892,9798215931018813676,10779665858841986661],[7340659059180155803,7171713123860587892,18431382379595272672,10989897386232385465,10507084483235320484,9157963288496356916,10188337730058049439,1268775104597510914,13861850149743924125,13442128106088307772],[18431382379595272672],[7340659059180155803,7171713123860587892,18431382379595272672,10989897386232385465,10507084483235320484,9157963288496356916,10188337730058049439,1268775104597510914,13861850149743924125,13442128106088307772],[7340659059180155803,13531127678140037818,3970872207068447290,2077983679740571162],[7340659059180155803,7171713123860587892,18431382379595272672,10989897386232385465,10507084483235320484,9157963288496356916,10188337730058049439,1268775104597510914,13861850149743924125,13442128106088307772],[7171713123860587892],[7340659059180155803,7171713123860587892,18431382379595272672,10989897386232385465,10507084483235320484,9157963288496356916,10188337730058049439,1268775104597510914,13861850149743924125,13442128106088307772],[2032185045476767535],[]],"selection_redo_history":[]}}},"collapsed":[7838724497953148310,9771562518763748678,14234384001010789009,4757672276235057646,4924169570021915607,15488533792651297822,16398743435291795905,972153153989181919,14019233912018234741,5574499968250848266,11776939455674933131,2032185045476767536,16069762220015310718],"name":"isometric-fountain.graphite","commit_hash":"8d83fa707928a1c54fe10224695a0c4791ab3501","document_ptz":{"pan":[-639.4105997694348,-319.94980900906876],"tilt":0.0,"zoom":1.0,"flip":false},"document_mode":"DesignMode","view_mode":"Normal","overlays_visibility_settings":{"all":true,"artboard_name":true,"compass_rose":true,"quick_measurement":true,"transform_measurement":true,"transform_cage":true,"hover_outline":true,"selection_outline":true,"pivot":true,"path":true,"anchors":true,"handles":true},"rulers_visible":true,"snapping_state":{"snapping_enabled":true,"grid_snapping":false,"artboards":true,"tolerance":8.0,"bounding_box":{"center_point":true,"corner_point":true,"edge_midpoint":true,"align_with_edges":true,"distribute_evenly":true},"path":{"anchor_point":true,"line_midpoint":true,"along_path":true,"normal_to_path":true,"tangent_to_path":true,"path_intersection_point":true,"align_with_anchor_point":true,"perpendicular_from_endpoint":true},"grid":{"origin":[0.0,0.0],"grid_type":{"Isometric":{"y_axis_spacing":20.0,"angle_a":15.0,"angle_b":15.0}},"rectangular_spacing":[1.0,1.0],"isometric_y_spacing":1.0,"isometric_angle_a":30.0,"isometric_angle_b":30.0,"grid_color":{"red":0.60784316,"green":0.60784316,"blue":0.60784316,"alpha":0.25},"dot_display":false}},"graph_view_overlay_open":false,"graph_fade_artwork_percentage":80.0} \ No newline at end of file diff --git a/demo-artwork/marbled-mandelbrot.graphite b/demo-artwork/marbled-mandelbrot.graphite new file mode 100644 index 0000000000000000000000000000000000000000..2558debe43d553ff74225b5899298d730cac4ead --- /dev/null +++ b/demo-artwork/marbled-mandelbrot.graphite @@ -0,0 +1 @@ +{"network_interface":{"network":{"exports":[{"Node":{"node_id":12241147352993594415,"output_index":0,"lambda":false}}],"nodes":[[4388711862172196665,{"inputs":[],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_std::raster::MandelbrotNode"}},"visible":true,"skip_deduplication":false}],[3606681156406984991,{"inputs":[{"Node":{"node_id":6323350524796370485,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"GradientStops":[[0.3237704918032787,{"red":1.0,"green":0.0,"blue":1.0,"alpha":0.1}],[0.5655737704918032,{"red":0.8901961,"green":0.8117647,"blue":0.39215687,"alpha":1.0}],[0.8155737704918032,{"red":0.0,"green":1.0,"blue":1.0,"alpha":0.5}]]},"exposed":false}},{"Value":{"tagged_value":{"Bool":true},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::raster::adjustments::GradientMapNode"}},"visible":true,"skip_deduplication":false}],[6029481207635803402,{"inputs":[{"Node":{"node_id":4388711862172196665,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"DVec2":[0.0,0.0]},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[1000.0,1000.0]},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[0.0,0.0]},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[0.5,0.5]},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":1}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":2}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":3}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":4}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":5}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::TransformNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[7624113397561636853,{"inputs":[{"Value":{"tagged_value":{"GraphicGroup":{"instance":[],"transform":[],"alpha_blending":[],"source_node_id":[]}},"exposed":true}},{"Node":{"node_id":3606681156406984991,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[80924370013313595,{"inputs":[{"Node":{"node_id":6029481207635803402,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"GradientStops":[[0.0,{"red":0.19607843,"green":0.0,"blue":0.21176471,"alpha":1.0}],[0.12704918032786883,{"red":0.0627451,"green":0.19215687,"blue":0.39607844,"alpha":1.0}],[0.5,{"red":0.8901961,"green":0.8117647,"blue":0.39215687,"alpha":1.0}],[1.0,{"red":0.58431375,"green":0.92941177,"blue":0.92941177,"alpha":0.01}]]},"exposed":false}},{"Value":{"tagged_value":{"Bool":false},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::raster::adjustments::GradientMapNode"}},"visible":true,"skip_deduplication":false}],[6323350524796370485,{"inputs":[{"Value":{"tagged_value":"None","exposed":false}},{"Value":{"tagged_value":{"Bool":false},"exposed":false}},{"Value":{"tagged_value":{"U32":0},"exposed":false}},{"Value":{"tagged_value":{"F64":35.0},"exposed":false}},{"Value":{"tagged_value":{"NoiseType":"OpenSimplex2"},"exposed":false}},{"Value":{"tagged_value":{"DomainWarpType":"OpenSimplex2"},"exposed":false}},{"Value":{"tagged_value":{"F64":100.0},"exposed":false}},{"Value":{"tagged_value":{"FractalType":"PingPong"},"exposed":false}},{"Value":{"tagged_value":{"U32":3},"exposed":false}},{"Value":{"tagged_value":{"F64":2.0},"exposed":false}},{"Value":{"tagged_value":{"F64":0.5},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"F64":2.0},"exposed":false}},{"Value":{"tagged_value":{"CellularDistanceFunction":"Hybrid"},"exposed":false}},{"Value":{"tagged_value":{"CellularReturnType":"CellValue"},"exposed":false}},{"Value":{"tagged_value":{"F64":1.0},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_std::raster::NoisePatternNode"}},"visible":true,"skip_deduplication":false}],[6565638614909771142,{"inputs":[{"Node":{"node_id":7624113397561636853,"output_index":0,"lambda":false}},{"Node":{"node_id":80924370013313595,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[12241147352993594415,{"inputs":[{"Value":{"tagged_value":{"ArtboardGroup":{"instance":[],"transform":[],"alpha_blending":[],"source_node_id":[]}},"exposed":true}},{"Node":{"node_id":6565638614909771142,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"IVec2":[0,0]},"exposed":false}},{"Value":{"tagged_value":{"IVec2":[1000,1000]},"exposed":false}},{"Value":{"tagged_value":{"Color":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}},"exposed":false}},{"Value":{"tagged_value":{"Bool":true},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":2,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graph_craft::document::value::TaggedValue","alias":null}},"import_index":1}},{"Value":{"tagged_value":{"String":"Artboard"},"exposed":false}},{"Network":{"import_type":{"Concrete":{"name":"graph_craft::document::value::TaggedValue","alias":null}},"import_index":2}},{"Network":{"import_type":{"Concrete":{"name":"graph_craft::document::value::TaggedValue","alias":null}},"import_index":3}},{"Network":{"import_type":{"Concrete":{"name":"graph_craft::document::value::TaggedValue","alias":null}},"import_index":4}},{"Network":{"import_type":{"Concrete":{"name":"graph_craft::document::value::TaggedValue","alias":null}},"import_index":5}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToArtboardNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Network":{"import_type":{"Fn":[{"Concrete":{"name":"core::option::Option>","alias":null}},{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}}]},"import_index":0}},{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::AppendArtboardNode"}},"visible":true,"skip_deduplication":false}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]},"network_metadata":{"persistent_metadata":{"node_metadata":[[6029481207635803402,{"persistent_metadata":{"reference":"Transform","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"x":"X","input_name":"Translation","unit":" px","y":"Y"},"widget_override":"vec2"},{"input_data":{"input_name":"Rotation"},"widget_override":"transform_rotation"},{"input_data":{"x":"W","unit":"x","y":"H","input_name":"Scale"},"widget_override":"vec2"},{"input_data":{"input_name":"Skew"},"widget_override":"hidden"},{"input_data":{"input_name":"Pivot"},"widget_override":"hidden"}],"output_names":["Data"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"Transform","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[7624113397561636853,{"persistent_metadata":{"reference":"Merge","display_name":"Swirly Noise","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":["Out"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":0}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[4388711862172196665,{"persistent_metadata":{"reference":"Mandelbrot","display_name":"","input_properties":[],"output_names":["Raster"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[6323350524796370485,{"persistent_metadata":{"reference":"Noise Pattern","display_name":"","input_properties":[{"input_data":{"input_name":"Spacer"},"widget_override":null},{"input_data":{"input_name":"Clip"},"widget_override":null},{"input_data":{"input_name":"Seed"},"widget_override":null},{"input_data":{"input_name":"Scale"},"widget_override":"noise_properties_scale"},{"input_data":{"input_name":"Noise Type"},"widget_override":"noise_properties_noise_type"},{"input_data":{"input_name":"Domain Warp Type"},"widget_override":"noise_properties_domain_warp_type"},{"input_data":{"input_name":"Domain Warp Amplitude"},"widget_override":"noise_properties_domain_warp_amplitude"},{"input_data":{"input_name":"Fractal Type"},"widget_override":"noise_properties_fractal_type"},{"input_data":{"input_name":"Fractal Octaves"},"widget_override":"noise_properties_fractal_octaves"},{"input_data":{"input_name":"Fractal Lacunarity"},"widget_override":"noise_properties_fractal_lacunarity"},{"input_data":{"input_name":"Fractal Gain"},"widget_override":"noise_properties_fractal_gain"},{"input_data":{"input_name":"Fractal Weighted Strength"},"widget_override":"noise_properties_fractal_weighted_strength"},{"input_data":{"input_name":"Fractal Ping Pong Strength"},"widget_override":"noise_properties_ping_pong_strength"},{"input_data":{"input_name":"Cellular Distance Function"},"widget_override":"noise_properties_cellular_distance_function"},{"input_data":{"input_name":"Cellular Return Type"},"widget_override":"noise_properties_cellular_return_type"},{"input_data":{"input_name":"Cellular Jitter"},"widget_override":"noise_properties_cellular_jitter"}],"output_names":["Image"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"Noise Pattern","input_properties":[],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"Cull","input_properties":[],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[12241147352993594415,{"persistent_metadata":{"reference":"Artboard","display_name":"","input_properties":[{"input_data":{"input_name":"Artboards"},"widget_override":null},{"input_data":{"input_name":"Contents"},"widget_override":"hidden"},{"input_data":{"input_name":"Location","x":"X","y":"Y","unit":" px"},"widget_override":"vec2"},{"input_data":{"input_name":"Dimensions","unit":" px","x":"W","y":"H"},"widget_override":"vec2"},{"input_data":{"input_name":"Background"},"widget_override":"artboard_background"},{"input_data":{"input_name":"Clip"},"widget_override":null}],"output_names":["Out"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Absolute":[-8,3]}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-2,-3]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"To Artboard","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-10,-3]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Append Artboards","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[6,-4]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[6565638614909771142,{"persistent_metadata":{"reference":"Merge","display_name":"Mandelbrot Set","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":["Out"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Absolute":[-16,6]}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[3606681156406984991,{"persistent_metadata":{"reference":"Gradient Map","display_name":"","input_properties":[{"input_data":{"input_name":"Image"},"widget_override":null},{"input_data":{"input_name":"Gradient"},"widget_override":null},{"input_data":{"input_name":"Reverse"},"widget_override":null}],"output_names":["Image"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[80924370013313595,{"persistent_metadata":{"reference":"Gradient Map","display_name":"","input_properties":[{"input_data":{"input_name":"Image"},"widget_override":null},{"input_data":{"input_name":"Gradient"},"widget_override":null},{"input_data":{"input_name":"Reverse"},"widget_override":null}],"output_names":["Image"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[345.0,-187.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,1336.0,394.0],"node_graph_top_right":[1468.796875,0.0]},"selection_undo_history":[[12241147352993594415]],"selection_redo_history":[]}}},"collapsed":[],"name":"marbled-mandelbrot.graphite","commit_hash":"f6ffa45a8180183d70a67d3e41249934a8fcacc9","document_ptz":{"pan":[-339.3903349049215,-502.62390663267854],"tilt":0.0,"zoom":4.0,"flip":false},"document_mode":"DesignMode","view_mode":"Normal","overlays_visibility_settings":{"all":true,"artboard_name":true,"compass_rose":true,"quick_measurement":true,"transform_measurement":true,"transform_cage":true,"hover_outline":true,"selection_outline":true,"pivot":true,"path":true,"anchors":true,"handles":true},"rulers_visible":true,"snapping_state":{"snapping_enabled":true,"grid_snapping":false,"artboards":true,"tolerance":8.0,"bounding_box":{"center_point":true,"corner_point":true,"edge_midpoint":true,"align_with_edges":true,"distribute_evenly":true},"path":{"anchor_point":true,"line_midpoint":true,"along_path":true,"normal_to_path":true,"tangent_to_path":true,"path_intersection_point":true,"align_with_anchor_point":true,"perpendicular_from_endpoint":true},"grid":{"origin":[0.0,0.0],"grid_type":{"Rectangular":{"spacing":[1.0,1.0]}},"rectangular_spacing":[1.0,1.0],"isometric_y_spacing":1.0,"isometric_angle_a":30.0,"isometric_angle_b":30.0,"grid_color":{"red":0.6038274,"green":0.6038274,"blue":0.6038274,"alpha":1.0},"dot_display":false}},"graph_view_overlay_open":false,"graph_fade_artwork_percentage":80.0} \ No newline at end of file diff --git a/demo-artwork/painted-dreams.graphite b/demo-artwork/painted-dreams.graphite new file mode 100644 index 0000000000000000000000000000000000000000..f59f017b7359dfd266073cd11b9fc5faf827ae93 --- /dev/null +++ b/demo-artwork/painted-dreams.graphite @@ -0,0 +1 @@ +{"network_interface":{"network":{"exports":[{"Node":{"node_id":392274448837115448,"output_index":0,"lambda":false}}],"nodes":[[13353438235848911576,{"inputs":[{"Value":{"tagged_value":{"VectorData":{"instance":[{"style":{"stroke":{"color":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0},"weight":0.0,"dash_lengths":[],"dash_offset":0.0,"cap":"Butt","join":"Miter","join_miter_limit":4.0,"align":"Center","transform":[1.0,0.0,0.0,1.0,0.0,0.0],"non_scaling":false,"paint_order":"StrokeAbove"},"fill":"None"},"colinear_manipulators":[],"point_domain":{"id":[],"position":[]},"segment_domain":{"id":[],"start_point":[],"end_point":[],"handles":[],"stroke":[]},"region_domain":{"id":[],"segment_range":[],"fill":[]},"upstream_graphic_group":null}],"transform":[[1.0,0.0,0.0,1.0,0.0,0.0]],"alpha_blending":[{"blend_mode":"Normal","opacity":1.0,"fill":1.0,"clip":false}],"source_node_id":[null]}},"exposed":true}},{"Value":{"tagged_value":{"VectorModification":{"points":{"add":[6379137305818664393,18442321214082298093,18118267825025549699,6351696498298648253,17863574903157697896,4691860614575868200,301778328144628917,10625296323957562985,533731991408535384,13357220652574593654,15992617814592812350],"remove":[],"delta":[[6379137305818664393,[625.4814814814813,0.0]],[6351696498298648253,[646.8148148148149,0.0]],[301778328144628917,[493.5149940383244,200.29629629629628]],[13357220652574593654,[574.2222222222222,108.44444444444449]],[18442321214082298093,[565.6296296296297,122.96296296296298]],[10625296323957562985,[473.4814814814815,272.5925925925926]],[18118267825025549699,[642.0740740740741,0.0]],[4691860614575868200,[528.2962962962963,283.8518518518518]],[15992617814592812350,[621.0370370370368,0.0]],[17863574903157697896,[606.8148151308641,95.19407372365433]],[533731991408535384,[501.6296296296296,175.40740740740742]]]},"segments":{"add":[13662059715350867364,3384102572540409881,12035095010819582754,10146665273368938971,318560030360358929,8462655819889292900,3303411878775644985,8661113083384527971,2035327810332855521,11346538709718766144,3710133387837274291],"remove":[],"start_point":[[8462655819889292900,4691860614575868200],[10146665273368938971,6351696498298648253],[318560030360358929,17863574903157697896],[3303411878775644985,301778328144628917],[8661113083384527971,10625296323957562985],[11346538709718766144,13357220652574593654],[3384102572540409881,18442321214082298093],[2035327810332855521,533731991408535384],[13662059715350867364,6379137305818664393],[12035095010819582754,18118267825025549699],[3710133387837274291,15992617814592812350]],"end_point":[[11346538709718766144,15992617814592812350],[3384102572540409881,18118267825025549699],[12035095010819582754,6351696498298648253],[3303411878775644985,10625296323957562985],[2035327810332855521,13357220652574593654],[3710133387837274291,6379137305818664393],[318560030360358929,4691860614575868200],[8462655819889292900,301778328144628917],[8661113083384527971,533731991408535384],[10146665273368938971,17863574903157697896],[13662059715350867364,18442321214082298093]],"handle_primary":[[8661113083384527971,[0.2962962962963047,0.2962962962963047]],[8462655819889292900,[0.0,0.0]],[13662059715350867364,[0.0,0.0]],[3710133387837274291,[0.0,0.0]],[3384102572540409881,[0.0,0.0]],[11346538709718766144,[9.925839724176626,-9.951533978271286]],[318560030360358929,[-46.95465552079859,46.40007297527743]],[2035327810332855521,[42.96296296296293,-41.7777777777778]],[3303411878775644985,[0.0,0.0]],[12035095010819582754,[0.0,0.0]],[10146665273368938971,[0.0,0.0]]],"handle_end":[[3384102572540409881,[0.5807410754567854,77.36888852918523]],[10146665273368938971,[48.16592595101224,-47.597037061827145]],[11346538709718766144,[1.1377781018271662,63.71555518874077]],[12035095010819582754,[0.0,0.0]],[8462655819889292900,[-21.74426522093495,47.99999999999997]],[2035327810332855521,[-8.299214014278164,8.32069754812484]],[3710133387837274291,[0.0,0.0]],[318560030360358929,[-97.48148148148152,-81.18518518518522]],[8661113083384527971,[-42.34888386913234,41.180638796880466]],[3303411878775644985,[-6.2222222222222285,-40.59259259259261]],[13662059715350867364,[68.68148181185177,-54.8859262904691]]],"stroke":[[318560030360358929,0],[10146665273368938971,0],[3384102572540409881,0],[3303411878775644985,0],[2035327810332855521,0],[8462655819889292900,0],[12035095010819582754,0],[3710133387837274291,0],[11346538709718766144,0],[8661113083384527971,0],[13662059715350867364,0]]},"regions":{"add":[],"remove":[],"segment_range":[],"fill":[]},"add_g1_continuous":[[{"ty":"End","segment":8661113083384527971},{"ty":"Primary","segment":2035327810332855521}],[{"ty":"End","segment":12035095010819582754},{"ty":"Primary","segment":10146665273368938971}],[{"ty":"Primary","segment":11346538709718766144},{"ty":"End","segment":2035327810332855521}],[{"ty":"End","segment":10146665273368938971},{"ty":"Primary","segment":318560030360358929}]],"remove_g1_continuous":[]}},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::vector_data::modification::VectorModification","alias":null}},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::vector_data::modification::PathModifyNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[16671141883125519098,{"inputs":[{"Node":{"node_id":16306737306999003555,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"Fill":{"Solid":{"red":0.92156863,"green":0.6039216,"blue":0.18039216,"alpha":1.0}}},"exposed":false}},{"Value":{"tagged_value":{"OptionalColor":{"red":0.101960786,"green":0.13333334,"blue":0.13725491,"alpha":1.0}},"exposed":false}},{"Value":{"tagged_value":{"Gradient":{"stops":[[0.0,{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}],[1.0,{"red":1.0,"green":1.0,"blue":1.0,"alpha":1.0}]],"gradient_type":"Linear","start":[0.0,0.5],"end":[1.0,0.5],"transform":[1.0,0.0,0.0,1.0,0.0,0.0]}},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::FillNode"}},"visible":true,"skip_deduplication":false}],[6445954214067437701,{"inputs":[{"Node":{"node_id":13670206802546093234,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"BooleanOperation":"SubtractFront"},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::style::Fill","alias":null}},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_path_bool::BooleanOperationNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":2,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::BoundlessFootprintNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::FreezeRealTimeNode"}},"visible":true,"skip_deduplication":false}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MemoNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[140396870212231820,{"inputs":[{"Node":{"node_id":18095952297474762348,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"BooleanOperation":"Intersect"},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::style::Fill","alias":null}},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_path_bool::BooleanOperationNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":2,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::BoundlessFootprintNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::FreezeRealTimeNode"}},"visible":true,"skip_deduplication":false}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MemoNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[5449860184735415958,{"inputs":[{"Value":{"tagged_value":{"VectorData":{"instance":[{"style":{"stroke":{"color":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0},"weight":0.0,"dash_lengths":[],"dash_offset":0.0,"cap":"Butt","join":"Miter","join_miter_limit":4.0,"align":"Center","transform":[1.0,0.0,0.0,1.0,0.0,0.0],"non_scaling":false,"paint_order":"StrokeAbove"},"fill":"None"},"colinear_manipulators":[],"point_domain":{"id":[],"position":[]},"segment_domain":{"id":[],"start_point":[],"end_point":[],"handles":[],"stroke":[]},"region_domain":{"id":[],"segment_range":[],"fill":[]},"upstream_graphic_group":null}],"transform":[[1.0,0.0,0.0,1.0,0.0,0.0]],"alpha_blending":[{"blend_mode":"Normal","opacity":1.0,"fill":1.0,"clip":false}],"source_node_id":[null]}},"exposed":true}},{"Value":{"tagged_value":{"VectorModification":{"points":{"add":[17520941196305861319,6029995238423674441,16590926169549948521,12817219955590128894,4723170318056755559,12317789037775437786,17339925811006567497,4659274885664969740,1541401134848201833,17321098837874422287,11084016020553554647,9729762716079513741,13279221198527484331,7727030009292816503,15701538241214188894],"remove":[],"delta":[[13279221198527484331,[564.0,768.0]],[17339925811006567497,[898.0,468.0]],[12317789037775437786,[902.0,394.0]],[9729762716079513741,[585.0,666.0]],[15701538241214188894,[0.0,0.0]],[6029995238423674441,[898.0,46.0]],[11084016020553554647,[655.0,636.0]],[1541401134848201833,[886.0,572.0]],[16590926169549948521,[869.0,147.0]],[12817219955590128894,[933.0,273.0]],[4659274885664969740,[896.0,523.0]],[17321098837874422287,[802.6666666666667,656.4444444444445]],[17520941196305861319,[889.0,0.0]],[4723170318056755559,[923.0,349.0]],[7727030009292816503,[0.0,768.0]]]},"segments":{"add":[862900208337901235,4806484166818510930,11569179934425192262,9808624553037921371,9730229894941201870,1248401493076165062,8832757535144158913,15056691877609602335,8919277736361106420,16631919016540861133,9314952320711038398,10137845066833192587,14740183693208469558,3307452201570141575,3876401232874291775],"remove":[],"start_point":[[8919277736361106420,1541401134848201833],[15056691877609602335,4659274885664969740],[14740183693208469558,13279221198527484331],[16631919016540861133,17321098837874422287],[3307452201570141575,7727030009292816503],[11569179934425192262,16590926169549948521],[1248401493076165062,12317789037775437786],[3876401232874291775,15701538241214188894],[9808624553037921371,12817219955590128894],[9314952320711038398,11084016020553554647],[9730229894941201870,4723170318056755559],[862900208337901235,17520941196305861319],[4806484166818510930,6029995238423674441],[8832757535144158913,17339925811006567497],[10137845066833192587,9729762716079513741]],"end_point":[[9314952320711038398,9729762716079513741],[8832757535144158913,4659274885664969740],[9808624553037921371,4723170318056755559],[4806484166818510930,16590926169549948521],[862900208337901235,6029995238423674441],[1248401493076165062,17339925811006567497],[16631919016540861133,11084016020553554647],[14740183693208469558,7727030009292816503],[11569179934425192262,12817219955590128894],[3876401232874291775,17520941196305861319],[8919277736361106420,17321098837874422287],[10137845066833192587,13279221198527484331],[15056691877609602335,1541401134848201833],[3307452201570141575,15701538241214188894],[9730229894941201870,12317789037775437786]],"handle_primary":[[9808624553037921371,[18.0,36.0]],[14740183693208469558,[0.0,0.0]],[3307452201570141575,[0.0,0.0]],[11569179934425192262,[-4.0,51.0]],[8832757535144158913,[14.888888888888914,4.8888888888888005]],[15056691877609602335,[0.0,0.0]],[8919277736361106420,[10.458809984597837,40.44073194044492]],[16631919016540861133,[-63.996421719362885,-1.2074796550824587]],[3876401232874291775,[0.0,0.0]],[1248401493076165062,[21.0,27.0]],[9314952320711038398,[-34.0,-7.0]],[4806484166818510930,[11.595886737767424,32.210796493798]],[862900208337901235,[0.0,0.0]],[10137845066833192587,[-19.0,43.0]],[9730229894941201870,[-24.00371914417652,11.366922485048674]]],"handle_end":[[3876401232874291775,[0.0,0.0]],[862900208337901235,[-9.000000000000114,-25.0]],[8832757535144158913,[33.33333333333326,-9.666666666666742]],[9808624553037921371,[28.703703703703695,-13.592592592592496]],[9730229894941201870,[-21.0,-27.0]],[1248401493076165062,[30.59259259259261,-36.59259259259255]],[3307452201570141575,[0.0,0.0]],[16631919016540861133,[34.0,7.0]],[8919277736361106420,[70.66666666666652,1.333333333333485]],[10137845066833192587,[0.0,0.0]],[4806484166818510930,[3.365858386031487,-42.91469442190146]],[14740183693208469558,[0.0,0.0]],[9314952320711038398,[19.0,-43.0]],[15056691877609602335,[-10.0,-38.66666666666663]],[11569179934425192262,[-18.0,-36.0]]],"stroke":[[4806484166818510930,0],[14740183693208469558,0],[1248401493076165062,0],[3876401232874291775,0],[862900208337901235,0],[16631919016540861133,0],[11569179934425192262,0],[9314952320711038398,0],[8919277736361106420,0],[15056691877609602335,0],[8832757535144158913,0],[10137845066833192587,0],[9808624553037921371,0],[3307452201570141575,0],[9730229894941201870,0]]},"regions":{"add":[],"remove":[],"segment_range":[],"fill":[]},"add_g1_continuous":[[{"ty":"End","segment":9314952320711038398},{"ty":"Primary","segment":10137845066833192587}],[{"ty":"End","segment":8919277736361106420},{"ty":"Primary","segment":16631919016540861133}],[{"ty":"End","segment":9730229894941201870},{"ty":"Primary","segment":1248401493076165062}],[{"ty":"End","segment":3307452201570141575},{"ty":"Primary","segment":3876401232874291775}],[{"ty":"End","segment":4806484166818510930},{"ty":"Primary","segment":11569179934425192262}],[{"ty":"End","segment":9808624553037921371},{"ty":"Primary","segment":9730229894941201870}],[{"ty":"End","segment":10137845066833192587},{"ty":"Primary","segment":14740183693208469558}],[{"ty":"End","segment":11569179934425192262},{"ty":"Primary","segment":9808624553037921371}],[{"ty":"End","segment":16631919016540861133},{"ty":"Primary","segment":9314952320711038398}],[{"ty":"End","segment":862900208337901235},{"ty":"Primary","segment":4806484166818510930}],[{"ty":"End","segment":14740183693208469558},{"ty":"Primary","segment":3307452201570141575}],[{"ty":"End","segment":15056691877609602335},{"ty":"Primary","segment":8919277736361106420}]],"remove_g1_continuous":[[{"ty":"Primary","segment":8832757535144158913},{"ty":"End","segment":1248401493076165062}]]}},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::vector_data::modification::VectorModification","alias":null}},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::vector_data::modification::PathModifyNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[12709602171929957216,{"inputs":[{"Node":{"node_id":17753909951719808506,"output_index":0,"lambda":false}},{"Node":{"node_id":12922148192688274227,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[16609137733952262762,{"inputs":[{"Node":{"node_id":17397123104674848450,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"Fill":{"Solid":{"red":0.3137255,"green":0.44705883,"blue":0.45490196,"alpha":1.0}}},"exposed":false}},{"Value":{"tagged_value":{"OptionalColor":{"red":0.3137255,"green":0.44705883,"blue":0.45490196,"alpha":1.0}},"exposed":false}},{"Value":{"tagged_value":{"Gradient":{"stops":[[0.0,{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}],[1.0,{"red":1.0,"green":1.0,"blue":1.0,"alpha":1.0}]],"gradient_type":"Linear","start":[0.0,0.5],"end":[1.0,0.5],"transform":[1.0,0.0,0.0,1.0,0.0,0.0]}},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::FillNode"}},"visible":true,"skip_deduplication":false}],[7855094781869605606,{"inputs":[{"Node":{"node_id":14141479077115894852,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"BooleanOperation":"SubtractBack"},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::style::Fill","alias":null}},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_path_bool::BooleanOperationNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":2,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::BoundlessFootprintNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::FreezeRealTimeNode"}},"visible":true,"skip_deduplication":false}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MemoNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[8460565235419043665,{"inputs":[{"Node":{"node_id":3079923906392020295,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"DVec2":[0.0,412.1]},"exposed":false}},{"Value":{"tagged_value":{"F64":27.6},"exposed":false}},{"Value":{"tagged_value":{"U32":8},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::RepeatNode"}},"visible":true,"skip_deduplication":false}],[6194305264313730032,{"inputs":[{"Node":{"node_id":4560146526699152877,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"BooleanOperation":"Intersect"},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::style::Fill","alias":null}},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_path_bool::BooleanOperationNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":2,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::BoundlessFootprintNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::FreezeRealTimeNode"}},"visible":true,"skip_deduplication":false}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MemoNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[14950060858756810933,{"inputs":[{"Value":{"tagged_value":{"VectorData":{"instance":[{"style":{"stroke":{"color":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0},"weight":0.0,"dash_lengths":[],"dash_offset":0.0,"cap":"Butt","join":"Miter","join_miter_limit":4.0,"align":"Center","transform":[1.0,0.0,0.0,1.0,0.0,0.0],"non_scaling":false,"paint_order":"StrokeAbove"},"fill":"None"},"colinear_manipulators":[],"point_domain":{"id":[],"position":[]},"segment_domain":{"id":[],"start_point":[],"end_point":[],"handles":[],"stroke":[]},"region_domain":{"id":[],"segment_range":[],"fill":[]},"upstream_graphic_group":null}],"transform":[[1.0,0.0,0.0,1.0,0.0,0.0]],"alpha_blending":[{"blend_mode":"Normal","opacity":1.0,"fill":1.0,"clip":false}],"source_node_id":[null]}},"exposed":true}},{"Value":{"tagged_value":{"VectorModification":{"points":{"add":[9346093213164033195,3249248431686392864,9577388580635291078],"remove":[],"delta":[[3249248431686392864,[1536.0,95.0]],[9577388580635291078,[1536.0,0.0]],[9346093213164033195,[1211.0,0.0]]]},"segments":{"add":[9585086796709645600,13980191878100735848,1147165232046305110],"remove":[],"start_point":[[13980191878100735848,3249248431686392864],[1147165232046305110,9577388580635291078],[9585086796709645600,9346093213164033195]],"end_point":[[9585086796709645600,3249248431686392864],[13980191878100735848,9577388580635291078],[1147165232046305110,9346093213164033195]],"handle_primary":[[1147165232046305110,[0.0,0.0]],[13980191878100735848,[4.547473508864641e-13,2.8421709430404014e-14]],[9585086796709645600,[0.0,0.0]]],"handle_end":[[1147165232046305110,[0.0,0.0]],[13980191878100735848,[0.0,0.0]],[9585086796709645600,[-281.0,-17.00000000000003]]],"stroke":[[13980191878100735848,0],[1147165232046305110,0],[9585086796709645600,0]]},"regions":{"add":[],"remove":[],"segment_range":[],"fill":[]},"add_g1_continuous":[[{"ty":"End","segment":13980191878100735848},{"ty":"Primary","segment":1147165232046305110}]],"remove_g1_continuous":[]}},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::vector_data::modification::VectorModification","alias":null}},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::vector_data::modification::PathModifyNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[14698962747138962125,{"inputs":[{"Node":{"node_id":17562801632450633291,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"BooleanOperation":"Intersect"},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::style::Fill","alias":null}},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_path_bool::BooleanOperationNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":2,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::BoundlessFootprintNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::FreezeRealTimeNode"}},"visible":true,"skip_deduplication":false}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MemoNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[18031616785650843168,{"inputs":[{"Node":{"node_id":17952673493105230490,"output_index":0,"lambda":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::SolidifyStrokeNode"}},"visible":true,"skip_deduplication":false}],[11196821089257149774,{"inputs":[{"Node":{"node_id":5888633415105234509,"output_index":0,"lambda":false}},{"Node":{"node_id":18031616785650843168,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[8359580532088731394,{"inputs":[{"Node":{"node_id":6726954210929537972,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"Fill":{"Solid":{"red":0.101960786,"green":0.13333334,"blue":0.13725491,"alpha":1.0}}},"exposed":false}},{"Value":{"tagged_value":{"OptionalColor":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}},"exposed":false}},{"Value":{"tagged_value":{"Gradient":{"stops":[[0.0,{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}],[1.0,{"red":1.0,"green":1.0,"blue":1.0,"alpha":1.0}]],"gradient_type":"Linear","start":[0.0,0.5],"end":[1.0,0.5],"transform":[1.0,0.0,0.0,1.0,0.0,0.0]}},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::FillNode"}},"visible":true,"skip_deduplication":false}],[8269257328703012432,{"inputs":[{"Node":{"node_id":4102754869474520966,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"Fill":{"Solid":{"red":0.92156863,"green":0.6039216,"blue":0.18039216,"alpha":1.0}}},"exposed":false}},{"Value":{"tagged_value":{"OptionalColor":{"red":0.92156863,"green":0.6039216,"blue":0.18039216,"alpha":1.0}},"exposed":false}},{"Value":{"tagged_value":{"Gradient":{"stops":[[0.0,{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}],[1.0,{"red":1.0,"green":1.0,"blue":1.0,"alpha":1.0}]],"gradient_type":"Linear","start":[0.0,0.5],"end":[1.0,0.5],"transform":[1.0,0.0,0.0,1.0,0.0,0.0]}},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::FillNode"}},"visible":true,"skip_deduplication":false}],[13203761224559198689,{"inputs":[{"Node":{"node_id":4809200889774783438,"output_index":0,"lambda":false}},{"Node":{"node_id":14690269209726153565,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[13670206802546093234,{"inputs":[{"Node":{"node_id":17285637344898461972,"output_index":0,"lambda":false}},{"Node":{"node_id":7855094781869605606,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[7201841978411396053,{"inputs":[{"Node":{"node_id":4328376070224119511,"output_index":0,"lambda":false}},{"Node":{"node_id":17735408893002232096,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[11429506195623419966,{"inputs":[{"Node":{"node_id":11301831865756336526,"output_index":0,"lambda":false}},{"Node":{"node_id":5449860184735415958,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[9071802450034150503,{"inputs":[{"Node":{"node_id":9338394475379815879,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"Fill":{"Solid":{"red":1.0,"green":1.0,"blue":1.0,"alpha":1.0}}},"exposed":false}},{"Value":{"tagged_value":{"OptionalColor":{"red":1.0,"green":1.0,"blue":1.0,"alpha":1.0}},"exposed":false}},{"Value":{"tagged_value":{"Gradient":{"stops":[[0.0,{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}],[1.0,{"red":1.0,"green":1.0,"blue":1.0,"alpha":1.0}]],"gradient_type":"Linear","start":[0.0,0.5],"end":[1.0,0.5],"transform":[1.0,0.0,0.0,1.0,0.0,0.0]}},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::FillNode"}},"visible":true,"skip_deduplication":false}],[10063704933309776584,{"inputs":[{"Node":{"node_id":13838011362258067867,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"F64":-1.0},"exposed":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_math_nodes::MultiplyNode"}},"visible":true,"skip_deduplication":false}],[3608604157153838227,{"inputs":[{"Node":{"node_id":17299978721726771610,"output_index":0,"lambda":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::BoundingBoxNode"}},"visible":true,"skip_deduplication":false}],[12185047359007423618,{"inputs":[{"Node":{"node_id":10080296672372912698,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"Fill":{"Solid":{"red":0.3137255,"green":0.44705883,"blue":0.45490196,"alpha":1.0}}},"exposed":false}},{"Value":{"tagged_value":{"OptionalColor":{"red":0.92156863,"green":0.6039216,"blue":0.18039216,"alpha":1.0}},"exposed":false}},{"Value":{"tagged_value":{"Gradient":{"stops":[[0.0,{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}],[1.0,{"red":1.0,"green":1.0,"blue":1.0,"alpha":1.0}]],"gradient_type":"Linear","start":[0.0,0.5],"end":[1.0,0.5],"transform":[1.0,0.0,0.0,1.0,0.0,0.0]}},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::FillNode"}},"visible":true,"skip_deduplication":false}],[7018444885869143173,{"inputs":[{"Node":{"node_id":12234961922142600898,"output_index":0,"lambda":false}},{"Node":{"node_id":8426490990601560741,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[1001728975241745659,{"inputs":[{"Node":{"node_id":12770183061753030023,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"BooleanOperation":"Intersect"},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::style::Fill","alias":null}},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_path_bool::BooleanOperationNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":2,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::BoundlessFootprintNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::FreezeRealTimeNode"}},"visible":true,"skip_deduplication":false}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MemoNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[392274448837115448,{"inputs":[{"Value":{"tagged_value":{"ArtboardGroup":{"instance":[],"transform":[],"alpha_blending":[],"source_node_id":[]}},"exposed":true}},{"Node":{"node_id":6787585796949551500,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"IVec2":[0,0]},"exposed":false}},{"Value":{"tagged_value":{"IVec2":[1536,768]},"exposed":false}},{"Value":{"tagged_value":{"Color":{"red":0.93333334,"green":0.8627451,"blue":0.7254902,"alpha":1.0}},"exposed":false}},{"Value":{"tagged_value":{"Bool":true},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":2,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graph_craft::document::value::TaggedValue","alias":null}},"import_index":1}},{"Value":{"tagged_value":{"String":"Artboard"},"exposed":false}},{"Network":{"import_type":{"Concrete":{"name":"graph_craft::document::value::TaggedValue","alias":null}},"import_index":2}},{"Network":{"import_type":{"Concrete":{"name":"graph_craft::document::value::TaggedValue","alias":null}},"import_index":3}},{"Network":{"import_type":{"Concrete":{"name":"graph_craft::document::value::TaggedValue","alias":null}},"import_index":4}},{"Network":{"import_type":{"Concrete":{"name":"graph_craft::document::value::TaggedValue","alias":null}},"import_index":5}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToArtboardNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Network":{"import_type":{"Fn":[{"Concrete":{"name":"core::option::Option>","alias":null}},{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}}]},"import_index":0}},{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::AppendArtboardNode"}},"visible":true,"skip_deduplication":false}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[17562801632450633291,{"inputs":[{"Node":{"node_id":10286817149456341619,"output_index":0,"lambda":false}},{"Node":{"node_id":5449860184735415958,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[3750439930725791025,{"inputs":[{"Node":{"node_id":12276520439585231336,"output_index":0,"lambda":false}},{"Node":{"node_id":14228923746783465609,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[682567808439406093,{"inputs":[{"Node":{"node_id":7755499790391969923,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"DVec2":[300.0,50.0]},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"U32":15},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::RepeatNode"}},"visible":true,"skip_deduplication":false}],[17740294143355019755,{"inputs":[{"Node":{"node_id":15301503532602557206,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"Fill":{"Solid":{"red":0.101960786,"green":0.13333334,"blue":0.13725491,"alpha":1.0}}},"exposed":false}},{"Value":{"tagged_value":{"OptionalColor":{"red":0.101960786,"green":0.13333334,"blue":0.13725491,"alpha":1.0}},"exposed":false}},{"Value":{"tagged_value":{"Gradient":{"stops":[[0.0,{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}],[1.0,{"red":1.0,"green":1.0,"blue":1.0,"alpha":1.0}]],"gradient_type":"Linear","start":[0.0,0.5],"end":[1.0,0.5],"transform":[1.0,0.0,0.0,1.0,0.0,0.0]}},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::FillNode"}},"visible":true,"skip_deduplication":false}],[16759836951269190891,{"inputs":[{"Node":{"node_id":11429506195623419966,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"BooleanOperation":"Intersect"},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::style::Fill","alias":null}},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_path_bool::BooleanOperationNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":2,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::BoundlessFootprintNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::FreezeRealTimeNode"}},"visible":true,"skip_deduplication":false}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MemoNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[17495267820524300686,{"inputs":[{"Node":{"node_id":13616602029989984195,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"DVec2":[1248.4973005620557,-153.1867628889006]},"exposed":false}},{"Value":{"tagged_value":{"F64":0.2972951295167027},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[1.0000000000000002,1.0000000000000002]},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[5.5511151231257815e-17,0.0]},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[0.5,0.5]},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":1}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":2}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":3}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":4}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":5}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::TransformNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[12234961922142600898,{"inputs":[{"Node":{"node_id":1627123781166851142,"output_index":0,"lambda":false}},{"Node":{"node_id":18351415092709164412,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[11095670964487764044,{"inputs":[{"Node":{"node_id":17603523494627491590,"output_index":0,"lambda":false}},{"Node":{"node_id":8359580532088731394,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[11301831865756336526,{"inputs":[{"Value":{"tagged_value":{"VectorData":{"instance":[{"style":{"stroke":{"color":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0},"weight":0.0,"dash_lengths":[],"dash_offset":0.0,"cap":"Butt","join":"Miter","join_miter_limit":4.0,"align":"Center","transform":[1.0,0.0,0.0,1.0,0.0,0.0],"non_scaling":false,"paint_order":"StrokeAbove"},"fill":"None"},"colinear_manipulators":[],"point_domain":{"id":[],"position":[]},"segment_domain":{"id":[],"start_point":[],"end_point":[],"handles":[],"stroke":[]},"region_domain":{"id":[],"segment_range":[],"fill":[]},"upstream_graphic_group":null}],"transform":[[1.0,0.0,0.0,1.0,0.0,0.0]],"alpha_blending":[{"blend_mode":"Normal","opacity":1.0,"fill":1.0,"clip":false}],"source_node_id":[null]}},"exposed":true}},{"Value":{"tagged_value":{"VectorModification":{"points":{"add":[3251241957527197760,11100418327549747778,8048619563638005414,1078998931754662073],"remove":[],"delta":[[1078998931754662073,[942.0246913580248,264.2962962962963]],[3251241957527197760,[875.8001811251517,185.6784024477276]],[11100418327549747778,[910.880658436214,243.0946502057613]],[8048619563638005414,[944.0577392578124,302.0703430175781]]]},"segments":{"add":[6165219920202055745,10795897848378052161,3439025775805007707,12551435438068218604],"remove":[],"start_point":[[6165219920202055745,3251241957527197760],[3439025775805007707,8048619563638005414],[10795897848378052161,11100418327549747778],[12551435438068218604,1078998931754662073]],"end_point":[[3439025775805007707,1078998931754662073],[12551435438068218604,3251241957527197760],[6165219920202055745,11100418327549747778],[10795897848378052161,8048619563638005414]],"handle_primary":[[3439025775805007707,[-2.629814161991817e-6,5.151861046215345e-6]],[10795897848378052161,[11.46027223334628,13.82427457744465]],[12551435438068218604,[-14.61728395061732,-27.456790123456813]],[6165219920202055745,[0.0,0.0]]],"handle_end":[[12551435438068218604,[23.33217876876199,5.204454965879364]],[6165219920202055745,[-29.36625514403283,-35.42386831275718]],[3439025775805007707,[14.61728395061732,27.456790123456813]],[10795897848378052161,[-4.732636377154108,-19.33783272951229]]],"stroke":[[12551435438068218604,0],[6165219920202055745,0],[10795897848378052161,0],[3439025775805007707,0]]},"regions":{"add":[],"remove":[],"segment_range":[],"fill":[]},"add_g1_continuous":[[{"ty":"End","segment":6165219920202055745},{"ty":"Primary","segment":10795897848378052161}],[{"ty":"End","segment":3439025775805007707},{"ty":"Primary","segment":12551435438068218604}]],"remove_g1_continuous":[]}},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::vector_data::modification::VectorModification","alias":null}},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::vector_data::modification::PathModifyNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[15301503532602557206,{"inputs":[{"Node":{"node_id":6728362629909402903,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"BooleanOperation":"Intersect"},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::style::Fill","alias":null}},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_path_bool::BooleanOperationNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":2,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::BoundlessFootprintNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::FreezeRealTimeNode"}},"visible":true,"skip_deduplication":false}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MemoNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[6787585796949551500,{"inputs":[{"Node":{"node_id":11095670964487764044,"output_index":0,"lambda":false}},{"Node":{"node_id":16177422101884031678,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[18003287685830153881,{"inputs":[{"Value":{"tagged_value":{"VectorData":{"instance":[{"style":{"stroke":{"color":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0},"weight":0.0,"dash_lengths":[],"dash_offset":0.0,"cap":"Butt","join":"Miter","join_miter_limit":4.0,"align":"Center","transform":[1.0,0.0,0.0,1.0,0.0,0.0],"non_scaling":false,"paint_order":"StrokeAbove"},"fill":"None"},"colinear_manipulators":[],"point_domain":{"id":[],"position":[]},"segment_domain":{"id":[],"start_point":[],"end_point":[],"handles":[],"stroke":[]},"region_domain":{"id":[],"segment_range":[],"fill":[]},"upstream_graphic_group":null}],"transform":[[1.0,0.0,0.0,1.0,0.0,0.0]],"alpha_blending":[{"blend_mode":"Normal","opacity":1.0,"fill":1.0,"clip":false}],"source_node_id":[null]}},"exposed":true}},{"Value":{"tagged_value":{"VectorModification":{"points":{"add":[4475009837548700636,4481635366652149569,1608608093193158603,4765910415851982345],"remove":[1647009925892902058],"delta":[[4481635366652149569,[684.8888888888889,395.55555555555554]],[4765910415851982345,[283.33331298828125,354.6666564941406]],[1608608093193158603,[609.7777777777777,620.0]],[4475009837548700636,[525.7325506063205,282.1042056224195]]]},"segments":{"add":[3045825504718908919,8024777209266880257,3983292299330016176,11103925991989272298],"remove":[13489289770112164650],"start_point":[[3983292299330016176,1608608093193158603],[11103925991989272298,4765910415851982345],[3045825504718908919,4475009837548700636],[8024777209266880257,4481635366652149569]],"end_point":[[8024777209266880257,1608608093193158603],[11103925991989272298,4475009837548700636],[3045825504718908919,4481635366652149569],[3983292299330016176,4765910415851982345]],"handle_primary":[[3045825504718908919,[62.22222222222217,43.111111111111086]],[3983292299330016176,[0.0,0.0]],[11103925991989272298,[0.0,0.0]],[8024777209266880257,[11.111111111111086,62.22222222222217]]],"handle_end":[[11103925991989272298,[-113.5844024581724,39.08097956276566]],[8024777209266880257,[34.66666666666674,-85.33333333333337]],[3045825504718908919,[-11.111111111111086,-62.22222222222217]],[3983292299330016176,[0.0,0.0]]],"stroke":[[11103925991989272298,0],[8024777209266880257,0],[3045825504718908919,0],[3983292299330016176,0]]},"regions":{"add":[],"remove":[],"segment_range":[],"fill":[]},"add_g1_continuous":[[{"ty":"End","segment":3045825504718908919},{"ty":"Primary","segment":8024777209266880257}],[{"ty":"End","segment":3983292299330016176},{"ty":"Primary","segment":11103925991989272298}]],"remove_g1_continuous":[[{"ty":"End","segment":11103925991989272298},{"ty":"Primary","segment":3045825504718908919}],[{"ty":"End","segment":13489289770112164650},{"ty":"Primary","segment":3045825504718908919}]]}},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::vector_data::modification::VectorModification","alias":null}},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::vector_data::modification::PathModifyNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[12770183061753030023,{"inputs":[{"Node":{"node_id":17495267820524300686,"output_index":0,"lambda":false}},{"Node":{"node_id":1009114585722052052,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[17299978721726771610,{"inputs":[{"Node":{"node_id":7029437790788498388,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"DVec2":[459.4,0.0]},"exposed":false}},{"Value":{"tagged_value":{"F64":-8.6},"exposed":false}},{"Value":{"tagged_value":{"U32":5},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::RepeatNode"}},"visible":true,"skip_deduplication":false}],[9135110142507605216,{"inputs":[{"Node":{"node_id":11196821089257149774,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"BooleanOperation":"SubtractFront"},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::style::Fill","alias":null}},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_path_bool::BooleanOperationNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":2,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::BoundlessFootprintNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::FreezeRealTimeNode"}},"visible":true,"skip_deduplication":false}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MemoNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[7104261880154687267,{"inputs":[{"Node":{"node_id":2834866505092039323,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"BooleanOperation":"Intersect"},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::style::Fill","alias":null}},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_path_bool::BooleanOperationNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":2,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::BoundlessFootprintNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::FreezeRealTimeNode"}},"visible":true,"skip_deduplication":false}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MemoNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[18271512507682813443,{"inputs":[{"Value":{"tagged_value":{"VectorData":{"instance":[{"style":{"stroke":{"color":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0},"weight":0.0,"dash_lengths":[],"dash_offset":0.0,"cap":"Butt","join":"Miter","join_miter_limit":4.0,"align":"Center","transform":[1.0,0.0,0.0,1.0,0.0,0.0],"non_scaling":false,"paint_order":"StrokeAbove"},"fill":"None"},"colinear_manipulators":[],"point_domain":{"id":[],"position":[]},"segment_domain":{"id":[],"start_point":[],"end_point":[],"handles":[],"stroke":[]},"region_domain":{"id":[],"segment_range":[],"fill":[]},"upstream_graphic_group":null}],"transform":[[1.0,0.0,0.0,1.0,0.0,0.0]],"alpha_blending":[{"blend_mode":"Normal","opacity":1.0,"fill":1.0,"clip":false}],"source_node_id":[null]}},"exposed":true}},{"Value":{"tagged_value":{"VectorModification":{"points":{"add":[10872099980755217048,13049263474526562389,2409359561719399794,9175973472325454282,14263506369487797530,5496457317579994340,7125168137854779179,9658821733796680583,425878374398720476,5252668597335249558],"remove":[],"delta":[[2409359561719399794,[892.7407407407408,111.70370370370372]],[5252668597335249558,[888.2516734908237,208.88931872324497]],[10872099980755217048,[889.0,0.0]],[9175973472325454282,[881.4814814814815,152.5925925925926]],[7125168137854779179,[912.2962962962964,205.6296296296296]],[14263506369487797530,[886.5185185185185,178.66666666666669]],[9658821733796680583,[920.5925925925926,208.0]],[425878374398720476,[898.633744855967,207.99999999999997]],[13049263474526562389,[903.1111111111112,55.70370370370371]],[5496457317579994340,[929.3607681755832,198.40877914951983]]]},"segments":{"add":[16241193756011776206,13961346931609713434,6443321953815072406,13223251807271379465,6545223889678917273,9745298522639115232,8058164935346100149,9187894839116405225,5210886161307886529,11050813873332011119],"remove":[],"start_point":[[16241193756011776206,10872099980755217048],[13961346931609713434,13049263474526562389],[6545223889678917273,14263506369487797530],[11050813873332011119,5252668597335249558],[8058164935346100149,7125168137854779179],[13223251807271379465,9175973472325454282],[6443321953815072406,2409359561719399794],[9187894839116405225,9658821733796680583],[9745298522639115232,5496457317579994340],[5210886161307886529,425878374398720476]],"end_point":[[5210886161307886529,5252668597335249558],[8058164935346100149,9658821733796680583],[6545223889678917273,5496457317579994340],[13961346931609713434,2409359561719399794],[6443321953815072406,9175973472325454282],[16241193756011776206,13049263474526562389],[11050813873332011119,10872099980755217048],[9745298522639115232,7125168137854779179],[13223251807271379465,14263506369487797530],[9187894839116405225,425878374398720476]],"handle_primary":[[13223251807271379465,[3.2812071330587287,8.329218106995853]],[5210886161307886529,[-1.1368683772161605e-13,-2.8421709430404014e-14]],[9187894839116405225,[-8.263374485596842,1.880201188843188]],[6443321953815072406,[-9.144953020396894,24.145964868041293]],[13961346931609713434,[6.522611384544012,17.67970980547415]],[9745298522639115232,[0.0,0.0]],[6545223889678917273,[0.0,0.0]],[8058164935346100149,[0.0,0.0]],[16241193756011776206,[0.0,0.0]],[11050813873332011119,[-5.947146741852521,-2.1403475298293415]]],"handle_end":[[5210886161307886529,[5.947146741852521,2.1403475298293415]],[6545223889678917273,[-25.3424782807499,-1.3461362597164737]],[9187894839116405225,[4.974851394604343,2.0557841792410443]],[11050813873332011119,[-86.26684502769479,250.37037037037035]],[8058164935346100149,[-5.925925925925867,-2.370370370370381]],[9745298522639115232,[7.703703703703695,-2.074074074074076]],[16241193756011776206,[-7.506172839506348,-20.345679012345684]],[6443321953815072406,[-3.3276401397055917,-8.447086508484054]],[13961346931609713434,[10.984910836762538,-29.00411522633746]],[13223251807271379465,[0.7901234567900701,-9.492455418381354]]],"stroke":[[6443321953815072406,0],[11050813873332011119,0],[9187894839116405225,0],[13961346931609713434,0],[13223251807271379465,0],[6545223889678917273,0],[9745298522639115232,0],[16241193756011776206,0],[8058164935346100149,0],[5210886161307886529,0]]},"regions":{"add":[],"remove":[],"segment_range":[],"fill":[]},"add_g1_continuous":[[{"ty":"End","segment":16241193756011776206},{"ty":"Primary","segment":13961346931609713434}],[{"ty":"End","segment":13961346931609713434},{"ty":"Primary","segment":6443321953815072406}],[{"ty":"End","segment":5210886161307886529},{"ty":"Primary","segment":11050813873332011119}],[{"ty":"End","segment":6443321953815072406},{"ty":"Primary","segment":13223251807271379465}]],"remove_g1_continuous":[[{"ty":"Primary","segment":9187894839116405225},{"ty":"End","segment":8058164935346100149}]]}},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::vector_data::modification::VectorModification","alias":null}},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::vector_data::modification::PathModifyNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[8511737864852441844,{"inputs":[{"Value":{"tagged_value":"None","exposed":false}},{"Value":{"tagged_value":{"F64":5.0},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::generator_nodes::CircleNode"}},"visible":true,"skip_deduplication":false}],[17696051535511578981,{"inputs":[{"Node":{"node_id":16780039553038473906,"output_index":0,"lambda":false}},{"Node":{"node_id":9071802450034150503,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[10286817149456341619,{"inputs":[{"Value":{"tagged_value":{"VectorData":{"instance":[{"style":{"stroke":{"color":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0},"weight":0.0,"dash_lengths":[],"dash_offset":0.0,"cap":"Butt","join":"Miter","join_miter_limit":4.0,"align":"Center","transform":[1.0,0.0,0.0,1.0,0.0,0.0],"non_scaling":false,"paint_order":"StrokeAbove"},"fill":"None"},"colinear_manipulators":[],"point_domain":{"id":[],"position":[]},"segment_domain":{"id":[],"start_point":[],"end_point":[],"handles":[],"stroke":[]},"region_domain":{"id":[],"segment_range":[],"fill":[]},"upstream_graphic_group":null}],"transform":[[1.0,0.0,0.0,1.0,0.0,0.0]],"alpha_blending":[{"blend_mode":"Normal","opacity":1.0,"fill":1.0,"clip":false}],"source_node_id":[null]}},"exposed":true}},{"Value":{"tagged_value":{"VectorModification":{"points":{"add":[10786213048155734586,12599396287665855262,6164201091766276213,6781153531246981076,15695128662656633322,8241402276734357681,10333377922713208038,3749627916562964805,2535476870476707501],"remove":[],"delta":[[3749627916562964805,[866.172839506173,558.2222222222224]],[8241402276734357681,[853.3333333333336,529.1851851851854]],[10786213048155734586,[917.7283950617284,502.91358024691374]],[10333377922713208038,[843.4567901234569,550.1234567901236]],[6164201091766276213,[902.9135802469136,506.8641975308643]],[2535476870476707501,[887.5061728395062,568.6913580246915]],[12599396287665855262,[902.5185185185188,498.56790123456807]],[15695128662656633322,[825.6790123456792,509.4320987654323]],[6781153531246981076,[872.6913580246915,513.7777777777779]]]},"segments":{"add":[15700595221504820396,6369399239389505343,17761347836385237495,3021925106447084698,14489254209548096966,3461110970422306113,14847678502054094837,14515109677644612103,264894972572137143],"remove":[],"start_point":[[264894972572137143,2535476870476707501],[17761347836385237495,6164201091766276213],[3461110970422306113,8241402276734357681],[6369399239389505343,12599396287665855262],[14847678502054094837,10333377922713208038],[14489254209548096966,15695128662656633322],[14515109677644612103,3749627916562964805],[3021925106447084698,6781153531246981076],[15700595221504820396,10786213048155734586]],"end_point":[[6369399239389505343,6164201091766276213],[17761347836385237495,6781153531246981076],[14515109677644612103,2535476870476707501],[3021925106447084698,15695128662656633322],[264894972572137143,10786213048155734586],[14847678502054094837,3749627916562964805],[14489254209548096966,8241402276734357681],[3461110970422306113,10333377922713208038],[15700595221504820396,12599396287665855262]],"handle_primary":[[264894972572137143,[0.0,0.0]],[6369399239389505343,[-7.1111111111111995,-5.530864197530889]],[17761347836385237495,[0.0,0.0]],[14847678502054094837,[0.7901234567900701,2.765432098765473]],[14489254209548096966,[-0.3950434518873181,1.0617032941893854]],[14515109677644612103,[8.888888888888914,0.0]],[15700595221504820396,[0.0,0.0]],[3461110970422306113,[0.38915905346209456,1.493515242756871]],[3021925106447084698,[-16.59259259259261,2.370370370370324]]],"handle_end":[[14489254209548096966,[-0.5712718875797691,-2.192428171126153]],[14515109677644612103,[0.0,0.0]],[17761347836385237495,[16.59259259259261,-2.370370370370324]],[264894972572137143,[3.753086419753003,37.1358024691358]],[3461110970422306113,[-0.7901234567900701,-2.765432098765473]],[14847678502054094837,[-8.888888888888914,0.0]],[6369399239389505343,[0.0,0.0]],[15700595221504820396,[7.1111111111111995,5.530864197530889]],[3021925106447084698,[0.5488119028742631,-1.474965354794051]]],"stroke":[[3461110970422306113,0],[14847678502054094837,0],[15700595221504820396,0],[3021925106447084698,0],[6369399239389505343,0],[14515109677644612103,0],[264894972572137143,0],[17761347836385237495,0],[14489254209548096966,0]]},"regions":{"add":[],"remove":[],"segment_range":[],"fill":[]},"add_g1_continuous":[[{"ty":"End","segment":14489254209548096966},{"ty":"Primary","segment":3461110970422306113}],[{"ty":"End","segment":14515109677644612103},{"ty":"Primary","segment":264894972572137143}],[{"ty":"End","segment":3021925106447084698},{"ty":"Primary","segment":14489254209548096966}],[{"ty":"End","segment":15700595221504820396},{"ty":"Primary","segment":6369399239389505343}],[{"ty":"End","segment":14847678502054094837},{"ty":"Primary","segment":14515109677644612103}],[{"ty":"End","segment":17761347836385237495},{"ty":"Primary","segment":3021925106447084698}],[{"ty":"End","segment":3461110970422306113},{"ty":"Primary","segment":14847678502054094837}],[{"ty":"End","segment":6369399239389505343},{"ty":"Primary","segment":17761347836385237495}]],"remove_g1_continuous":[]}},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::vector_data::modification::VectorModification","alias":null}},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::vector_data::modification::PathModifyNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[6726954210929537972,{"inputs":[{"Value":{"tagged_value":{"VectorData":{"instance":[{"style":{"stroke":{"color":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0},"weight":0.0,"dash_lengths":[],"dash_offset":0.0,"cap":"Butt","join":"Miter","join_miter_limit":4.0,"align":"Center","transform":[1.0,0.0,0.0,1.0,0.0,0.0],"non_scaling":false,"paint_order":"StrokeAbove"},"fill":"None"},"colinear_manipulators":[],"point_domain":{"id":[],"position":[]},"segment_domain":{"id":[],"start_point":[],"end_point":[],"handles":[],"stroke":[]},"region_domain":{"id":[],"segment_range":[],"fill":[]},"upstream_graphic_group":null}],"transform":[[1.0,0.0,0.0,1.0,0.0,0.0]],"alpha_blending":[{"blend_mode":"Normal","opacity":1.0,"fill":1.0,"clip":false}],"source_node_id":[null]}},"exposed":true}},{"Value":{"tagged_value":{"VectorModification":{"points":{"add":[177515045030371783,4609870404630548899,1458337690478625792,16230687409600568539,8055802412900565217,12390708657704154619,12909592102393222573,6873550371723398444,13416153271806375161,2492294980235986276,12448133448335459077,7624137673235413199],"remove":[],"delta":[[177515045030371783,[604.2883706752018,0.0]],[13416153271806375161,[531.8518518518517,131.2592592592593]],[7624137673235413199,[617.8765432098766,2.465190328815662e-32]],[12390708657704154619,[596.6748971193416,72.42798353909465]],[2492294980235986276,[604.4434936307387,42.970116997735616]],[4609870404630548899,[589.432098765432,64.79012345679011]],[6873550371723398444,[538.6666666666667,136.0]],[16230687409600568539,[491.55555555555554,311.55555555555566]],[1458337690478625792,[473.1851851851851,213.62962962962965]],[8055802412900565217,[480.4444444444445,219.7777777777778]],[12448133448335459077,[610.3703703703706,2.4308653429145085e-63]],[12909592102393222573,[607.8024691358027,0.0]]]},"segments":{"add":[12529947318087068663,5578827639764758986,1705877195608053135,2463526518527501592,9361245670457788924,921651403153242564,9825559201153691780,15749222431214672690,14294722277069184337,4341232355541306629,3818841110886669992],"remove":[5057709998225566481,16939098306153440303,17799038492181728804,17843645051722826880,11060716078587457450],"start_point":[[9361245670457788924,6873550371723398444],[14294722277069184337,12448133448335459077],[2463526518527501592,8055802412900565217],[12529947318087068663,177515045030371783],[9825559201153691780,13416153271806375161],[4341232355541306629,12390708657704154619],[921651403153242564,4609870404630548899],[5578827639764758986,1458337690478625792],[15749222431214672690,2492294980235986276],[3818841110886669992,7624137673235413199],[1705877195608053135,16230687409600568539]],"end_point":[[1705877195608053135,8055802412900565217],[921651403153242564,13416153271806375161],[5578827639764758986,16230687409600568539],[9361245670457788924,12390708657704154619],[9825559201153691780,1458337690478625792],[14294722277069184337,2492294980235986276],[12529947318087068663,4609870404630548899],[3818841110886669992,12448133448335459077],[2463526518527501592,6873550371723398444],[4341232355541306629,7624137673235413199],[15749222431214672690,12909592102393222573]],"handle_primary":[[14294722277069184337,[-0.2633744855968416,28.576131687242796]],[9825559201153691780,[-30.00610951685011,28.39287782239575]],[1705877195608053135,[0.0,0.0]],[3818841110886669992,[0.0,0.0]],[5578827639764758986,[-19.25925925925924,60.44444444444443]],[2463526518527501592,[9.74414620103056,-24.528368023283747]],[12529947318087068663,[0.0,0.0]],[921651403153242564,[-7.513106110924076,12.956274823940417]],[15749222431214672690,[3.877242131088792,-22.333682252383095]],[9361245670457788924,[22.844654233974516,-21.876660410500975]],[4341232355541306629,[19.753086419753117,-26.73251028806584]]],"handle_end":[[921651403153242564,[27.555555555555657,-26.07407407407412]],[9361245670457788924,[-16.14969885498249,21.855925783742933]],[1705877195608053135,[-19.33333333333331,48.66666666666666]],[14294722277069184337,[0.0,0.0]],[12529947318087068663,[12.90534979423876,-22.255144032921805]],[5578827639764758986,[0.0,0.0]],[2463526518527501592,[-34.96296296296305,33.481481481481495]],[9825559201153691780,[6.194184133897295,-19.440208666385132]],[15749222431214672690,[0.0,0.0]],[4341232355541306629,[0.0,0.0]],[3818841110886669992,[0.0,0.0]]],"stroke":[[9361245670457788924,0],[2463526518527501592,0],[921651403153242564,0],[1705877195608053135,0],[4341232355541306629,0],[15749222431214672690,0],[14294722277069184337,0],[3818841110886669992,0],[12529947318087068663,0],[5578827639764758986,0],[9825559201153691780,0]]},"regions":{"add":[],"remove":[],"segment_range":[],"fill":[]},"add_g1_continuous":[[{"ty":"End","segment":9361245670457788924},{"ty":"Primary","segment":17843645051722826880}],[{"ty":"Primary","segment":5578827639764758986},{"ty":"End","segment":9825559201153691780}],[{"ty":"Primary","segment":16939098306153440303},{"ty":"End","segment":9361245670457788924}],[{"ty":"End","segment":12529947318087068663},{"ty":"Primary","segment":921651403153242564}],[{"ty":"End","segment":17843645051722826880},{"ty":"Primary","segment":15749222431214672690}],[{"ty":"End","segment":9361245670457788924},{"ty":"Primary","segment":5057709998225566481}],[{"ty":"End","segment":1705877195608053135},{"ty":"Primary","segment":17799038492181728804}],[{"ty":"End","segment":17799038492181728804},{"ty":"Primary","segment":16939098306153440303}],[{"ty":"End","segment":2463526518527501592},{"ty":"Primary","segment":9361245670457788924}],[{"ty":"End","segment":11060716078587457450},{"ty":"Primary","segment":5578827639764758986}],[{"ty":"End","segment":9361245670457788924},{"ty":"Primary","segment":4341232355541306629}],[{"ty":"End","segment":12529947318087068663},{"ty":"Primary","segment":11060716078587457450}],[{"ty":"End","segment":1705877195608053135},{"ty":"Primary","segment":2463526518527501592}],[{"ty":"End","segment":921651403153242564},{"ty":"Primary","segment":9825559201153691780}]],"remove_g1_continuous":[[{"ty":"Primary","segment":14294722277069184337},{"ty":"End","segment":3818841110886669992}],[{"ty":"End","segment":5057709998225566481},{"ty":"Primary","segment":14294722277069184337}],[{"ty":"End","segment":4341232355541306629},{"ty":"Primary","segment":3818841110886669992}],[{"ty":"Primary","segment":15749222431214672690},{"ty":"End","segment":14294722277069184337}]]}},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::vector_data::modification::VectorModification","alias":null}},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::vector_data::modification::PathModifyNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[17603523494627491590,{"inputs":[{"Node":{"node_id":10995640810984321903,"output_index":0,"lambda":false}},{"Node":{"node_id":17740294143355019755,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[13616602029989984195,{"inputs":[{"Node":{"node_id":3050731459444225191,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::FlattenPathNode"}},"visible":true,"skip_deduplication":false}],[4301099429811409147,{"inputs":[{"Node":{"node_id":57390435731316553,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"DVec2":[81.3755165062,-154.9064700048801]},"exposed":false}},{"Value":{"tagged_value":{"F64":0.4164633072520061},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[0.9999999999999998,0.9999999999999998]},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[0.0,0.0]},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[0.5,0.5]},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":1}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":2}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":3}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":4}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":5}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::TransformNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[3109716240255919254,{"inputs":[{"Node":{"node_id":5877930116725120460,"output_index":0,"lambda":false}},{"Node":{"node_id":18053728639616073084,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[2723198387862533596,{"inputs":[{"Node":{"node_id":14030142873804552388,"output_index":0,"lambda":false}},{"Node":{"node_id":11201759760883367635,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[18351415092709164412,{"inputs":[{"Node":{"node_id":1009114585722052052,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"Fill":{"Solid":{"red":0.101960786,"green":0.13333334,"blue":0.13725491,"alpha":1.0}}},"exposed":false}},{"Value":{"tagged_value":{"OptionalColor":{"red":0.3137255,"green":0.44705883,"blue":0.45490196,"alpha":1.0}},"exposed":false}},{"Value":{"tagged_value":{"Gradient":{"stops":[[0.0,{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}],[1.0,{"red":1.0,"green":1.0,"blue":1.0,"alpha":1.0}]],"gradient_type":"Linear","start":[0.0,0.5],"end":[1.0,0.5],"transform":[1.0,0.0,0.0,1.0,0.0,0.0]}},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::FillNode"}},"visible":true,"skip_deduplication":false}],[6484183251661832039,{"inputs":[{"Node":{"node_id":294265135510952894,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"DVec2":[474.2,0.0]},"exposed":false}},{"Value":{"tagged_value":{"F64":-7.2},"exposed":false}},{"Value":{"tagged_value":{"U32":5},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::RepeatNode"}},"visible":true,"skip_deduplication":false}],[12922148192688274227,{"inputs":[{"Node":{"node_id":18188505856445531484,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"DVec2":[0.0,0.0]},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[1.0,1.0]},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[0.0,0.0]},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[0.5,0.5]},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":1}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":2}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":3}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":4}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":5}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::TransformNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[7755499790391969923,{"inputs":[{"Value":{"tagged_value":"None","exposed":false}},{"Value":{"tagged_value":{"F64":4.0},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::generator_nodes::CircleNode"}},"visible":true,"skip_deduplication":false}],[6503655938154160104,{"inputs":[{"Node":{"node_id":17696051535511578981,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"BooleanOperation":"SubtractFront"},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::style::Fill","alias":null}},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_path_bool::BooleanOperationNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":2,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::BoundlessFootprintNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::FreezeRealTimeNode"}},"visible":true,"skip_deduplication":false}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MemoNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[16780039553038473906,{"inputs":[{"Value":{"tagged_value":{"GraphicGroup":{"instance":[],"transform":[],"alpha_blending":[],"source_node_id":[]}},"exposed":true}},{"Node":{"node_id":7104088139635280554,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[1508440849951861669,{"inputs":[{"Node":{"node_id":8566844905246185636,"output_index":0,"lambda":false}},{"Node":{"node_id":7480253252288032958,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[5856350938151339368,{"inputs":[{"Value":{"tagged_value":{"VectorData":{"instance":[{"style":{"stroke":{"color":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0},"weight":0.0,"dash_lengths":[],"dash_offset":0.0,"cap":"Butt","join":"Miter","join_miter_limit":4.0,"align":"Center","transform":[1.0,0.0,0.0,1.0,0.0,0.0],"non_scaling":false,"paint_order":"StrokeAbove"},"fill":"None"},"colinear_manipulators":[],"point_domain":{"id":[],"position":[]},"segment_domain":{"id":[],"start_point":[],"end_point":[],"handles":[],"stroke":[]},"region_domain":{"id":[],"segment_range":[],"fill":[]},"upstream_graphic_group":null}],"transform":[[1.0,0.0,0.0,1.0,0.0,0.0]],"alpha_blending":[{"blend_mode":"Normal","opacity":1.0,"fill":1.0,"clip":false}],"source_node_id":[null]}},"exposed":true}},{"Value":{"tagged_value":{"VectorModification":{"points":{"add":[5138872293174440313,14935583009751134816,9014079831396927156,7008812441195504980,9603704700847490044,7238075805746621699,2355002738045707979,5021902985892894619,17629528758352690600,5995306636877552],"remove":[10768931421586254879],"delta":[[7008812441195504980,[888.8888888888887,421.3333333333333]],[5138872293174440313,[922.9629629629628,422.22222222222223]],[9603704700847490044,[821.037037037037,464.2962962962963]],[14935583009751134816,[914.9629629629628,418.3703703703703]],[2355002738045707979,[826.2057613168724,485.0041152263375]],[5021902985892894619,[857.679012345679,478.2880658436215]],[5995306636877552,[912.8888888888888,479.7037037037037]],[7238075805746621699,[798.6831275720165,497.9094650205762]],[9014079831396927156,[908.4444444444443,429.9259259259259]],[17629528758352690600,[892.148148148148,480.2962962962963]]]},"segments":{"add":[7250062683967197158,14131440324578863745,4499620435559196394,14571502160667941876,7203043366367198812,239843798079287870,7655921914272804429,12687760936062936386,7117413478945421556,9071432674597727163],"remove":[3746587001535987651],"start_point":[[239843798079287870,2355002738045707979],[12687760936062936386,17629528758352690600],[7655921914272804429,5021902985892894619],[4499620435559196394,9014079831396927156],[9071432674597727163,7238075805746621699],[7203043366367198812,9603704700847490044],[7250062683967197158,5138872293174440313],[14571502160667941876,7008812441195504980],[7117413478945421556,5995306636877552],[14131440324578863745,14935583009751134816]],"end_point":[[4499620435559196394,7008812441195504980],[7655921914272804429,17629528758352690600],[14131440324578863745,9014079831396927156],[239843798079287870,5021902985892894619],[14571502160667941876,9603704700847490044],[7250062683967197158,14935583009751134816],[9071432674597727163,2355002738045707979],[7203043366367198812,7238075805746621699],[7117413478945421556,5138872293174440313],[12687760936062936386,5995306636877552]],"handle_primary":[[7203043366367198812,[0.0,0.2962962962963047]],[7117413478945421556,[0.0,0.0]],[9071432674597727163,[4.345679012345499,-3.555555555555543]],[14571502160667941876,[-0.5925925925926094,0.0]],[7655921914272804429,[18.172839506172863,-1.9753086419753456]],[14131440324578863745,[0.0,0.0]],[239843798079287870,[9.61316872427983,-1.843621399176982]],[12687760936062936386,[10.666666666666742,3.555555555555543]],[4499620435559196394,[-0.2962962962963047,-0.2962962962963047]],[7250062683967197158,[0.0,0.0]]],"handle_end":[[12687760936062936386,[0.0,0.0]],[7250062683967197158,[0.0,0.0]],[7117413478945421556,[15.703703703703695,33.48148148148147]],[4499620435559196394,[8.59259259259261,5.629629629629619]],[7203043366367198812,[-1.1851851851852189,-25.18518518518516]],[9071432674597727163,[-9.913826570592164,1.9012818080587977]],[7655921914272804429,[-10.666666666666742,-3.555555555555543]],[14571502160667941876,[24.395061728395035,-0.36213991769540144]],[14131440324578863745,[2.962962962963047,-3.259259259259238]],[239843798079287870,[-21.502976534539364,2.3372800581021456]]],"stroke":[[7203043366367198812,0],[239843798079287870,0],[4499620435559196394,0],[7117413478945421556,0],[12687760936062936386,0],[14131440324578863745,0],[7655921914272804429,0],[7250062683967197158,0],[9071432674597727163,0],[14571502160667941876,0]]},"regions":{"add":[],"remove":[],"segment_range":[],"fill":[]},"add_g1_continuous":[[{"ty":"End","segment":7250062683967197158},{"ty":"Primary","segment":14131440324578863745}],[{"ty":"End","segment":12687760936062936386},{"ty":"Primary","segment":7117413478945421556}],[{"ty":"End","segment":7655921914272804429},{"ty":"Primary","segment":12687760936062936386}],[{"ty":"Primary","segment":239843798079287870},{"ty":"End","segment":9071432674597727163}],[{"ty":"End","segment":239843798079287870},{"ty":"Primary","segment":7655921914272804429}]],"remove_g1_continuous":[[{"ty":"End","segment":3746587001535987651},{"ty":"Primary","segment":239843798079287870}],[{"ty":"End","segment":9071432674597727163},{"ty":"Primary","segment":3746587001535987651}]]}},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::vector_data::modification::VectorModification","alias":null}},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::vector_data::modification::PathModifyNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[14257963317028524134,{"inputs":[{"Node":{"node_id":1001728975241745659,"output_index":0,"lambda":false}},{"Node":{"node_id":6503655938154160104,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[1491840484128555837,{"inputs":[{"Node":{"node_id":1508440849951861669,"output_index":0,"lambda":false}},{"Node":{"node_id":9808637865669223270,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[5888633415105234509,{"inputs":[{"Node":{"node_id":3750439930725791025,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"BooleanOperation":"Intersect"},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::style::Fill","alias":null}},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_path_bool::BooleanOperationNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":2,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::BoundlessFootprintNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::FreezeRealTimeNode"}},"visible":true,"skip_deduplication":false}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MemoNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[1258994191538244490,{"inputs":[{"Node":{"node_id":5488285068107445023,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"Fill":{"Solid":{"red":0.101960786,"green":0.13333334,"blue":0.13725491,"alpha":1.0}}},"exposed":false}},{"Value":{"tagged_value":{"OptionalColor":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}},"exposed":false}},{"Value":{"tagged_value":{"Gradient":{"stops":[[0.0,{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}],[1.0,{"red":1.0,"green":1.0,"blue":1.0,"alpha":1.0}]],"gradient_type":"Linear","start":[0.0,0.5],"end":[1.0,0.5],"transform":[1.0,0.0,0.0,1.0,0.0,0.0]}},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::FillNode"}},"visible":true,"skip_deduplication":false}],[5486211022469996717,{"inputs":[{"Value":{"tagged_value":{"VectorData":{"instance":[{"style":{"stroke":{"color":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0},"weight":0.0,"dash_lengths":[],"dash_offset":0.0,"cap":"Butt","join":"Miter","join_miter_limit":4.0,"align":"Center","transform":[1.0,0.0,0.0,1.0,0.0,0.0],"non_scaling":false,"paint_order":"StrokeAbove"},"fill":"None"},"colinear_manipulators":[],"point_domain":{"id":[],"position":[]},"segment_domain":{"id":[],"start_point":[],"end_point":[],"handles":[],"stroke":[]},"region_domain":{"id":[],"segment_range":[],"fill":[]},"upstream_graphic_group":null}],"transform":[[1.0,0.0,0.0,1.0,0.0,0.0]],"alpha_blending":[{"blend_mode":"Normal","opacity":1.0,"fill":1.0,"clip":false}],"source_node_id":[null]}},"exposed":true}},{"Value":{"tagged_value":{"VectorModification":{"points":{"add":[266134622800431246,12075466065090700811,7115673652122600762,9852238672814254137],"remove":[134095410253559933],"delta":[[266134622800431246,[525.7325506063205,282.1042056224195]],[7115673652122600762,[646.5386352539062,343.99395751953125]],[12075466065090700811,[877.0370370370372,136.5925925925926]],[9852238672814254137,[879.7947439326053,110.54094004739208]]]},"segments":{"add":[17255728395700231433,3166693019207180063,10242199012993595528,2159953159628520134],"remove":[13980530488817762548,10196443086284452827,3769008694104161528],"start_point":[[17255728395700231433,12075466065090700811],[3166693019207180063,7115673652122600762],[2159953159628520134,9852238672814254137],[10242199012993595528,266134622800431246]],"end_point":[[17255728395700231433,7115673652122600762],[2159953159628520134,12075466065090700811],[10242199012993595528,9852238672814254137],[3166693019207180063,266134622800431246]],"handle_primary":[[17255728395700231433,[0.0010773420832492775,-0.01370555995902123]],[10242199012993595528,[137.37856050479058,-43.88198340019727]],[2159953159628520134,[0.0,0.0]],[3166693019207180063,[-126.67994767097883,-51.72627287889763]]],"handle_end":[[10242199012993595528,[-15.794743932605344,36.71831921186718]],[2159953159628520134,[0.0,0.0]],[17255728395700231433,[165.46136474609386,67.5615980360243]],[3166693019207180063,[0.0,0.0]]],"stroke":[[17255728395700231433,0],[10242199012993595528,0],[2159953159628520134,0],[3166693019207180063,0]]},"regions":{"add":[],"remove":[],"segment_range":[],"fill":[]},"add_g1_continuous":[[{"ty":"Primary","segment":3166693019207180063},{"ty":"End","segment":17255728395700231433}]],"remove_g1_continuous":[[{"ty":"End","segment":10242199012993595528},{"ty":"Primary","segment":2159953159628520134}],[{"ty":"Primary","segment":3769008694104161528},{"ty":"End","segment":10196443086284452827}],[{"ty":"End","segment":3166693019207180063},{"ty":"Primary","segment":13980530488817762548}],[{"ty":"Primary","segment":10242199012993595528},{"ty":"End","segment":3166693019207180063}]]}},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::vector_data::modification::VectorModification","alias":null}},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::vector_data::modification::PathModifyNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[14139129879376457893,{"inputs":[{"Node":{"node_id":11373527190663101881,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"Fill":{"Solid":{"red":0.101960786,"green":0.13333334,"blue":0.13725491,"alpha":1.0}}},"exposed":false}},{"Value":{"tagged_value":{"OptionalColor":{"red":0.101960786,"green":0.13333334,"blue":0.13725491,"alpha":1.0}},"exposed":false}},{"Value":{"tagged_value":{"Gradient":{"stops":[[0.0,{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}],[1.0,{"red":1.0,"green":1.0,"blue":1.0,"alpha":1.0}]],"gradient_type":"Linear","start":[0.0,0.5],"end":[1.0,0.5],"transform":[1.0,0.0,0.0,1.0,0.0,0.0]}},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::FillNode"}},"visible":true,"skip_deduplication":false}],[5954536408321808728,{"inputs":[{"Value":{"tagged_value":{"VectorData":{"instance":[{"style":{"stroke":{"color":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0},"weight":0.0,"dash_lengths":[],"dash_offset":0.0,"cap":"Butt","join":"Miter","join_miter_limit":4.0,"align":"Center","transform":[1.0,0.0,0.0,1.0,0.0,0.0],"non_scaling":false,"paint_order":"StrokeAbove"},"fill":"None"},"colinear_manipulators":[],"point_domain":{"id":[],"position":[]},"segment_domain":{"id":[],"start_point":[],"end_point":[],"handles":[],"stroke":[]},"region_domain":{"id":[],"segment_range":[],"fill":[]},"upstream_graphic_group":null}],"transform":[[1.0,0.0,0.0,1.0,0.0,0.0]],"alpha_blending":[{"blend_mode":"Normal","opacity":1.0,"fill":1.0,"clip":false}],"source_node_id":[null]}},"exposed":true}},{"Value":{"tagged_value":{"VectorModification":{"points":{"add":[8323145223085840944,87630150944518163,8212340198835025146,6057321578372831916,16788403743390653241,16686047298905200065,15635903913637220842,8652457572576966876,3124531241960914803,18307826411292029066,9969822516610975381,16995054111951247369,16808246968731723098],"remove":[],"delta":[[16808246968731723098,[891.5555555555554,768.0]],[9969822516610975381,[0.0,0.0]],[16788403743390653241,[467.99999999999994,487.3333333333333]],[8323145223085840944,[891.5555555555554,569.3827160493826]],[3124531241960914803,[589.9588477366256,64.65843621399176]],[16995054111951247369,[0.0,768.0]],[6057321578372831916,[708.148148148148,616.2962962962962]],[8652457572576966876,[514.4523315429688,146.72100830078125]],[16686047298905200065,[283.3333333333333,354.66666666666663]],[87630150944518163,[879.1111111111111,595.8518518518517]],[18307826411292029066,[601.1756940654021,0.0]],[15635903913637220842,[468.4799499511719,219.78570556640625]],[8212340198835025146,[830.8148148148148,633.7777777777776]]]},"segments":{"add":[14879480148926424885,5227512358023446442,17410347049685436697,9544743211426701912,14715945740984195653,515539069333222772,9242150930423817167,8823161072525575433,15885450050057549950,1662692131856898001,178608879920007638,12162371359208565273,16224358815792062223],"remove":[],"start_point":[[9242150930423817167,15635903913637220842],[14879480148926424885,8323145223085840944],[17410347049685436697,8212340198835025146],[178608879920007638,9969822516610975381],[12162371359208565273,16995054111951247369],[515539069333222772,16686047298905200065],[1662692131856898001,18307826411292029066],[8823161072525575433,8652457572576966876],[15885450050057549950,3124531241960914803],[14715945740984195653,16788403743390653241],[9544743211426701912,6057321578372831916],[16224358815792062223,16808246968731723098],[5227512358023446442,87630150944518163]],"end_point":[[14879480148926424885,87630150944518163],[17410347049685436697,6057321578372831916],[9544743211426701912,16788403743390653241],[16224358815792062223,8323145223085840944],[178608879920007638,16995054111951247369],[9242150930423817167,8652457572576966876],[15885450050057549950,18307826411292029066],[1662692131856898001,9969822516610975381],[515539069333222772,15635903913637220842],[5227512358023446442,8212340198835025146],[12162371359208565273,16808246968731723098],[14715945740984195653,16686047298905200065],[8823161072525575433,3124531241960914803]],"handle_primary":[[1662692131856898001,[0.0,0.0]],[5227512358023446442,[-4.444444444444457,18.074074074074133]],[14879480148926424885,[0.0,0.0]],[12162371359208565273,[0.0,0.0]],[9544743211426701912,[-57.48148148148141,-21.629629629629676]],[9242150930423817167,[27.25925925925918,-22.518518518518533]],[8823161072525575433,[11.259252477575274,-22.666663275824646]],[15885450050057549950,[11.193415637860312,-27.25925925925926]],[17410347049685436697,[-26.37037037037044,2.3703703703704377]],[14715945740984195653,[-92.66666666666656,-80.66666666666669]],[515539069333222772,[48.66666666666663,-23.999999999999943]],[16224358815792062223,[0.0,0.0]],[178608879920007638,[0.0,0.0]]],"handle_end":[[17410347049685436697,[57.48148148148141,21.629629629629676]],[12162371359208565273,[0.0,0.0]],[1662692131856898001,[0.0,0.0]],[8823161072525575433,[-12.439135136214697,30.29295262583988]],[16224358815792062223,[0.0,0.0]],[5227512358023446442,[26.37037037037044,-2.3703703703704377]],[515539069333222772,[-95.07216232621772,78.5378732260062]],[178608879920007638,[0.0,0.0]],[14879480148926424885,[4.444444444444457,-18.074074074074133]],[9544743211426701912,[92.66666666666656,80.66666666666669]],[14715945740984195653,[0.0,0.0]],[15885450050057549950,[0.0,0.0]],[9242150930423817167,[-9.36826657882972,18.859808361471693]]],"stroke":[[14715945740984195653,0],[16224358815792062223,0],[14879480148926424885,0],[9544743211426701912,0],[8823161072525575433,0],[178608879920007638,0],[5227512358023446442,0],[17410347049685436697,0],[1662692131856898001,0],[9242150930423817167,0],[515539069333222772,0],[15885450050057549950,0],[12162371359208565273,0]]},"regions":{"add":[],"remove":[],"segment_range":[],"fill":[]},"add_g1_continuous":[[{"ty":"End","segment":515539069333222772},{"ty":"Primary","segment":9242150930423817167}],[{"ty":"End","segment":12162371359208565273},{"ty":"Primary","segment":16224358815792062223}],[{"ty":"End","segment":9544743211426701912},{"ty":"Primary","segment":14715945740984195653}],[{"ty":"End","segment":8823161072525575433},{"ty":"Primary","segment":15885450050057549950}],[{"ty":"End","segment":5227512358023446442},{"ty":"Primary","segment":17410347049685436697}],[{"ty":"End","segment":9242150930423817167},{"ty":"Primary","segment":8823161072525575433}],[{"ty":"End","segment":15885450050057549950},{"ty":"Primary","segment":1662692131856898001}],[{"ty":"End","segment":178608879920007638},{"ty":"Primary","segment":12162371359208565273}],[{"ty":"End","segment":1662692131856898001},{"ty":"Primary","segment":178608879920007638}],[{"ty":"End","segment":17410347049685436697},{"ty":"Primary","segment":9544743211426701912}],[{"ty":"End","segment":14879480148926424885},{"ty":"Primary","segment":5227512358023446442}]],"remove_g1_continuous":[[{"ty":"End","segment":14715945740984195653},{"ty":"Primary","segment":515539069333222772}]]}},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::vector_data::modification::VectorModification","alias":null}},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::vector_data::modification::PathModifyNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[18053728639616073084,{"inputs":[{"Node":{"node_id":6616450276140292763,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"Fill":{"Solid":{"red":0.101960786,"green":0.13333334,"blue":0.13725491,"alpha":1.0}}},"exposed":false}},{"Value":{"tagged_value":{"OptionalColor":{"red":0.101960786,"green":0.13333334,"blue":0.13725491,"alpha":1.0}},"exposed":false}},{"Value":{"tagged_value":{"Gradient":{"stops":[[0.0,{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}],[1.0,{"red":1.0,"green":1.0,"blue":1.0,"alpha":1.0}]],"gradient_type":"Linear","start":[0.0,0.5],"end":[1.0,0.5],"transform":[1.0,0.0,0.0,1.0,0.0,0.0]}},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::FillNode"}},"visible":true,"skip_deduplication":false}],[17569892869974995307,{"inputs":[{"Node":{"node_id":3997031659711823213,"output_index":0,"lambda":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}],[5534800796196967885,{"inputs":[{"Node":{"node_id":3608604157153838227,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"CentroidType":"Area"},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::CentroidNode"}},"visible":true,"skip_deduplication":false}],[7029437790788498388,{"inputs":[{"Node":{"node_id":1809704172129195322,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"Fill":{"Solid":{"red":0.3137255,"green":0.44705883,"blue":0.45490196,"alpha":1.0}}},"exposed":false}},{"Value":{"tagged_value":{"OptionalColor":{"red":0.8509804,"green":0.24313726,"blue":0.18431373,"alpha":1.0}},"exposed":false}},{"Value":{"tagged_value":{"Gradient":{"stops":[[0.0,{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}],[1.0,{"red":1.0,"green":1.0,"blue":1.0,"alpha":1.0}]],"gradient_type":"Linear","start":[0.0,0.5],"end":[1.0,0.5],"transform":[1.0,0.0,0.0,1.0,0.0,0.0]}},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::FillNode"}},"visible":true,"skip_deduplication":false}],[17351444026127625357,{"inputs":[{"Node":{"node_id":14808063168960305551,"output_index":0,"lambda":false}},{"Node":{"node_id":13916027199283115943,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[17735408893002232096,{"inputs":[{"Node":{"node_id":14228923746783465609,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"Fill":{"Solid":{"red":0.101960786,"green":0.13333334,"blue":0.13725491,"alpha":1.0}}},"exposed":false}},{"Value":{"tagged_value":{"OptionalColor":{"red":0.101960786,"green":0.13333334,"blue":0.13725491,"alpha":1.0}},"exposed":false}},{"Value":{"tagged_value":{"Gradient":{"stops":[[0.0,{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}],[1.0,{"red":1.0,"green":1.0,"blue":1.0,"alpha":1.0}]],"gradient_type":"Linear","start":[0.0,0.5],"end":[1.0,0.5],"transform":[1.0,0.0,0.0,1.0,0.0,0.0]}},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::FillNode"}},"visible":true,"skip_deduplication":false}],[17285637344898461972,{"inputs":[{"Value":{"tagged_value":{"VectorData":{"instance":[{"style":{"stroke":{"color":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0},"weight":0.0,"dash_lengths":[],"dash_offset":0.0,"cap":"Butt","join":"Miter","join_miter_limit":4.0,"align":"Center","transform":[1.0,0.0,0.0,1.0,0.0,0.0],"non_scaling":false,"paint_order":"StrokeAbove"},"fill":"None"},"colinear_manipulators":[],"point_domain":{"id":[],"position":[]},"segment_domain":{"id":[],"start_point":[],"end_point":[],"handles":[],"stroke":[]},"region_domain":{"id":[],"segment_range":[],"fill":[]},"upstream_graphic_group":null}],"transform":[[1.0,0.0,0.0,1.0,0.0,0.0]],"alpha_blending":[{"blend_mode":"Normal","opacity":1.0,"fill":1.0,"clip":false}],"source_node_id":[null]}},"exposed":true}},{"Value":{"tagged_value":{"VectorModification":{"points":{"add":[16608607268690234590,17457877227823502997,13436129231170586617,5992570223148766873],"remove":[],"delta":[[17457877227823502997,[273.0,476.0]],[13436129231170586617,[481.3333333333333,768.0]],[16608607268690234590,[0.0,340.0]],[5992570223148766873,[-2.273736754432321e-13,768.0]]]},"segments":{"add":[13284808974014161135,5472571334856691465,8776124420595946733,4274372337254864190],"remove":[],"start_point":[[5472571334856691465,17457877227823502997],[13284808974014161135,16608607268690234590],[4274372337254864190,5992570223148766873],[8776124420595946733,13436129231170586617]],"end_point":[[5472571334856691465,13436129231170586617],[8776124420595946733,5992570223148766873],[4274372337254864190,16608607268690234590],[13284808974014161135,17457877227823502997]],"handle_primary":[[4274372337254864190,[0.0,0.0]],[8776124420595946733,[0.0,0.0]],[5472571334856691465,[146.0,-13.0]],[13284808974014161135,[161.73791370620617,43.57576470888159]]],"handle_end":[[13284808974014161135,[-165.43581782916667,14.730586519035386]],[8776124420595946733,[0.0,0.0]],[4274372337254864190,[0.0,0.0]],[5472571334856691465,[0.4078646547782227,-253.307727480567]]],"stroke":[[5472571334856691465,0],[4274372337254864190,0],[13284808974014161135,0],[8776124420595946733,0]]},"regions":{"add":[],"remove":[],"segment_range":[],"fill":[]},"add_g1_continuous":[[{"ty":"End","segment":13284808974014161135},{"ty":"Primary","segment":5472571334856691465}],[{"ty":"End","segment":8776124420595946733},{"ty":"Primary","segment":4274372337254864190}]],"remove_g1_continuous":[[{"ty":"Primary","segment":13284808974014161135},{"ty":"End","segment":4274372337254864190}]]}},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::vector_data::modification::VectorModification","alias":null}},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::vector_data::modification::PathModifyNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[15900830679378240619,{"inputs":[{"Node":{"node_id":2287485748649359627,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"BooleanOperation":"Intersect"},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::style::Fill","alias":null}},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_path_bool::BooleanOperationNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":2,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::BoundlessFootprintNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::FreezeRealTimeNode"}},"visible":true,"skip_deduplication":false}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MemoNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[1662641269094032596,{"inputs":[{"Node":{"node_id":16304636129468583592,"output_index":0,"lambda":false}},{"Node":{"node_id":14139765080256493579,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[6728362629909402903,{"inputs":[{"Node":{"node_id":5856350938151339368,"output_index":0,"lambda":false}},{"Node":{"node_id":5449860184735415958,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[12276520439585231336,{"inputs":[{"Node":{"node_id":13795432594059356320,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"DVec2":[997.5029638869316,545.7213923090854]},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[1.0,1.0]},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[0.0,0.0]},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[0.5,0.5]},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":1}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":2}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":3}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":4}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":5}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::TransformNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[10995640810984321903,{"inputs":[{"Node":{"node_id":12353675714904258944,"output_index":0,"lambda":false}},{"Node":{"node_id":10265035897167064154,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[15354358358546908017,{"inputs":[{"Node":{"node_id":14950060858756810933,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"Fill":{"Solid":{"red":0.92156863,"green":0.6039216,"blue":0.18039216,"alpha":1.0}}},"exposed":false}},{"Value":{"tagged_value":{"OptionalColor":{"red":0.93333334,"green":0.8627451,"blue":0.7254902,"alpha":1.0}},"exposed":false}},{"Value":{"tagged_value":{"Gradient":{"stops":[[0.0,{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}],[1.0,{"red":1.0,"green":1.0,"blue":1.0,"alpha":1.0}]],"gradient_type":"Linear","start":[0.0,0.5],"end":[1.0,0.5],"transform":[1.0,0.0,0.0,1.0,0.0,0.0]}},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::FillNode"}},"visible":true,"skip_deduplication":false}],[4328376070224119511,{"inputs":[{"Value":{"tagged_value":{"GraphicGroup":{"instance":[],"transform":[],"alpha_blending":[],"source_node_id":[]}},"exposed":true}},{"Node":{"node_id":13446205009526451196,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[1009114585722052052,{"inputs":[{"Node":{"node_id":15692102598187739001,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"BooleanOperation":"Intersect"},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::style::Fill","alias":null}},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_path_bool::BooleanOperationNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":2,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::BoundlessFootprintNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::FreezeRealTimeNode"}},"visible":true,"skip_deduplication":false}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MemoNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[7252918969430566594,{"inputs":[{"Node":{"node_id":5534800796196967885,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"F64":-1.0},"exposed":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_math_nodes::MultiplyNode"}},"visible":true,"skip_deduplication":false}],[14684142559936015947,{"inputs":[{"Node":{"node_id":15930698052919171086,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"Fill":{"Solid":{"red":0.101960786,"green":0.13333334,"blue":0.13725491,"alpha":1.0}}},"exposed":false}},{"Value":{"tagged_value":{"OptionalColor":{"red":0.101960786,"green":0.13333334,"blue":0.13725491,"alpha":1.0}},"exposed":false}},{"Value":{"tagged_value":{"Gradient":{"stops":[[0.0,{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}],[1.0,{"red":1.0,"green":1.0,"blue":1.0,"alpha":1.0}]],"gradient_type":"Linear","start":[0.0,0.5],"end":[1.0,0.5],"transform":[1.0,0.0,0.0,1.0,0.0,0.0]}},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::FillNode"}},"visible":true,"skip_deduplication":false}],[4771789845668099116,{"inputs":[{"Node":{"node_id":17351444026127625357,"output_index":0,"lambda":false}},{"Node":{"node_id":14684142559936015947,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[14690269209726153565,{"inputs":[{"Node":{"node_id":7376049709233607419,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"Fill":{"Solid":{"red":0.101960786,"green":0.13333334,"blue":0.13725491,"alpha":1.0}}},"exposed":false}},{"Value":{"tagged_value":{"OptionalColor":{"red":0.101960786,"green":0.13333334,"blue":0.13725491,"alpha":1.0}},"exposed":false}},{"Value":{"tagged_value":{"Gradient":{"stops":[[0.0,{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}],[1.0,{"red":1.0,"green":1.0,"blue":1.0,"alpha":1.0}]],"gradient_type":"Linear","start":[0.0,0.5],"end":[1.0,0.5],"transform":[1.0,0.0,0.0,1.0,0.0,0.0]}},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::FillNode"}},"visible":true,"skip_deduplication":false}],[18188505856445531484,{"inputs":[{"Node":{"node_id":8887924609778270360,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"Fill":{"Solid":{"red":0.92156863,"green":0.6039216,"blue":0.18039216,"alpha":1.0}}},"exposed":false}},{"Value":{"tagged_value":{"OptionalColor":{"red":0.92156863,"green":0.6039216,"blue":0.18039216,"alpha":1.0}},"exposed":false}},{"Value":{"tagged_value":{"Gradient":{"stops":[[0.0,{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}],[1.0,{"red":1.0,"green":1.0,"blue":1.0,"alpha":1.0}]],"gradient_type":"Linear","start":[0.0,0.5],"end":[1.0,0.5],"transform":[1.0,0.0,0.0,1.0,0.0,0.0]}},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::FillNode"}},"visible":true,"skip_deduplication":false}],[3410481056630111806,{"inputs":[{"Node":{"node_id":1097494158696050491,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"Fill":{"Solid":{"red":0.8509804,"green":0.24313726,"blue":0.18431373,"alpha":1.0}}},"exposed":false}},{"Value":{"tagged_value":{"OptionalColor":{"red":0.3137255,"green":0.44705883,"blue":0.45490196,"alpha":1.0}},"exposed":false}},{"Value":{"tagged_value":{"Gradient":{"stops":[[0.0,{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}],[1.0,{"red":1.0,"green":1.0,"blue":1.0,"alpha":1.0}]],"gradient_type":"Linear","start":[0.0,0.5],"end":[1.0,0.5],"transform":[1.0,0.0,0.0,1.0,0.0,0.0]}},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::FillNode"}},"visible":true,"skip_deduplication":false}],[2834866505092039323,{"inputs":[{"Node":{"node_id":18003287685830153881,"output_index":0,"lambda":false}},{"Node":{"node_id":14139765080256493579,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[5014806436727666175,{"inputs":[{"Node":{"node_id":7855094781869605606,"output_index":0,"lambda":false}},{"Node":{"node_id":8863346544623578893,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[14139765080256493579,{"inputs":[{"Value":{"tagged_value":{"VectorData":{"instance":[{"style":{"stroke":{"color":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0},"weight":0.0,"dash_lengths":[],"dash_offset":0.0,"cap":"Butt","join":"Miter","join_miter_limit":4.0,"align":"Center","transform":[1.0,0.0,0.0,1.0,0.0,0.0],"non_scaling":false,"paint_order":"StrokeAbove"},"fill":"None"},"colinear_manipulators":[],"point_domain":{"id":[],"position":[]},"segment_domain":{"id":[],"start_point":[],"end_point":[],"handles":[],"stroke":[]},"region_domain":{"id":[],"segment_range":[],"fill":[]},"upstream_graphic_group":null}],"transform":[[1.0,0.0,0.0,1.0,0.0,0.0]],"alpha_blending":[{"blend_mode":"Normal","opacity":1.0,"fill":1.0,"clip":false}],"source_node_id":[null]}},"exposed":true}},{"Value":{"tagged_value":{"VectorModification":{"points":{"add":[3507505346656189771,2904729023031858224,854708012647259796,4175610638601362388,7821224334582795476,2195807584570698921],"remove":[1009888023123207923,16332448509429125699],"delta":[[4175610638601362388,[957.0,324.0]],[2904729023031858224,[491.3420376907663,506.7530051313737]],[3507505346656189771,[552.0,768.0000000000001]],[854708012647259796,[740.0,298.0]],[2195807584570698921,[993.0,767.9999999999999]],[7821224334582795476,[1093.0,600.0]]]},"segments":{"add":[4553965744616493549,13993263006398686359,6577640955869157325,17304574948462342226,8570276641842028192,17183285389582020412],"remove":[546565283439891712,5710832026764395735],"start_point":[[8570276641842028192,2195807584570698921],[13993263006398686359,2904729023031858224],[4553965744616493549,3507505346656189771],[17183285389582020412,7821224334582795476],[6577640955869157325,854708012647259796],[17304574948462342226,4175610638601362388]],"end_point":[[4553965744616493549,2904729023031858224],[17183285389582020412,2195807584570698921],[13993263006398686359,854708012647259796],[6577640955869157325,4175610638601362388],[8570276641842028192,3507505346656189771],[17304574948462342226,7821224334582795476]],"handle_primary":[[4553965744616493549,[0.0,0.0]],[13993263006398686359,[0.0,-84.7537417270637]],[17183285389582020412,[-24.08196064282073,82.4624712920831]],[17304574948462342226,[50.35246044959922,33.38607084805801]],[6577640955869157325,[102.0,-45.0]],[8570276641842028192,[0.0,0.0]]],"handle_end":[[4553965744616493549,[0.0,135.2464055295568]],[6577640955869157325,[-50.35246044959922,-33.38607084805801]],[17304574948462342226,[33.0,-113.0]],[8570276641842028192,[0.0,0.0]],[13993263006398686359,[-102.0,45.0]],[17183285389582020412,[0.0,0.0]]],"stroke":[[17304574948462342226,0],[4553965744616493549,0],[8570276641842028192,0],[13993263006398686359,0],[17183285389582020412,0],[6577640955869157325,0]]},"regions":{"add":[],"remove":[],"segment_range":[],"fill":[]},"add_g1_continuous":[[{"ty":"Primary","segment":8570276641842028192},{"ty":"End","segment":17183285389582020412}],[{"ty":"End","segment":4553965744616493549},{"ty":"Primary","segment":13993263006398686359}],[{"ty":"End","segment":6577640955869157325},{"ty":"Primary","segment":17304574948462342226}],[{"ty":"End","segment":17304574948462342226},{"ty":"Primary","segment":17183285389582020412}],[{"ty":"End","segment":13993263006398686359},{"ty":"Primary","segment":6577640955869157325}]],"remove_g1_continuous":[[{"ty":"End","segment":17183285389582020412},{"ty":"Primary","segment":546565283439891712}],[{"ty":"Primary","segment":8570276641842028192},{"ty":"End","segment":546565283439891712}],[{"ty":"End","segment":5710832026764395735},{"ty":"Primary","segment":8570276641842028192}],[{"ty":"End","segment":546565283439891712},{"ty":"Primary","segment":5710832026764395735}]]}},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::vector_data::modification::VectorModification","alias":null}},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::vector_data::modification::PathModifyNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[10080296672372912698,{"inputs":[{"Node":{"node_id":12867379765049504290,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"BooleanOperation":"SubtractFront"},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::style::Fill","alias":null}},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_path_bool::BooleanOperationNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":2,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::BoundlessFootprintNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::FreezeRealTimeNode"}},"visible":true,"skip_deduplication":false}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MemoNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[12353675714904258944,{"inputs":[{"Node":{"node_id":13203761224559198689,"output_index":0,"lambda":false}},{"Node":{"node_id":17271572793812678706,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[17271572793812678706,{"inputs":[{"Node":{"node_id":15900830679378240619,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"Fill":{"Solid":{"red":0.101960786,"green":0.13333334,"blue":0.13725491,"alpha":1.0}}},"exposed":false}},{"Value":{"tagged_value":{"OptionalColor":{"red":0.101960786,"green":0.13333334,"blue":0.13725491,"alpha":1.0}},"exposed":false}},{"Value":{"tagged_value":{"Gradient":{"stops":[[0.0,{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}],[1.0,{"red":1.0,"green":1.0,"blue":1.0,"alpha":1.0}]],"gradient_type":"Linear","start":[0.0,0.5],"end":[1.0,0.5],"transform":[1.0,0.0,0.0,1.0,0.0,0.0]}},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::FillNode"}},"visible":true,"skip_deduplication":false}],[14228923746783465609,{"inputs":[{"Node":{"node_id":16304636129468583592,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"VectorModification":{"points":{"add":[2003133867055127539,13758328146055368475],"remove":[],"delta":[[13758328146055368475,[1299.3064572949788,786.3993743175897]],[4648964341912884959,[324.66666666666646,0.0]],[16569120368910754547,[-43.0,0.0]],[2003133867055127539,[1011.111083984375,786.3993530273438]]]},"segments":{"add":[8214025514312603513,7334532063810723038,13431612844608018700],"remove":[6602880736207868665,3433930674303663828],"start_point":[[8214025514312603513,2003133867055127539],[7334532063810723038,16569120368910754547],[13431612844608018700,13758328146055368475]],"end_point":[[7334532063810723038,13758328146055368475],[13431612844608018700,2003133867055127539],[8214025514312603513,4648964341912884959]],"handle_primary":[[13431612844608018700,null],[9030015329489789075,[69.08057198853999,-80.19415805947563]],[7334532063810723038,null],[8214025514312603513,null]],"handle_end":[[7334532063810723038,null],[8214025514312603513,null],[2197140374690997530,[-24.333333333333485,-86.99999999999977]],[13431612844608018700,null],[9030015329489789075,[0.0,0.0]]],"stroke":[[7334532063810723038,0],[13431612844608018700,0],[8214025514312603513,0]]},"regions":{"add":[],"remove":[],"segment_range":[],"fill":[]},"add_g1_continuous":[],"remove_g1_continuous":[[{"ty":"Primary","segment":9030015329489789075},{"ty":"End","segment":3433930674303663828}],[{"ty":"End","segment":9030015329489789075},{"ty":"Primary","segment":2197140374690997530}]]}},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::vector_data::modification::VectorModification","alias":null}},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::vector_data::modification::PathModifyNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[11210964267417873667,{"inputs":[{"Node":{"node_id":4261249487994076490,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"DVec2":[91.7203910728,-99.9607940061]},"exposed":false}},{"Value":{"tagged_value":{"F64":0.40698564029617024},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[1.0,1.0]},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[0.0,0.0]},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[0.5,0.5]},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":1}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":2}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":3}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":4}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":5}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::TransformNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[1097494158696050491,{"inputs":[{"Value":{"tagged_value":"None","exposed":false}},{"Value":{"tagged_value":{"F64":15.0},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::generator_nodes::CircleNode"}},"visible":true,"skip_deduplication":false}],[8887924609778270360,{"inputs":[{"Node":{"node_id":5014806436727666175,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"BooleanOperation":"Intersect"},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::style::Fill","alias":null}},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_path_bool::BooleanOperationNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":2,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::BoundlessFootprintNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::FreezeRealTimeNode"}},"visible":true,"skip_deduplication":false}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MemoNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[17036604842139972912,{"inputs":[{"Node":{"node_id":1491840484128555837,"output_index":0,"lambda":false}},{"Node":{"node_id":11210964267417873667,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[12145355397916841389,{"inputs":[{"Node":{"node_id":16759836951269190891,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"Fill":{"Solid":{"red":0.101960786,"green":0.13333334,"blue":0.13725491,"alpha":1.0}}},"exposed":false}},{"Value":{"tagged_value":{"OptionalColor":{"red":0.92156863,"green":0.6039216,"blue":0.18039216,"alpha":1.0}},"exposed":false}},{"Value":{"tagged_value":{"Gradient":{"stops":[[0.0,{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}],[1.0,{"red":1.0,"green":1.0,"blue":1.0,"alpha":1.0}]],"gradient_type":"Linear","start":[0.0,0.5],"end":[1.0,0.5],"transform":[1.0,0.0,0.0,1.0,0.0,0.0]}},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::FillNode"}},"visible":true,"skip_deduplication":false}],[4470272391975492611,{"inputs":[{"Node":{"node_id":7018444885869143173,"output_index":0,"lambda":false}},{"Node":{"node_id":12145355397916841389,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[7962101329808960965,{"inputs":[{"Node":{"node_id":16322546010403524636,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"F64":-1.0},"exposed":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_math_nodes::MultiplyNode"}},"visible":true,"skip_deduplication":false}],[5556372312033787775,{"inputs":[{"Node":{"node_id":6484183251661832039,"output_index":0,"lambda":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::BoundingBoxNode"}},"visible":true,"skip_deduplication":false}],[294265135510952894,{"inputs":[{"Node":{"node_id":11264395591110193456,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"Fill":{"Solid":{"red":0.92156863,"green":0.6039216,"blue":0.18039216,"alpha":1.0}}},"exposed":false}},{"Value":{"tagged_value":{"OptionalColor":{"red":0.8509804,"green":0.24313726,"blue":0.18431373,"alpha":1.0}},"exposed":false}},{"Value":{"tagged_value":{"Gradient":{"stops":[[0.0,{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}],[1.0,{"red":1.0,"green":1.0,"blue":1.0,"alpha":1.0}]],"gradient_type":"Linear","start":[0.0,0.5],"end":[1.0,0.5],"transform":[1.0,0.0,0.0,1.0,0.0,0.0]}},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::FillNode"}},"visible":true,"skip_deduplication":false}],[2025899804080897524,{"inputs":[{"Node":{"node_id":17740496701763775226,"output_index":0,"lambda":false}},{"Node":{"node_id":3214181946162459584,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[990192925663920333,{"inputs":[{"Node":{"node_id":3410481056630111806,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"DVec2":[466.8,0.0]},"exposed":false}},{"Value":{"tagged_value":{"F64":-7.9},"exposed":false}},{"Value":{"tagged_value":{"U32":5},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::RepeatNode"}},"visible":true,"skip_deduplication":false}],[11264395591110193456,{"inputs":[{"Value":{"tagged_value":"None","exposed":false}},{"Value":{"tagged_value":{"F64":10.0},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::generator_nodes::CircleNode"}},"visible":true,"skip_deduplication":false}],[13027689870767713939,{"inputs":[{"Node":{"node_id":7201841978411396053,"output_index":0,"lambda":false}},{"Node":{"node_id":13340751444307201866,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[9338394475379815879,{"inputs":[{"Node":{"node_id":7977952035097419157,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"DVec2":[1327.0278641242007,11.102707365920756]},"exposed":false}},{"Value":{"tagged_value":{"F64":0.23820276778328575},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[230.36030209674013,67.6958526826066]},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[3.855605378252775e-17,0.0]},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[0.5,0.5]},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":1}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":2}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":3}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":4}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":5}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::TransformNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[14496934933990319842,{"inputs":[{"Node":{"node_id":12709602171929957216,"output_index":0,"lambda":false}},{"Node":{"node_id":12185047359007423618,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[13739729101529293427,{"inputs":[{"Node":{"node_id":18003287685830153881,"output_index":0,"lambda":false}},{"Node":{"node_id":14139765080256493579,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[3214181946162459584,{"inputs":[{"Node":{"node_id":5449860184735415958,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"Fill":{"Solid":{"red":0.93333334,"green":0.8627451,"blue":0.7254902,"alpha":1.0}}},"exposed":false}},{"Value":{"tagged_value":{"OptionalColor":{"red":0.93333334,"green":0.8627451,"blue":0.7254902,"alpha":1.0}},"exposed":false}},{"Value":{"tagged_value":{"Gradient":{"stops":[[0.0,{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}],[1.0,{"red":1.0,"green":1.0,"blue":1.0,"alpha":1.0}]],"gradient_type":"Linear","start":[0.0,0.5],"end":[1.0,0.5],"transform":[1.0,0.0,0.0,1.0,0.0,0.0]}},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::FillNode"}},"visible":true,"skip_deduplication":false}],[16322546010403524636,{"inputs":[{"Node":{"node_id":5556372312033787775,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"CentroidType":"Area"},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::CentroidNode"}},"visible":true,"skip_deduplication":false}],[804622576568168609,{"inputs":[{"Value":{"tagged_value":{"VectorData":{"instance":[{"style":{"stroke":{"color":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0},"weight":0.0,"dash_lengths":[],"dash_offset":0.0,"cap":"Butt","join":"Miter","join_miter_limit":4.0,"align":"Center","transform":[1.0,0.0,0.0,1.0,0.0,0.0],"non_scaling":false,"paint_order":"StrokeAbove"},"fill":"None"},"colinear_manipulators":[],"point_domain":{"id":[],"position":[]},"segment_domain":{"id":[],"start_point":[],"end_point":[],"handles":[],"stroke":[]},"region_domain":{"id":[],"segment_range":[],"fill":[]},"upstream_graphic_group":null}],"transform":[[1.0,0.0,0.0,1.0,0.0,0.0]],"alpha_blending":[{"blend_mode":"Normal","opacity":1.0,"fill":1.0,"clip":false}],"source_node_id":[null]}},"exposed":true}},{"Value":{"tagged_value":{"VectorModification":{"points":{"add":[13654185056786459919,6952183320761642858,2802617302192982616,7639287212006638253,15117515618866904690,15750781936547583892,7025422618543191491,3831533579307185652,16937470333767479918,10412162547161259027,5269777039739103358],"remove":[],"delta":[[15117515618866904690,[819.1111111111109,354.44444444444434]],[5269777039739103358,[902.2222222222222,394.66666666666663]],[15750781936547583892,[840.6666666666665,368.66666666666663]],[7639287212006638253,[862.8888888888888,349.3333333333333]],[2802617302192982616,[911.7777777777776,334.88888888888886]],[10412162547161259027,[887.3333333333333,376.0]],[6952183320761642858,[933.9259259259262,324.3456790123457]],[16937470333767479918,[876.6666666666665,359.55555555555554]],[3831533579307185652,[880.4444444444443,357.3333333333333]],[7025422618543191491,[911.5555555555554,345.3333333333333]],[13654185056786459919,[946.1728395061732,330.8641975308642]]]},"segments":{"add":[10498175376126066982,10426255560432238561,11214998966879437330,1241631398419524272,15286139376878919277,15838384105575178137,12854270992100552972,379744301215040936,4069217348643062888,10438163357339042361,9330486019469919863],"remove":[],"start_point":[[11214998966879437330,2802617302192982616],[4069217348643062888,16937470333767479918],[10438163357339042361,10412162547161259027],[379744301215040936,3831533579307185652],[10498175376126066982,13654185056786459919],[15286139376878919277,15117515618866904690],[12854270992100552972,7025422618543191491],[10426255560432238561,6952183320761642858],[1241631398419524272,7639287212006638253],[15838384105575178137,15750781936547583892],[9330486019469919863,5269777039739103358]],"end_point":[[11214998966879437330,7639287212006638253],[4069217348643062888,10412162547161259027],[15286139376878919277,15750781936547583892],[9330486019469919863,13654185056786459919],[12854270992100552972,3831533579307185652],[10498175376126066982,6952183320761642858],[10438163357339042361,5269777039739103358],[1241631398419524272,15117515618866904690],[10426255560432238561,2802617302192982616],[379744301215040936,16937470333767479918],[15838384105575178137,7025422618543191491]],"handle_primary":[[379744301215040936,[-0.2222222222221717,0.0]],[10438163357339042361,[1.3333333333332575,10.888888888888856]],[4069217348643062888,[0.0,0.0]],[12854270992100552972,[-0.4444444444443434,0.0]],[1241631398419524272,[-17.111111111111086,12.888888888888856]],[15286139376878919277,[-0.5188510642573192,0.6084707935380038]],[9330486019469919863,[5.555555555555429,-0.2222222222221717]],[15838384105575178137,[22.222222222222285,5.555555555555543]],[11214998966879437330,[-16.666666666666515,-3.777777777777771]],[10498175376126066982,[0.0,0.0]],[10426255560432238561,[-0.39506172839503506,-0.19753086419757435]]],"handle_end":[[1241631398419524272,[0.5951379226228255,-0.6979344728938486]],[10438163357339042361,[-5.555555555555429,0.2222222222221717]],[10498175376126066982,[4.9382716049382225,0.19753086419757435]],[15838384105575178137,[-20.0,2.0]],[10426255560432238561,[16.666666666666515,3.777777777777771]],[11214998966879437330,[17.111111111111086,-12.888888888888856]],[9330486019469919863,[0.0,0.0]],[4069217348643062888,[-1.3333333333332575,-10.888888888888856]],[15286139376878919277,[-22.222222222222285,-5.555555555555543]],[12854270992100552972,[33.77777777777783,2.2222222222222285]],[379744301215040936,[0.0,0.0]]],"stroke":[[4069217348643062888,0],[15286139376878919277,0],[12854270992100552972,0],[15838384105575178137,0],[1241631398419524272,0],[379744301215040936,0],[10498175376126066982,0],[10426255560432238561,0],[9330486019469919863,0],[11214998966879437330,0],[10438163357339042361,0]]},"regions":{"add":[],"remove":[],"segment_range":[],"fill":[]},"add_g1_continuous":[[{"ty":"End","segment":10438163357339042361},{"ty":"Primary","segment":9330486019469919863}],[{"ty":"End","segment":15286139376878919277},{"ty":"Primary","segment":15838384105575178137}],[{"ty":"End","segment":11214998966879437330},{"ty":"Primary","segment":1241631398419524272}],[{"ty":"End","segment":10426255560432238561},{"ty":"Primary","segment":11214998966879437330}],[{"ty":"End","segment":379744301215040936},{"ty":"Primary","segment":4069217348643062888}],[{"ty":"End","segment":1241631398419524272},{"ty":"Primary","segment":15286139376878919277}],[{"ty":"End","segment":4069217348643062888},{"ty":"Primary","segment":10438163357339042361}]],"remove_g1_continuous":[]}},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::vector_data::modification::VectorModification","alias":null}},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::vector_data::modification::PathModifyNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[17753909951719808506,{"inputs":[{"Node":{"node_id":2185437945364824599,"output_index":0,"lambda":false}},{"Node":{"node_id":9563008199132558110,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[8566844905246185636,{"inputs":[{"Node":{"node_id":6852799892628327372,"output_index":0,"lambda":false}},{"Node":{"node_id":17131529656312051452,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[18095952297474762348,{"inputs":[{"Node":{"node_id":5954536408321808728,"output_index":0,"lambda":false}},{"Node":{"node_id":5449860184735415958,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[4261249487994076490,{"inputs":[{"Node":{"node_id":14516211820212764316,"output_index":0,"lambda":false}},{"Node":{"node_id":5534800796196967885,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[1.0,1.0]},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[0.0,0.0]},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[0.5,0.5]},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":1}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":2}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":3}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":4}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":5}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::TransformNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[8426490990601560741,{"inputs":[{"Node":{"node_id":10760002922115563021,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"Fill":{"Solid":{"red":0.93333334,"green":0.8627451,"blue":0.7254902,"alpha":1.0}}},"exposed":false}},{"Value":{"tagged_value":{"OptionalColor":{"red":0.92156863,"green":0.6039216,"blue":0.18039216,"alpha":1.0}},"exposed":false}},{"Value":{"tagged_value":{"Gradient":{"stops":[[0.0,{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}],[1.0,{"red":1.0,"green":1.0,"blue":1.0,"alpha":1.0}]],"gradient_type":"Linear","start":[0.0,0.5],"end":[1.0,0.5],"transform":[1.0,0.0,0.0,1.0,0.0,0.0]}},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::FillNode"}},"visible":true,"skip_deduplication":false}],[13795432594059356320,{"inputs":[{"Node":{"node_id":2871608309888343463,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::FlattenPathNode"}},"visible":true,"skip_deduplication":false}],[7651693425519490419,{"inputs":[{"Node":{"node_id":4771789845668099116,"output_index":0,"lambda":false}},{"Node":{"node_id":15817956847588799375,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[6616450276140292763,{"inputs":[{"Value":{"tagged_value":{"VectorData":{"instance":[{"style":{"stroke":{"color":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0},"weight":0.0,"dash_lengths":[],"dash_offset":0.0,"cap":"Butt","join":"Miter","join_miter_limit":4.0,"align":"Center","transform":[1.0,0.0,0.0,1.0,0.0,0.0],"non_scaling":false,"paint_order":"StrokeAbove"},"fill":"None"},"colinear_manipulators":[],"point_domain":{"id":[],"position":[]},"segment_domain":{"id":[],"start_point":[],"end_point":[],"handles":[],"stroke":[]},"region_domain":{"id":[],"segment_range":[],"fill":[]},"upstream_graphic_group":null}],"transform":[[1.0,0.0,0.0,1.0,0.0,0.0]],"alpha_blending":[{"blend_mode":"Normal","opacity":1.0,"fill":1.0,"clip":false}],"source_node_id":[null]}},"exposed":true}},{"Value":{"tagged_value":{"VectorModification":{"points":{"add":[14760110820354327749,9465415708990918986,13517856880347849115,12398030966924498647,2930103517622848405,9496337687212684441],"remove":[],"delta":[[9465415708990918986,[706.3703703703703,86.51851851851853]],[13517856880347849115,[777.1851851851851,92.44444444444446]],[14760110820354327749,[614.8148148148148,129.1851851851852]],[9496337687212684441,[732.148148148148,57.18518518518518]],[2930103517622848405,[819.2592592592591,69.33333333333334]],[12398030966924498647,[823.4074074074074,97.4814814814815]]]},"segments":{"add":[18226408581696793441,16628058317667581864,3809009367670994230,13496648265229692336,10686631697241750410,11696351847604335156],"remove":[],"start_point":[[16628058317667581864,9465415708990918986],[18226408581696793441,14760110820354327749],[10686631697241750410,2930103517622848405],[13496648265229692336,12398030966924498647],[3809009367670994230,13517856880347849115],[11696351847604335156,9496337687212684441]],"end_point":[[10686631697241750410,9496337687212684441],[18226408581696793441,9465415708990918986],[3809009367670994230,12398030966924498647],[16628058317667581864,13517856880347849115],[11696351847604335156,14760110820354327749],[13496648265229692336,2930103517622848405]],"handle_primary":[[13496648265229692336,[14.222222222222172,-0.8888888888888857]],[3809009367670994230,[21.33333333333337,4.740740740740733]],[16628058317667581864,[41.185185185185105,-9.7777777777778]],[10686631697241750410,[-13.037037037036953,-4.444444444444457]],[11696351847604335156,[-29.333333333333258,11.55555555555555]],[18226408581696793441,[0.0,0.0]]],"handle_end":[[13496648265229692336,[13.037037037036953,4.444444444444457]],[11696351847604335156,[54.81481481481478,-42.37037037037035]],[18226408581696793441,[-41.185185185185105,9.7777777777778]],[16628058317667581864,[-21.33333333333337,-4.740740740740733]],[3809009367670994230,[-14.222222222222172,0.8888888888888857]],[10686631697241750410,[29.333333333333258,-11.55555555555555]]],"stroke":[[16628058317667581864,0],[10686631697241750410,0],[18226408581696793441,0],[13496648265229692336,0],[11696351847604335156,0],[3809009367670994230,0]]},"regions":{"add":[],"remove":[],"segment_range":[],"fill":[]},"add_g1_continuous":[[{"ty":"End","segment":10686631697241750410},{"ty":"Primary","segment":11696351847604335156}],[{"ty":"End","segment":18226408581696793441},{"ty":"Primary","segment":16628058317667581864}],[{"ty":"End","segment":13496648265229692336},{"ty":"Primary","segment":10686631697241750410}],[{"ty":"End","segment":16628058317667581864},{"ty":"Primary","segment":3809009367670994230}],[{"ty":"End","segment":3809009367670994230},{"ty":"Primary","segment":13496648265229692336}]],"remove_g1_continuous":[]}},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::vector_data::modification::VectorModification","alias":null}},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::vector_data::modification::PathModifyNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[4560146526699152877,{"inputs":[{"Node":{"node_id":5486211022469996717,"output_index":0,"lambda":false}},{"Node":{"node_id":13646498613066619660,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[57390435731316553,{"inputs":[{"Node":{"node_id":8460565235419043665,"output_index":0,"lambda":false}},{"Node":{"node_id":13838011362258067867,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[1.0,1.0]},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[0.0,0.0]},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[0.5,0.5]},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":1}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":2}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":3}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":4}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":5}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::TransformNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[16785043320296790229,{"inputs":[{"Node":{"node_id":1009114585722052052,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"OptionalColor":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}},"exposed":false}},{"Value":{"tagged_value":{"F64":20.0},"exposed":false}},{"Value":{"tagged_value":{"StrokeAlign":"Center"},"exposed":false}},{"Value":{"tagged_value":{"StrokeCap":"Butt"},"exposed":false}},{"Value":{"tagged_value":{"StrokeJoin":"Miter"},"exposed":false}},{"Value":{"tagged_value":{"F64":4.0},"exposed":false}},{"Value":{"tagged_value":{"PaintOrder":"StrokeAbove"},"exposed":false}},{"Value":{"tagged_value":{"VecF64":[]},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::StrokeNode"}},"visible":true,"skip_deduplication":false}],[9808637865669223270,{"inputs":[{"Node":{"node_id":140396870212231820,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"Fill":{"Solid":{"red":0.101960786,"green":0.13333334,"blue":0.13725491,"alpha":1.0}}},"exposed":false}},{"Value":{"tagged_value":{"OptionalColor":{"red":0.101960786,"green":0.13333334,"blue":0.13725491,"alpha":1.0}},"exposed":false}},{"Value":{"tagged_value":{"Gradient":{"stops":[[0.0,{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}],[1.0,{"red":1.0,"green":1.0,"blue":1.0,"alpha":1.0}]],"gradient_type":"Linear","start":[0.0,0.5],"end":[1.0,0.5],"transform":[1.0,0.0,0.0,1.0,0.0,0.0]}},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::FillNode"}},"visible":true,"skip_deduplication":false}],[16177422101884031678,{"inputs":[{"Node":{"node_id":13353438235848911576,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"Fill":{"Solid":{"red":0.101960786,"green":0.13333334,"blue":0.13725491,"alpha":1.0}}},"exposed":false}},{"Value":{"tagged_value":{"OptionalColor":{"red":0.101960786,"green":0.13333334,"blue":0.13725491,"alpha":1.0}},"exposed":false}},{"Value":{"tagged_value":{"Gradient":{"stops":[[0.0,{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}],[1.0,{"red":1.0,"green":1.0,"blue":1.0,"alpha":1.0}]],"gradient_type":"Linear","start":[0.0,0.5],"end":[1.0,0.5],"transform":[1.0,0.0,0.0,1.0,0.0,0.0]}},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::FillNode"}},"visible":true,"skip_deduplication":false}],[11201759760883367635,{"inputs":[{"Value":{"tagged_value":{"VectorData":{"instance":[{"style":{"stroke":{"color":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0},"weight":0.0,"dash_lengths":[],"dash_offset":0.0,"cap":"Butt","join":"Miter","join_miter_limit":4.0,"align":"Center","transform":[1.0,0.0,0.0,1.0,0.0,0.0],"non_scaling":false,"paint_order":"StrokeAbove"},"fill":"None"},"colinear_manipulators":[],"point_domain":{"id":[],"position":[]},"segment_domain":{"id":[],"start_point":[],"end_point":[],"handles":[],"stroke":[]},"region_domain":{"id":[],"segment_range":[],"fill":[]},"upstream_graphic_group":null}],"transform":[[1.0,0.0,0.0,1.0,0.0,0.0]],"alpha_blending":[{"blend_mode":"Normal","opacity":1.0,"fill":1.0,"clip":false}],"source_node_id":[null]}},"exposed":true}},{"Value":{"tagged_value":{"VectorModification":{"points":{"add":[5173348374891662425,12314285668680405002,7388288026322342161,12796056970187696453],"remove":[],"delta":[[5173348374891662425,[969.0,0.0]],[12314285668680405002,[1085.0,181.0]],[7388288026322342161,[1277.0,319.0]],[12796056970187696453,[1418.0,0.0]]]},"segments":{"add":[10860608091363771974,9177623211202289793,18091265337503274797,9065140293539496953],"remove":[],"start_point":[[9065140293539496953,12796056970187696453],[10860608091363771974,5173348374891662425],[18091265337503274797,7388288026322342161],[9177623211202289793,12314285668680405002]],"end_point":[[9065140293539496953,5173348374891662425],[18091265337503274797,12796056970187696453],[10860608091363771974,12314285668680405002],[9177623211202289793,7388288026322342161]],"handle_primary":[[10860608091363771974,[0.0,0.0]],[18091265337503274797,[178.0,-35.0]],[9065140293539496953,[0.0,0.0]],[9177623211202289793,[-33.0,137.0]]],"handle_end":[[18091265337503274797,[168.99998492988766,81.0]],[10860608091363771974,[25.066898104916696,-104.0656072840481]],[9177623211202289793,[-77.81941867085992,15.301571086966838]],[9065140293539496953,[0.0,0.0]]],"stroke":[[18091265337503274797,0],[9065140293539496953,0],[9177623211202289793,0],[10860608091363771974,0]]},"regions":{"add":[],"remove":[],"segment_range":[],"fill":[]},"add_g1_continuous":[[{"ty":"End","segment":9177623211202289793},{"ty":"Primary","segment":18091265337503274797}],[{"ty":"End","segment":10860608091363771974},{"ty":"Primary","segment":9177623211202289793}]],"remove_g1_continuous":[]}},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::vector_data::modification::VectorModification","alias":null}},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::vector_data::modification::PathModifyNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[10760002922115563021,{"inputs":[{"Node":{"node_id":14257963317028524134,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"BooleanOperation":"SubtractFront"},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::style::Fill","alias":null}},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_path_bool::BooleanOperationNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":2,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::BoundlessFootprintNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::FreezeRealTimeNode"}},"visible":true,"skip_deduplication":false}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MemoNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[13588160462734303101,{"inputs":[{"Node":{"node_id":17036604842139972912,"output_index":0,"lambda":false}},{"Node":{"node_id":4301099429811409147,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[11373527190663101881,{"inputs":[{"Value":{"tagged_value":{"VectorData":{"instance":[{"style":{"stroke":{"color":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0},"weight":0.0,"dash_lengths":[],"dash_offset":0.0,"cap":"Butt","join":"Miter","join_miter_limit":4.0,"align":"Center","transform":[1.0,0.0,0.0,1.0,0.0,0.0],"non_scaling":false,"paint_order":"StrokeAbove"},"fill":"None"},"colinear_manipulators":[],"point_domain":{"id":[],"position":[]},"segment_domain":{"id":[],"start_point":[],"end_point":[],"handles":[],"stroke":[]},"region_domain":{"id":[],"segment_range":[],"fill":[]},"upstream_graphic_group":null}],"transform":[[1.0,0.0,0.0,1.0,0.0,0.0]],"alpha_blending":[{"blend_mode":"Normal","opacity":1.0,"fill":1.0,"clip":false}],"source_node_id":[null]}},"exposed":true}},{"Value":{"tagged_value":{"VectorModification":{"points":{"add":[12058665768506126331,6802441093413090533,4854280308383915721,17729943149159368459,7436032950540776377,2189722519288419244,15817054697695831753,15744271344233846756,13877679667762731651,13567509413382199058,5664077098702810122,14178520291283306679,15575201098426093294],"remove":[],"delta":[[15744271344233846756,[785.7777777777777,205.62962962962965]],[6802441093413090533,[783.4074074074074,172.74074074074073]],[7436032950540776377,[815.4074074074074,203.25925925925927]],[2189722519288419244,[796.0493827160494,202.2716049382716]],[12058665768506126331,[693.7283950617283,174.35390946502056]],[4854280308383915721,[813.9259259259259,200.2962962962963]],[17729943149159368459,[801.1851851851852,199.90123456790124]],[13877679667762731651,[743.4074074074074,234.66666666666669]],[15817054697695831753,[806.716049382716,206.22222222222223]],[14178520291283306679,[668.4444444444443,183.1111111111111]],[13567509413382199058,[702.6831275720166,195.95061728395063]],[15575201098426093294,[636.7407407407406,173.33333333333331]],[5664077098702810122,[686.5185185185185,191.1111111111111]]]},"segments":{"add":[2336956120616260883,1639796012074210121,3918280827204321712,13932755083907220179,14941832641240060361,94092576912261794,18299135553255571870,3109091330258982137,11037018395008586448,16261506098907231989,8279051592565434787,2367379450383978497,5102625335252315850],"remove":[],"start_point":[[14941832641240060361,7436032950540776377],[18299135553255571870,15817054697695831753],[8279051592565434787,5664077098702810122],[3918280827204321712,4854280308383915721],[13932755083907220179,17729943149159368459],[2336956120616260883,12058665768506126331],[3109091330258982137,15744271344233846756],[1639796012074210121,6802441093413090533],[5102625335252315850,15575201098426093294],[2367379450383978497,14178520291283306679],[11037018395008586448,13877679667762731651],[16261506098907231989,13567509413382199058],[94092576912261794,2189722519288419244]],"end_point":[[18299135553255571870,15744271344233846756],[14941832641240060361,2189722519288419244],[16261506098907231989,5664077098702810122],[2367379450383978497,15575201098426093294],[13932755083907220179,7436032950540776377],[1639796012074210121,4854280308383915721],[3109091330258982137,13877679667762731651],[11037018395008586448,13567509413382199058],[94092576912261794,15817054697695831753],[2336956120616260883,6802441093413090533],[3918280827204321712,17729943149159368459],[5102625335252315850,12058665768506126331],[8279051592565434787,14178520291283306679]],"handle_primary":[[3918280827204321712,[0.0,0.0]],[11037018395008586448,[0.0,0.0]],[18299135553255571870,[0.0,0.0]],[1639796012074210121,[0.0,0.0]],[16261506098907231989,[0.0,0.0]],[3109091330258982137,[0.0,0.0]],[8279051592565434787,[-16.75720164609038,-2.1399176954732297]],[2367379450383978497,[-5.037037037036953,-1.7777777777777717]],[13932755083907220179,[0.0,0.0]],[2336956120616260883,[0.0,0.0]],[5102625335252315850,[0.0,0.0]],[14941832641240060361,[0.0,0.0]],[94092576912261794,[0.0,0.0]]],"handle_end":[[2336956120616260883,[-65.77777777777783,13.333333333333314]],[14941832641240060361,[7.1111111111111995,1.7777777777778]],[16261506098907231989,[12.1395654462896,1.5502392023748983]],[13932755083907220179,[0.0,0.0]],[8279051592565434787,[5.037037037036953,1.7777777777777717]],[5102625335252315850,[-27.12757201646093,2.633744855967052]],[11037018395008586448,[13.168724279835374,22.12345679012344]],[94092576912261794,[0.0,0.0]],[18299135553255571870,[10.07407407407402,2.7654320987654444]],[3109091330258982137,[18.962962962963047,2.074074074074048]],[1639796012074210121,[-19.259259259259352,-3.259259259259238]],[2367379450383978497,[12.740740740740648,5.037037037037038]],[3918280827204321712,[0.0,0.0]]],"stroke":[[2336956120616260883,0],[2367379450383978497,0],[1639796012074210121,0],[18299135553255571870,0],[8279051592565434787,0],[3918280827204321712,0],[11037018395008586448,0],[13932755083907220179,0],[94092576912261794,0],[3109091330258982137,0],[5102625335252315850,0],[16261506098907231989,0],[14941832641240060361,0]]},"regions":{"add":[],"remove":[],"segment_range":[],"fill":[]},"add_g1_continuous":[[{"ty":"End","segment":3918280827204321712},{"ty":"Primary","segment":13932755083907220179}],[{"ty":"End","segment":94092576912261794},{"ty":"Primary","segment":18299135553255571870}],[{"ty":"End","segment":8279051592565434787},{"ty":"Primary","segment":2367379450383978497}],[{"ty":"End","segment":13932755083907220179},{"ty":"Primary","segment":14941832641240060361}],[{"ty":"End","segment":16261506098907231989},{"ty":"Primary","segment":8279051592565434787}]],"remove_g1_continuous":[[{"ty":"Primary","segment":16261506098907231989},{"ty":"End","segment":11037018395008586448}]]}},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::vector_data::modification::VectorModification","alias":null}},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::vector_data::modification::PathModifyNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[9563008199132558110,{"inputs":[{"Node":{"node_id":7855094781869605606,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"Fill":{"Solid":{"red":0.8509804,"green":0.24313726,"blue":0.18431373,"alpha":1.0}}},"exposed":false}},{"Value":{"tagged_value":{"OptionalColor":{"red":0.8509804,"green":0.24313726,"blue":0.18431373,"alpha":1.0}},"exposed":false}},{"Value":{"tagged_value":{"Gradient":{"stops":[[0.0,{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}],[1.0,{"red":1.0,"green":1.0,"blue":1.0,"alpha":1.0}]],"gradient_type":"Linear","start":[0.0,0.5],"end":[1.0,0.5],"transform":[1.0,0.0,0.0,1.0,0.0,0.0]}},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::FillNode"}},"visible":true,"skip_deduplication":false}],[18081743490344004315,{"inputs":[{"Node":{"node_id":13588160462734303101,"output_index":0,"lambda":false}},{"Node":{"node_id":18068340617333437755,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[6852799892628327372,{"inputs":[{"Node":{"node_id":2025899804080897524,"output_index":0,"lambda":false}},{"Node":{"node_id":16671141883125519098,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[17952673493105230490,{"inputs":[{"Node":{"node_id":14228923746783465609,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"OptionalColor":{"red":0.101960786,"green":0.13333334,"blue":0.13725491,"alpha":1.0}},"exposed":false}},{"Value":{"tagged_value":{"F64":20.0},"exposed":false}},{"Value":{"tagged_value":{"StrokeAlign":"Center"},"exposed":false}},{"Value":{"tagged_value":{"StrokeCap":"Butt"},"exposed":false}},{"Value":{"tagged_value":{"StrokeJoin":"Miter"},"exposed":false}},{"Value":{"tagged_value":{"F64":4.0},"exposed":false}},{"Value":{"tagged_value":{"PaintOrder":"StrokeAbove"},"exposed":false}},{"Value":{"tagged_value":{"VecF64":[]},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::StrokeNode"}},"visible":true,"skip_deduplication":false}],[8863346544623578893,{"inputs":[{"Value":{"tagged_value":{"VectorData":{"instance":[{"style":{"stroke":{"color":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0},"weight":0.0,"dash_lengths":[],"dash_offset":0.0,"cap":"Butt","join":"Miter","join_miter_limit":4.0,"align":"Center","transform":[1.0,0.0,0.0,1.0,0.0,0.0],"non_scaling":false,"paint_order":"StrokeAbove"},"fill":"None"},"colinear_manipulators":[],"point_domain":{"id":[],"position":[]},"segment_domain":{"id":[],"start_point":[],"end_point":[],"handles":[],"stroke":[]},"region_domain":{"id":[],"segment_range":[],"fill":[]},"upstream_graphic_group":null}],"transform":[[1.0,0.0,0.0,1.0,0.0,0.0]],"alpha_blending":[{"blend_mode":"Normal","opacity":1.0,"fill":1.0,"clip":false}],"source_node_id":[null]}},"exposed":true}},{"Value":{"tagged_value":{"VectorModification":{"points":{"add":[5480246971175127548,949359986970918930,6461719056721357962,6265491311473200676],"remove":[947514826240006203],"delta":[[6461719056721357962,[173.33333333333331,506.66666666666674]],[949359986970918930,[0.0,608.0]],[5480246971175127548,[364.0,767.9999999999999]],[6265491311473200676,[-2.273736754432321e-13,768.0000000000001]]]},"segments":{"add":[8951068186878308228,9717584104793611782,15710828508798332384,12480300844056666979],"remove":[6561081452252813685,11231973846952426191,15926511461198813522],"start_point":[[15710828508798332384,5480246971175127548],[8951068186878308228,6461719056721357962],[12480300844056666979,6265491311473200676],[9717584104793611782,949359986970918930]],"end_point":[[15710828508798332384,6265491311473200676],[8951068186878308228,5480246971175127548],[9717584104793611782,6461719056721357962],[12480300844056666979,949359986970918930]],"handle_primary":[[12480300844056666979,null],[8951068186878308228,[121.00000000000006,-37.99999999999994]],[9717584104793611782,[0.0,0.0]],[15710828508798332384,null]],"handle_end":[[12480300844056666979,null],[9717584104793611782,[-63.1770926995265,19.84073985604961]],[15710828508798332384,null],[8951068186878308228,[-92.0,-81.99999999999989]]],"stroke":[[9717584104793611782,0],[15710828508798332384,0],[8951068186878308228,0],[12480300844056666979,0]]},"regions":{"add":[],"remove":[],"segment_range":[],"fill":[]},"add_g1_continuous":[[{"ty":"Primary","segment":9717584104793611782},{"ty":"End","segment":12480300844056666979}],[{"ty":"Primary","segment":8951068186878308228},{"ty":"End","segment":9717584104793611782}],[{"ty":"End","segment":6561081452252813685},{"ty":"Primary","segment":9717584104793611782}]],"remove_g1_continuous":[[{"ty":"Primary","segment":11231973846952426191},{"ty":"End","segment":9717584104793611782}],[{"ty":"End","segment":15926511461198813522},{"ty":"Primary","segment":8951068186878308228}]]}},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::vector_data::modification::VectorModification","alias":null}},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::vector_data::modification::PathModifyNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[15692102598187739001,{"inputs":[{"Node":{"node_id":14950060858756810933,"output_index":0,"lambda":false}},{"Node":{"node_id":11201759760883367635,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[4421418468606442725,{"inputs":[{"Node":{"node_id":8863346544623578893,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"Fill":{"Solid":{"red":0.93333334,"green":0.8627451,"blue":0.7254902,"alpha":1.0}}},"exposed":false}},{"Value":{"tagged_value":{"OptionalColor":{"red":0.93333334,"green":0.8627451,"blue":0.7254902,"alpha":1.0}},"exposed":false}},{"Value":{"tagged_value":{"Gradient":{"stops":[[0.0,{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}],[1.0,{"red":1.0,"green":1.0,"blue":1.0,"alpha":1.0}]],"gradient_type":"Linear","start":[0.0,0.5],"end":[1.0,0.5],"transform":[1.0,0.0,0.0,1.0,0.0,0.0]}},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::FillNode"}},"visible":true,"skip_deduplication":false}],[4807760870555738383,{"inputs":[{"Node":{"node_id":876963243827503916,"output_index":0,"lambda":false}},{"Node":{"node_id":8269257328703012432,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[4102754869474520966,{"inputs":[{"Node":{"node_id":2723198387862533596,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"BooleanOperation":"Intersect"},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::style::Fill","alias":null}},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_path_bool::BooleanOperationNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":2,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::BoundlessFootprintNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::FreezeRealTimeNode"}},"visible":true,"skip_deduplication":false}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MemoNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[2880630606834119505,{"inputs":[{"Node":{"node_id":8297015715799006244,"output_index":0,"lambda":false}},{"Node":{"node_id":16322546010403524636,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[1.0,1.0]},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[0.0,0.0]},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[0.5,0.5]},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":1}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":2}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":3}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":4}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":5}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::TransformNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[10265035897167064154,{"inputs":[{"Node":{"node_id":14698962747138962125,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"Fill":{"Solid":{"red":0.101960786,"green":0.13333334,"blue":0.13725491,"alpha":1.0}}},"exposed":false}},{"Value":{"tagged_value":{"OptionalColor":{"red":0.101960786,"green":0.13333334,"blue":0.13725491,"alpha":1.0}},"exposed":false}},{"Value":{"tagged_value":{"Gradient":{"stops":[[0.0,{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}],[1.0,{"red":1.0,"green":1.0,"blue":1.0,"alpha":1.0}]],"gradient_type":"Linear","start":[0.0,0.5],"end":[1.0,0.5],"transform":[1.0,0.0,0.0,1.0,0.0,0.0]}},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::FillNode"}},"visible":true,"skip_deduplication":false}],[17131529656312051452,{"inputs":[{"Node":{"node_id":13646498613066619660,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"Fill":{"Solid":{"red":0.92156863,"green":0.6039216,"blue":0.18039216,"alpha":1.0}}},"exposed":false}},{"Value":{"tagged_value":{"OptionalColor":{"red":0.92156863,"green":0.6039216,"blue":0.18039216,"alpha":1.0}},"exposed":false}},{"Value":{"tagged_value":{"Gradient":{"stops":[[0.0,{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}],[1.0,{"red":1.0,"green":1.0,"blue":1.0,"alpha":1.0}]],"gradient_type":"Linear","start":[0.0,0.5],"end":[1.0,0.5],"transform":[1.0,0.0,0.0,1.0,0.0,0.0]}},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::FillNode"}},"visible":true,"skip_deduplication":false}],[7104088139635280554,{"inputs":[{"Node":{"node_id":16785043320296790229,"output_index":0,"lambda":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::SolidifyStrokeNode"}},"visible":true,"skip_deduplication":false}],[18068340617333437755,{"inputs":[{"Node":{"node_id":2880630606834119505,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"DVec2":[73.0306419396,-200.8521460039]},"exposed":false}},{"Value":{"tagged_value":{"F64":0.42594097420784194},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[0.9999999999999998,0.9999999999999998]},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[0.0,0.0]},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[0.5,0.5]},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":1}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":2}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":3}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":4}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":5}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::TransformNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[2185437945364824599,{"inputs":[{"Node":{"node_id":18081743490344004315,"output_index":0,"lambda":false}},{"Node":{"node_id":4421418468606442725,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[1627123781166851142,{"inputs":[{"Node":{"node_id":4807760870555738383,"output_index":0,"lambda":false}},{"Node":{"node_id":15354358358546908017,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[14141479077115894852,{"inputs":[{"Node":{"node_id":15433707377961038695,"output_index":0,"lambda":false}},{"Node":{"node_id":17285637344898461972,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[17397123104674848450,{"inputs":[{"Node":{"node_id":1662641269094032596,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"BooleanOperation":"Intersect"},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::style::Fill","alias":null}},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_path_bool::BooleanOperationNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":2,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::BoundlessFootprintNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::FreezeRealTimeNode"}},"visible":true,"skip_deduplication":false}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MemoNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[15877481873925059044,{"inputs":[{"Node":{"node_id":17299978721726771610,"output_index":0,"lambda":false}},{"Node":{"node_id":7252918969430566594,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[1.0,1.0]},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[0.0,0.0]},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[0.5,0.5]},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":1}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":2}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":3}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":4}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":5}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::TransformNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[13340751444307201866,{"inputs":[{"Node":{"node_id":9135110142507605216,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"Fill":{"Solid":{"red":0.93333334,"green":0.8627451,"blue":0.7254902,"alpha":1.0}}},"exposed":false}},{"Value":{"tagged_value":{"OptionalColor":{"red":0.93333334,"green":0.8627451,"blue":0.7254902,"alpha":1.0}},"exposed":false}},{"Value":{"tagged_value":{"Gradient":{"stops":[[0.0,{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}],[1.0,{"red":1.0,"green":1.0,"blue":1.0,"alpha":1.0}]],"gradient_type":"Linear","start":[0.0,0.5],"end":[1.0,0.5],"transform":[1.0,0.0,0.0,1.0,0.0,0.0]}},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::FillNode"}},"visible":true,"skip_deduplication":false}],[12741076678082295759,{"inputs":[{"Node":{"node_id":14139765080256493579,"output_index":0,"lambda":false}},{"Node":{"node_id":5449860184735415958,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[13916027199283115943,{"inputs":[{"Node":{"node_id":6194305264313730032,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"Fill":{"Solid":{"red":0.101960786,"green":0.13333334,"blue":0.13725491,"alpha":1.0}}},"exposed":false}},{"Value":{"tagged_value":{"OptionalColor":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}},"exposed":false}},{"Value":{"tagged_value":{"Gradient":{"stops":[[0.0,{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}],[1.0,{"red":1.0,"green":1.0,"blue":1.0,"alpha":1.0}]],"gradient_type":"Linear","start":[0.0,0.5],"end":[1.0,0.5],"transform":[1.0,0.0,0.0,1.0,0.0,0.0]}},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::FillNode"}},"visible":true,"skip_deduplication":false}],[15930698052919171086,{"inputs":[{"Node":{"node_id":13739729101529293427,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"BooleanOperation":"SubtractFront"},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::style::Fill","alias":null}},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_path_bool::BooleanOperationNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":2,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::BoundlessFootprintNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::FreezeRealTimeNode"}},"visible":true,"skip_deduplication":false}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MemoNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[4631655038168471552,{"inputs":[{"Node":{"node_id":990192925663920333,"output_index":0,"lambda":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::BoundingBoxNode"}},"visible":true,"skip_deduplication":false}],[17223836790030950966,{"inputs":[{"Node":{"node_id":14030142873804552388,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"Fill":{"Solid":{"red":0.8509804,"green":0.24313726,"blue":0.18431373,"alpha":1.0}}},"exposed":false}},{"Value":{"tagged_value":{"OptionalColor":{"red":0.8509804,"green":0.24313726,"blue":0.18431373,"alpha":1.0}},"exposed":false}},{"Value":{"tagged_value":{"Gradient":{"stops":[[0.0,{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}],[1.0,{"red":1.0,"green":1.0,"blue":1.0,"alpha":1.0}]],"gradient_type":"Linear","start":[0.0,0.5],"end":[1.0,0.5],"transform":[1.0,0.0,0.0,1.0,0.0,0.0]}},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::FillNode"}},"visible":true,"skip_deduplication":false}],[17056531964793634106,{"inputs":[{"Node":{"node_id":990192925663920333,"output_index":0,"lambda":false}},{"Node":{"node_id":10063704933309776584,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[1.0,1.0]},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[0.0,0.0]},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[0.5,0.5]},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":1}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":2}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":3}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":4}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":5}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::TransformNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[13446205009526451196,{"inputs":[{"Node":{"node_id":14139765080256493579,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"Fill":{"Solid":{"red":0.92156863,"green":0.6039216,"blue":0.18039216,"alpha":1.0}}},"exposed":false}},{"Value":{"tagged_value":{"OptionalColor":{"red":0.92156863,"green":0.6039216,"blue":0.18039216,"alpha":1.0}},"exposed":false}},{"Value":{"tagged_value":{"Gradient":{"stops":[[0.0,{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}],[1.0,{"red":1.0,"green":1.0,"blue":1.0,"alpha":1.0}]],"gradient_type":"Linear","start":[0.0,0.5],"end":[1.0,0.5],"transform":[1.0,0.0,0.0,1.0,0.0,0.0]}},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::FillNode"}},"visible":true,"skip_deduplication":false}],[15433707377961038695,{"inputs":[{"Value":{"tagged_value":{"VectorData":{"instance":[{"style":{"stroke":{"color":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0},"weight":0.0,"dash_lengths":[],"dash_offset":0.0,"cap":"Butt","join":"Miter","join_miter_limit":4.0,"align":"Center","transform":[1.0,0.0,0.0,1.0,0.0,0.0],"non_scaling":false,"paint_order":"StrokeAbove"},"fill":"None"},"colinear_manipulators":[],"point_domain":{"id":[],"position":[]},"segment_domain":{"id":[],"start_point":[],"end_point":[],"handles":[],"stroke":[]},"region_domain":{"id":[],"segment_range":[],"fill":[]},"upstream_graphic_group":null}],"transform":[[1.0,0.0,0.0,1.0,0.0,0.0]],"alpha_blending":[{"blend_mode":"Normal","opacity":1.0,"fill":1.0,"clip":false}],"source_node_id":[null]}},"exposed":true}},{"Value":{"tagged_value":{"VectorModification":{"points":{"add":[16723991032614525258,1623125309784127684,7209807874503344461,3123395482103162919,2668496811386192321],"remove":[12344391980636687302],"delta":[[3123395482103162919,[-2.273736754432321e-13,689.0]],[7209807874503344461,[188.0,694.6666666666669]],[16723991032614525258,[553.0000000000001,768.0]],[2668496811386192321,[0.0,768.0]],[1623125309784127684,[643.9258958566198,633.6997633965701]]]},"segments":{"add":[3656277643115996070,6789459806904610761,16287649713110748258,16456150086799119359,1652964032977338610],"remove":[1848051273241122771],"start_point":[[6789459806904610761,1623125309784127684],[16456150086799119359,2668496811386192321],[16287649713110748258,3123395482103162919],[1652964032977338610,7209807874503344461],[3656277643115996070,16723991032614525258]],"end_point":[[16456150086799119359,16723991032614525258],[16287649713110748258,2668496811386192321],[1652964032977338610,3123395482103162919],[3656277643115996070,1623125309784127684],[6789459806904610761,7209807874503344461]],"handle_primary":[[3656277643115996070,[0.0,0.0]],[16287649713110748258,[0.0,0.0]],[16456150086799119359,[0.0,0.0]],[6789459806904610761,[-213.92589585661983,-68.82675604113183]],[1652964032977338610,[-81.48609837852206,84.6759456460087]]],"handle_end":[[6789459806904610761,[187.33333333333343,-194.6666666666667]],[3656277643115996070,[0.0,0.0]],[16287649713110748258,[0.0,0.0]],[1652964032977338610,[56.00000000000023,11.0]],[16456150086799119359,[0.0,0.0]]],"stroke":[[16287649713110748258,0],[16456150086799119359,0],[6789459806904610761,0],[1652964032977338610,0],[3656277643115996070,0]]},"regions":{"add":[],"remove":[],"segment_range":[],"fill":[]},"add_g1_continuous":[[{"ty":"End","segment":6789459806904610761},{"ty":"Primary","segment":1652964032977338610}],[{"ty":"End","segment":16287649713110748258},{"ty":"Primary","segment":16456150086799119359}]],"remove_g1_continuous":[[{"ty":"End","segment":1652964032977338610},{"ty":"Primary","segment":1848051273241122771}],[{"ty":"End","segment":3656277643115996070},{"ty":"Primary","segment":6789459806904610761}]]}},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::vector_data::modification::VectorModification","alias":null}},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::vector_data::modification::PathModifyNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[5877930116725120460,{"inputs":[{"Node":{"node_id":4470272391975492611,"output_index":0,"lambda":false}},{"Node":{"node_id":1258994191538244490,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[14516211820212764316,{"inputs":[{"Node":{"node_id":2124231869409556689,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"DVec2":[0.0,416.7]},"exposed":false}},{"Value":{"tagged_value":{"F64":31.0},"exposed":false}},{"Value":{"tagged_value":{"U32":8},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::RepeatNode"}},"visible":true,"skip_deduplication":false}],[3997031659711823213,{"inputs":[{"Node":{"node_id":6484183251661832039,"output_index":0,"lambda":false}},{"Node":{"node_id":7962101329808960965,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[1.0,1.0]},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[0.0,0.0]},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[0.5,0.5]},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":1}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":2}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":3}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":4}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":5}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::TransformNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[3471746866096043087,{"inputs":[{"Node":{"node_id":5486211022469996717,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"Fill":{"Solid":{"red":0.3137255,"green":0.44705883,"blue":0.45490196,"alpha":1.0}}},"exposed":false}},{"Value":{"tagged_value":{"OptionalColor":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}},"exposed":false}},{"Value":{"tagged_value":{"Gradient":{"stops":[[0.0,{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}],[1.0,{"red":1.0,"green":1.0,"blue":1.0,"alpha":1.0}]],"gradient_type":"Linear","start":[0.0,0.5],"end":[1.0,0.5],"transform":[1.0,0.0,0.0,1.0,0.0,0.0]}},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::FillNode"}},"visible":true,"skip_deduplication":false}],[7480253252288032958,{"inputs":[{"Node":{"node_id":7104261880154687267,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"Fill":{"Solid":{"red":0.8509804,"green":0.24313726,"blue":0.18431373,"alpha":1.0}}},"exposed":false}},{"Value":{"tagged_value":{"OptionalColor":{"red":0.8509804,"green":0.24313726,"blue":0.18431373,"alpha":1.0}},"exposed":false}},{"Value":{"tagged_value":{"Gradient":{"stops":[[0.0,{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}],[1.0,{"red":1.0,"green":1.0,"blue":1.0,"alpha":1.0}]],"gradient_type":"Linear","start":[0.0,0.5],"end":[1.0,0.5],"transform":[1.0,0.0,0.0,1.0,0.0,0.0]}},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::FillNode"}},"visible":true,"skip_deduplication":false}],[3079923906392020295,{"inputs":[{"Node":{"node_id":17056531964793634106,"output_index":0,"lambda":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}],[4809200889774783438,{"inputs":[{"Node":{"node_id":3109716240255919254,"output_index":0,"lambda":false}},{"Node":{"node_id":14139129879376457893,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[16304636129468583592,{"inputs":[{"Value":{"tagged_value":{"VectorData":{"instance":[{"style":{"stroke":{"color":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0},"weight":0.0,"dash_lengths":[],"dash_offset":0.0,"cap":"Butt","join":"Miter","join_miter_limit":4.0,"align":"Center","transform":[1.0,0.0,0.0,1.0,0.0,0.0],"non_scaling":false,"paint_order":"StrokeAbove"},"fill":"None"},"colinear_manipulators":[],"point_domain":{"id":[],"position":[]},"segment_domain":{"id":[],"start_point":[],"end_point":[],"handles":[],"stroke":[]},"region_domain":{"id":[],"segment_range":[],"fill":[]},"upstream_graphic_group":null}],"transform":[[1.0,0.0,0.0,1.0,0.0,0.0]],"alpha_blending":[{"blend_mode":"Normal","opacity":1.0,"fill":1.0,"clip":false}],"source_node_id":[null]}},"exposed":true}},{"Value":{"tagged_value":{"VectorModification":{"points":{"add":[4648964341912884959,10156053545530752213,16569120368910754547],"remove":[],"delta":[[4648964341912884959,[665.0000000000001,768.0]],[10156053545530752213,[1094.162353515625,594.2965698242188]],[16569120368910754547,[1361.0,768.0]]]},"segments":{"add":[9030015329489789075,2197140374690997530,3433930674303663828],"remove":[],"start_point":[[3433930674303663828,16569120368910754547],[2197140374690997530,10156053545530752213],[9030015329489789075,4648964341912884959]],"end_point":[[9030015329489789075,10156053545530752213],[3433930674303663828,4648964341912884959],[2197140374690997530,16569120368910754547]],"handle_primary":[[2197140374690997530,[79.20069951994813,30.807024746222492]],[9030015329489789075,[32.66666666666663,-95.99999999999989]],[3433930674303663828,[0.0,0.0]]],"handle_end":[[3433930674303663828,[0.0,0.0]],[2197140374690997530,[-24.333333333333485,-86.99999999999977]],[9030015329489789075,[-238.88331323750492,-92.9194336284096]]],"stroke":[[3433930674303663828,0],[9030015329489789075,0],[2197140374690997530,0]]},"regions":{"add":[],"remove":[],"segment_range":[],"fill":[]},"add_g1_continuous":[[{"ty":"End","segment":9030015329489789075},{"ty":"Primary","segment":2197140374690997530}]],"remove_g1_continuous":[[{"ty":"End","segment":2197140374690997530},{"ty":"Primary","segment":3433930674303663828}],[{"ty":"Primary","segment":9030015329489789075},{"ty":"End","segment":3433930674303663828}]]}},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::vector_data::modification::VectorModification","alias":null}},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::vector_data::modification::PathModifyNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[2871608309888343463,{"inputs":[{"Node":{"node_id":12494428953087324640,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"DVec2":[0.0,200.0]},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"U32":8},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::RepeatNode"}},"visible":true,"skip_deduplication":false}],[5488285068107445023,{"inputs":[{"Node":{"node_id":7667878689218439065,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"BooleanOperation":"SubtractFront"},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::style::Fill","alias":null}},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_path_bool::BooleanOperationNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":2,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::BoundlessFootprintNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::FreezeRealTimeNode"}},"visible":true,"skip_deduplication":false}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MemoNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[3050731459444225191,{"inputs":[{"Node":{"node_id":682567808439406093,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"DVec2":[0.0,200.0]},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"U32":12},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::RepeatNode"}},"visible":true,"skip_deduplication":false}],[16306737306999003555,{"inputs":[{"Value":{"tagged_value":{"VectorData":{"instance":[{"style":{"stroke":{"color":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0},"weight":0.0,"dash_lengths":[],"dash_offset":0.0,"cap":"Butt","join":"Miter","join_miter_limit":4.0,"align":"Center","transform":[1.0,0.0,0.0,1.0,0.0,0.0],"non_scaling":false,"paint_order":"StrokeAbove"},"fill":"None"},"colinear_manipulators":[],"point_domain":{"id":[],"position":[]},"segment_domain":{"id":[],"start_point":[],"end_point":[],"handles":[],"stroke":[]},"region_domain":{"id":[],"segment_range":[],"fill":[]},"upstream_graphic_group":null}],"transform":[[1.0,0.0,0.0,1.0,0.0,0.0]],"alpha_blending":[{"blend_mode":"Normal","opacity":1.0,"fill":1.0,"clip":false}],"source_node_id":[null]}},"exposed":true}},{"Value":{"tagged_value":{"VectorModification":{"points":{"add":[6082833770141706533,7903705226822768120,17147466439590042359,13341364271767916194],"remove":[],"delta":[[13341364271767916194,[262.22222222222223,364.1481481481481]],[17147466439590042359,[526.0109927536641,282.1042175292969]],[6082833770141706533,[504.0987654320987,184.6255144032922]],[7903705226822768120,[497.3827160493826,248.88888888888889]]]},"segments":{"add":[14649965831690031908,801877719748058643,9659144961849433642,2255088856072565305],"remove":[],"start_point":[[14649965831690031908,6082833770141706533],[9659144961849433642,17147466439590042359],[2255088856072565305,13341364271767916194],[801877719748058643,7903705226822768120]],"end_point":[[2255088856072565305,6082833770141706533],[801877719748058643,17147466439590042359],[9659144961849433642,13341364271767916194],[14649965831690031908,7903705226822768120]],"handle_primary":[[9659144961849433642,[0.0,0.0]],[801877719748058643,[13.173601585124231,23.615912208504938]],[2255088856072565305,[0.0,0.0]],[14649965831690031908,[0.0,0.0]]],"handle_end":[[2255088856072565305,[-112.09876543209862,43.81893004115227]],[9659144961849433642,[195.55555555555569,-16.14814814814804]],[14649965831690031908,[-17.920501046401128,-32.12553353079403]],[801877719748058643,[0.0,0.0]]],"stroke":[[9659144961849433642,0],[801877719748058643,0],[2255088856072565305,0],[14649965831690031908,0]]},"regions":{"add":[],"remove":[],"segment_range":[],"fill":[]},"add_g1_continuous":[[{"ty":"End","segment":14649965831690031908},{"ty":"Primary","segment":801877719748058643}],[{"ty":"End","segment":801877719748058643},{"ty":"Primary","segment":9659144961849433642}]],"remove_g1_continuous":[]}},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::vector_data::modification::VectorModification","alias":null}},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::vector_data::modification::PathModifyNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[8297015715799006244,{"inputs":[{"Node":{"node_id":17569892869974995307,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"DVec2":[0.0,407.5]},"exposed":false}},{"Value":{"tagged_value":{"F64":24.2},"exposed":false}},{"Value":{"tagged_value":{"U32":8},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::RepeatNode"}},"visible":true,"skip_deduplication":false}],[12867379765049504290,{"inputs":[{"Node":{"node_id":6445954214067437701,"output_index":0,"lambda":false}},{"Node":{"node_id":8863346544623578893,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[17740496701763775226,{"inputs":[{"Node":{"node_id":13027689870767713939,"output_index":0,"lambda":false}},{"Node":{"node_id":16609137733952262762,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[14808063168960305551,{"inputs":[{"Node":{"node_id":14496934933990319842,"output_index":0,"lambda":false}},{"Node":{"node_id":3471746866096043087,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[12494428953087324640,{"inputs":[{"Node":{"node_id":8511737864852441844,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"DVec2":[300.0,50.0]},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"U32":12},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::RepeatNode"}},"visible":true,"skip_deduplication":false}],[15817956847588799375,{"inputs":[{"Node":{"node_id":11201759760883367635,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"Fill":{"Solid":{"red":0.3137255,"green":0.44705883,"blue":0.45490196,"alpha":1.0}}},"exposed":false}},{"Value":{"tagged_value":{"OptionalColor":{"red":0.3137255,"green":0.44705883,"blue":0.45490196,"alpha":1.0}},"exposed":false}},{"Value":{"tagged_value":{"Gradient":{"stops":[[0.0,{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}],[1.0,{"red":1.0,"green":1.0,"blue":1.0,"alpha":1.0}]],"gradient_type":"Linear","start":[0.0,0.5],"end":[1.0,0.5],"transform":[1.0,0.0,0.0,1.0,0.0,0.0]}},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::FillNode"}},"visible":true,"skip_deduplication":false}],[2287485748649359627,{"inputs":[{"Node":{"node_id":804622576568168609,"output_index":0,"lambda":false}},{"Node":{"node_id":5449860184735415958,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[13646498613066619660,{"inputs":[{"Node":{"node_id":12741076678082295759,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"BooleanOperation":"Intersect"},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::style::Fill","alias":null}},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_path_bool::BooleanOperationNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":2,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::BoundlessFootprintNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::FreezeRealTimeNode"}},"visible":true,"skip_deduplication":false}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MemoNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[1809704172129195322,{"inputs":[{"Value":{"tagged_value":"None","exposed":false}},{"Value":{"tagged_value":{"F64":20.0},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::generator_nodes::CircleNode"}},"visible":true,"skip_deduplication":false}],[2124231869409556689,{"inputs":[{"Node":{"node_id":15877481873925059044,"output_index":0,"lambda":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}],[876963243827503916,{"inputs":[{"Node":{"node_id":7651693425519490419,"output_index":0,"lambda":false}},{"Node":{"node_id":17223836790030950966,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[13838011362258067867,{"inputs":[{"Node":{"node_id":4631655038168471552,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"CentroidType":"Area"},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::CentroidNode"}},"visible":true,"skip_deduplication":false}],[7376049709233607419,{"inputs":[{"Value":{"tagged_value":{"VectorData":{"instance":[{"style":{"stroke":{"color":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0},"weight":0.0,"dash_lengths":[],"dash_offset":0.0,"cap":"Butt","join":"Miter","join_miter_limit":4.0,"align":"Center","transform":[1.0,0.0,0.0,1.0,0.0,0.0],"non_scaling":false,"paint_order":"StrokeAbove"},"fill":"None"},"colinear_manipulators":[],"point_domain":{"id":[],"position":[]},"segment_domain":{"id":[],"start_point":[],"end_point":[],"handles":[],"stroke":[]},"region_domain":{"id":[],"segment_range":[],"fill":[]},"upstream_graphic_group":null}],"transform":[[1.0,0.0,0.0,1.0,0.0,0.0]],"alpha_blending":[{"blend_mode":"Normal","opacity":1.0,"fill":1.0,"clip":false}],"source_node_id":[null]}},"exposed":true}},{"Value":{"tagged_value":{"VectorModification":{"points":{"add":[16958489363675356032,7347160684180114694,4322398537034510509,3438797896265725901,16005438712872589849,1674257131044231065,10491326691824745018,9374180853656949931,13358295350421759755,15245407364463454564],"remove":[],"delta":[[1674257131044231065,[829.4320987654323,121.67901234567904]],[4322398537034510509,[776.888888888889,117.53086419753087]],[13358295350421759755,[778.4691358024693,177.1851851851852]],[16005438712872589849,[817.1851851851852,94.61728395061728]],[16958489363675356032,[658.172839506173,169.08641975308643]],[10491326691824745018,[811.851851851852,148.54320987654322]],[7347160684180114694,[772.1481481481483,138.66666666666669]],[9374180853656949931,[784.0000000000002,176.98765432098767]],[3438797896265725901,[795.4567901234569,94.41975308641976]],[15245407364463454564,[773.530864197531,141.4320987654321]]]},"segments":{"add":[11663644781855838202,198953627342130434,8327087349631976772,13015157349146777770,8528911024810728168,3235570761188242773,16847383896493391194,16846650637386857857,3784798568712268630,12873317883441611394],"remove":[],"start_point":[[3235570761188242773,1674257131044231065],[12873317883441611394,15245407364463454564],[16847383896493391194,10491326691824745018],[8528911024810728168,16005438712872589849],[11663644781855838202,16958489363675356032],[3784798568712268630,13358295350421759755],[13015157349146777770,3438797896265725901],[198953627342130434,7347160684180114694],[16846650637386857857,9374180853656949931],[8327087349631976772,4322398537034510509]],"end_point":[[13015157349146777770,16005438712872589849],[16847383896493391194,9374180853656949931],[8528911024810728168,1674257131044231065],[12873317883441611394,16958489363675356032],[3784798568712268630,15245407364463454564],[198953627342130434,4322398537034510509],[8327087349631976772,3438797896265725901],[16846650637386857857,13358295350421759755],[3235570761188242773,10491326691824745018],[11663644781855838202,7347160684180114694]],"handle_primary":[[12873317883441611394,[-19.75308641975323,2.172839506172835]],[198953627342130434,[0.0,0.3950617283950635]],[8327087349631976772,[-0.19753086419757435,-13.82716049382715]],[16847383896493391194,[-17.185185185185105,13.234567901234584]],[16846650637386857857,[0.0,0.0]],[13015157349146777770,[0.0,0.0]],[3235570761188242773,[0.1975308641974607,7.703703703703709]],[3784798568712268630,[-2.962962962963161,-10.864197530864232]],[11663644781855838202,[0.0,0.0]],[8528911024810728168,[5.530864197530946,5.925925925925924]]],"handle_end":[[13015157349146777770,[-5.530864197530946,-5.925925925925924]],[11663644781855838202,[-74.27160493827171,29.03703703703698]],[16847383896493391194,[0.0,0.0]],[3235570761188242773,[17.185185185185105,-13.234567901234584]],[198953627342130434,[0.19753086419757435,13.82716049382715]],[12873317883441611394,[33.382716049382566,14.222222222222172]],[8327087349631976772,[0.0,0.0]],[8528911024810728168,[-0.1975308641974607,-7.703703703703709]],[3784798568712268630,[2.9629629629629335,5.135802469135797]],[16846650637386857857,[0.0,0.0]]],"stroke":[[13015157349146777770,0],[11663644781855838202,0],[3784798568712268630,0],[12873317883441611394,0],[8528911024810728168,0],[198953627342130434,0],[8327087349631976772,0],[16847383896493391194,0],[16846650637386857857,0],[3235570761188242773,0]]},"regions":{"add":[],"remove":[],"segment_range":[],"fill":[]},"add_g1_continuous":[[{"ty":"End","segment":3235570761188242773},{"ty":"Primary","segment":16847383896493391194}],[{"ty":"End","segment":8528911024810728168},{"ty":"Primary","segment":3235570761188242773}],[{"ty":"End","segment":8327087349631976772},{"ty":"Primary","segment":13015157349146777770}],[{"ty":"End","segment":16847383896493391194},{"ty":"Primary","segment":16846650637386857857}],[{"ty":"End","segment":13015157349146777770},{"ty":"Primary","segment":8528911024810728168}],[{"ty":"End","segment":198953627342130434},{"ty":"Primary","segment":8327087349631976772}]],"remove_g1_continuous":[[{"ty":"End","segment":16846650637386857857},{"ty":"Primary","segment":3784798568712268630}],[{"ty":"End","segment":3784798568712268630},{"ty":"Primary","segment":12873317883441611394}]]}},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::vector_data::modification::VectorModification","alias":null}},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::vector_data::modification::PathModifyNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[7977952035097419157,{"inputs":[{"Value":{"tagged_value":"None","exposed":false}},{"Value":{"tagged_value":{"F64":0.5},"exposed":false}},{"Value":{"tagged_value":{"F64":0.5},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::generator_nodes::EllipseNode"}},"visible":true,"skip_deduplication":false}],[7667878689218439065,{"inputs":[{"Node":{"node_id":18271512507682813443,"output_index":0,"lambda":false}},{"Node":{"node_id":5449860184735415958,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[14030142873804552388,{"inputs":[{"Value":{"tagged_value":{"VectorData":{"instance":[{"style":{"stroke":{"color":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0},"weight":0.0,"dash_lengths":[],"dash_offset":0.0,"cap":"Butt","join":"Miter","join_miter_limit":4.0,"align":"Center","transform":[1.0,0.0,0.0,1.0,0.0,0.0],"non_scaling":false,"paint_order":"StrokeAbove"},"fill":"None"},"colinear_manipulators":[],"point_domain":{"id":[],"position":[]},"segment_domain":{"id":[],"start_point":[],"end_point":[],"handles":[],"stroke":[]},"region_domain":{"id":[],"segment_range":[],"fill":[]},"upstream_graphic_group":null}],"transform":[[1.0,0.0,0.0,1.0,0.0,0.0]],"alpha_blending":[{"blend_mode":"Normal","opacity":1.0,"fill":1.0,"clip":false}],"source_node_id":[null]}},"exposed":true}},{"Value":{"tagged_value":{"VectorModification":{"points":{"add":[11163144542703672167,7233902871991446034,9403888920678312544,5714042674660607880,9912917483675332510],"remove":[],"delta":[[5714042674660607880,[1536.0,0.0]],[11163144542703672167,[763.0,0.0]],[7233902871991446034,[908.0,134.0]],[9403888920678312544,[1271.0,199.0]],[9912917483675332510,[1536.0,254.00000000000009]]]},"segments":{"add":[7099980686025805826,11879054056208937348,7804540624589615499,3118709054343469746,12085471811343146506],"remove":[8174738144062904321],"start_point":[[7804540624589615499,5714042674660607880],[12085471811343146506,9912917483675332510],[3118709054343469746,9403888920678312544],[11879054056208937348,7233902871991446034],[7099980686025805826,11163144542703672167]],"end_point":[[3118709054343469746,9912917483675332510],[7099980686025805826,7233902871991446034],[12085471811343146506,5714042674660607880],[7804540624589615499,11163144542703672167],[11879054056208937348,9403888920678312544]],"handle_primary":[[12085471811343146506,[0.0,0.0]],[7099980686025805826,[0.0,0.0]],[3118709054343469746,[191.0,-106.0]],[7804540624589615499,[0.0,0.0]],[11879054056208937348,[68.41365603453937,54.51084151791355]]],"handle_end":[[12085471811343146506,[0.0,0.0]],[7099980686025805826,[-68.41365603453914,-54.51084151791349]],[7804540624589615499,[0.0,0.0]],[11879054056208937348,[-121.83694366711715,67.61631428646292]],[3118709054343469746,[0.0,0.0]]],"stroke":[[11879054056208937348,0],[7099980686025805826,0],[7804540624589615499,0],[3118709054343469746,0],[12085471811343146506,0]]},"regions":{"add":[],"remove":[],"segment_range":[],"fill":[]},"add_g1_continuous":[[{"ty":"End","segment":7099980686025805826},{"ty":"Primary","segment":11879054056208937348}],[{"ty":"End","segment":11879054056208937348},{"ty":"Primary","segment":8174738144062904321}],[{"ty":"End","segment":11879054056208937348},{"ty":"Primary","segment":3118709054343469746}]],"remove_g1_continuous":[[{"ty":"End","segment":3118709054343469746},{"ty":"Primary","segment":12085471811343146506}]]}},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::vector_data::modification::VectorModification","alias":null}},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::vector_data::modification::PathModifyNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]},"network_metadata":{"persistent_metadata":{"node_metadata":[[294265135510952894,{"persistent_metadata":{"reference":"Fill","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Fill"},"widget_override":null},{"input_data":{"input_name":"Backup Color"},"widget_override":null},{"input_data":{"input_name":"Backup Gradient"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-71,93]}}},"network_metadata":null}}],[8269257328703012432,{"persistent_metadata":{"reference":"Fill","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Fill"},"widget_override":null},{"input_data":{"input_name":"Backup Color"},"widget_override":null},{"input_data":{"input_name":"Backup Gradient"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[6194305264313730032,{"persistent_metadata":{"reference":"Boolean Operation","display_name":"","input_properties":[{"input_data":{"input_name":"Group of Paths"},"widget_override":null},{"input_data":{"input_name":"Operation"},"widget_override":null}],"output_names":["Vector"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"Memoize","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Boundless Footprint","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[21,0]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Freeze Real Time","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[14,0]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"Boolean Operation","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[16671141883125519098,{"persistent_metadata":{"reference":"Fill","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Fill"},"widget_override":null},{"input_data":{"input_name":"Backup Color"},"widget_override":null},{"input_data":{"input_name":"Backup Gradient"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[10063704933309776584,{"persistent_metadata":{"reference":"Multiply","display_name":"","input_properties":[{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null}],"output_names":["f64"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-50,101]}}},"network_metadata":null}}],[16780039553038473906,{"persistent_metadata":{"reference":"Merge","display_name":"","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":["Out"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":0}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[1662641269094032596,{"persistent_metadata":{"reference":"Merge","display_name":"","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":["Out"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[1097494158696050491,{"persistent_metadata":{"reference":"Circle","display_name":"","input_properties":[{"input_data":{"input_name":"Primary"},"widget_override":null},{"input_data":{"input_name":"Radius"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-78,99]}}},"network_metadata":null}}],[5014806436727666175,{"persistent_metadata":{"reference":"Merge","display_name":"","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":["Out"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[7252918969430566594,{"persistent_metadata":{"reference":"Multiply","display_name":"","input_properties":[{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null}],"output_names":["f64"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-50,107]}}},"network_metadata":null}}],[14496934933990319842,{"persistent_metadata":{"reference":"Merge","display_name":"Bottom Left Blue","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":0}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[2124231869409556689,{"persistent_metadata":{"reference":"To Group","display_name":"","input_properties":[{"input_data":{},"widget_override":null}],"output_names":["Instances"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[7755499790391969923,{"persistent_metadata":{"reference":"Circle","display_name":"","input_properties":[{"input_data":{"input_name":"Primary"},"widget_override":null},{"input_data":{"input_name":"Radius"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[17740496701763775226,{"persistent_metadata":{"reference":"Merge","display_name":"Bottom Blue","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":0}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[4809200889774783438,{"persistent_metadata":{"reference":"Merge","display_name":"Front Eye","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":0}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[4261249487994076490,{"persistent_metadata":{"reference":"Transform","display_name":"","input_properties":[{"input_data":{},"widget_override":null},{"input_data":{"x":"X","y":"Y","unit":" px"},"widget_override":"vec2"},{"input_data":{},"widget_override":"transform_rotation"},{"input_data":{"x":"W","y":"H","unit":"x"},"widget_override":"vec2"},{"input_data":{},"widget_override":"transform_skew"},{"input_data":{},"widget_override":"hidden"}],"output_names":["Data"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"Transform","input_properties":[{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[14684142559936015947,{"persistent_metadata":{"reference":"Fill","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Fill"},"widget_override":null},{"input_data":{"input_name":"Backup Color"},"widget_override":null},{"input_data":{"input_name":"Backup Gradient"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[6616450276140292763,{"persistent_metadata":{"reference":"Path","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Modification"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"Path Modify","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[1001728975241745659,{"persistent_metadata":{"reference":"Boolean Operation","display_name":"","input_properties":[{"input_data":{"input_name":"Group of Paths"},"widget_override":null},{"input_data":{"input_name":"Operation"},"widget_override":null}],"output_names":["Vector"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"Boolean Operation","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"Memoize","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Freeze Real Time","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[14,0]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Boundless Footprint","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[21,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[13739729101529293427,{"persistent_metadata":{"reference":"Merge","display_name":"","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":["Out"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[8460565235419043665,{"persistent_metadata":{"reference":"Repeat","display_name":"","input_properties":[{"input_data":{"input_name":"Instance"},"widget_override":null},{"input_data":{"input_name":"Direction"},"widget_override":null},{"input_data":{"input_name":"Angle"},"widget_override":null},{"input_data":{"input_name":"Instances"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[2723198387862533596,{"persistent_metadata":{"reference":"Merge","display_name":"","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":["Out"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[7480253252288032958,{"persistent_metadata":{"reference":"Fill","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Fill"},"widget_override":null},{"input_data":{"input_name":"Backup Color"},"widget_override":null},{"input_data":{"input_name":"Backup Gradient"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[11264395591110193456,{"persistent_metadata":{"reference":"Circle","display_name":"","input_properties":[{"input_data":{"input_name":"Primary"},"widget_override":null},{"input_data":{"input_name":"Radius"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-78,93]}}},"network_metadata":null}}],[3214181946162459584,{"persistent_metadata":{"reference":"Fill","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Fill"},"widget_override":null},{"input_data":{"input_name":"Backup Color"},"widget_override":null},{"input_data":{"input_name":"Backup Gradient"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[4771789845668099116,{"persistent_metadata":{"reference":"Merge","display_name":"Cheek Shadow","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":0}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[2871608309888343463,{"persistent_metadata":{"reference":"Repeat","display_name":"","input_properties":[{"input_data":{"input_name":"Instance"},"widget_override":null},{"input_data":{"input_name":"Direction"},"widget_override":null},{"input_data":{"input_name":"Angle"},"widget_override":null},{"input_data":{"input_name":"Instances"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[4470272391975492611,{"persistent_metadata":{"reference":"Merge","display_name":"Rose Sliver Silhouette","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":0}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[7376049709233607419,{"persistent_metadata":{"reference":"Path","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Modification"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"Path Modify","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[18068340617333437755,{"persistent_metadata":{"reference":"Transform","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"x":"X","unit":" px","y":"Y","input_name":"Translation"},"widget_override":"vec2"},{"input_data":{"input_name":"Rotation"},"widget_override":"transform_rotation"},{"input_data":{"unit":"x","x":"W","y":"H","input_name":"Scale"},"widget_override":"vec2"},{"input_data":{"input_name":"Skew"},"widget_override":"hidden"},{"input_data":{"input_name":"Pivot"},"widget_override":"hidden"}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"Transform","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[7977952035097419157,{"persistent_metadata":{"reference":"Ellipse","display_name":"","input_properties":[{"input_data":{"input_name":"Primary"},"widget_override":null},{"input_data":{"input_name":"Radius X"},"widget_override":null},{"input_data":{"input_name":"Radius Y"},"widget_override":null}],"output_names":["Instances"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[6728362629909402903,{"persistent_metadata":{"reference":"Merge","display_name":"","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":["Out"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[18081743490344004315,{"persistent_metadata":{"reference":"Merge","display_name":"Hair Dots Orange","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":0}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[13838011362258067867,{"persistent_metadata":{"reference":"Centroid","display_name":"","input_properties":[{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null}],"output_names":["DVec2"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-50,103]}}},"network_metadata":null}}],[17696051535511578981,{"persistent_metadata":{"reference":"Merge","display_name":"","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":["Out"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Absolute":[-41,47]}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[1258994191538244490,{"persistent_metadata":{"reference":"Fill","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Fill"},"widget_override":null},{"input_data":{"input_name":"Backup Color"},"widget_override":null},{"input_data":{"input_name":"Backup Gradient"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[4328376070224119511,{"persistent_metadata":{"reference":"Merge","display_name":"Bottom Orange","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":0}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[6726954210929537972,{"persistent_metadata":{"reference":"Path","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Modification"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"Path Modify","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[13670206802546093234,{"persistent_metadata":{"reference":"Merge","display_name":"","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":["Out"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[6787585796949551500,{"persistent_metadata":{"reference":"Merge","display_name":"Hair Strand 1","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Absolute":[-8,12]}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[14141479077115894852,{"persistent_metadata":{"reference":"Merge","display_name":"","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":["Out"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-57,87]}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[9071802450034150503,{"persistent_metadata":{"reference":"Fill","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Fill"},"widget_override":null},{"input_data":{"input_name":"Backup Color"},"widget_override":null},{"input_data":{"input_name":"Backup Gradient"},"widget_override":null}],"output_names":["Instances"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[7104088139635280554,{"persistent_metadata":{"reference":"Solidify Stroke","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[15433707377961038695,{"persistent_metadata":{"reference":"Path","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Modification"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-64,87]}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"Path Modify","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[8511737864852441844,{"persistent_metadata":{"reference":"Circle","display_name":"","input_properties":[{"input_data":{"input_name":"Primary"},"widget_override":null},{"input_data":{"input_name":"Radius"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[9135110142507605216,{"persistent_metadata":{"reference":"Boolean Operation","display_name":"","input_properties":[{"input_data":{"input_name":"Group of Paths"},"widget_override":null},{"input_data":{"input_name":"Operation"},"widget_override":null}],"output_names":["Vector"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[3,{"persistent_metadata":{"reference":null,"display_name":"Boundless Footprint","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[21,0]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Freeze Real Time","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[14,0]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"Boolean Operation","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"Memoize","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[2880630606834119505,{"persistent_metadata":{"reference":"Transform","display_name":"","input_properties":[{"input_data":{},"widget_override":null},{"input_data":{"unit":" px","y":"Y","x":"X"},"widget_override":"vec2"},{"input_data":{},"widget_override":"transform_rotation"},{"input_data":{"x":"W","unit":"x","y":"H"},"widget_override":"vec2"},{"input_data":{},"widget_override":"transform_skew"},{"input_data":{},"widget_override":"hidden"}],"output_names":["Data"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"Transform","input_properties":[{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[7651693425519490419,{"persistent_metadata":{"reference":"Merge","display_name":"Top Right Blue","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":0}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[17056531964793634106,{"persistent_metadata":{"reference":"Transform","display_name":"","input_properties":[{"input_data":{},"widget_override":null},{"input_data":{"x":"X","y":"Y","unit":" px"},"widget_override":"vec2"},{"input_data":{},"widget_override":"transform_rotation"},{"input_data":{"x":"W","unit":"x","y":"H"},"widget_override":"vec2"},{"input_data":{},"widget_override":"transform_skew"},{"input_data":{},"widget_override":"hidden"}],"output_names":["Data"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"Transform","input_properties":[{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[3471746866096043087,{"persistent_metadata":{"reference":"Fill","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Fill"},"widget_override":null},{"input_data":{"input_name":"Backup Color"},"widget_override":null},{"input_data":{"input_name":"Backup Gradient"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[876963243827503916,{"persistent_metadata":{"reference":"Merge","display_name":"Top Right Red","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":0}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[11301831865756336526,{"persistent_metadata":{"reference":"Path","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Modification"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"Path Modify","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[17299978721726771610,{"persistent_metadata":{"reference":"Repeat","display_name":"","input_properties":[{"input_data":{"input_name":"Instance"},"widget_override":null},{"input_data":{"input_name":"Direction"},"widget_override":null},{"input_data":{"input_name":"Angle"},"widget_override":null},{"input_data":{"input_name":"Instances"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-64,106]}}},"network_metadata":null}}],[6484183251661832039,{"persistent_metadata":{"reference":"Repeat","display_name":"","input_properties":[{"input_data":{"input_name":"Instance"},"widget_override":null},{"input_data":{"input_name":"Direction"},"widget_override":null},{"input_data":{"input_name":"Angle"},"widget_override":null},{"input_data":{"input_name":"Instances"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-64,93]}}},"network_metadata":null}}],[12145355397916841389,{"persistent_metadata":{"reference":"Fill","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Fill"},"widget_override":null},{"input_data":{"input_name":"Backup Color"},"widget_override":null},{"input_data":{"input_name":"Backup Gradient"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[17351444026127625357,{"persistent_metadata":{"reference":"Merge","display_name":"Face Black","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":0}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[10995640810984321903,{"persistent_metadata":{"reference":"Merge","display_name":"Lip Bottom","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":0}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[17397123104674848450,{"persistent_metadata":{"reference":"Boolean Operation","display_name":"","input_properties":[{"input_data":{"input_name":"Group of Paths"},"widget_override":null},{"input_data":{"input_name":"Operation"},"widget_override":null}],"output_names":["Vector"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"Memoize","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"Boolean Operation","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Boundless Footprint","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[21,0]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Freeze Real Time","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[14,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[7018444885869143173,{"persistent_metadata":{"reference":"Merge","display_name":"Top Right Black - Dots","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":0}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[11196821089257149774,{"persistent_metadata":{"reference":"Merge","display_name":"","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":["Out"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[6503655938154160104,{"persistent_metadata":{"reference":"Boolean Operation","display_name":"","input_properties":[{"input_data":{"input_name":"Group of Paths"},"widget_override":null},{"input_data":{"input_name":"Operation"},"widget_override":null}],"output_names":["Vector"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-35,44]}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[2,{"persistent_metadata":{"reference":null,"display_name":"Freeze Real Time","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[14,0]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"Boolean Operation","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Boundless Footprint","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[21,0]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"Memoize","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[8863346544623578893,{"persistent_metadata":{"reference":"Path","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Modification"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-50,90]}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"Path Modify","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[5856350938151339368,{"persistent_metadata":{"reference":"Path","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Modification"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"Path Modify","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[11210964267417873667,{"persistent_metadata":{"reference":"Transform","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"x":"X","input_name":"Translation","unit":" px","y":"Y"},"widget_override":"vec2"},{"input_data":{"input_name":"Rotation"},"widget_override":"transform_rotation"},{"input_data":{"y":"H","input_name":"Scale","unit":"x","x":"W"},"widget_override":"vec2"},{"input_data":{"input_name":"Skew"},"widget_override":"hidden"},{"input_data":{"input_name":"Pivot"},"widget_override":"hidden"}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"Transform","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[3079923906392020295,{"persistent_metadata":{"reference":"To Group","display_name":"","input_properties":[{"input_data":{},"widget_override":null}],"output_names":["Instances"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[5556372312033787775,{"persistent_metadata":{"reference":"Bounding Box","display_name":"","input_properties":[{"input_data":{},"widget_override":null}],"output_names":["Instances"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-57,96]}}},"network_metadata":null}}],[12770183061753030023,{"persistent_metadata":{"reference":"Merge","display_name":"","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":["Out"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[16609137733952262762,{"persistent_metadata":{"reference":"Fill","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Fill"},"widget_override":null},{"input_data":{"input_name":"Backup Color"},"widget_override":null},{"input_data":{"input_name":"Backup Gradient"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[8426490990601560741,{"persistent_metadata":{"reference":"Fill","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Fill"},"widget_override":null},{"input_data":{"input_name":"Backup Color"},"widget_override":null},{"input_data":{"input_name":"Backup Gradient"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[12494428953087324640,{"persistent_metadata":{"reference":"Repeat","display_name":"","input_properties":[{"input_data":{"input_name":"Instance"},"widget_override":null},{"input_data":{"input_name":"Direction"},"widget_override":null},{"input_data":{"input_name":"Angle"},"widget_override":null},{"input_data":{"input_name":"Instances"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[18271512507682813443,{"persistent_metadata":{"reference":"Path","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Modification"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"Path Modify","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[17753909951719808506,{"persistent_metadata":{"reference":"Merge","display_name":"Bottom Left Red","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":0}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[14950060858756810933,{"persistent_metadata":{"reference":"Path","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Modification"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-64,60]}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"Path Modify","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[7667878689218439065,{"persistent_metadata":{"reference":"Merge","display_name":"","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":["Out"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[10286817149456341619,{"persistent_metadata":{"reference":"Path","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Modification"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"Path Modify","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[16304636129468583592,{"persistent_metadata":{"reference":"Path","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Modification"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-57,135]}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"Path Modify","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[13795432594059356320,{"persistent_metadata":{"reference":"Flatten Path","display_name":"","input_properties":[{"input_data":{"input_name":"Graphic Group Input"},"widget_override":null}],"output_names":["Instances"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[8887924609778270360,{"persistent_metadata":{"reference":"Boolean Operation","display_name":"","input_properties":[{"input_data":{"input_name":"Group of Paths"},"widget_override":null},{"input_data":{"input_name":"Operation"},"widget_override":null}],"output_names":["Vector"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"Memoize","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Freeze Real Time","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[14,0]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Boundless Footprint","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[21,0]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"Boolean Operation","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[4102754869474520966,{"persistent_metadata":{"reference":"Boolean Operation","display_name":"","input_properties":[{"input_data":{"input_name":"Group of Paths"},"widget_override":null},{"input_data":{"input_name":"Operation"},"widget_override":null}],"output_names":["Vector"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[2,{"persistent_metadata":{"reference":null,"display_name":"Freeze Real Time","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[14,0]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Boundless Footprint","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[21,0]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"Memoize","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"Boolean Operation","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[18003287685830153881,{"persistent_metadata":{"reference":"Path","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Modification"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-43,72]}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"Path Modify","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[1809704172129195322,{"persistent_metadata":{"reference":"Circle","display_name":"","input_properties":[{"input_data":{"input_name":"Primary"},"widget_override":null},{"input_data":{"input_name":"Radius"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-78,106]}}},"network_metadata":null}}],[15354358358546908017,{"persistent_metadata":{"reference":"Fill","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Fill"},"widget_override":null},{"input_data":{"input_name":"Backup Color"},"widget_override":null},{"input_data":{"input_name":"Backup Gradient"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[1491840484128555837,{"persistent_metadata":{"reference":"Merge","display_name":"Face Shadow","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":3}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[15817956847588799375,{"persistent_metadata":{"reference":"Fill","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Fill"},"widget_override":null},{"input_data":{"input_name":"Backup Color"},"widget_override":null},{"input_data":{"input_name":"Backup Gradient"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[3050731459444225191,{"persistent_metadata":{"reference":"Repeat","display_name":"","input_properties":[{"input_data":{"input_name":"Instance"},"widget_override":null},{"input_data":{"input_name":"Direction"},"widget_override":null},{"input_data":{"input_name":"Angle"},"widget_override":null},{"input_data":{"input_name":"Instances"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[5888633415105234509,{"persistent_metadata":{"reference":"Boolean Operation","display_name":"","input_properties":[{"input_data":{"input_name":"Group of Paths"},"widget_override":null},{"input_data":{"input_name":"Operation"},"widget_override":null}],"output_names":["Vector"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"Boolean Operation","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Boundless Footprint","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[21,0]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Freeze Real Time","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[14,0]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"Memoize","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[804622576568168609,{"persistent_metadata":{"reference":"Path","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Modification"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"Path Modify","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[57390435731316553,{"persistent_metadata":{"reference":"Transform","display_name":"","input_properties":[{"input_data":{},"widget_override":null},{"input_data":{"x":"X","unit":" px","y":"Y"},"widget_override":"vec2"},{"input_data":{},"widget_override":"transform_rotation"},{"input_data":{"unit":"x","x":"W","y":"H"},"widget_override":"vec2"},{"input_data":{},"widget_override":"transform_skew"},{"input_data":{},"widget_override":"hidden"}],"output_names":["Data"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"Transform","input_properties":[{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[7201841978411396053,{"persistent_metadata":{"reference":"Merge","display_name":"Bottom Black","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":2}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[11373527190663101881,{"persistent_metadata":{"reference":"Path","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Modification"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"Path Modify","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[2185437945364824599,{"persistent_metadata":{"reference":"Merge","display_name":"Bottom Left White","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":0}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[1009114585722052052,{"persistent_metadata":{"reference":"Boolean Operation","display_name":"","input_properties":[{"input_data":{"input_name":"Group of Paths"},"widget_override":null},{"input_data":{"input_name":"Operation"},"widget_override":null}],"output_names":["Vector"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-50,57]}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"Boolean Operation","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Boundless Footprint","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[21,0]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Freeze Real Time","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[14,0]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"Memoize","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[12234961922142600898,{"persistent_metadata":{"reference":"Merge","display_name":"Top Right Black","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":12}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[16306737306999003555,{"persistent_metadata":{"reference":"Path","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Modification"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"Path Modify","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[1627123781166851142,{"persistent_metadata":{"reference":"Merge","display_name":"Top Right Corner Orange","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":0}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[15930698052919171086,{"persistent_metadata":{"reference":"Boolean Operation","display_name":"","input_properties":[{"input_data":{"input_name":"Group of Paths"},"widget_override":null},{"input_data":{"input_name":"Operation"},"widget_override":null}],"output_names":["Vector"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[3,{"persistent_metadata":{"reference":null,"display_name":"Boundless Footprint","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[21,0]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"Memoize","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Freeze Real Time","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[14,0]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"Boolean Operation","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[7029437790788498388,{"persistent_metadata":{"reference":"Fill","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Fill"},"widget_override":null},{"input_data":{"input_name":"Backup Color"},"widget_override":null},{"input_data":{"input_name":"Backup Gradient"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-71,106]}}},"network_metadata":null}}],[4807760870555738383,{"persistent_metadata":{"reference":"Merge","display_name":"Top Right Main Orange","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":0}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[5877930116725120460,{"persistent_metadata":{"reference":"Merge","display_name":"Rear Eyelash","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":0}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[14690269209726153565,{"persistent_metadata":{"reference":"Fill","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Fill"},"widget_override":null},{"input_data":{"input_name":"Backup Color"},"widget_override":null},{"input_data":{"input_name":"Backup Gradient"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[14516211820212764316,{"persistent_metadata":{"reference":"Repeat","display_name":"","input_properties":[{"input_data":{"input_name":"Instance"},"widget_override":null},{"input_data":{"input_name":"Direction"},"widget_override":null},{"input_data":{"input_name":"Angle"},"widget_override":null},{"input_data":{"input_name":"Instances"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[13646498613066619660,{"persistent_metadata":{"reference":"Boolean Operation","display_name":"","input_properties":[{"input_data":{"input_name":"Group of Paths"},"widget_override":null},{"input_data":{"input_name":"Operation"},"widget_override":null}],"output_names":["Vector"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-35,118]}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"Boolean Operation","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Freeze Real Time","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[14,0]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"Memoize","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Boundless Footprint","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[21,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[4631655038168471552,{"persistent_metadata":{"reference":"Bounding Box","display_name":"","input_properties":[{"input_data":{},"widget_override":null}],"output_names":["Instances"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-57,103]}}},"network_metadata":null}}],[8359580532088731394,{"persistent_metadata":{"reference":"Fill","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Fill"},"widget_override":null},{"input_data":{"input_name":"Backup Color"},"widget_override":null},{"input_data":{"input_name":"Backup Gradient"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[3410481056630111806,{"persistent_metadata":{"reference":"Fill","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Fill"},"widget_override":null},{"input_data":{"input_name":"Backup Color"},"widget_override":null},{"input_data":{"input_name":"Backup Gradient"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-71,99]}}},"network_metadata":null}}],[12185047359007423618,{"persistent_metadata":{"reference":"Fill","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Fill"},"widget_override":null},{"input_data":{"input_name":"Backup Color"},"widget_override":null},{"input_data":{"input_name":"Backup Gradient"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[13916027199283115943,{"persistent_metadata":{"reference":"Fill","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Fill"},"widget_override":null},{"input_data":{"input_name":"Backup Color"},"widget_override":null},{"input_data":{"input_name":"Backup Gradient"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[2025899804080897524,{"persistent_metadata":{"reference":"Merge","display_name":"Face White","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":0}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[10080296672372912698,{"persistent_metadata":{"reference":"Boolean Operation","display_name":"","input_properties":[{"input_data":{"input_name":"Group of Paths"},"widget_override":null},{"input_data":{"input_name":"Operation"},"widget_override":null}],"output_names":["Vector"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"Memoize","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Freeze Real Time","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[14,0]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Boundless Footprint","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[21,0]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"Boolean Operation","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[17952673493105230490,{"persistent_metadata":{"reference":"Stroke","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Color"},"widget_override":null},{"input_data":{"input_name":"Weight"},"widget_override":null},{"input_data":{"input_name":"Dash Lengths"},"widget_override":null},{"input_data":{"input_name":"Dash Offset"},"widget_override":null},{"input_data":{"input_name":"Line Cap"},"widget_override":null},{"input_data":{"input_name":"Line Join"},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{"input_name":"Miter Limit"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-42,133]}}},"network_metadata":null}}],[9808637865669223270,{"persistent_metadata":{"reference":"Fill","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Fill"},"widget_override":null},{"input_data":{"input_name":"Backup Color"},"widget_override":null},{"input_data":{"input_name":"Backup Gradient"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[18031616785650843168,{"persistent_metadata":{"reference":"Solidify Stroke","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-35,133]}}},"network_metadata":null}}],[14030142873804552388,{"persistent_metadata":{"reference":"Path","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Modification"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-36,66]}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"Path Modify","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[12741076678082295759,{"persistent_metadata":{"reference":"Merge","display_name":"","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":["Out"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-42,118]}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[14139129879376457893,{"persistent_metadata":{"reference":"Fill","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Fill"},"widget_override":null},{"input_data":{"input_name":"Backup Color"},"widget_override":null},{"input_data":{"input_name":"Backup Gradient"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[15692102598187739001,{"persistent_metadata":{"reference":"Merge","display_name":"","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":["Out"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-57,57]}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[18351415092709164412,{"persistent_metadata":{"reference":"Fill","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Fill"},"widget_override":null},{"input_data":{"input_name":"Backup Color"},"widget_override":null},{"input_data":{"input_name":"Backup Gradient"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[17495267820524300686,{"persistent_metadata":{"reference":"Transform","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"y":"Y","input_name":"Translation","x":"X","unit":" px"},"widget_override":"vec2"},{"input_data":{"input_name":"Rotation"},"widget_override":"transform_rotation"},{"input_data":{"y":"H","x":"W","unit":"x","input_name":"Scale"},"widget_override":"vec2"},{"input_data":{"input_name":"Skew"},"widget_override":"hidden"},{"input_data":{"input_name":"Pivot"},"widget_override":"hidden"}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"Transform","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[18188505856445531484,{"persistent_metadata":{"reference":"Fill","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Fill"},"widget_override":null},{"input_data":{"input_name":"Backup Color"},"widget_override":null},{"input_data":{"input_name":"Backup Gradient"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[14698962747138962125,{"persistent_metadata":{"reference":"Boolean Operation","display_name":"","input_properties":[{"input_data":{"input_name":"Group of Paths"},"widget_override":null},{"input_data":{"input_name":"Operation"},"widget_override":null}],"output_names":["Vector"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"Memoize","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"Boolean Operation","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Freeze Real Time","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[14,0]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Boundless Footprint","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[21,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[13203761224559198689,{"persistent_metadata":{"reference":"Merge","display_name":"Front Eye Shadow","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":0}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[17131529656312051452,{"persistent_metadata":{"reference":"Fill","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Fill"},"widget_override":null},{"input_data":{"input_name":"Backup Color"},"widget_override":null},{"input_data":{"input_name":"Backup Gradient"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[4560146526699152877,{"persistent_metadata":{"reference":"Merge","display_name":"","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":["Out"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[7962101329808960965,{"persistent_metadata":{"reference":"Multiply","display_name":"","input_properties":[{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null}],"output_names":["f64"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-50,94]}}},"network_metadata":null}}],[17271572793812678706,{"persistent_metadata":{"reference":"Fill","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Fill"},"widget_override":null},{"input_data":{"input_name":"Backup Color"},"widget_override":null},{"input_data":{"input_name":"Backup Gradient"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[15877481873925059044,{"persistent_metadata":{"reference":"Transform","display_name":"","input_properties":[{"input_data":{},"widget_override":null},{"input_data":{"x":"X","y":"Y","unit":" px"},"widget_override":"vec2"},{"input_data":{},"widget_override":"transform_rotation"},{"input_data":{"unit":"x","x":"W","y":"H"},"widget_override":"vec2"},{"input_data":{},"widget_override":"transform_skew"},{"input_data":{},"widget_override":"hidden"}],"output_names":["Data"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"Transform","input_properties":[{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[140396870212231820,{"persistent_metadata":{"reference":"Boolean Operation","display_name":"","input_properties":[{"input_data":{"input_name":"Group of Paths"},"widget_override":null},{"input_data":{"input_name":"Operation"},"widget_override":null}],"output_names":["Vector"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"Memoize","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Freeze Real Time","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[14,0]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Boundless Footprint","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[21,0]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"Boolean Operation","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[11095670964487764044,{"persistent_metadata":{"reference":"Merge","display_name":"Hair Strand 2","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":0}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[14228923746783465609,{"persistent_metadata":{"reference":"Path","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Modification"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-49,135]}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"Path Modify","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[12709602171929957216,{"persistent_metadata":{"reference":"Merge","display_name":"Bottom Left Orange","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":0}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[3608604157153838227,{"persistent_metadata":{"reference":"Bounding Box","display_name":"","input_properties":[{"input_data":{},"widget_override":null}],"output_names":["Instances"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-57,109]}}},"network_metadata":null}}],[17223836790030950966,{"persistent_metadata":{"reference":"Fill","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Fill"},"widget_override":null},{"input_data":{"input_name":"Backup Color"},"widget_override":null},{"input_data":{"input_name":"Backup Gradient"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[13616602029989984195,{"persistent_metadata":{"reference":"Flatten Path","display_name":"","input_properties":[{"input_data":{"input_name":"Graphic Group Input"},"widget_override":null}],"output_names":["Instances"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[13340751444307201866,{"persistent_metadata":{"reference":"Fill","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Fill"},"widget_override":null},{"input_data":{"input_name":"Backup Color"},"widget_override":null},{"input_data":{"input_name":"Backup Gradient"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[3750439930725791025,{"persistent_metadata":{"reference":"Merge","display_name":"","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":["Out"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[16177422101884031678,{"persistent_metadata":{"reference":"Fill","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Fill"},"widget_override":null},{"input_data":{"input_name":"Backup Color"},"widget_override":null},{"input_data":{"input_name":"Backup Gradient"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[12353675714904258944,{"persistent_metadata":{"reference":"Merge","display_name":"Nose Shadow","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":0}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[17285637344898461972,{"persistent_metadata":{"reference":"Path","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Modification"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-64,81]}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"Path Modify","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[11429506195623419966,{"persistent_metadata":{"reference":"Merge","display_name":"","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":["Out"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[12867379765049504290,{"persistent_metadata":{"reference":"Merge","display_name":"","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":["Out"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[990192925663920333,{"persistent_metadata":{"reference":"Repeat","display_name":"","input_properties":[{"input_data":{"input_name":"Instance"},"widget_override":null},{"input_data":{"input_name":"Direction"},"widget_override":null},{"input_data":{"input_name":"Angle"},"widget_override":null},{"input_data":{"input_name":"Instances"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-64,99]}}},"network_metadata":null}}],[16322546010403524636,{"persistent_metadata":{"reference":"Centroid","display_name":"","input_properties":[{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null}],"output_names":["DVec2"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-50,96]}}},"network_metadata":null}}],[14808063168960305551,{"persistent_metadata":{"reference":"Merge","display_name":"Face Blue","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":0}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[14257963317028524134,{"persistent_metadata":{"reference":"Merge","display_name":"","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":["Out"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[17569892869974995307,{"persistent_metadata":{"reference":"To Group","display_name":"","input_properties":[{"input_data":{},"widget_override":null}],"output_names":["Instances"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[1508440849951861669,{"persistent_metadata":{"reference":"Merge","display_name":"Face Red","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":0}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[10760002922115563021,{"persistent_metadata":{"reference":"Boolean Operation","display_name":"","input_properties":[{"input_data":{"input_name":"Group of Paths"},"widget_override":null},{"input_data":{"input_name":"Operation"},"widget_override":null}],"output_names":["Vector"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[2,{"persistent_metadata":{"reference":null,"display_name":"Freeze Real Time","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[14,0]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Boundless Footprint","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[21,0]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"Boolean Operation","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"Memoize","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[16759836951269190891,{"persistent_metadata":{"reference":"Boolean Operation","display_name":"","input_properties":[{"input_data":{"input_name":"Group of Paths"},"widget_override":null},{"input_data":{"input_name":"Operation"},"widget_override":null}],"output_names":["Vector"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[3,{"persistent_metadata":{"reference":null,"display_name":"Boundless Footprint","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[21,0]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"Memoize","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"Boolean Operation","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Freeze Real Time","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[14,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[15900830679378240619,{"persistent_metadata":{"reference":"Boolean Operation","display_name":"","input_properties":[{"input_data":{"input_name":"Group of Paths"},"widget_override":null},{"input_data":{"input_name":"Operation"},"widget_override":null}],"output_names":["Vector"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"Boolean Operation","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"Memoize","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Boundless Footprint","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[21,0]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Freeze Real Time","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[14,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[12276520439585231336,{"persistent_metadata":{"reference":"Transform","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"y":"Y","unit":" px","x":"X","input_name":"Translation"},"widget_override":"vec2"},{"input_data":{"input_name":"Rotation"},"widget_override":"transform_rotation"},{"input_data":{"unit":"x","input_name":"Scale","x":"W","y":"H"},"widget_override":"vec2"},{"input_data":{"input_name":"Skew"},"widget_override":"hidden"},{"input_data":{"input_name":"Pivot"},"widget_override":"hidden"}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"Transform","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[3109716240255919254,{"persistent_metadata":{"reference":"Merge","display_name":"Front Eyebrow","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":0}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[14139765080256493579,{"persistent_metadata":{"reference":"Path","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Modification"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-57,138]}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"Path Modify","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[18095952297474762348,{"persistent_metadata":{"reference":"Merge","display_name":"","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":["Out"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[2287485748649359627,{"persistent_metadata":{"reference":"Merge","display_name":"","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":["Out"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[3997031659711823213,{"persistent_metadata":{"reference":"Transform","display_name":"","input_properties":[{"input_data":{},"widget_override":null},{"input_data":{"x":"X","y":"Y","unit":" px"},"widget_override":"vec2"},{"input_data":{},"widget_override":"transform_rotation"},{"input_data":{"x":"W","unit":"x","y":"H"},"widget_override":"vec2"},{"input_data":{},"widget_override":"transform_skew"},{"input_data":{},"widget_override":"hidden"}],"output_names":["Data"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"Transform","input_properties":[{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[6445954214067437701,{"persistent_metadata":{"reference":"Boolean Operation","display_name":"","input_properties":[{"input_data":{"input_name":"Group of Paths"},"widget_override":null},{"input_data":{"input_name":"Operation"},"widget_override":null}],"output_names":["Vector"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[3,{"persistent_metadata":{"reference":null,"display_name":"Boundless Footprint","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[21,0]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Freeze Real Time","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[14,0]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"Memoize","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"Boolean Operation","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[13027689870767713939,{"persistent_metadata":{"reference":"Merge","display_name":"Bottom Black - Dots","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":0}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[6852799892628327372,{"persistent_metadata":{"reference":"Merge","display_name":"Head Orange","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":0}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[12922148192688274227,{"persistent_metadata":{"reference":"Transform","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"x":"X","input_name":"Translation","unit":" px","y":"Y"},"widget_override":"vec2"},{"input_data":{"input_name":"Rotation"},"widget_override":"transform_rotation"},{"input_data":{"x":"W","y":"H","unit":"x","input_name":"Scale"},"widget_override":"vec2"},{"input_data":{"input_name":"Skew"},"widget_override":"hidden"},{"input_data":{"input_name":"Pivot"},"widget_override":"hidden"}],"output_names":["Data"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"Transform","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[5488285068107445023,{"persistent_metadata":{"reference":"Boolean Operation","display_name":"","input_properties":[{"input_data":{"input_name":"Group of Paths"},"widget_override":null},{"input_data":{"input_name":"Operation"},"widget_override":null}],"output_names":["Vector"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[3,{"persistent_metadata":{"reference":null,"display_name":"Boundless Footprint","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[21,0]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"Memoize","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Freeze Real Time","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[14,0]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"Boolean Operation","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[2834866505092039323,{"persistent_metadata":{"reference":"Merge","display_name":"","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":["Out"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[682567808439406093,{"persistent_metadata":{"reference":"Repeat","display_name":"","input_properties":[{"input_data":{"input_name":"Instance"},"widget_override":null},{"input_data":{"input_name":"Direction"},"widget_override":null},{"input_data":{"input_name":"Angle"},"widget_override":null},{"input_data":{"input_name":"Instances"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[8297015715799006244,{"persistent_metadata":{"reference":"Repeat","display_name":"","input_properties":[{"input_data":{"input_name":"Instance"},"widget_override":null},{"input_data":{"input_name":"Direction"},"widget_override":null},{"input_data":{"input_name":"Angle"},"widget_override":null},{"input_data":{"input_name":"Instances"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[15301503532602557206,{"persistent_metadata":{"reference":"Boolean Operation","display_name":"","input_properties":[{"input_data":{"input_name":"Group of Paths"},"widget_override":null},{"input_data":{"input_name":"Operation"},"widget_override":null}],"output_names":["Vector"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"Boolean Operation","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"Memoize","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Boundless Footprint","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[21,0]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Freeze Real Time","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[14,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[4421418468606442725,{"persistent_metadata":{"reference":"Fill","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Fill"},"widget_override":null},{"input_data":{"input_name":"Backup Color"},"widget_override":null},{"input_data":{"input_name":"Backup Gradient"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[7104261880154687267,{"persistent_metadata":{"reference":"Boolean Operation","display_name":"","input_properties":[{"input_data":{"input_name":"Group of Paths"},"widget_override":null},{"input_data":{"input_name":"Operation"},"widget_override":null}],"output_names":["Vector"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"Memoize","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"Boolean Operation","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Freeze Real Time","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[14,0]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Boundless Footprint","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[21,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[7855094781869605606,{"persistent_metadata":{"reference":"Boolean Operation","display_name":"","input_properties":[{"input_data":{"input_name":"Group of Paths"},"widget_override":null},{"input_data":{"input_name":"Operation"},"widget_override":null}],"output_names":["Vector"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-50,87]}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"Memoize","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Boundless Footprint","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[21,0]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"Boolean Operation","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Freeze Real Time","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[14,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[-312.5,-36.5],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,678.0,544.0],"node_graph_top_right":[1980.796875,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[5954536408321808728,{"persistent_metadata":{"reference":"Path","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Modification"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"Path Modify","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[13588160462734303101,{"persistent_metadata":{"reference":"Merge","display_name":"Hair Dots Red","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":3}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[5486211022469996717,{"persistent_metadata":{"reference":"Path","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Modification"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-43,75]}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"Path Modify","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[9338394475379815879,{"persistent_metadata":{"reference":"Transform","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Translation","y":"Y","x":"X","unit":" px"},"widget_override":"vec2"},{"input_data":{"input_name":"Rotation"},"widget_override":"transform_rotation"},{"input_data":{"unit":"x","x":"W","y":"H","input_name":"Scale"},"widget_override":"vec2"},{"input_data":{"input_name":"Skew"},"widget_override":"hidden"},{"input_data":{"input_name":"Pivot"},"widget_override":"hidden"}],"output_names":["Data"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"Transform","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[11201759760883367635,{"persistent_metadata":{"reference":"Path","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Modification"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-64,64]}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"Path Modify","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[16785043320296790229,{"persistent_metadata":{"reference":"Stroke","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Color"},"widget_override":null},{"input_data":{"input_name":"Weight"},"widget_override":null},{"input_data":{"input_name":"Dash Lengths"},"widget_override":null},{"input_data":{"input_name":"Dash Offset"},"widget_override":null},{"input_data":{"input_name":"Line Cap"},"widget_override":null},{"input_data":{"input_name":"Line Join"},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{"input_name":"Miter Limit"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[17036604842139972912,{"persistent_metadata":{"reference":"Merge","display_name":"Hair Dots Blue","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":4}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[13353438235848911576,{"persistent_metadata":{"reference":"Path","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Modification"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"Path Modify","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[17740294143355019755,{"persistent_metadata":{"reference":"Fill","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Fill"},"widget_override":null},{"input_data":{"input_name":"Backup Color"},"widget_override":null},{"input_data":{"input_name":"Backup Gradient"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[17562801632450633291,{"persistent_metadata":{"reference":"Merge","display_name":"","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":["Out"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[13446205009526451196,{"persistent_metadata":{"reference":"Fill","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Fill"},"widget_override":null},{"input_data":{"input_name":"Backup Color"},"widget_override":null},{"input_data":{"input_name":"Backup Gradient"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[5534800796196967885,{"persistent_metadata":{"reference":"Centroid","display_name":"","input_properties":[{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null}],"output_names":["DVec2"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-50,109]}}},"network_metadata":null}}],[8566844905246185636,{"persistent_metadata":{"reference":"Merge","display_name":"Mouth Orange","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":0}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[4301099429811409147,{"persistent_metadata":{"reference":"Transform","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Translation","unit":" px","x":"X","y":"Y"},"widget_override":"vec2"},{"input_data":{"input_name":"Rotation"},"widget_override":"transform_rotation"},{"input_data":{"x":"W","y":"H","input_name":"Scale","unit":"x"},"widget_override":"vec2"},{"input_data":{"input_name":"Skew"},"widget_override":"hidden"},{"input_data":{"input_name":"Pivot"},"widget_override":"hidden"}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"Transform","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[10265035897167064154,{"persistent_metadata":{"reference":"Fill","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Fill"},"widget_override":null},{"input_data":{"input_name":"Backup Color"},"widget_override":null},{"input_data":{"input_name":"Backup Gradient"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[392274448837115448,{"persistent_metadata":{"reference":"Artboard","display_name":"","input_properties":[{"input_data":{"input_name":"Artboards"},"widget_override":null},{"input_data":{"input_name":"Contents"},"widget_override":"hidden"},{"input_data":{"input_name":"Location","x":"X","y":"Y","unit":" px"},"widget_override":"vec2"},{"input_data":{"y":"H","input_name":"Dimensions","unit":" px","x":"W"},"widget_override":"vec2"},{"input_data":{"input_name":"Background"},"widget_override":"artboard_background"},{"input_data":{"input_name":"Clip"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Absolute":[-4,9]}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-2,-3]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Append Artboards","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[6,-4]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"To Artboard","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-10,-3]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[17603523494627491590,{"persistent_metadata":{"reference":"Merge","display_name":"Lip Top","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":0}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[5449860184735415958,{"persistent_metadata":{"reference":"Path","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Modification"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-57,124]}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"Path Modify","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[9563008199132558110,{"persistent_metadata":{"reference":"Fill","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Fill"},"widget_override":null},{"input_data":{"input_name":"Backup Color"},"widget_override":null},{"input_data":{"input_name":"Backup Gradient"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[17735408893002232096,{"persistent_metadata":{"reference":"Fill","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Fill"},"widget_override":null},{"input_data":{"input_name":"Backup Color"},"widget_override":null},{"input_data":{"input_name":"Backup Gradient"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[18053728639616073084,{"persistent_metadata":{"reference":"Fill","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Fill"},"widget_override":null},{"input_data":{"input_name":"Backup Color"},"widget_override":null},{"input_data":{"input_name":"Backup Gradient"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[866.5700198973645,-2549.4579096366515],"tilt":0.0,"zoom":0.6666666666666666,"flip":false},"node_graph_to_viewport":[0.6666666666666666,0.0,0.0,0.6666666666666666,1568.0,-1119.0],"node_graph_top_right":[1980.796875,0.0]},"selection_undo_history":[[3410481056630111806],[1097494158696050491],[3410481056630111806],[11684705487012407227],[],[294265135510952894],[],[],[],[13340751444307201866],[3765280235392282097],[3765280235392282097],[],[13795432594059356320],[],[2871608309888343463],[2871608309888343463,12494428953087324640],[3765280235392282097,12494428953087324640,2871608309888343463],[8511737864852441844,2871608309888343463,12494428953087324640,3765280235392282097],[],[13795432594059356320],[],[12494428953087324640,2871608309888343463],[2871608309888343463,3765280235392282097,12494428953087324640],[12494428953087324640,2871608309888343463,3765280235392282097,8511737864852441844],[],[3765280235392282097],[],[],[13616602029989984195],[],[],[],[16780039553038473906],[7104088139635280554],[],[],[7104088139635280554],[],[7104088139635280554],[],[],[16785043320296790229],[6503655938154160104],[17696051535511578981],[6503655938154160104],[17696051535511578981],[9071802450034150503],[],[17696051535511578981],[6503655938154160104],[],[18031616785650843168],[17952673493105230490],[],[4328376070224119511],[18031616785650843168,3750439930725791025,13446205009526451196,7201841978411396053,17735408893002232096,11196821089257149774,13027689870767713939,17952673493105230490,14228923746783465609,4328376070224119511],[13027689870767713939,16609137733952262762,12276520439585231336,13795432594059356320,7201841978411396053,17740496701763775226,13340751444307201866,5888633415105234509,17735408893002232096,9135110142507605216,3750439930725791025,11196821089257149774,17397123104674848450,13446205009526451196,4328376070224119511,14228923746783465609,1662641269094032596,18031616785650843168,17952673493105230490],[5888633415105234509,17740496701763775226,14228923746783465609,12276520439585231336,18031616785650843168,16306737306999003555,6852799892628327372,17952673493105230490,3750439930725791025,16671141883125519098,13446205009526451196,11196821089257149774,1662641269094032596,9135110142507605216,17397123104674848450,3214181946162459584,13027689870767713939,16609137733952262762,7201841978411396053,13795432594059356320,17735408893002232096,2871608309888343463,4328376070224119511,2025899804080897524,13340751444307201866],[17952673493105230490,13027689870767713939,13646498613066619660,14139765080256493579,3214181946162459584,13795432594059356320,1662641269094032596,16671141883125519098,17740496701763775226,16306737306999003555,17735408893002232096,14228923746783465609,4328376070224119511,12276520439585231336,9135110142507605216,11196821089257149774,2025899804080897524,17397123104674848450,5888633415105234509,7201841978411396053,16609137733952262762,2871608309888343463,16304636129468583592,13446205009526451196,17131529656312051452,8566844905246185636,5449860184735415958,3750439930725791025,18031616785650843168,12494428953087324640,12741076678082295759,6852799892628327372,13340751444307201866],[3750439930725791025,5888633415105234509,18031616785650843168,12494428953087324640,13340751444307201866,16306737306999003555,17952673493105230490,17397123104674848450,13795432594059356320,12741076678082295759,7201841978411396053,9135110142507605216,3214181946162459584,2871608309888343463,6852799892628327372,13646498613066619660,17740496701763775226,17131529656312051452,16671141883125519098,13446205009526451196,12276520439585231336,14139765080256493579,14228923746783465609,5449860184735415958,4328376070224119511,16609137733952262762,17735408893002232096,16304636129468583592,8566844905246185636,1662641269094032596,2025899804080897524,11196821089257149774,13027689870767713939,8511737864852441844],[13340751444307201866,5888633415105234509,14139765080256493579,8566844905246185636,13795432594059356320,16609137733952262762,5449860184735415958,13027689870767713939,6852799892628327372,3750439930725791025,8511737864852441844,11196821089257149774,12494428953087324640,17131529656312051452,16306737306999003555,2834866505092039323,17735408893002232096,13646498613066619660,18031616785650843168,12276520439585231336,17740496701763775226,3214181946162459584,12741076678082295759,16671141883125519098,9135110142507605216,14228923746783465609,2871608309888343463,16304636129468583592,2025899804080897524,17397123104674848450,17952673493105230490,1662641269094032596,7201841978411396053,13446205009526451196,4328376070224119511],[9135110142507605216,12276520439585231336,2871608309888343463,1508440849951861669,2025899804080897524,7201841978411396053,11196821089257149774,17740496701763775226,13446205009526451196,6852799892628327372,3214181946162459584,1662641269094032596,4328376070224119511,12741076678082295759,13340751444307201866,13795432594059356320,16671141883125519098,14139765080256493579,5888633415105234509,17735408893002232096,18031616785650843168,17131529656312051452,13027689870767713939,8566844905246185636,17952673493105230490,2834866505092039323,5449860184735415958,16304636129468583592,16609137733952262762,16306737306999003555,17397123104674848450,13646498613066619660,14228923746783465609,3750439930725791025,12494428953087324640,8511737864852441844],[17397123104674848450,13340751444307201866,12494428953087324640,13446205009526451196,3214181946162459584,17131529656312051452,16609137733952262762,16306737306999003555,12276520439585231336,2871608309888343463,4328376070224119511,16304636129468583592,17740496701763775226,7201841978411396053,2834866505092039323,9135110142507605216,8511737864852441844,5888633415105234509,13795432594059356320,17952673493105230490,7480253252288032958,11196821089257149774,5449860184735415958,14228923746783465609,3750439930725791025,13027689870767713939,17735408893002232096,1508440849951861669,8566844905246185636,18031616785650843168,13646498613066619660,14139765080256493579,7104261880154687267,2025899804080897524,12741076678082295759,1662641269094032596,6852799892628327372,16671141883125519098],[17952673493105230490,7104261880154687267,18031616785650843168,8566844905246185636,17735408893002232096,7201841978411396053,12741076678082295759,5449860184735415958,16609137733952262762,1662641269094032596,3214181946162459584,11196821089257149774,1508440849951861669,13340751444307201866,13446205009526451196,8511737864852441844,9135110142507605216,6852799892628327372,3750439930725791025,13795432594059356320,4328376070224119511,17131529656312051452,16304636129468583592,16306737306999003555,17740496701763775226,12494428953087324640,17397123104674848450,16671141883125519098,5888633415105234509,12276520439585231336,2834866505092039323,7480253252288032958,18095952297474762348,13646498613066619660,2871608309888343463,2025899804080897524,14228923746783465609,14139765080256493579,13027689870767713939],[1491840484128555837,7104261880154687267,17397123104674848450,8511737864852441844,13446205009526451196,13795432594059356320,14228923746783465609,7480253252288032958,2025899804080897524,17735408893002232096,16306737306999003555,17740496701763775226,12741076678082295759,13646498613066619660,4328376070224119511,12276520439585231336,18031616785650843168,3750439930725791025,3214181946162459584,2871608309888343463,5888633415105234509,16304636129468583592,13340751444307201866,1662641269094032596,11196821089257149774,5449860184735415958,16671141883125519098,13027689870767713939,17952673493105230490,6852799892628327372,17131529656312051452,14139765080256493579,1508440849951861669,18095952297474762348,8566844905246185636,12494428953087324640,16609137733952262762,2834866505092039323,9135110142507605216,7201841978411396053],[13027689870767713939,8511737864852441844,2871608309888343463,3214181946162459584,14228923746783465609,9808637865669223270,1508440849951861669,12494428953087324640,7201841978411396053,16671141883125519098,13340751444307201866,140396870212231820,1491840484128555837,13446205009526451196,14139765080256493579,5888633415105234509,2834866505092039323,7480253252288032958,17397123104674848450,17740496701763775226,1662641269094032596,18095952297474762348,16306737306999003555,16304636129468583592,17735408893002232096,12276520439585231336,16609137733952262762,4328376070224119511,13795432594059356320,7104261880154687267,5449860184735415958,17131529656312051452,13646498613066619660,6852799892628327372,3750439930725791025,2025899804080897524,9135110142507605216,5954536408321808728,11196821089257149774,12741076678082295759,8566844905246185636,17952673493105230490,18031616785650843168],[7252918969430566594,15877481873925059044,4261249487994076490,5534800796196967885,17036604842139972912],[5534800796196967885,11210964267417873667,4261249487994076490,17036604842139972912,2124231869409556689,7252918969430566594,14516211820212764316,15877481873925059044],[17036604842139972912,4261249487994076490,11210964267417873667,3608604157153838227,15877481873925059044,5534800796196967885,2124231869409556689,14516211820212764316,7252918969430566594],[14516211820212764316,4261249487994076490,11210964267417873667,7252918969430566594,15877481873925059044,17036604842139972912,5534800796196967885,3608604157153838227,2124231869409556689,17299978721726771610],[7252918969430566594,11210964267417873667,15877481873925059044,3608604157153838227,4261249487994076490,2124231869409556689,17299978721726771610,7029437790788498388,5534800796196967885,14516211820212764316,17036604842139972912],[4261249487994076490,17036604842139972912,5534800796196967885,17299978721726771610,7252918969430566594,3608604157153838227,14516211820212764316,11210964267417873667,1809704172129195322,2124231869409556689,15877481873925059044,7029437790788498388],[57390435731316553,13838011362258067867,17056531964793634106,4631655038168471552,13588160462734303101,10063704933309776584],[3410481056630111806,13838011362258067867,990192925663920333,57390435731316553,4631655038168471552,8460565235419043665,10063704933309776584,3079923906392020295,13588160462734303101,4301099429811409147,17056531964793634106],[57390435731316553,1097494158696050491,3410481056630111806,990192925663920333,8460565235419043665,13588160462734303101,13838011362258067867,17056531964793634106,4631655038168471552,3079923906392020295,4301099429811409147,10063704933309776584],[13588160462734303101],[4301099429811409147,8460565235419043665,13588160462734303101,57390435731316553],[3079923906392020295,17056531964793634106,4301099429811409147,8460565235419043665,57390435731316553,13588160462734303101],[57390435731316553,13588160462734303101,4301099429811409147,10063704933309776584,3079923906392020295,8460565235419043665,17056531964793634106],[4301099429811409147,990192925663920333,10063704933309776584,57390435731316553,17056531964793634106,3079923906392020295,8460565235419043665,13588160462734303101],[3410481056630111806,57390435731316553,990192925663920333,13588160462734303101,10063704933309776584,8460565235419043665,3079923906392020295,4301099429811409147,17056531964793634106],[3410481056630111806,13588160462734303101,57390435731316553,3079923906392020295,17056531964793634106,10063704933309776584,4301099429811409147,1097494158696050491,990192925663920333,8460565235419043665],[17056531964793634106,4631655038168471552,10063704933309776584,3410481056630111806,8460565235419043665,3079923906392020295,990192925663920333,1097494158696050491,13838011362258067867,13588160462734303101,4301099429811409147,57390435731316553],[11210964267417873667,4261249487994076490,14516211820212764316,17036604842139972912],[14516211820212764316,7252918969430566594,4261249487994076490,15877481873925059044,17036604842139972912,2124231869409556689,11210964267417873667],[7252918969430566594,17299978721726771610,15877481873925059044,4261249487994076490,17036604842139972912,11210964267417873667,14516211820212764316,2124231869409556689],[4261249487994076490,15877481873925059044,14516211820212764316,7252918969430566594,17299978721726771610,11210964267417873667,17036604842139972912,7029437790788498388,2124231869409556689],[15877481873925059044,7252918969430566594,4261249487994076490,17036604842139972912,17299978721726771610,1809704172129195322,7029437790788498388,2124231869409556689,11210964267417873667,14516211820212764316],[2124231869409556689,5534800796196967885,7029437790788498388,7252918969430566594,14516211820212764316,4261249487994076490,11210964267417873667,15877481873925059044,17299978721726771610,3608604157153838227,1809704172129195322,17036604842139972912],[17299978721726771610,4261249487994076490,1809704172129195322,7029437790788498388,14516211820212764316,11210964267417873667,15877481873925059044,17036604842139972912,7252918969430566594,2124231869409556689],[14516211820212764316,15877481873925059044,17299978721726771610,7252918969430566594,17036604842139972912,1809704172129195322,5534800796196967885,7029437790788498388,4261249487994076490,11210964267417873667,2124231869409556689,3608604157153838227],[4328376070224119511],[13340751444307201866,6852799892628327372,14228923746783465609,2871608309888343463,11196821089257149774,9135110142507605216,17740496701763775226,12276520439585231336,2025899804080897524,3750439930725791025,1662641269094032596,5888633415105234509,4328376070224119511,17735408893002232096,7201841978411396053,17397123104674848450,13795432594059356320,18031616785650843168,16609137733952262762,13027689870767713939,17952673493105230490,3214181946162459584,16671141883125519098,16306737306999003555,13446205009526451196],[3750439930725791025,12741076678082295759,7201841978411396053,7480253252288032958,13446205009526451196,3214181946162459584,13340751444307201866,13646498613066619660,14139765080256493579,6852799892628327372,16306737306999003555,4328376070224119511,8566844905246185636,7104261880154687267,12494428953087324640,5449860184735415958,1662641269094032596,17740496701763775226,17952673493105230490,16304636129468583592,2025899804080897524,9135110142507605216,2871608309888343463,18031616785650843168,2834866505092039323,13027689870767713939,13795432594059356320,12276520439585231336,11196821089257149774,17397123104674848450,16609137733952262762,17131529656312051452,14228923746783465609,16671141883125519098,5888633415105234509,8511737864852441844,17735408893002232096,1508440849951861669],[17131529656312051452,16306737306999003555,12276520439585231336,17735408893002232096,18095952297474762348,7201841978411396053,17740496701763775226,14139765080256493579,13795432594059356320,8511737864852441844,4328376070224119511,6852799892628327372,5449860184735415958,140396870212231820,14228923746783465609,13446205009526451196,11196821089257149774,9808637865669223270,1508440849951861669,13027689870767713939,1491840484128555837,5954536408321808728,17397123104674848450,9135110142507605216,2871608309888343463,18031616785650843168,2834866505092039323,3214181946162459584,3750439930725791025,1662641269094032596,13646498613066619660,16304636129468583592,8566844905246185636,7480253252288032958,5888633415105234509,2025899804080897524,12741076678082295759,16671141883125519098,12494428953087324640,17952673493105230490,16609137733952262762,7104261880154687267,13340751444307201866],[17036604842139972912],[13588160462734303101],[18081743490344004315],[]],"selection_redo_history":[]}}},"collapsed":[],"name":"painted-dreams.graphite","commit_hash":"3a591dac6a53454813c8df6ceed5b44b91d1e816","document_ptz":{"pan":[-768.2748744089959,-384.56142660725646],"tilt":0.0,"zoom":1.0,"flip":false},"document_mode":"DesignMode","view_mode":"Normal","overlays_visibility_settings":{"all":true,"artboard_name":true,"compass_rose":true,"quick_measurement":true,"transform_measurement":true,"transform_cage":true,"hover_outline":true,"selection_outline":true,"pivot":true,"path":true,"anchors":true,"handles":true},"rulers_visible":true,"snapping_state":{"snapping_enabled":true,"grid_snapping":false,"artboards":true,"tolerance":8.0,"bounding_box":{"center_point":true,"corner_point":true,"edge_midpoint":true,"align_with_edges":true,"distribute_evenly":true},"path":{"anchor_point":true,"line_midpoint":true,"along_path":true,"normal_to_path":true,"tangent_to_path":true,"path_intersection_point":true,"align_with_anchor_point":true,"perpendicular_from_endpoint":true},"grid":{"origin":[0.0,0.0],"grid_type":{"Rectangular":{"spacing":[1.0,1.0]}},"rectangular_spacing":[1.0,1.0],"isometric_y_spacing":1.0,"isometric_angle_a":30.0,"isometric_angle_b":30.0,"grid_color":{"red":0.6038274,"green":0.6038274,"blue":0.6038274,"alpha":1.0},"dot_display":false}},"graph_view_overlay_open":false,"graph_fade_artwork_percentage":80.0} \ No newline at end of file diff --git a/demo-artwork/parametric-dunescape.graphite b/demo-artwork/parametric-dunescape.graphite new file mode 100644 index 0000000000000000000000000000000000000000..56c1760c602aa76a2168af1f746db3671f2fe69f --- /dev/null +++ b/demo-artwork/parametric-dunescape.graphite @@ -0,0 +1 @@ +{"network_interface":{"network":{"exports":[{"Node":{"node_id":4445985685181725042,"output_index":0,"lambda":false}}],"nodes":[[17154757625902243313,{"inputs":[{"Value":{"tagged_value":"None","exposed":true}},{"Value":{"tagged_value":{"OptionalColor":{"red":0.23529412,"green":0.23529412,"blue":0.24313726,"alpha":1.0}},"exposed":false}},{"Value":{"tagged_value":{"F64":1670.79570439},"exposed":false}},{"Value":{"tagged_value":{"F64":24.0},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":2288754089236120499,"output_index":0,"lambda":false}}],"nodes":[[11731553664207576737,{"inputs":[{"Node":{"node_id":757876048866560520,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"F64":48.900000000000006},"exposed":false}},{"Node":{"node_id":7828034197076821310,"output_index":0,"lambda":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::JitterPointsNode"}},"visible":true,"skip_deduplication":false}],[14158287945315818946,{"inputs":[{"Node":{"node_id":16943732999059587742,"output_index":0,"lambda":false}},{"Node":{"node_id":14577956936089455769,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[0.6181095265062186,3.496297826945966]},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[0.0,0.0]},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[0.4855225354961647,0.31002285853371414]},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":1}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":2}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":3}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":4}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":5}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::TransformNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[2288754089236120499,{"inputs":[{"Node":{"node_id":14158287945315818946,"output_index":0,"lambda":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::SplineNode"}},"visible":true,"skip_deduplication":false}],[7828034197076821310,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":3}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_math_nodes::ToU32Node"}},"visible":true,"skip_deduplication":false}],[640915213983348287,{"inputs":[{"Value":{"tagged_value":"None","exposed":false}},{"Value":{"tagged_value":{"F64":4000.0},"exposed":false}},{"Value":{"tagged_value":{"F64":500.0},"exposed":false}},{"Value":{"tagged_value":{"Bool":false},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"Bool":true},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::generator_nodes::RectangleNode"}},"visible":true,"skip_deduplication":false}],[1791308547102433540,{"inputs":[{"Node":{"node_id":640915213983348287,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Generic":"T"},"import_index":1}},{"Value":{"tagged_value":{"OptionalColor":{"red":0.99607843,"green":0.827451,"blue":0.65882355,"alpha":1.0}},"exposed":false}},{"Value":{"tagged_value":{"Gradient":{"stops":[[0.0,{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}],[1.0,{"red":1.0,"green":1.0,"blue":1.0,"alpha":1.0}]],"gradient_type":"Linear","start":[0.0,0.5],"end":[1.0,0.5],"transform":[1.0,0.0,0.0,1.0,0.0,0.0]}},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::FillNode"}},"visible":true,"skip_deduplication":false}],[14577956936089455769,{"inputs":[{"Value":{"tagged_value":"None","exposed":false}},{"Value":{"tagged_value":{"F64":1050.10498991},"exposed":false}},{"Network":{"import_type":{"Generic":"T"},"import_index":2}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_math_nodes::CoordinateValueNode"}},"visible":true,"skip_deduplication":false}],[16943732999059587742,{"inputs":[{"Node":{"node_id":1357621220363171879,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"F64":1.399999999999956},"exposed":false}},{"Value":{"tagged_value":{"U32":0},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::JitterPointsNode"}},"visible":true,"skip_deduplication":false}],[1357621220363171879,{"inputs":[{"Node":{"node_id":11731553664207576737,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"PointSpacingType":"Separation"},"exposed":false}},{"Value":{"tagged_value":{"F64":172.9},"exposed":false}},{"Value":{"tagged_value":{"U32":100},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"Bool":false},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":4,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::SubpathSegmentLengthsNode"}},"visible":true,"skip_deduplication":false}],[4,{"inputs":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::BoundlessFootprintNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":2,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::FreezeRealTimeNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MemoNode"}},"visible":true,"skip_deduplication":false}],[1,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::misc::PointSpacingType","alias":null}},"import_index":1}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":2}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":3}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":4}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":5}},{"Network":{"import_type":{"Concrete":{"name":"bool","alias":null}},"import_index":6}},{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::SamplePolylineNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[757876048866560520,{"inputs":[{"Node":{"node_id":1791308547102433540,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"PointSpacingType":"Separation"},"exposed":false}},{"Value":{"tagged_value":{"F64":800.0},"exposed":false}},{"Value":{"tagged_value":{"U32":100},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"Bool":false},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":4,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::SubpathSegmentLengthsNode"}},"visible":true,"skip_deduplication":false}],[4,{"inputs":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::BoundlessFootprintNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":2,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::FreezeRealTimeNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MemoNode"}},"visible":true,"skip_deduplication":false}],[1,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::misc::PointSpacingType","alias":null}},"import_index":1}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":2}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":3}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":4}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":5}},{"Network":{"import_type":{"Concrete":{"name":"bool","alias":null}},"import_index":6}},{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::SamplePolylineNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[3683309254695891012,{"inputs":[{"Value":{"tagged_value":"None","exposed":true}},{"Value":{"tagged_value":{"OptionalColor":{"red":0.68235296,"green":0.5372549,"blue":0.4627451,"alpha":1.0}},"exposed":false}},{"Value":{"tagged_value":{"F64":1485.34393334},"exposed":false}},{"Value":{"tagged_value":{"F64":225.0},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":2288754089236120499,"output_index":0,"lambda":false}}],"nodes":[[3916070947050514908,{"inputs":[{"Node":{"node_id":1791308547102433540,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"PointSpacingType":"Separation"},"exposed":false}},{"Value":{"tagged_value":{"F64":800.0},"exposed":false}},{"Value":{"tagged_value":{"U32":100},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"Bool":false},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":4,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::SubpathSegmentLengthsNode"}},"visible":true,"skip_deduplication":false}],[4,{"inputs":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::BoundlessFootprintNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":2,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::FreezeRealTimeNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MemoNode"}},"visible":true,"skip_deduplication":false}],[1,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::misc::PointSpacingType","alias":null}},"import_index":1}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":2}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":3}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":4}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":5}},{"Network":{"import_type":{"Concrete":{"name":"bool","alias":null}},"import_index":6}},{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::SamplePolylineNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[2288754089236120499,{"inputs":[{"Node":{"node_id":14158287945315818946,"output_index":0,"lambda":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::SplineNode"}},"visible":true,"skip_deduplication":false}],[14158287945315818946,{"inputs":[{"Node":{"node_id":16943732999059587742,"output_index":0,"lambda":false}},{"Node":{"node_id":14577956936089455769,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[0.6181095265062186,3.496297826945966]},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[0.0,0.0]},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[0.4855225354961647,0.31002285853371414]},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":1}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":2}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":3}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":4}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":5}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::TransformNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[11731553664207576737,{"inputs":[{"Node":{"node_id":3916070947050514908,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"F64":48.900000000000006},"exposed":false}},{"Node":{"node_id":7828034197076821310,"output_index":0,"lambda":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::JitterPointsNode"}},"visible":true,"skip_deduplication":false}],[7828034197076821310,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":3}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_math_nodes::ToU32Node"}},"visible":true,"skip_deduplication":false}],[640915213983348287,{"inputs":[{"Value":{"tagged_value":"None","exposed":false}},{"Value":{"tagged_value":{"F64":4000.0},"exposed":false}},{"Value":{"tagged_value":{"F64":500.0},"exposed":false}},{"Value":{"tagged_value":{"Bool":false},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"Bool":true},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::generator_nodes::RectangleNode"}},"visible":true,"skip_deduplication":false}],[1791308547102433540,{"inputs":[{"Node":{"node_id":640915213983348287,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Generic":"T"},"import_index":1}},{"Value":{"tagged_value":{"OptionalColor":{"red":0.99607843,"green":0.827451,"blue":0.65882355,"alpha":1.0}},"exposed":false}},{"Value":{"tagged_value":{"Gradient":{"stops":[[0.0,{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}],[1.0,{"red":1.0,"green":1.0,"blue":1.0,"alpha":1.0}]],"gradient_type":"Linear","start":[0.0,0.5],"end":[1.0,0.5],"transform":[1.0,0.0,0.0,1.0,0.0,0.0]}},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::FillNode"}},"visible":true,"skip_deduplication":false}],[14577956936089455769,{"inputs":[{"Value":{"tagged_value":"None","exposed":false}},{"Value":{"tagged_value":{"F64":1050.10498991},"exposed":false}},{"Network":{"import_type":{"Generic":"T"},"import_index":2}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_math_nodes::CoordinateValueNode"}},"visible":true,"skip_deduplication":false}],[16943732999059587742,{"inputs":[{"Node":{"node_id":10720574559271598132,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"F64":1.399999999999956},"exposed":false}},{"Value":{"tagged_value":{"U32":0},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::JitterPointsNode"}},"visible":true,"skip_deduplication":false}],[10720574559271598132,{"inputs":[{"Node":{"node_id":11731553664207576737,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"PointSpacingType":"Separation"},"exposed":false}},{"Value":{"tagged_value":{"F64":172.9},"exposed":false}},{"Value":{"tagged_value":{"U32":100},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"Bool":false},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":4,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::SubpathSegmentLengthsNode"}},"visible":true,"skip_deduplication":false}],[4,{"inputs":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::BoundlessFootprintNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":2,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::FreezeRealTimeNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MemoNode"}},"visible":true,"skip_deduplication":false}],[1,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::misc::PointSpacingType","alias":null}},"import_index":1}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":2}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":3}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":4}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":5}},{"Network":{"import_type":{"Concrete":{"name":"bool","alias":null}},"import_index":6}},{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::SamplePolylineNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[13644002059194136823,{"inputs":[{"Node":{"node_id":17437077810654043142,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"F64":5.599999999999968},"exposed":false}},{"Value":{"tagged_value":{"U32":0},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::JitterPointsNode"}},"visible":true,"skip_deduplication":false}],[4037968351431607570,{"inputs":[{"Value":{"tagged_value":"None","exposed":true}},{"Value":{"tagged_value":{"OptionalColor":{"red":0.8666667,"green":0.69803923,"blue":0.56078434,"alpha":1.0}},"exposed":false}},{"Value":{"tagged_value":{"F64":1442.36628417},"exposed":false}},{"Value":{"tagged_value":{"F64":318.0},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":2288754089236120499,"output_index":0,"lambda":false}}],"nodes":[[11874141024063691837,{"inputs":[{"Node":{"node_id":1791308547102433540,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"PointSpacingType":"Separation"},"exposed":false}},{"Value":{"tagged_value":{"F64":800.0},"exposed":false}},{"Value":{"tagged_value":{"U32":100},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"Bool":false},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":4,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::SubpathSegmentLengthsNode"}},"visible":true,"skip_deduplication":false}],[4,{"inputs":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::BoundlessFootprintNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":2,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::FreezeRealTimeNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MemoNode"}},"visible":true,"skip_deduplication":false}],[1,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::misc::PointSpacingType","alias":null}},"import_index":1}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":2}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":3}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":4}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":5}},{"Network":{"import_type":{"Concrete":{"name":"bool","alias":null}},"import_index":6}},{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::SamplePolylineNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[2288754089236120499,{"inputs":[{"Node":{"node_id":14158287945315818946,"output_index":0,"lambda":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::SplineNode"}},"visible":true,"skip_deduplication":false}],[14158287945315818946,{"inputs":[{"Node":{"node_id":16943732999059587742,"output_index":0,"lambda":false}},{"Node":{"node_id":14577956936089455769,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[0.6181095265062186,3.496297826945966]},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[0.0,0.0]},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[0.4855225354961647,0.31002285853371414]},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":1}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":2}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":3}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":4}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":5}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::TransformNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[11731553664207576737,{"inputs":[{"Node":{"node_id":11874141024063691837,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"F64":48.900000000000006},"exposed":false}},{"Node":{"node_id":7828034197076821310,"output_index":0,"lambda":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::JitterPointsNode"}},"visible":true,"skip_deduplication":false}],[7828034197076821310,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":3}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_math_nodes::ToU32Node"}},"visible":true,"skip_deduplication":false}],[640915213983348287,{"inputs":[{"Value":{"tagged_value":"None","exposed":false}},{"Value":{"tagged_value":{"F64":4000.0},"exposed":false}},{"Value":{"tagged_value":{"F64":500.0},"exposed":false}},{"Value":{"tagged_value":{"Bool":false},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"Bool":true},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::generator_nodes::RectangleNode"}},"visible":true,"skip_deduplication":false}],[1791308547102433540,{"inputs":[{"Node":{"node_id":640915213983348287,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Generic":"T"},"import_index":1}},{"Value":{"tagged_value":{"OptionalColor":{"red":0.99607843,"green":0.827451,"blue":0.65882355,"alpha":1.0}},"exposed":false}},{"Value":{"tagged_value":{"Gradient":{"stops":[[0.0,{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}],[1.0,{"red":1.0,"green":1.0,"blue":1.0,"alpha":1.0}]],"gradient_type":"Linear","start":[0.0,0.5],"end":[1.0,0.5],"transform":[1.0,0.0,0.0,1.0,0.0,0.0]}},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::FillNode"}},"visible":true,"skip_deduplication":false}],[14577956936089455769,{"inputs":[{"Value":{"tagged_value":"None","exposed":false}},{"Value":{"tagged_value":{"F64":1050.10498991},"exposed":false}},{"Network":{"import_type":{"Generic":"T"},"import_index":2}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_math_nodes::CoordinateValueNode"}},"visible":true,"skip_deduplication":false}],[16943732999059587742,{"inputs":[{"Node":{"node_id":7807438675023750219,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"F64":1.399999999999956},"exposed":false}},{"Value":{"tagged_value":{"U32":0},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::JitterPointsNode"}},"visible":true,"skip_deduplication":false}],[7807438675023750219,{"inputs":[{"Node":{"node_id":11731553664207576737,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"PointSpacingType":"Separation"},"exposed":false}},{"Value":{"tagged_value":{"F64":172.9},"exposed":false}},{"Value":{"tagged_value":{"U32":100},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"Bool":false},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":4,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::SubpathSegmentLengthsNode"}},"visible":true,"skip_deduplication":false}],[4,{"inputs":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::BoundlessFootprintNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":2,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::FreezeRealTimeNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MemoNode"}},"visible":true,"skip_deduplication":false}],[1,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::misc::PointSpacingType","alias":null}},"import_index":1}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":2}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":3}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":4}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":5}},{"Network":{"import_type":{"Concrete":{"name":"bool","alias":null}},"import_index":6}},{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::SamplePolylineNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[13323241418027154136,{"inputs":[{"Value":{"tagged_value":"None","exposed":true}},{"Value":{"tagged_value":{"OptionalColor":{"red":0.18039216,"green":0.19215687,"blue":0.21960784,"alpha":1.0}},"exposed":false}},{"Value":{"tagged_value":{"F64":1733.30579952},"exposed":false}},{"Value":{"tagged_value":{"F64":77.0},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":2288754089236120499,"output_index":0,"lambda":false}}],"nodes":[[11731553664207576737,{"inputs":[{"Node":{"node_id":16504069171520924548,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"F64":48.900000000000006},"exposed":false}},{"Node":{"node_id":7828034197076821310,"output_index":0,"lambda":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::JitterPointsNode"}},"visible":true,"skip_deduplication":false}],[14158287945315818946,{"inputs":[{"Node":{"node_id":16943732999059587742,"output_index":0,"lambda":false}},{"Node":{"node_id":14577956936089455769,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[0.6181095265062186,3.496297826945966]},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[0.0,0.0]},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[0.4855225354961647,0.31002285853371414]},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":1}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":2}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":3}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":4}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":5}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::TransformNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[2288754089236120499,{"inputs":[{"Node":{"node_id":14158287945315818946,"output_index":0,"lambda":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::SplineNode"}},"visible":true,"skip_deduplication":false}],[7828034197076821310,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":3}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_math_nodes::ToU32Node"}},"visible":true,"skip_deduplication":false}],[3434804841107735149,{"inputs":[{"Node":{"node_id":11731553664207576737,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"PointSpacingType":"Separation"},"exposed":false}},{"Value":{"tagged_value":{"F64":172.9},"exposed":false}},{"Value":{"tagged_value":{"U32":100},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"Bool":false},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":4,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::SubpathSegmentLengthsNode"}},"visible":true,"skip_deduplication":false}],[4,{"inputs":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::BoundlessFootprintNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":2,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::FreezeRealTimeNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MemoNode"}},"visible":true,"skip_deduplication":false}],[1,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::misc::PointSpacingType","alias":null}},"import_index":1}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":2}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":3}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":4}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":5}},{"Network":{"import_type":{"Concrete":{"name":"bool","alias":null}},"import_index":6}},{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::SamplePolylineNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[640915213983348287,{"inputs":[{"Value":{"tagged_value":"None","exposed":false}},{"Value":{"tagged_value":{"F64":4000.0},"exposed":false}},{"Value":{"tagged_value":{"F64":500.0},"exposed":false}},{"Value":{"tagged_value":{"Bool":false},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"Bool":true},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::generator_nodes::RectangleNode"}},"visible":true,"skip_deduplication":false}],[1791308547102433540,{"inputs":[{"Node":{"node_id":640915213983348287,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Generic":"T"},"import_index":1}},{"Value":{"tagged_value":{"OptionalColor":{"red":0.99607843,"green":0.827451,"blue":0.65882355,"alpha":1.0}},"exposed":false}},{"Value":{"tagged_value":{"Gradient":{"stops":[[0.0,{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}],[1.0,{"red":1.0,"green":1.0,"blue":1.0,"alpha":1.0}]],"gradient_type":"Linear","start":[0.0,0.5],"end":[1.0,0.5],"transform":[1.0,0.0,0.0,1.0,0.0,0.0]}},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::FillNode"}},"visible":true,"skip_deduplication":false}],[14577956936089455769,{"inputs":[{"Value":{"tagged_value":"None","exposed":false}},{"Value":{"tagged_value":{"F64":1050.10498991},"exposed":false}},{"Network":{"import_type":{"Generic":"T"},"import_index":2}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_math_nodes::CoordinateValueNode"}},"visible":true,"skip_deduplication":false}],[16943732999059587742,{"inputs":[{"Node":{"node_id":3434804841107735149,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"F64":1.399999999999956},"exposed":false}},{"Value":{"tagged_value":{"U32":0},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::JitterPointsNode"}},"visible":true,"skip_deduplication":false}],[16504069171520924548,{"inputs":[{"Node":{"node_id":1791308547102433540,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"PointSpacingType":"Separation"},"exposed":false}},{"Value":{"tagged_value":{"F64":800.0},"exposed":false}},{"Value":{"tagged_value":{"U32":100},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"Bool":false},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":4,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::SubpathSegmentLengthsNode"}},"visible":true,"skip_deduplication":false}],[4,{"inputs":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::BoundlessFootprintNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":2,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::FreezeRealTimeNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MemoNode"}},"visible":true,"skip_deduplication":false}],[1,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::misc::PointSpacingType","alias":null}},"import_index":1}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":2}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":3}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":4}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":5}},{"Network":{"import_type":{"Concrete":{"name":"bool","alias":null}},"import_index":6}},{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::SamplePolylineNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[12110920487474373676,{"inputs":[{"Node":{"node_id":12639486733043466090,"output_index":0,"lambda":false}},{"Node":{"node_id":13323241418027154136,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[10806978668166337270,{"inputs":[{"Value":{"tagged_value":"None","exposed":true}},{"Value":{"tagged_value":{"OptionalColor":{"red":0.21176471,"green":0.21568628,"blue":0.23137255,"alpha":1.0}},"exposed":false}},{"Value":{"tagged_value":{"F64":1579.30304164},"exposed":false}},{"Value":{"tagged_value":{"F64":142.0},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":2288754089236120499,"output_index":0,"lambda":false}}],"nodes":[[9133354469966676056,{"inputs":[{"Node":{"node_id":11731553664207576737,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"PointSpacingType":"Separation"},"exposed":false}},{"Value":{"tagged_value":{"F64":172.9},"exposed":false}},{"Value":{"tagged_value":{"U32":100},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"Bool":false},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":4,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::SubpathSegmentLengthsNode"}},"visible":true,"skip_deduplication":false}],[4,{"inputs":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::BoundlessFootprintNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":2,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::FreezeRealTimeNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MemoNode"}},"visible":true,"skip_deduplication":false}],[1,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::misc::PointSpacingType","alias":null}},"import_index":1}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":2}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":3}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":4}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":5}},{"Network":{"import_type":{"Concrete":{"name":"bool","alias":null}},"import_index":6}},{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::SamplePolylineNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[2288754089236120499,{"inputs":[{"Node":{"node_id":14158287945315818946,"output_index":0,"lambda":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::SplineNode"}},"visible":true,"skip_deduplication":false}],[14158287945315818946,{"inputs":[{"Node":{"node_id":16943732999059587742,"output_index":0,"lambda":false}},{"Node":{"node_id":14577956936089455769,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[0.6181095265062186,3.496297826945966]},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[0.0,0.0]},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[0.4855225354961647,0.31002285853371414]},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":1}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":2}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":3}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":4}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":5}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::TransformNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[11731553664207576737,{"inputs":[{"Node":{"node_id":3765311973789472189,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"F64":48.900000000000006},"exposed":false}},{"Node":{"node_id":7828034197076821310,"output_index":0,"lambda":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::JitterPointsNode"}},"visible":true,"skip_deduplication":false}],[7828034197076821310,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":3}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_math_nodes::ToU32Node"}},"visible":true,"skip_deduplication":false}],[640915213983348287,{"inputs":[{"Value":{"tagged_value":"None","exposed":false}},{"Value":{"tagged_value":{"F64":4000.0},"exposed":false}},{"Value":{"tagged_value":{"F64":500.0},"exposed":false}},{"Value":{"tagged_value":{"Bool":false},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"Bool":true},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::generator_nodes::RectangleNode"}},"visible":true,"skip_deduplication":false}],[1791308547102433540,{"inputs":[{"Node":{"node_id":640915213983348287,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Generic":"T"},"import_index":1}},{"Value":{"tagged_value":{"OptionalColor":{"red":0.99607843,"green":0.827451,"blue":0.65882355,"alpha":1.0}},"exposed":false}},{"Value":{"tagged_value":{"Gradient":{"stops":[[0.0,{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}],[1.0,{"red":1.0,"green":1.0,"blue":1.0,"alpha":1.0}]],"gradient_type":"Linear","start":[0.0,0.5],"end":[1.0,0.5],"transform":[1.0,0.0,0.0,1.0,0.0,0.0]}},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::FillNode"}},"visible":true,"skip_deduplication":false}],[14577956936089455769,{"inputs":[{"Value":{"tagged_value":"None","exposed":false}},{"Value":{"tagged_value":{"F64":1050.10498991},"exposed":false}},{"Network":{"import_type":{"Generic":"T"},"import_index":2}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_math_nodes::CoordinateValueNode"}},"visible":true,"skip_deduplication":false}],[16943732999059587742,{"inputs":[{"Node":{"node_id":9133354469966676056,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"F64":1.399999999999956},"exposed":false}},{"Value":{"tagged_value":{"U32":0},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::JitterPointsNode"}},"visible":true,"skip_deduplication":false}],[3765311973789472189,{"inputs":[{"Node":{"node_id":1791308547102433540,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"PointSpacingType":"Separation"},"exposed":false}},{"Value":{"tagged_value":{"F64":800.0},"exposed":false}},{"Value":{"tagged_value":{"U32":100},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"Bool":false},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":4,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::SubpathSegmentLengthsNode"}},"visible":true,"skip_deduplication":false}],[4,{"inputs":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::BoundlessFootprintNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":2,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::FreezeRealTimeNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MemoNode"}},"visible":true,"skip_deduplication":false}],[1,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::misc::PointSpacingType","alias":null}},"import_index":1}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":2}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":3}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":4}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":5}},{"Network":{"import_type":{"Concrete":{"name":"bool","alias":null}},"import_index":6}},{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::SamplePolylineNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[4390668436091073484,{"inputs":[{"Node":{"node_id":13676600738025998635,"output_index":0,"lambda":false}},{"Node":{"node_id":12122314434656187176,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[5883606306991910210,{"inputs":[{"Value":{"tagged_value":"None","exposed":true}},{"Value":{"tagged_value":{"OptionalColor":{"red":0.4862745,"green":0.43137255,"blue":0.39607844,"alpha":1.0}},"exposed":false}},{"Value":{"tagged_value":{"F64":1524.31304726},"exposed":false}},{"Value":{"tagged_value":{"F64":175.0},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":2288754089236120499,"output_index":0,"lambda":false}}],"nodes":[[16598825029377599083,{"inputs":[{"Node":{"node_id":1791308547102433540,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"PointSpacingType":"Separation"},"exposed":false}},{"Value":{"tagged_value":{"F64":800.0},"exposed":false}},{"Value":{"tagged_value":{"U32":100},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"Bool":false},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":4,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::SubpathSegmentLengthsNode"}},"visible":true,"skip_deduplication":false}],[4,{"inputs":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::BoundlessFootprintNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":2,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::FreezeRealTimeNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MemoNode"}},"visible":true,"skip_deduplication":false}],[1,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::misc::PointSpacingType","alias":null}},"import_index":1}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":2}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":3}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":4}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":5}},{"Network":{"import_type":{"Concrete":{"name":"bool","alias":null}},"import_index":6}},{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::SamplePolylineNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[2288754089236120499,{"inputs":[{"Node":{"node_id":14158287945315818946,"output_index":0,"lambda":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::SplineNode"}},"visible":true,"skip_deduplication":false}],[14158287945315818946,{"inputs":[{"Node":{"node_id":16943732999059587742,"output_index":0,"lambda":false}},{"Node":{"node_id":14577956936089455769,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[0.6181095265062186,3.496297826945966]},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[0.0,0.0]},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[0.4855225354961647,0.31002285853371414]},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":1}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":2}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":3}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":4}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":5}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::TransformNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[11731553664207576737,{"inputs":[{"Node":{"node_id":16598825029377599083,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"F64":48.900000000000006},"exposed":false}},{"Node":{"node_id":7828034197076821310,"output_index":0,"lambda":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::JitterPointsNode"}},"visible":true,"skip_deduplication":false}],[7828034197076821310,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":3}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_math_nodes::ToU32Node"}},"visible":true,"skip_deduplication":false}],[6686718746443793247,{"inputs":[{"Node":{"node_id":11731553664207576737,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"PointSpacingType":"Separation"},"exposed":false}},{"Value":{"tagged_value":{"F64":172.9},"exposed":false}},{"Value":{"tagged_value":{"U32":100},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"Bool":false},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":4,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::SubpathSegmentLengthsNode"}},"visible":true,"skip_deduplication":false}],[4,{"inputs":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::BoundlessFootprintNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":2,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::FreezeRealTimeNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MemoNode"}},"visible":true,"skip_deduplication":false}],[1,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::misc::PointSpacingType","alias":null}},"import_index":1}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":2}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":3}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":4}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":5}},{"Network":{"import_type":{"Concrete":{"name":"bool","alias":null}},"import_index":6}},{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::SamplePolylineNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[640915213983348287,{"inputs":[{"Value":{"tagged_value":"None","exposed":false}},{"Value":{"tagged_value":{"F64":4000.0},"exposed":false}},{"Value":{"tagged_value":{"F64":500.0},"exposed":false}},{"Value":{"tagged_value":{"Bool":false},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"Bool":true},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::generator_nodes::RectangleNode"}},"visible":true,"skip_deduplication":false}],[1791308547102433540,{"inputs":[{"Node":{"node_id":640915213983348287,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Generic":"T"},"import_index":1}},{"Value":{"tagged_value":{"OptionalColor":{"red":0.99607843,"green":0.827451,"blue":0.65882355,"alpha":1.0}},"exposed":false}},{"Value":{"tagged_value":{"Gradient":{"stops":[[0.0,{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}],[1.0,{"red":1.0,"green":1.0,"blue":1.0,"alpha":1.0}]],"gradient_type":"Linear","start":[0.0,0.5],"end":[1.0,0.5],"transform":[1.0,0.0,0.0,1.0,0.0,0.0]}},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::FillNode"}},"visible":true,"skip_deduplication":false}],[14577956936089455769,{"inputs":[{"Value":{"tagged_value":"None","exposed":false}},{"Value":{"tagged_value":{"F64":1050.10498991},"exposed":false}},{"Network":{"import_type":{"Generic":"T"},"import_index":2}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_math_nodes::CoordinateValueNode"}},"visible":true,"skip_deduplication":false}],[16943732999059587742,{"inputs":[{"Node":{"node_id":6686718746443793247,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"F64":1.399999999999956},"exposed":false}},{"Value":{"tagged_value":{"U32":0},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::JitterPointsNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[13132104524813958174,{"inputs":[{"Node":{"node_id":4390668436091073484,"output_index":0,"lambda":false}},{"Node":{"node_id":2163528024003768644,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[12416569579970107543,{"inputs":[{"Node":{"node_id":13644002059194136823,"output_index":0,"lambda":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::SplineNode"}},"visible":true,"skip_deduplication":false}],[9069881382900058607,{"inputs":[{"Value":{"tagged_value":{"GraphicGroup":{"instance":[],"transform":[],"alpha_blending":[],"source_node_id":[]}},"exposed":true}},{"Node":{"node_id":4037968351431607570,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[12639486733043466090,{"inputs":[{"Node":{"node_id":8804763001225416124,"output_index":0,"lambda":false}},{"Node":{"node_id":1801066723091712434,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[7128559142392931896,{"inputs":[{"Value":{"tagged_value":"None","exposed":true}},{"Value":{"tagged_value":{"OptionalColor":{"red":0.15686275,"green":0.16862746,"blue":0.1882353,"alpha":1.0}},"exposed":false}},{"Value":{"tagged_value":{"F64":1803.43646796},"exposed":false}},{"Value":{"tagged_value":{"F64":35.0},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":2288754089236120499,"output_index":0,"lambda":false}}],"nodes":[[11731553664207576737,{"inputs":[{"Node":{"node_id":10094915787292727725,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"F64":48.900000000000006},"exposed":false}},{"Node":{"node_id":7828034197076821310,"output_index":0,"lambda":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::JitterPointsNode"}},"visible":true,"skip_deduplication":false}],[14158287945315818946,{"inputs":[{"Node":{"node_id":16943732999059587742,"output_index":0,"lambda":false}},{"Node":{"node_id":14577956936089455769,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[0.6181095265062186,3.496297826945966]},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[0.0,0.0]},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[0.4855225354961647,0.31002285853371414]},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":1}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":2}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":3}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":4}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":5}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::TransformNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[2288754089236120499,{"inputs":[{"Node":{"node_id":14158287945315818946,"output_index":0,"lambda":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::SplineNode"}},"visible":true,"skip_deduplication":false}],[18443039976647938912,{"inputs":[{"Node":{"node_id":11731553664207576737,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"PointSpacingType":"Separation"},"exposed":false}},{"Value":{"tagged_value":{"F64":172.9},"exposed":false}},{"Value":{"tagged_value":{"U32":100},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"Bool":false},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":4,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::SubpathSegmentLengthsNode"}},"visible":true,"skip_deduplication":false}],[4,{"inputs":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::BoundlessFootprintNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":2,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::FreezeRealTimeNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MemoNode"}},"visible":true,"skip_deduplication":false}],[1,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::misc::PointSpacingType","alias":null}},"import_index":1}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":2}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":3}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":4}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":5}},{"Network":{"import_type":{"Concrete":{"name":"bool","alias":null}},"import_index":6}},{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::SamplePolylineNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[7828034197076821310,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":3}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_math_nodes::ToU32Node"}},"visible":true,"skip_deduplication":false}],[10094915787292727725,{"inputs":[{"Node":{"node_id":1791308547102433540,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"PointSpacingType":"Separation"},"exposed":false}},{"Value":{"tagged_value":{"F64":800.0},"exposed":false}},{"Value":{"tagged_value":{"U32":100},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"Bool":false},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":4,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::SubpathSegmentLengthsNode"}},"visible":true,"skip_deduplication":false}],[4,{"inputs":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::BoundlessFootprintNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":2,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::FreezeRealTimeNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MemoNode"}},"visible":true,"skip_deduplication":false}],[1,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::misc::PointSpacingType","alias":null}},"import_index":1}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":2}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":3}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":4}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":5}},{"Network":{"import_type":{"Concrete":{"name":"bool","alias":null}},"import_index":6}},{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::SamplePolylineNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[640915213983348287,{"inputs":[{"Value":{"tagged_value":"None","exposed":false}},{"Value":{"tagged_value":{"F64":4000.0},"exposed":false}},{"Value":{"tagged_value":{"F64":500.0},"exposed":false}},{"Value":{"tagged_value":{"Bool":false},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"Bool":true},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::generator_nodes::RectangleNode"}},"visible":true,"skip_deduplication":false}],[1791308547102433540,{"inputs":[{"Node":{"node_id":640915213983348287,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Generic":"T"},"import_index":1}},{"Value":{"tagged_value":{"OptionalColor":{"red":0.99607843,"green":0.827451,"blue":0.65882355,"alpha":1.0}},"exposed":false}},{"Value":{"tagged_value":{"Gradient":{"stops":[[0.0,{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}],[1.0,{"red":1.0,"green":1.0,"blue":1.0,"alpha":1.0}]],"gradient_type":"Linear","start":[0.0,0.5],"end":[1.0,0.5],"transform":[1.0,0.0,0.0,1.0,0.0,0.0]}},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::FillNode"}},"visible":true,"skip_deduplication":false}],[14577956936089455769,{"inputs":[{"Value":{"tagged_value":"None","exposed":false}},{"Value":{"tagged_value":{"F64":1050.10498991},"exposed":false}},{"Network":{"import_type":{"Generic":"T"},"import_index":2}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_math_nodes::CoordinateValueNode"}},"visible":true,"skip_deduplication":false}],[16943732999059587742,{"inputs":[{"Node":{"node_id":18443039976647938912,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"F64":1.399999999999956},"exposed":false}},{"Value":{"tagged_value":{"U32":0},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::JitterPointsNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[17327221498641745184,{"inputs":[{"Node":{"node_id":12317719117993811200,"output_index":0,"lambda":false}},{"Node":{"node_id":3683309254695891012,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[7711570794020903773,{"inputs":[{"Value":{"tagged_value":"None","exposed":true}},{"Value":{"tagged_value":{"OptionalColor":{"red":0.8784314,"green":0.49019608,"blue":0.36862746,"alpha":1.0}},"exposed":false}},{"Value":{"tagged_value":{"F64":1513.3360814},"exposed":false}},{"Value":{"tagged_value":{"F64":22.0},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":2288754089236120499,"output_index":0,"lambda":false}}],"nodes":[[3025883099767376126,{"inputs":[{"Node":{"node_id":1791308547102433540,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"PointSpacingType":"Separation"},"exposed":false}},{"Value":{"tagged_value":{"F64":800.0},"exposed":false}},{"Value":{"tagged_value":{"U32":100},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"Bool":false},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":4,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::SubpathSegmentLengthsNode"}},"visible":true,"skip_deduplication":false}],[4,{"inputs":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::BoundlessFootprintNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":2,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::FreezeRealTimeNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MemoNode"}},"visible":true,"skip_deduplication":false}],[1,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::misc::PointSpacingType","alias":null}},"import_index":1}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":2}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":3}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":4}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":5}},{"Network":{"import_type":{"Concrete":{"name":"bool","alias":null}},"import_index":6}},{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::SamplePolylineNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[2288754089236120499,{"inputs":[{"Node":{"node_id":14158287945315818946,"output_index":0,"lambda":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::SplineNode"}},"visible":true,"skip_deduplication":false}],[14158287945315818946,{"inputs":[{"Node":{"node_id":16943732999059587742,"output_index":0,"lambda":false}},{"Node":{"node_id":14577956936089455769,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[0.6181095265062186,3.496297826945966]},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[0.0,0.0]},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[0.4855225354961647,0.31002285853371414]},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":1}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":2}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":3}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":4}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":5}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::TransformNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[11731553664207576737,{"inputs":[{"Node":{"node_id":3025883099767376126,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"F64":48.900000000000006},"exposed":false}},{"Node":{"node_id":7828034197076821310,"output_index":0,"lambda":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::JitterPointsNode"}},"visible":true,"skip_deduplication":false}],[1126802566044359983,{"inputs":[{"Node":{"node_id":11731553664207576737,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"PointSpacingType":"Separation"},"exposed":false}},{"Value":{"tagged_value":{"F64":172.9},"exposed":false}},{"Value":{"tagged_value":{"U32":100},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"Bool":false},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":4,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::SubpathSegmentLengthsNode"}},"visible":true,"skip_deduplication":false}],[4,{"inputs":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::BoundlessFootprintNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":2,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::FreezeRealTimeNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MemoNode"}},"visible":true,"skip_deduplication":false}],[1,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::misc::PointSpacingType","alias":null}},"import_index":1}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":2}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":3}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":4}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":5}},{"Network":{"import_type":{"Concrete":{"name":"bool","alias":null}},"import_index":6}},{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::SamplePolylineNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[7828034197076821310,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":3}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_math_nodes::ToU32Node"}},"visible":true,"skip_deduplication":false}],[640915213983348287,{"inputs":[{"Value":{"tagged_value":"None","exposed":false}},{"Value":{"tagged_value":{"F64":4000.0},"exposed":false}},{"Value":{"tagged_value":{"F64":500.0},"exposed":false}},{"Value":{"tagged_value":{"Bool":false},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"Bool":true},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::generator_nodes::RectangleNode"}},"visible":true,"skip_deduplication":false}],[1791308547102433540,{"inputs":[{"Node":{"node_id":640915213983348287,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Generic":"T"},"import_index":1}},{"Value":{"tagged_value":{"OptionalColor":{"red":0.99607843,"green":0.827451,"blue":0.65882355,"alpha":1.0}},"exposed":false}},{"Value":{"tagged_value":{"Gradient":{"stops":[[0.0,{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}],[1.0,{"red":1.0,"green":1.0,"blue":1.0,"alpha":1.0}]],"gradient_type":"Linear","start":[0.0,0.5],"end":[1.0,0.5],"transform":[1.0,0.0,0.0,1.0,0.0,0.0]}},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::FillNode"}},"visible":true,"skip_deduplication":false}],[14577956936089455769,{"inputs":[{"Value":{"tagged_value":"None","exposed":false}},{"Value":{"tagged_value":{"F64":1050.10498991},"exposed":false}},{"Network":{"import_type":{"Generic":"T"},"import_index":2}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_math_nodes::CoordinateValueNode"}},"visible":true,"skip_deduplication":false}],[16943732999059587742,{"inputs":[{"Node":{"node_id":1126802566044359983,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"F64":1.399999999999956},"exposed":false}},{"Value":{"tagged_value":{"U32":0},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::JitterPointsNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[10686861494573327243,{"inputs":[{"Node":{"node_id":11386926595254122633,"output_index":0,"lambda":false}},{"Node":{"node_id":10806978668166337270,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[17589660903986237301,{"inputs":[{"Value":{"tagged_value":"None","exposed":true}},{"Value":{"tagged_value":{"OptionalColor":{"red":0.9529412,"green":0.6431373,"blue":0.42352942,"alpha":1.0}},"exposed":false}},{"Value":{"tagged_value":{"F64":1614.38741737},"exposed":false}},{"Value":{"tagged_value":{"F64":17.0},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":2288754089236120499,"output_index":0,"lambda":false}}],"nodes":[[3289411516263327806,{"inputs":[{"Node":{"node_id":1791308547102433540,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"PointSpacingType":"Separation"},"exposed":false}},{"Value":{"tagged_value":{"F64":800.0},"exposed":false}},{"Value":{"tagged_value":{"U32":100},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"Bool":false},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":4,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::SubpathSegmentLengthsNode"}},"visible":true,"skip_deduplication":false}],[4,{"inputs":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::BoundlessFootprintNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":2,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::FreezeRealTimeNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MemoNode"}},"visible":true,"skip_deduplication":false}],[1,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::misc::PointSpacingType","alias":null}},"import_index":1}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":2}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":3}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":4}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":5}},{"Network":{"import_type":{"Concrete":{"name":"bool","alias":null}},"import_index":6}},{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::SamplePolylineNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[2288754089236120499,{"inputs":[{"Node":{"node_id":14158287945315818946,"output_index":0,"lambda":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::SplineNode"}},"visible":true,"skip_deduplication":false}],[14158287945315818946,{"inputs":[{"Node":{"node_id":16943732999059587742,"output_index":0,"lambda":false}},{"Node":{"node_id":14577956936089455769,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[0.6181095265062186,3.496297826945966]},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[0.0,0.0]},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[0.4855225354961647,0.31002285853371414]},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":1}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":2}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":3}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":4}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":5}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::TransformNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[11731553664207576737,{"inputs":[{"Node":{"node_id":3289411516263327806,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"F64":48.900000000000006},"exposed":false}},{"Node":{"node_id":7828034197076821310,"output_index":0,"lambda":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::JitterPointsNode"}},"visible":true,"skip_deduplication":false}],[7828034197076821310,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":3}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_math_nodes::ToU32Node"}},"visible":true,"skip_deduplication":false}],[640915213983348287,{"inputs":[{"Value":{"tagged_value":"None","exposed":false}},{"Value":{"tagged_value":{"F64":4000.0},"exposed":false}},{"Value":{"tagged_value":{"F64":500.0},"exposed":false}},{"Value":{"tagged_value":{"Bool":false},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"Bool":true},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::generator_nodes::RectangleNode"}},"visible":true,"skip_deduplication":false}],[1791308547102433540,{"inputs":[{"Node":{"node_id":640915213983348287,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Generic":"T"},"import_index":1}},{"Value":{"tagged_value":{"OptionalColor":{"red":0.99607843,"green":0.827451,"blue":0.65882355,"alpha":1.0}},"exposed":false}},{"Value":{"tagged_value":{"Gradient":{"stops":[[0.0,{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}],[1.0,{"red":1.0,"green":1.0,"blue":1.0,"alpha":1.0}]],"gradient_type":"Linear","start":[0.0,0.5],"end":[1.0,0.5],"transform":[1.0,0.0,0.0,1.0,0.0,0.0]}},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::FillNode"}},"visible":true,"skip_deduplication":false}],[14577956936089455769,{"inputs":[{"Value":{"tagged_value":"None","exposed":false}},{"Value":{"tagged_value":{"F64":1050.10498991},"exposed":false}},{"Network":{"import_type":{"Generic":"T"},"import_index":2}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_math_nodes::CoordinateValueNode"}},"visible":true,"skip_deduplication":false}],[16943732999059587742,{"inputs":[{"Node":{"node_id":12029121808718862100,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"F64":1.399999999999956},"exposed":false}},{"Value":{"tagged_value":{"U32":0},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::JitterPointsNode"}},"visible":true,"skip_deduplication":false}],[12029121808718862100,{"inputs":[{"Node":{"node_id":11731553664207576737,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"PointSpacingType":"Separation"},"exposed":false}},{"Value":{"tagged_value":{"F64":172.9},"exposed":false}},{"Value":{"tagged_value":{"U32":100},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"Bool":false},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":4,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::SubpathSegmentLengthsNode"}},"visible":true,"skip_deduplication":false}],[4,{"inputs":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::BoundlessFootprintNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":2,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::FreezeRealTimeNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MemoNode"}},"visible":true,"skip_deduplication":false}],[1,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::misc::PointSpacingType","alias":null}},"import_index":1}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":2}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":3}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":4}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":5}},{"Network":{"import_type":{"Concrete":{"name":"bool","alias":null}},"import_index":6}},{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::SamplePolylineNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[2163528024003768644,{"inputs":[{"Node":{"node_id":12110920487474373676,"output_index":0,"lambda":false}},{"Node":{"node_id":7128559142392931896,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[6523786079462141312,{"inputs":[{"Value":{"tagged_value":"None","exposed":true}},{"Value":{"tagged_value":{"OptionalColor":{"red":0.85882354,"green":0.57254905,"blue":0.43529412,"alpha":1.0}},"exposed":false}},{"Value":{"tagged_value":{"F64":1491.01593158},"exposed":false}},{"Value":{"tagged_value":{"F64":173.0},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":2288754089236120499,"output_index":0,"lambda":false}}],"nodes":[[7783268010546120518,{"inputs":[{"Node":{"node_id":11731553664207576737,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"PointSpacingType":"Separation"},"exposed":false}},{"Value":{"tagged_value":{"F64":172.9},"exposed":false}},{"Value":{"tagged_value":{"U32":100},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"Bool":false},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":4,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::SubpathSegmentLengthsNode"}},"visible":true,"skip_deduplication":false}],[4,{"inputs":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::BoundlessFootprintNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":2,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::FreezeRealTimeNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MemoNode"}},"visible":true,"skip_deduplication":false}],[1,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::misc::PointSpacingType","alias":null}},"import_index":1}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":2}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":3}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":4}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":5}},{"Network":{"import_type":{"Concrete":{"name":"bool","alias":null}},"import_index":6}},{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::SamplePolylineNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[2288754089236120499,{"inputs":[{"Node":{"node_id":14158287945315818946,"output_index":0,"lambda":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::SplineNode"}},"visible":true,"skip_deduplication":false}],[14158287945315818946,{"inputs":[{"Node":{"node_id":16943732999059587742,"output_index":0,"lambda":false}},{"Node":{"node_id":14577956936089455769,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[0.6181095265062186,3.496297826945966]},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[0.0,0.0]},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[0.4855225354961647,0.31002285853371414]},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":1}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":2}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":3}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":4}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":5}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::TransformNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[11731553664207576737,{"inputs":[{"Node":{"node_id":16009834030113172488,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"F64":48.900000000000006},"exposed":false}},{"Node":{"node_id":7828034197076821310,"output_index":0,"lambda":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::JitterPointsNode"}},"visible":true,"skip_deduplication":false}],[7828034197076821310,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":3}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_math_nodes::ToU32Node"}},"visible":true,"skip_deduplication":false}],[640915213983348287,{"inputs":[{"Value":{"tagged_value":"None","exposed":false}},{"Value":{"tagged_value":{"F64":4000.0},"exposed":false}},{"Value":{"tagged_value":{"F64":500.0},"exposed":false}},{"Value":{"tagged_value":{"Bool":false},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"Bool":true},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::generator_nodes::RectangleNode"}},"visible":true,"skip_deduplication":false}],[1791308547102433540,{"inputs":[{"Node":{"node_id":640915213983348287,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Generic":"T"},"import_index":1}},{"Value":{"tagged_value":{"OptionalColor":{"red":0.99607843,"green":0.827451,"blue":0.65882355,"alpha":1.0}},"exposed":false}},{"Value":{"tagged_value":{"Gradient":{"stops":[[0.0,{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}],[1.0,{"red":1.0,"green":1.0,"blue":1.0,"alpha":1.0}]],"gradient_type":"Linear","start":[0.0,0.5],"end":[1.0,0.5],"transform":[1.0,0.0,0.0,1.0,0.0,0.0]}},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::FillNode"}},"visible":true,"skip_deduplication":false}],[14577956936089455769,{"inputs":[{"Value":{"tagged_value":"None","exposed":false}},{"Value":{"tagged_value":{"F64":1050.10498991},"exposed":false}},{"Network":{"import_type":{"Generic":"T"},"import_index":2}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_math_nodes::CoordinateValueNode"}},"visible":true,"skip_deduplication":false}],[16943732999059587742,{"inputs":[{"Node":{"node_id":7783268010546120518,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"F64":1.399999999999956},"exposed":false}},{"Value":{"tagged_value":{"U32":0},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::JitterPointsNode"}},"visible":true,"skip_deduplication":false}],[16009834030113172488,{"inputs":[{"Node":{"node_id":1791308547102433540,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"PointSpacingType":"Separation"},"exposed":false}},{"Value":{"tagged_value":{"F64":800.0},"exposed":false}},{"Value":{"tagged_value":{"U32":100},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"Bool":false},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":4,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::SubpathSegmentLengthsNode"}},"visible":true,"skip_deduplication":false}],[4,{"inputs":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::BoundlessFootprintNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":2,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::FreezeRealTimeNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MemoNode"}},"visible":true,"skip_deduplication":false}],[1,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::misc::PointSpacingType","alias":null}},"import_index":1}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":2}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":3}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":4}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":5}},{"Network":{"import_type":{"Concrete":{"name":"bool","alias":null}},"import_index":6}},{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::SamplePolylineNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[11386926595254122633,{"inputs":[{"Value":{"tagged_value":{"GraphicGroup":{"instance":[],"transform":[],"alpha_blending":[],"source_node_id":[]}},"exposed":true}},{"Node":{"node_id":6523786079462141312,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[15002088321732485705,{"inputs":[{"Value":{"tagged_value":"None","exposed":true}},{"Value":{"tagged_value":{"OptionalColor":{"red":0.99607843,"green":0.827451,"blue":0.65882355,"alpha":1.0}},"exposed":false}},{"Value":{"tagged_value":{"F64":1343.63187023},"exposed":false}},{"Value":{"tagged_value":{"F64":349.0},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":2288754089236120499,"output_index":0,"lambda":false}}],"nodes":[[11731553664207576737,{"inputs":[{"Node":{"node_id":15212962088799153943,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"F64":48.900000000000006},"exposed":false}},{"Node":{"node_id":7828034197076821310,"output_index":0,"lambda":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::JitterPointsNode"}},"visible":true,"skip_deduplication":false}],[14158287945315818946,{"inputs":[{"Node":{"node_id":16943732999059587742,"output_index":0,"lambda":false}},{"Node":{"node_id":14577956936089455769,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[0.6181095265062186,3.496297826945966]},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[0.0,0.0]},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[0.4855225354961647,0.31002285853371414]},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":1}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":2}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":3}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":4}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":5}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::TransformNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[2288754089236120499,{"inputs":[{"Node":{"node_id":14158287945315818946,"output_index":0,"lambda":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::SplineNode"}},"visible":true,"skip_deduplication":false}],[7828034197076821310,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":3}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_math_nodes::ToU32Node"}},"visible":true,"skip_deduplication":false}],[640915213983348287,{"inputs":[{"Value":{"tagged_value":"None","exposed":false}},{"Value":{"tagged_value":{"F64":4000.0},"exposed":false}},{"Value":{"tagged_value":{"F64":500.0},"exposed":false}},{"Value":{"tagged_value":{"Bool":false},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"Bool":true},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::generator_nodes::RectangleNode"}},"visible":true,"skip_deduplication":false}],[1791308547102433540,{"inputs":[{"Node":{"node_id":640915213983348287,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Generic":"T"},"import_index":1}},{"Value":{"tagged_value":{"OptionalColor":{"red":0.99607843,"green":0.827451,"blue":0.65882355,"alpha":1.0}},"exposed":false}},{"Value":{"tagged_value":{"Gradient":{"stops":[[0.0,{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}],[1.0,{"red":1.0,"green":1.0,"blue":1.0,"alpha":1.0}]],"gradient_type":"Linear","start":[0.0,0.5],"end":[1.0,0.5],"transform":[1.0,0.0,0.0,1.0,0.0,0.0]}},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::FillNode"}},"visible":true,"skip_deduplication":false}],[14577956936089455769,{"inputs":[{"Value":{"tagged_value":"None","exposed":false}},{"Value":{"tagged_value":{"F64":1050.10498991},"exposed":false}},{"Network":{"import_type":{"Generic":"T"},"import_index":2}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_math_nodes::CoordinateValueNode"}},"visible":true,"skip_deduplication":false}],[16943732999059587742,{"inputs":[{"Node":{"node_id":8591396027454826376,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"F64":1.399999999999956},"exposed":false}},{"Value":{"tagged_value":{"U32":0},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::JitterPointsNode"}},"visible":true,"skip_deduplication":false}],[15212962088799153943,{"inputs":[{"Node":{"node_id":1791308547102433540,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"PointSpacingType":"Separation"},"exposed":false}},{"Value":{"tagged_value":{"F64":800.0},"exposed":false}},{"Value":{"tagged_value":{"U32":100},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"Bool":false},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":4,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::SubpathSegmentLengthsNode"}},"visible":true,"skip_deduplication":false}],[4,{"inputs":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::BoundlessFootprintNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":2,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::FreezeRealTimeNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MemoNode"}},"visible":true,"skip_deduplication":false}],[1,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::misc::PointSpacingType","alias":null}},"import_index":1}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":2}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":3}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":4}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":5}},{"Network":{"import_type":{"Concrete":{"name":"bool","alias":null}},"import_index":6}},{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::SamplePolylineNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[8591396027454826376,{"inputs":[{"Node":{"node_id":11731553664207576737,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"PointSpacingType":"Separation"},"exposed":false}},{"Value":{"tagged_value":{"F64":172.9},"exposed":false}},{"Value":{"tagged_value":{"U32":100},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"Bool":false},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":4,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::SubpathSegmentLengthsNode"}},"visible":true,"skip_deduplication":false}],[4,{"inputs":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::BoundlessFootprintNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":2,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::FreezeRealTimeNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MemoNode"}},"visible":true,"skip_deduplication":false}],[1,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::misc::PointSpacingType","alias":null}},"import_index":1}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":2}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":3}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":4}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":5}},{"Network":{"import_type":{"Concrete":{"name":"bool","alias":null}},"import_index":6}},{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::SamplePolylineNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[3934928477288442109,{"inputs":[{"Node":{"node_id":239716716021064150,"output_index":0,"lambda":false}},{"Node":{"node_id":17589660903986237301,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[16611856724057842399,{"inputs":[{"Value":{"tagged_value":"None","exposed":true}},{"Value":{"tagged_value":{"OptionalColor":{"red":0.23529412,"green":0.23529412,"blue":0.24313726,"alpha":1.0}},"exposed":false}},{"Value":{"tagged_value":{"F64":1554.40785539},"exposed":false}},{"Value":{"tagged_value":{"F64":50.0},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":2288754089236120499,"output_index":0,"lambda":false}}],"nodes":[[17232801702996970986,{"inputs":[{"Node":{"node_id":1791308547102433540,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"PointSpacingType":"Separation"},"exposed":false}},{"Value":{"tagged_value":{"F64":800.0},"exposed":false}},{"Value":{"tagged_value":{"U32":100},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"Bool":false},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":4,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::SubpathSegmentLengthsNode"}},"visible":true,"skip_deduplication":false}],[4,{"inputs":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::BoundlessFootprintNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":2,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::FreezeRealTimeNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MemoNode"}},"visible":true,"skip_deduplication":false}],[1,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::misc::PointSpacingType","alias":null}},"import_index":1}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":2}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":3}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":4}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":5}},{"Network":{"import_type":{"Concrete":{"name":"bool","alias":null}},"import_index":6}},{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::SamplePolylineNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[9065988052616974602,{"inputs":[{"Node":{"node_id":11731553664207576737,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"PointSpacingType":"Separation"},"exposed":false}},{"Value":{"tagged_value":{"F64":172.9},"exposed":false}},{"Value":{"tagged_value":{"U32":100},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"Bool":false},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":4,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::SubpathSegmentLengthsNode"}},"visible":true,"skip_deduplication":false}],[4,{"inputs":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::BoundlessFootprintNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":2,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::FreezeRealTimeNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MemoNode"}},"visible":true,"skip_deduplication":false}],[1,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::misc::PointSpacingType","alias":null}},"import_index":1}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":2}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":3}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":4}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":5}},{"Network":{"import_type":{"Concrete":{"name":"bool","alias":null}},"import_index":6}},{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::SamplePolylineNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[2288754089236120499,{"inputs":[{"Node":{"node_id":14158287945315818946,"output_index":0,"lambda":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::SplineNode"}},"visible":true,"skip_deduplication":false}],[14158287945315818946,{"inputs":[{"Node":{"node_id":16943732999059587742,"output_index":0,"lambda":false}},{"Node":{"node_id":14577956936089455769,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[0.6181095265062186,3.496297826945966]},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[0.0,0.0]},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[0.4855225354961647,0.31002285853371414]},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":1}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":2}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":3}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":4}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":5}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::TransformNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[11731553664207576737,{"inputs":[{"Node":{"node_id":17232801702996970986,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"F64":48.900000000000006},"exposed":false}},{"Node":{"node_id":7828034197076821310,"output_index":0,"lambda":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::JitterPointsNode"}},"visible":true,"skip_deduplication":false}],[7828034197076821310,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":3}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_math_nodes::ToU32Node"}},"visible":true,"skip_deduplication":false}],[640915213983348287,{"inputs":[{"Value":{"tagged_value":"None","exposed":false}},{"Value":{"tagged_value":{"F64":4000.0},"exposed":false}},{"Value":{"tagged_value":{"F64":500.0},"exposed":false}},{"Value":{"tagged_value":{"Bool":false},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"Bool":true},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::generator_nodes::RectangleNode"}},"visible":true,"skip_deduplication":false}],[1791308547102433540,{"inputs":[{"Node":{"node_id":640915213983348287,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Generic":"T"},"import_index":1}},{"Value":{"tagged_value":{"OptionalColor":{"red":0.99607843,"green":0.827451,"blue":0.65882355,"alpha":1.0}},"exposed":false}},{"Value":{"tagged_value":{"Gradient":{"stops":[[0.0,{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}],[1.0,{"red":1.0,"green":1.0,"blue":1.0,"alpha":1.0}]],"gradient_type":"Linear","start":[0.0,0.5],"end":[1.0,0.5],"transform":[1.0,0.0,0.0,1.0,0.0,0.0]}},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::FillNode"}},"visible":true,"skip_deduplication":false}],[14577956936089455769,{"inputs":[{"Value":{"tagged_value":"None","exposed":false}},{"Value":{"tagged_value":{"F64":1050.10498991},"exposed":false}},{"Network":{"import_type":{"Generic":"T"},"import_index":2}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_math_nodes::CoordinateValueNode"}},"visible":true,"skip_deduplication":false}],[16943732999059587742,{"inputs":[{"Node":{"node_id":9065988052616974602,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"F64":1.399999999999956},"exposed":false}},{"Value":{"tagged_value":{"U32":0},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::JitterPointsNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[3726756269632080543,{"inputs":[{"Value":{"tagged_value":"None","exposed":true}},{"Value":{"tagged_value":{"OptionalColor":{"red":0.5254902,"green":0.45882353,"blue":0.41568628,"alpha":1.0}},"exposed":false}},{"Value":{"tagged_value":{"F64":1465.6573046},"exposed":false}},{"Value":{"tagged_value":{"F64":230.0},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":2288754089236120499,"output_index":0,"lambda":false}}],"nodes":[[5294703684886212416,{"inputs":[{"Node":{"node_id":1791308547102433540,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"PointSpacingType":"Separation"},"exposed":false}},{"Value":{"tagged_value":{"F64":800.0},"exposed":false}},{"Value":{"tagged_value":{"U32":100},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"Bool":false},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":4,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::SubpathSegmentLengthsNode"}},"visible":true,"skip_deduplication":false}],[4,{"inputs":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::BoundlessFootprintNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":2,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::FreezeRealTimeNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MemoNode"}},"visible":true,"skip_deduplication":false}],[1,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::misc::PointSpacingType","alias":null}},"import_index":1}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":2}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":3}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":4}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":5}},{"Network":{"import_type":{"Concrete":{"name":"bool","alias":null}},"import_index":6}},{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::SamplePolylineNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[7419291594083587754,{"inputs":[{"Node":{"node_id":11731553664207576737,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"PointSpacingType":"Separation"},"exposed":false}},{"Value":{"tagged_value":{"F64":172.9},"exposed":false}},{"Value":{"tagged_value":{"U32":100},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"Bool":false},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":4,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::SubpathSegmentLengthsNode"}},"visible":true,"skip_deduplication":false}],[4,{"inputs":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::BoundlessFootprintNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":2,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::FreezeRealTimeNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MemoNode"}},"visible":true,"skip_deduplication":false}],[1,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::misc::PointSpacingType","alias":null}},"import_index":1}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":2}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":3}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":4}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":5}},{"Network":{"import_type":{"Concrete":{"name":"bool","alias":null}},"import_index":6}},{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::SamplePolylineNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[2288754089236120499,{"inputs":[{"Node":{"node_id":14158287945315818946,"output_index":0,"lambda":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::SplineNode"}},"visible":true,"skip_deduplication":false}],[14158287945315818946,{"inputs":[{"Node":{"node_id":16943732999059587742,"output_index":0,"lambda":false}},{"Node":{"node_id":14577956936089455769,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[0.6181095265062186,3.496297826945966]},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[0.0,0.0]},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[0.4855225354961647,0.31002285853371414]},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":1}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":2}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":3}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":4}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":5}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::TransformNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[11731553664207576737,{"inputs":[{"Node":{"node_id":5294703684886212416,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"F64":48.900000000000006},"exposed":false}},{"Node":{"node_id":7828034197076821310,"output_index":0,"lambda":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::JitterPointsNode"}},"visible":true,"skip_deduplication":false}],[7828034197076821310,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":3}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_math_nodes::ToU32Node"}},"visible":true,"skip_deduplication":false}],[640915213983348287,{"inputs":[{"Value":{"tagged_value":"None","exposed":false}},{"Value":{"tagged_value":{"F64":4000.0},"exposed":false}},{"Value":{"tagged_value":{"F64":500.0},"exposed":false}},{"Value":{"tagged_value":{"Bool":false},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"Bool":true},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::generator_nodes::RectangleNode"}},"visible":true,"skip_deduplication":false}],[1791308547102433540,{"inputs":[{"Node":{"node_id":640915213983348287,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Generic":"T"},"import_index":1}},{"Value":{"tagged_value":{"OptionalColor":{"red":0.99607843,"green":0.827451,"blue":0.65882355,"alpha":1.0}},"exposed":false}},{"Value":{"tagged_value":{"Gradient":{"stops":[[0.0,{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}],[1.0,{"red":1.0,"green":1.0,"blue":1.0,"alpha":1.0}]],"gradient_type":"Linear","start":[0.0,0.5],"end":[1.0,0.5],"transform":[1.0,0.0,0.0,1.0,0.0,0.0]}},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::FillNode"}},"visible":true,"skip_deduplication":false}],[14577956936089455769,{"inputs":[{"Value":{"tagged_value":"None","exposed":false}},{"Value":{"tagged_value":{"F64":1050.10498991},"exposed":false}},{"Network":{"import_type":{"Generic":"T"},"import_index":2}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_math_nodes::CoordinateValueNode"}},"visible":true,"skip_deduplication":false}],[16943732999059587742,{"inputs":[{"Node":{"node_id":7419291594083587754,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"F64":1.399999999999956},"exposed":false}},{"Value":{"tagged_value":{"U32":0},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::JitterPointsNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[1801066723091712434,{"inputs":[{"Value":{"tagged_value":"None","exposed":true}},{"Value":{"tagged_value":{"OptionalColor":{"red":0.21176471,"green":0.21568628,"blue":0.23137255,"alpha":1.0}},"exposed":false}},{"Value":{"tagged_value":{"F64":1744.31393592},"exposed":false}},{"Value":{"tagged_value":{"F64":63.0},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":2288754089236120499,"output_index":0,"lambda":false}}],"nodes":[[11731553664207576737,{"inputs":[{"Node":{"node_id":14514477720912258595,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"F64":48.900000000000006},"exposed":false}},{"Node":{"node_id":7828034197076821310,"output_index":0,"lambda":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::JitterPointsNode"}},"visible":true,"skip_deduplication":false}],[14158287945315818946,{"inputs":[{"Node":{"node_id":16943732999059587742,"output_index":0,"lambda":false}},{"Node":{"node_id":14577956936089455769,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[0.6181095265062186,3.496297826945966]},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[0.0,0.0]},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[0.4855225354961647,0.31002285853371414]},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":1}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":2}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":3}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":4}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":5}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::TransformNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[2288754089236120499,{"inputs":[{"Node":{"node_id":14158287945315818946,"output_index":0,"lambda":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::SplineNode"}},"visible":true,"skip_deduplication":false}],[7828034197076821310,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":3}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_math_nodes::ToU32Node"}},"visible":true,"skip_deduplication":false}],[640915213983348287,{"inputs":[{"Value":{"tagged_value":"None","exposed":false}},{"Value":{"tagged_value":{"F64":4000.0},"exposed":false}},{"Value":{"tagged_value":{"F64":500.0},"exposed":false}},{"Value":{"tagged_value":{"Bool":false},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"Bool":true},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::generator_nodes::RectangleNode"}},"visible":true,"skip_deduplication":false}],[1791308547102433540,{"inputs":[{"Node":{"node_id":640915213983348287,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Generic":"T"},"import_index":1}},{"Value":{"tagged_value":{"OptionalColor":{"red":0.99607843,"green":0.827451,"blue":0.65882355,"alpha":1.0}},"exposed":false}},{"Value":{"tagged_value":{"Gradient":{"stops":[[0.0,{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}],[1.0,{"red":1.0,"green":1.0,"blue":1.0,"alpha":1.0}]],"gradient_type":"Linear","start":[0.0,0.5],"end":[1.0,0.5],"transform":[1.0,0.0,0.0,1.0,0.0,0.0]}},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::FillNode"}},"visible":true,"skip_deduplication":false}],[14577956936089455769,{"inputs":[{"Value":{"tagged_value":"None","exposed":false}},{"Value":{"tagged_value":{"F64":1050.10498991},"exposed":false}},{"Network":{"import_type":{"Generic":"T"},"import_index":2}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_math_nodes::CoordinateValueNode"}},"visible":true,"skip_deduplication":false}],[16943732999059587742,{"inputs":[{"Node":{"node_id":18341697272814101120,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"F64":1.399999999999956},"exposed":false}},{"Value":{"tagged_value":{"U32":0},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::JitterPointsNode"}},"visible":true,"skip_deduplication":false}],[18341697272814101120,{"inputs":[{"Node":{"node_id":11731553664207576737,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"PointSpacingType":"Separation"},"exposed":false}},{"Value":{"tagged_value":{"F64":172.9},"exposed":false}},{"Value":{"tagged_value":{"U32":100},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"Bool":false},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":4,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::SubpathSegmentLengthsNode"}},"visible":true,"skip_deduplication":false}],[4,{"inputs":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::BoundlessFootprintNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":2,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::FreezeRealTimeNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MemoNode"}},"visible":true,"skip_deduplication":false}],[1,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::misc::PointSpacingType","alias":null}},"import_index":1}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":2}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":3}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":4}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":5}},{"Network":{"import_type":{"Concrete":{"name":"bool","alias":null}},"import_index":6}},{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::SamplePolylineNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[14514477720912258595,{"inputs":[{"Node":{"node_id":1791308547102433540,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"PointSpacingType":"Separation"},"exposed":false}},{"Value":{"tagged_value":{"F64":800.0},"exposed":false}},{"Value":{"tagged_value":{"U32":100},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"Bool":false},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":4,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::SubpathSegmentLengthsNode"}},"visible":true,"skip_deduplication":false}],[4,{"inputs":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::BoundlessFootprintNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":2,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::FreezeRealTimeNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MemoNode"}},"visible":true,"skip_deduplication":false}],[1,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::misc::PointSpacingType","alias":null}},"import_index":1}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":2}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":3}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":4}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":5}},{"Network":{"import_type":{"Concrete":{"name":"bool","alias":null}},"import_index":6}},{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::SamplePolylineNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[12317719117993811200,{"inputs":[{"Node":{"node_id":9069881382900058607,"output_index":0,"lambda":false}},{"Node":{"node_id":17239043462037837834,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[8804763001225416124,{"inputs":[{"Node":{"node_id":3934928477288442109,"output_index":0,"lambda":false}},{"Node":{"node_id":17154757625902243313,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[17239043462037837834,{"inputs":[{"Value":{"tagged_value":"None","exposed":true}},{"Value":{"tagged_value":{"OptionalColor":{"red":0.8039216,"green":0.6627451,"blue":0.52156866,"alpha":1.0}},"exposed":false}},{"Value":{"tagged_value":{"F64":1447.11050605},"exposed":false}},{"Value":{"tagged_value":{"F64":309.0},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":2288754089236120499,"output_index":0,"lambda":false}}],"nodes":[[11731553664207576737,{"inputs":[{"Node":{"node_id":7260397085903590160,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"F64":48.900000000000006},"exposed":false}},{"Node":{"node_id":7828034197076821310,"output_index":0,"lambda":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::JitterPointsNode"}},"visible":true,"skip_deduplication":false}],[14158287945315818946,{"inputs":[{"Node":{"node_id":16943732999059587742,"output_index":0,"lambda":false}},{"Node":{"node_id":14577956936089455769,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[0.6181095265062186,3.496297826945966]},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[0.0,0.0]},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[0.4855225354961647,0.31002285853371414]},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":1}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":2}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":3}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":4}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":5}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::TransformNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[2288754089236120499,{"inputs":[{"Node":{"node_id":14158287945315818946,"output_index":0,"lambda":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::SplineNode"}},"visible":true,"skip_deduplication":false}],[15937218612227302315,{"inputs":[{"Node":{"node_id":11731553664207576737,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"PointSpacingType":"Separation"},"exposed":false}},{"Value":{"tagged_value":{"F64":172.9},"exposed":false}},{"Value":{"tagged_value":{"U32":100},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"Bool":false},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":4,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::SubpathSegmentLengthsNode"}},"visible":true,"skip_deduplication":false}],[4,{"inputs":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::BoundlessFootprintNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":2,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::FreezeRealTimeNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MemoNode"}},"visible":true,"skip_deduplication":false}],[1,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::misc::PointSpacingType","alias":null}},"import_index":1}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":2}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":3}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":4}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":5}},{"Network":{"import_type":{"Concrete":{"name":"bool","alias":null}},"import_index":6}},{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::SamplePolylineNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[7828034197076821310,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":3}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_math_nodes::ToU32Node"}},"visible":true,"skip_deduplication":false}],[7260397085903590160,{"inputs":[{"Node":{"node_id":1791308547102433540,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"PointSpacingType":"Separation"},"exposed":false}},{"Value":{"tagged_value":{"F64":800.0},"exposed":false}},{"Value":{"tagged_value":{"U32":100},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"Bool":false},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":4,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::SubpathSegmentLengthsNode"}},"visible":true,"skip_deduplication":false}],[4,{"inputs":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::BoundlessFootprintNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":2,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::FreezeRealTimeNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MemoNode"}},"visible":true,"skip_deduplication":false}],[1,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::misc::PointSpacingType","alias":null}},"import_index":1}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":2}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":3}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":4}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":5}},{"Network":{"import_type":{"Concrete":{"name":"bool","alias":null}},"import_index":6}},{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::SamplePolylineNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[640915213983348287,{"inputs":[{"Value":{"tagged_value":"None","exposed":false}},{"Value":{"tagged_value":{"F64":4000.0},"exposed":false}},{"Value":{"tagged_value":{"F64":500.0},"exposed":false}},{"Value":{"tagged_value":{"Bool":false},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"Bool":true},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::generator_nodes::RectangleNode"}},"visible":true,"skip_deduplication":false}],[1791308547102433540,{"inputs":[{"Node":{"node_id":640915213983348287,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Generic":"T"},"import_index":1}},{"Value":{"tagged_value":{"OptionalColor":{"red":0.99607843,"green":0.827451,"blue":0.65882355,"alpha":1.0}},"exposed":false}},{"Value":{"tagged_value":{"Gradient":{"stops":[[0.0,{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}],[1.0,{"red":1.0,"green":1.0,"blue":1.0,"alpha":1.0}]],"gradient_type":"Linear","start":[0.0,0.5],"end":[1.0,0.5],"transform":[1.0,0.0,0.0,1.0,0.0,0.0]}},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::FillNode"}},"visible":true,"skip_deduplication":false}],[14577956936089455769,{"inputs":[{"Value":{"tagged_value":"None","exposed":false}},{"Value":{"tagged_value":{"F64":1050.10498991},"exposed":false}},{"Network":{"import_type":{"Generic":"T"},"import_index":2}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_math_nodes::CoordinateValueNode"}},"visible":true,"skip_deduplication":false}],[16943732999059587742,{"inputs":[{"Node":{"node_id":15937218612227302315,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"F64":1.399999999999956},"exposed":false}},{"Value":{"tagged_value":{"U32":0},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::JitterPointsNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[2128810469968776913,{"inputs":[{"Value":{"tagged_value":{"GraphicGroup":{"instance":[],"transform":[],"alpha_blending":[],"source_node_id":[]}},"exposed":true}},{"Node":{"node_id":12416569579970107543,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[239716716021064150,{"inputs":[{"Value":{"tagged_value":{"GraphicGroup":{"instance":[],"transform":[],"alpha_blending":[],"source_node_id":[]}},"exposed":true}},{"Node":{"node_id":7711570794020903773,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[15385259560644295534,{"inputs":[{"Node":{"node_id":17327221498641745184,"output_index":0,"lambda":false}},{"Node":{"node_id":3726756269632080543,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[4445985685181725042,{"inputs":[{"Value":{"tagged_value":{"ArtboardGroup":{"instance":[],"transform":[],"alpha_blending":[],"source_node_id":[]}},"exposed":true}},{"Node":{"node_id":13132104524813958174,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"IVec2":[0,0]},"exposed":false}},{"Value":{"tagged_value":{"IVec2":[2000,1000]},"exposed":false}},{"Value":{"tagged_value":{"Color":{"red":0.99607843,"green":0.8745098,"blue":0.7019608,"alpha":1.0}},"exposed":false}},{"Value":{"tagged_value":{"Bool":true},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":2,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graph_craft::document::value::TaggedValue","alias":null}},"import_index":1}},{"Value":{"tagged_value":{"String":"Artboard"},"exposed":false}},{"Network":{"import_type":{"Concrete":{"name":"graph_craft::document::value::TaggedValue","alias":null}},"import_index":2}},{"Network":{"import_type":{"Concrete":{"name":"graph_craft::document::value::TaggedValue","alias":null}},"import_index":3}},{"Network":{"import_type":{"Concrete":{"name":"graph_craft::document::value::TaggedValue","alias":null}},"import_index":4}},{"Network":{"import_type":{"Concrete":{"name":"graph_craft::document::value::TaggedValue","alias":null}},"import_index":5}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToArtboardNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Network":{"import_type":{"Fn":[{"Concrete":{"name":"core::option::Option>","alias":null}},{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}}]},"import_index":0}},{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::AppendArtboardNode"}},"visible":true,"skip_deduplication":false}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[12122314434656187176,{"inputs":[{"Node":{"node_id":10686861494573327243,"output_index":0,"lambda":false}},{"Node":{"node_id":16611856724057842399,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[13676600738025998635,{"inputs":[{"Node":{"node_id":2128810469968776913,"output_index":0,"lambda":false}},{"Node":{"node_id":6097807941755042226,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[6097807941755042226,{"inputs":[{"Node":{"node_id":15385259560644295534,"output_index":0,"lambda":false}},{"Node":{"node_id":5883606306991910210,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[17437077810654043142,{"inputs":[{"Node":{"node_id":15002088321732485705,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"PointSpacingType":"Separation"},"exposed":false}},{"Value":{"tagged_value":{"F64":40.0},"exposed":false}},{"Value":{"tagged_value":{"U32":40},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"Bool":false},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":4,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::SubpathSegmentLengthsNode"}},"visible":true,"skip_deduplication":false}],[4,{"inputs":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::BoundlessFootprintNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":2,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::FreezeRealTimeNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MemoNode"}},"visible":true,"skip_deduplication":false}],[1,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::misc::PointSpacingType","alias":null}},"import_index":1}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":2}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":3}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":4}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":5}},{"Network":{"import_type":{"Concrete":{"name":"bool","alias":null}},"import_index":6}},{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::SamplePolylineNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]},"network_metadata":{"persistent_metadata":{"node_metadata":[[1801066723091712434,{"persistent_metadata":{"reference":null,"display_name":"Dune","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":"Color"},"widget_override":null},{"input_data":{"input_name":"Height"},"widget_override":null},{"input_data":{"input_name":"Seed"},"widget_override":null}],"output_names":[""],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[7828034197076821310,{"persistent_metadata":{"reference":"To u32","display_name":"","input_properties":[{"input_data":{"input_name":"Value"},"widget_override":null}],"output_names":["Future"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-13,1]}}},"network_metadata":null}}],[14514477720912258595,{"persistent_metadata":{"reference":"Sample Polyline","display_name":"","input_properties":[{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{"mode":"Increment","is_integer":false,"unit":" px","blank_assist":true,"min":0.0},"widget_override":"number"},{"input_data":{"min":2.0,"is_integer":true,"blank_assist":true,"mode":"Increment"},"widget_override":"number"},{"input_data":{"unit":" px","is_integer":false,"min":0.0,"mode":"Increment","blank_assist":true},"widget_override":"number"},{"input_data":{"min":0.0,"blank_assist":true,"mode":"Increment","unit":" px","is_integer":false},"widget_override":"number"},{"input_data":{},"widget_override":null}],"output_names":["Vector"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-13,-3]}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"Subpath Segment Lengths","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,7]}}},"network_metadata":null}}],[4,{"persistent_metadata":{"reference":null,"display_name":"Boundless Footprint","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[28,0]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Freeze Real Time","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[21,0]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"Sample Polyline","input_properties":[{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Memoize","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[14,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[11731553664207576737,{"persistent_metadata":{"reference":"Jitter Points","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Amount"},"widget_override":null},{"input_data":{"input_name":"Seed"},"widget_override":null}],"output_names":["Future>"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-6,-3]}}},"network_metadata":null}}],[14577956936089455769,{"persistent_metadata":{"reference":"Coordinate Value","display_name":"","input_properties":[{"input_data":{"input_name":"Primary"},"widget_override":null},{"input_data":{"input_name":"X"},"widget_override":null},{"input_data":{"input_name":"Y"},"widget_override":null}],"output_names":["Future"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[8,-1]}}},"network_metadata":null}}],[1791308547102433540,{"persistent_metadata":{"reference":"Fill","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Fill"},"widget_override":null},{"input_data":{"input_name":"Backup Color"},"widget_override":null},{"input_data":{"input_name":"Backup Gradient"},"widget_override":null}],"output_names":["Future>"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-20,-3]}}},"network_metadata":null}}],[18341697272814101120,{"persistent_metadata":{"reference":"Sample Polyline","display_name":"","input_properties":[{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{"is_integer":false,"unit":" px","blank_assist":true,"min":0.0,"mode":"Increment"},"widget_override":"number"},{"input_data":{"blank_assist":true,"mode":"Increment","is_integer":true,"min":2.0},"widget_override":"number"},{"input_data":{"is_integer":false,"unit":" px","blank_assist":true,"min":0.0,"mode":"Increment"},"widget_override":"number"},{"input_data":{"is_integer":false,"blank_assist":true,"unit":" px","min":0.0,"mode":"Increment"},"widget_override":"number"},{"input_data":{},"widget_override":null}],"output_names":["Vector"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[3,{"persistent_metadata":{"reference":null,"display_name":"Freeze Real Time","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[21,0]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Memoize","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[14,0]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"Subpath Segment Lengths","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,7]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"Sample Polyline","input_properties":[{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}],[4,{"persistent_metadata":{"reference":null,"display_name":"Boundless Footprint","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[28,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[2288754089236120499,{"persistent_metadata":{"reference":"Spline","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null}],"output_names":["Future>"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[22,-3]}}},"network_metadata":null}}],[640915213983348287,{"persistent_metadata":{"reference":"Rectangle","display_name":"","input_properties":[{"input_data":{"input_name":"Primary"},"widget_override":null},{"input_data":{"input_name":"Width"},"widget_override":null},{"input_data":{"input_name":"Height"},"widget_override":null},{"input_data":{"input_name":"Individual Corner Radii"},"widget_override":null},{"input_data":{"input_name":"Corner Radius"},"widget_override":null},{"input_data":{"input_name":"Clamped"},"widget_override":null}],"output_names":["Future>"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-27,-3]}}},"network_metadata":null}}],[16943732999059587742,{"persistent_metadata":{"reference":"Jitter Points","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Amount"},"widget_override":null},{"input_data":{"input_name":"Seed"},"widget_override":null}],"output_names":["Future>"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[8,-3]}}},"network_metadata":null}}],[14158287945315818946,{"persistent_metadata":{"reference":"Transform","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"unit":" px","input_name":"Translation","x":"X","y":"Y"},"widget_override":"vec2"},{"input_data":{"input_name":"Rotation"},"widget_override":"transform_rotation"},{"input_data":{"input_name":"Scale","unit":"x","x":"W","y":"H"},"widget_override":"vec2"},{"input_data":{"input_name":"Skew"},"widget_override":"transform_skew"},{"input_data":{"input_name":"Pivot"},"widget_override":"hidden"}],"output_names":["Data"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[15,-3]}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"Transform","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[17.0,-79.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,1008.0,502.0],"node_graph_top_right":[1980.796875,0.0]},"selection_undo_history":[[]],"selection_redo_history":[]}}}}],[17437077810654043142,{"persistent_metadata":{"reference":"Sample Polyline","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Spacing","min":1.0,"is_integer":false,"tooltip":"Distance between each instance (exact if 'Adaptive Spacing' is disabled, approximate if enabled)","unit":" px","blank_assist":true,"mode":"Increment"},"widget_override":"number"},{"input_data":{"mode":"Increment","blank_assist":true,"input_name":"Start Offset","tooltip":"Exclude some distance from the start of the path before the first instance","unit":" px","min":0.0,"is_integer":false},"widget_override":"number"},{"input_data":{"min":0.0,"is_integer":false,"tooltip":"Exclude some distance from the end of the path after the last instance","blank_assist":true,"unit":" px","input_name":"Stop Offset","mode":"Increment"},"widget_override":"number"},{"input_data":{"tooltip":"Round 'Spacing' to a nearby value that divides into the path length evenly","input_name":"Adaptive Spacing"},"widget_override":null}],"output_names":["Vector"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[2,{"persistent_metadata":{"reference":null,"display_name":"Memoize","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[14,0]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"Subpath Segment Lengths","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,7]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"Sample Polyline","input_properties":[{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}],[4,{"persistent_metadata":{"reference":null,"display_name":"Boundless Footprint","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[28,0]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Freeze Real Time","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[21,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[8804763001225416124,{"persistent_metadata":{"reference":"Merge","display_name":"Dune in Shadow 4","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":["Out"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":0}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[13644002059194136823,{"persistent_metadata":{"reference":"Jitter Points","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Amount"},"widget_override":null},{"input_data":{"input_name":"Seed"},"widget_override":null}],"output_names":["Future>"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[10686861494573327243,{"persistent_metadata":{"reference":"Merge","display_name":"Dune in Shadow 2","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":["Out"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":0}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[3726756269632080543,{"persistent_metadata":{"reference":null,"display_name":"Dune","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":"Color"},"widget_override":null},{"input_data":{"input_name":"Height"},"widget_override":null},{"input_data":{"input_name":"Seed"},"widget_override":null}],"output_names":[""],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[14577956936089455769,{"persistent_metadata":{"reference":"Coordinate Value","display_name":"","input_properties":[{"input_data":{"input_name":"Primary"},"widget_override":null},{"input_data":{"input_name":"X"},"widget_override":null},{"input_data":{"input_name":"Y"},"widget_override":null}],"output_names":["Future"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[8,-1]}}},"network_metadata":null}}],[640915213983348287,{"persistent_metadata":{"reference":"Rectangle","display_name":"","input_properties":[{"input_data":{"input_name":"Primary"},"widget_override":null},{"input_data":{"input_name":"Width"},"widget_override":null},{"input_data":{"input_name":"Height"},"widget_override":null},{"input_data":{"input_name":"Individual Corner Radii"},"widget_override":null},{"input_data":{"input_name":"Corner Radius"},"widget_override":null},{"input_data":{"input_name":"Clamped"},"widget_override":null}],"output_names":["Future>"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-27,-3]}}},"network_metadata":null}}],[14158287945315818946,{"persistent_metadata":{"reference":"Transform","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Translation","x":"X","y":"Y","unit":" px"},"widget_override":"vec2"},{"input_data":{"input_name":"Rotation"},"widget_override":"transform_rotation"},{"input_data":{"unit":"x","input_name":"Scale","x":"W","y":"H"},"widget_override":"vec2"},{"input_data":{"input_name":"Skew"},"widget_override":"transform_skew"},{"input_data":{"input_name":"Pivot"},"widget_override":"hidden"}],"output_names":["Data"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[15,-3]}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"Transform","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[1791308547102433540,{"persistent_metadata":{"reference":"Fill","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Fill"},"widget_override":null},{"input_data":{"input_name":"Backup Color"},"widget_override":null},{"input_data":{"input_name":"Backup Gradient"},"widget_override":null}],"output_names":["Future>"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-20,-3]}}},"network_metadata":null}}],[7419291594083587754,{"persistent_metadata":{"reference":"Sample Polyline","display_name":"","input_properties":[{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{"is_integer":false,"mode":"Increment","blank_assist":true,"min":0.0,"unit":" px"},"widget_override":"number"},{"input_data":{"is_integer":true,"blank_assist":true,"mode":"Increment","min":2.0},"widget_override":"number"},{"input_data":{"min":0.0,"blank_assist":true,"mode":"Increment","unit":" px","is_integer":false},"widget_override":"number"},{"input_data":{"mode":"Increment","is_integer":false,"min":0.0,"blank_assist":true,"unit":" px"},"widget_override":"number"},{"input_data":{},"widget_override":null}],"output_names":["Vector"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[2,{"persistent_metadata":{"reference":null,"display_name":"Memoize","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[14,0]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Freeze Real Time","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[21,0]}}},"network_metadata":null}}],[4,{"persistent_metadata":{"reference":null,"display_name":"Boundless Footprint","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[28,0]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"Sample Polyline","input_properties":[{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"Subpath Segment Lengths","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,7]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[16943732999059587742,{"persistent_metadata":{"reference":"Jitter Points","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Amount"},"widget_override":null},{"input_data":{"input_name":"Seed"},"widget_override":null}],"output_names":["Future>"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[8,-3]}}},"network_metadata":null}}],[11731553664207576737,{"persistent_metadata":{"reference":"Jitter Points","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Amount"},"widget_override":null},{"input_data":{"input_name":"Seed"},"widget_override":null}],"output_names":["Future>"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-6,-3]}}},"network_metadata":null}}],[7828034197076821310,{"persistent_metadata":{"reference":"To u32","display_name":"","input_properties":[{"input_data":{"input_name":"Value"},"widget_override":null}],"output_names":["Future"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-13,1]}}},"network_metadata":null}}],[5294703684886212416,{"persistent_metadata":{"reference":"Sample Polyline","display_name":"","input_properties":[{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{"unit":" px","is_integer":false,"mode":"Increment","min":0.0,"blank_assist":true},"widget_override":"number"},{"input_data":{"is_integer":true,"blank_assist":true,"mode":"Increment","min":2.0},"widget_override":"number"},{"input_data":{"is_integer":false,"min":0.0,"unit":" px","blank_assist":true,"mode":"Increment"},"widget_override":"number"},{"input_data":{"blank_assist":true,"min":0.0,"mode":"Increment","is_integer":false,"unit":" px"},"widget_override":"number"},{"input_data":{},"widget_override":null}],"output_names":["Vector"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-13,-3]}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"Subpath Segment Lengths","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,7]}}},"network_metadata":null}}],[4,{"persistent_metadata":{"reference":null,"display_name":"Boundless Footprint","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[28,0]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Memoize","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[14,0]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"Sample Polyline","input_properties":[{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Freeze Real Time","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[21,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[2288754089236120499,{"persistent_metadata":{"reference":"Spline","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null}],"output_names":["Future>"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[22,-3]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,991.0,581.0],"node_graph_top_right":[1980.796875,0.0]},"selection_undo_history":[[]],"selection_redo_history":[]}}}}],[6097807941755042226,{"persistent_metadata":{"reference":"Merge","display_name":"Dune 1","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":["Out"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Absolute":[-14,40]}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[3683309254695891012,{"persistent_metadata":{"reference":null,"display_name":"Dune","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":"Color"},"widget_override":null},{"input_data":{"input_name":"Height"},"widget_override":null},{"input_data":{"input_name":"Seed"},"widget_override":null}],"output_names":[""],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[14577956936089455769,{"persistent_metadata":{"reference":"Coordinate Value","display_name":"","input_properties":[{"input_data":{"input_name":"Primary"},"widget_override":null},{"input_data":{"input_name":"X"},"widget_override":null},{"input_data":{"input_name":"Y"},"widget_override":null}],"output_names":["Future"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[8,-1]}}},"network_metadata":null}}],[2288754089236120499,{"persistent_metadata":{"reference":"Spline","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null}],"output_names":["Future>"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[22,-3]}}},"network_metadata":null}}],[16943732999059587742,{"persistent_metadata":{"reference":"Jitter Points","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Amount"},"widget_override":null},{"input_data":{"input_name":"Seed"},"widget_override":null}],"output_names":["Future>"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[8,-3]}}},"network_metadata":null}}],[10720574559271598132,{"persistent_metadata":{"reference":"Sample Polyline","display_name":"","input_properties":[{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{"blank_assist":true,"is_integer":false,"min":0.0,"mode":"Increment","unit":" px"},"widget_override":"number"},{"input_data":{"blank_assist":true,"is_integer":true,"min":2.0,"mode":"Increment"},"widget_override":"number"},{"input_data":{"min":0.0,"unit":" px","mode":"Increment","is_integer":false,"blank_assist":true},"widget_override":"number"},{"input_data":{"unit":" px","min":0.0,"mode":"Increment","blank_assist":true,"is_integer":false},"widget_override":"number"},{"input_data":{},"widget_override":null}],"output_names":["Vector"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[3,{"persistent_metadata":{"reference":null,"display_name":"Freeze Real Time","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[21,0]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"Subpath Segment Lengths","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,7]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"Sample Polyline","input_properties":[{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}],[4,{"persistent_metadata":{"reference":null,"display_name":"Boundless Footprint","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[28,0]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Memoize","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[14,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[640915213983348287,{"persistent_metadata":{"reference":"Rectangle","display_name":"","input_properties":[{"input_data":{"input_name":"Primary"},"widget_override":null},{"input_data":{"input_name":"Width"},"widget_override":null},{"input_data":{"input_name":"Height"},"widget_override":null},{"input_data":{"input_name":"Individual Corner Radii"},"widget_override":null},{"input_data":{"input_name":"Corner Radius"},"widget_override":null},{"input_data":{"input_name":"Clamped"},"widget_override":null}],"output_names":["Future>"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-27,-3]}}},"network_metadata":null}}],[14158287945315818946,{"persistent_metadata":{"reference":"Transform","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"unit":" px","x":"X","y":"Y","input_name":"Translation"},"widget_override":"vec2"},{"input_data":{"input_name":"Rotation"},"widget_override":"transform_rotation"},{"input_data":{"input_name":"Scale","unit":"x","y":"H","x":"W"},"widget_override":"vec2"},{"input_data":{"input_name":"Skew"},"widget_override":"transform_skew"},{"input_data":{"input_name":"Pivot"},"widget_override":"hidden"}],"output_names":["Data"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[15,-3]}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"Transform","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[3916070947050514908,{"persistent_metadata":{"reference":"Sample Polyline","display_name":"","input_properties":[{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{"mode":"Increment","min":0.0,"is_integer":false,"unit":" px","blank_assist":true},"widget_override":"number"},{"input_data":{"is_integer":true,"blank_assist":true,"mode":"Increment","min":2.0},"widget_override":"number"},{"input_data":{"mode":"Increment","unit":" px","blank_assist":true,"is_integer":false,"min":0.0},"widget_override":"number"},{"input_data":{"blank_assist":true,"min":0.0,"is_integer":false,"mode":"Increment","unit":" px"},"widget_override":"number"},{"input_data":{},"widget_override":null}],"output_names":["Vector"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-13,-3]}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[4,{"persistent_metadata":{"reference":null,"display_name":"Boundless Footprint","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[28,0]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Freeze Real Time","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[21,0]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Memoize","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[14,0]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"Sample Polyline","input_properties":[{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"Subpath Segment Lengths","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,7]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[1791308547102433540,{"persistent_metadata":{"reference":"Fill","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Fill"},"widget_override":null},{"input_data":{"input_name":"Backup Color"},"widget_override":null},{"input_data":{"input_name":"Backup Gradient"},"widget_override":null}],"output_names":["Future>"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-20,-3]}}},"network_metadata":null}}],[11731553664207576737,{"persistent_metadata":{"reference":"Jitter Points","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Amount"},"widget_override":null},{"input_data":{"input_name":"Seed"},"widget_override":null}],"output_names":["Future>"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-6,-3]}}},"network_metadata":null}}],[7828034197076821310,{"persistent_metadata":{"reference":"To u32","display_name":"","input_properties":[{"input_data":{"input_name":"Value"},"widget_override":null}],"output_names":["Future"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-13,1]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,991.0,581.0],"node_graph_top_right":[1980.796875,0.0]},"selection_undo_history":[[]],"selection_redo_history":[]}}}}],[15002088321732485705,{"persistent_metadata":{"reference":null,"display_name":"Dune","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":"Color"},"widget_override":null},{"input_data":{"input_name":"Height"},"widget_override":null},{"input_data":{"input_name":"Seed"},"widget_override":null}],"output_names":[""],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1791308547102433540,{"persistent_metadata":{"reference":"Fill","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Fill"},"widget_override":null},{"input_data":{"input_name":"Backup Color"},"widget_override":null},{"input_data":{"input_name":"Backup Gradient"},"widget_override":null}],"output_names":["Future>"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-20,-3]}}},"network_metadata":null}}],[15212962088799153943,{"persistent_metadata":{"reference":"Sample Polyline","display_name":"","input_properties":[{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{"is_integer":false,"unit":" px","min":0.0,"blank_assist":true,"mode":"Increment"},"widget_override":"number"},{"input_data":{"blank_assist":true,"mode":"Increment","is_integer":true,"min":2.0},"widget_override":"number"},{"input_data":{"blank_assist":true,"is_integer":false,"min":0.0,"mode":"Increment","unit":" px"},"widget_override":"number"},{"input_data":{"unit":" px","is_integer":false,"blank_assist":true,"min":0.0,"mode":"Increment"},"widget_override":"number"},{"input_data":{},"widget_override":null}],"output_names":["Vector"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-13,-3]}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[4,{"persistent_metadata":{"reference":null,"display_name":"Boundless Footprint","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[28,0]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"Subpath Segment Lengths","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,7]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Freeze Real Time","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[21,0]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Memoize","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[14,0]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"Sample Polyline","input_properties":[{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[16943732999059587742,{"persistent_metadata":{"reference":"Jitter Points","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Amount"},"widget_override":null},{"input_data":{"input_name":"Seed"},"widget_override":null}],"output_names":["Future>"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[8,-3]}}},"network_metadata":null}}],[8591396027454826376,{"persistent_metadata":{"reference":"Sample Polyline","display_name":"","input_properties":[{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{"blank_assist":true,"is_integer":false,"min":0.0,"mode":"Increment","unit":" px"},"widget_override":"number"},{"input_data":{"blank_assist":true,"is_integer":true,"min":2.0,"mode":"Increment"},"widget_override":"number"},{"input_data":{"unit":" px","mode":"Increment","min":0.0,"is_integer":false,"blank_assist":true},"widget_override":"number"},{"input_data":{"is_integer":false,"mode":"Increment","unit":" px","blank_assist":true,"min":0.0},"widget_override":"number"},{"input_data":{},"widget_override":null}],"output_names":["Vector"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"Subpath Segment Lengths","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,7]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Memoize","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[14,0]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"Sample Polyline","input_properties":[{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Freeze Real Time","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[21,0]}}},"network_metadata":null}}],[4,{"persistent_metadata":{"reference":null,"display_name":"Boundless Footprint","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[28,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[14158287945315818946,{"persistent_metadata":{"reference":"Transform","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"unit":" px","input_name":"Translation","x":"X","y":"Y"},"widget_override":"vec2"},{"input_data":{"input_name":"Rotation"},"widget_override":"transform_rotation"},{"input_data":{"input_name":"Scale","unit":"x","x":"W","y":"H"},"widget_override":"vec2"},{"input_data":{"input_name":"Skew"},"widget_override":"transform_skew"},{"input_data":{"input_name":"Pivot"},"widget_override":"hidden"}],"output_names":["Data"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[15,-3]}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"Transform","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[11731553664207576737,{"persistent_metadata":{"reference":"Jitter Points","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Amount"},"widget_override":null},{"input_data":{"input_name":"Seed"},"widget_override":null}],"output_names":["Future>"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-6,-3]}}},"network_metadata":null}}],[14577956936089455769,{"persistent_metadata":{"reference":"Coordinate Value","display_name":"","input_properties":[{"input_data":{"input_name":"Primary"},"widget_override":null},{"input_data":{"input_name":"X"},"widget_override":null},{"input_data":{"input_name":"Y"},"widget_override":null}],"output_names":["Future"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[8,-1]}}},"network_metadata":null}}],[640915213983348287,{"persistent_metadata":{"reference":"Rectangle","display_name":"","input_properties":[{"input_data":{"input_name":"Primary"},"widget_override":null},{"input_data":{"input_name":"Width"},"widget_override":null},{"input_data":{"input_name":"Height"},"widget_override":null},{"input_data":{"input_name":"Individual Corner Radii"},"widget_override":null},{"input_data":{"input_name":"Corner Radius"},"widget_override":null},{"input_data":{"input_name":"Clamped"},"widget_override":null}],"output_names":["Future>"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-27,-3]}}},"network_metadata":null}}],[7828034197076821310,{"persistent_metadata":{"reference":"To u32","display_name":"","input_properties":[{"input_data":{"input_name":"Value"},"widget_override":null}],"output_names":["Future"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-13,1]}}},"network_metadata":null}}],[2288754089236120499,{"persistent_metadata":{"reference":"Spline","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null}],"output_names":["Future>"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[22,-3]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,991.0,581.0],"node_graph_top_right":[1980.796875,0.0]},"selection_undo_history":[[]],"selection_redo_history":[]}}}}],[12317719117993811200,{"persistent_metadata":{"reference":"Merge","display_name":"Dune 4","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":["Out"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":0}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[2128810469968776913,{"persistent_metadata":{"reference":"Merge","display_name":"Far Mountains","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":["Out"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":16}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[15385259560644295534,{"persistent_metadata":{"reference":"Merge","display_name":"Dune 2","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":["Out"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":0}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[11386926595254122633,{"persistent_metadata":{"reference":"Merge","display_name":"Dune","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":["Out"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":0}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[5883606306991910210,{"persistent_metadata":{"reference":null,"display_name":"Dune","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":"Color"},"widget_override":null},{"input_data":{"input_name":"Height"},"widget_override":null},{"input_data":{"input_name":"Seed"},"widget_override":null}],"output_names":[""],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[640915213983348287,{"persistent_metadata":{"reference":"Rectangle","display_name":"","input_properties":[{"input_data":{"input_name":"Primary"},"widget_override":null},{"input_data":{"input_name":"Width"},"widget_override":null},{"input_data":{"input_name":"Height"},"widget_override":null},{"input_data":{"input_name":"Individual Corner Radii"},"widget_override":null},{"input_data":{"input_name":"Corner Radius"},"widget_override":null},{"input_data":{"input_name":"Clamped"},"widget_override":null}],"output_names":["Future>"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-27,-3]}}},"network_metadata":null}}],[16943732999059587742,{"persistent_metadata":{"reference":"Jitter Points","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Amount"},"widget_override":null},{"input_data":{"input_name":"Seed"},"widget_override":null}],"output_names":["Future>"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[8,-3]}}},"network_metadata":null}}],[6686718746443793247,{"persistent_metadata":{"reference":"Sample Polyline","display_name":"","input_properties":[{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{"blank_assist":true,"is_integer":false,"unit":" px","min":0.0,"mode":"Increment"},"widget_override":"number"},{"input_data":{"blank_assist":true,"mode":"Increment","is_integer":true,"min":2.0},"widget_override":"number"},{"input_data":{"min":0.0,"unit":" px","is_integer":false,"blank_assist":true,"mode":"Increment"},"widget_override":"number"},{"input_data":{"mode":"Increment","unit":" px","blank_assist":true,"is_integer":false,"min":0.0},"widget_override":"number"},{"input_data":{},"widget_override":null}],"output_names":["Vector"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"Sample Polyline","input_properties":[{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Freeze Real Time","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[21,0]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"Subpath Segment Lengths","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,7]}}},"network_metadata":null}}],[4,{"persistent_metadata":{"reference":null,"display_name":"Boundless Footprint","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[28,0]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Memoize","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[14,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[16598825029377599083,{"persistent_metadata":{"reference":"Sample Polyline","display_name":"","input_properties":[{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{"min":0.0,"unit":" px","is_integer":false,"blank_assist":true,"mode":"Increment"},"widget_override":"number"},{"input_data":{"mode":"Increment","blank_assist":true,"is_integer":true,"min":2.0},"widget_override":"number"},{"input_data":{"is_integer":false,"blank_assist":true,"min":0.0,"mode":"Increment","unit":" px"},"widget_override":"number"},{"input_data":{"min":0.0,"mode":"Increment","blank_assist":true,"is_integer":false,"unit":" px"},"widget_override":"number"},{"input_data":{},"widget_override":null}],"output_names":["Vector"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-13,-3]}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"Subpath Segment Lengths","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,7]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Freeze Real Time","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[21,0]}}},"network_metadata":null}}],[4,{"persistent_metadata":{"reference":null,"display_name":"Boundless Footprint","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[28,0]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"Sample Polyline","input_properties":[{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Memoize","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[14,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[2288754089236120499,{"persistent_metadata":{"reference":"Spline","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null}],"output_names":["Future>"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[22,-3]}}},"network_metadata":null}}],[7828034197076821310,{"persistent_metadata":{"reference":"To u32","display_name":"","input_properties":[{"input_data":{"input_name":"Value"},"widget_override":null}],"output_names":["Future"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-13,1]}}},"network_metadata":null}}],[14158287945315818946,{"persistent_metadata":{"reference":"Transform","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"unit":" px","y":"Y","x":"X","input_name":"Translation"},"widget_override":"vec2"},{"input_data":{"input_name":"Rotation"},"widget_override":"transform_rotation"},{"input_data":{"unit":"x","y":"H","x":"W","input_name":"Scale"},"widget_override":"vec2"},{"input_data":{"input_name":"Skew"},"widget_override":"transform_skew"},{"input_data":{"input_name":"Pivot"},"widget_override":"hidden"}],"output_names":["Data"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[15,-3]}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"Transform","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[11731553664207576737,{"persistent_metadata":{"reference":"Jitter Points","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Amount"},"widget_override":null},{"input_data":{"input_name":"Seed"},"widget_override":null}],"output_names":["Future>"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-6,-3]}}},"network_metadata":null}}],[1791308547102433540,{"persistent_metadata":{"reference":"Fill","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Fill"},"widget_override":null},{"input_data":{"input_name":"Backup Color"},"widget_override":null},{"input_data":{"input_name":"Backup Gradient"},"widget_override":null}],"output_names":["Future>"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-20,-3]}}},"network_metadata":null}}],[14577956936089455769,{"persistent_metadata":{"reference":"Coordinate Value","display_name":"","input_properties":[{"input_data":{"input_name":"Primary"},"widget_override":null},{"input_data":{"input_name":"X"},"widget_override":null},{"input_data":{"input_name":"Y"},"widget_override":null}],"output_names":["Future"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[8,-1]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,991.0,581.0],"node_graph_top_right":[1980.796875,0.0]},"selection_undo_history":[[]],"selection_redo_history":[]}}}}],[2163528024003768644,{"persistent_metadata":{"reference":"Merge","display_name":"Dune in Shadow 1","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":["Out"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Absolute":[-14,6]}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[4037968351431607570,{"persistent_metadata":{"reference":null,"display_name":"Dune","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":"Color"},"widget_override":null},{"input_data":{"input_name":"Height"},"widget_override":null},{"input_data":{"input_name":"Seed"},"widget_override":null}],"output_names":[""],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[11874141024063691837,{"persistent_metadata":{"reference":"Sample Polyline","display_name":"","input_properties":[{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{"min":0.0,"blank_assist":true,"is_integer":false,"mode":"Increment","unit":" px"},"widget_override":"number"},{"input_data":{"blank_assist":true,"is_integer":true,"min":2.0,"mode":"Increment"},"widget_override":"number"},{"input_data":{"min":0.0,"mode":"Increment","unit":" px","is_integer":false,"blank_assist":true},"widget_override":"number"},{"input_data":{"mode":"Increment","unit":" px","blank_assist":true,"is_integer":false,"min":0.0},"widget_override":"number"},{"input_data":{},"widget_override":null}],"output_names":["Vector"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-13,-3]}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[4,{"persistent_metadata":{"reference":null,"display_name":"Boundless Footprint","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[28,0]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"Sample Polyline","input_properties":[{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Memoize","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[14,0]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"Subpath Segment Lengths","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,7]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Freeze Real Time","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[21,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[2288754089236120499,{"persistent_metadata":{"reference":"Spline","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null}],"output_names":["Future>"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[22,-3]}}},"network_metadata":null}}],[7828034197076821310,{"persistent_metadata":{"reference":"To u32","display_name":"","input_properties":[{"input_data":{"input_name":"Value"},"widget_override":null}],"output_names":["Future"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-13,1]}}},"network_metadata":null}}],[640915213983348287,{"persistent_metadata":{"reference":"Rectangle","display_name":"","input_properties":[{"input_data":{"input_name":"Primary"},"widget_override":null},{"input_data":{"input_name":"Width"},"widget_override":null},{"input_data":{"input_name":"Height"},"widget_override":null},{"input_data":{"input_name":"Individual Corner Radii"},"widget_override":null},{"input_data":{"input_name":"Corner Radius"},"widget_override":null},{"input_data":{"input_name":"Clamped"},"widget_override":null}],"output_names":["Future>"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-27,-3]}}},"network_metadata":null}}],[1791308547102433540,{"persistent_metadata":{"reference":"Fill","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Fill"},"widget_override":null},{"input_data":{"input_name":"Backup Color"},"widget_override":null},{"input_data":{"input_name":"Backup Gradient"},"widget_override":null}],"output_names":["Future>"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-20,-3]}}},"network_metadata":null}}],[14158287945315818946,{"persistent_metadata":{"reference":"Transform","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"x":"X","unit":" px","y":"Y","input_name":"Translation"},"widget_override":"vec2"},{"input_data":{"input_name":"Rotation"},"widget_override":"transform_rotation"},{"input_data":{"unit":"x","input_name":"Scale","x":"W","y":"H"},"widget_override":"vec2"},{"input_data":{"input_name":"Skew"},"widget_override":"transform_skew"},{"input_data":{"input_name":"Pivot"},"widget_override":"hidden"}],"output_names":["Data"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[15,-3]}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"Transform","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[11731553664207576737,{"persistent_metadata":{"reference":"Jitter Points","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Amount"},"widget_override":null},{"input_data":{"input_name":"Seed"},"widget_override":null}],"output_names":["Future>"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-6,-3]}}},"network_metadata":null}}],[14577956936089455769,{"persistent_metadata":{"reference":"Coordinate Value","display_name":"","input_properties":[{"input_data":{"input_name":"Primary"},"widget_override":null},{"input_data":{"input_name":"X"},"widget_override":null},{"input_data":{"input_name":"Y"},"widget_override":null}],"output_names":["Future"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[8,-1]}}},"network_metadata":null}}],[16943732999059587742,{"persistent_metadata":{"reference":"Jitter Points","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Amount"},"widget_override":null},{"input_data":{"input_name":"Seed"},"widget_override":null}],"output_names":["Future>"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[8,-3]}}},"network_metadata":null}}],[7807438675023750219,{"persistent_metadata":{"reference":"Sample Polyline","display_name":"","input_properties":[{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{"mode":"Increment","min":0.0,"blank_assist":true,"is_integer":false,"unit":" px"},"widget_override":"number"},{"input_data":{"is_integer":true,"min":2.0,"mode":"Increment","blank_assist":true},"widget_override":"number"},{"input_data":{"min":0.0,"mode":"Increment","unit":" px","is_integer":false,"blank_assist":true},"widget_override":"number"},{"input_data":{"blank_assist":true,"is_integer":false,"min":0.0,"mode":"Increment","unit":" px"},"widget_override":"number"},{"input_data":{},"widget_override":null}],"output_names":["Vector"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[2,{"persistent_metadata":{"reference":null,"display_name":"Memoize","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[14,0]}}},"network_metadata":null}}],[4,{"persistent_metadata":{"reference":null,"display_name":"Boundless Footprint","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[28,0]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"Sample Polyline","input_properties":[{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"Subpath Segment Lengths","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,7]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Freeze Real Time","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[21,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,991.0,581.0],"node_graph_top_right":[1980.796875,0.0]},"selection_undo_history":[[]],"selection_redo_history":[]}}}}],[12122314434656187176,{"persistent_metadata":{"reference":"Merge","display_name":"Dune in Shadow 1","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":["Out"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Absolute":[-14,27]}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[17327221498641745184,{"persistent_metadata":{"reference":"Merge","display_name":"Dune 3","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":["Out"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":0}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[95.5,23.5],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,1086.0,604.0],"node_graph_top_right":[1980.796875,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[12416569579970107543,{"persistent_metadata":{"reference":"Spline","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null}],"output_names":["Future>"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[17239043462037837834,{"persistent_metadata":{"reference":null,"display_name":"Dune","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":"Color"},"widget_override":null},{"input_data":{"input_name":"Height"},"widget_override":null},{"input_data":{"input_name":"Seed"},"widget_override":null}],"output_names":[""],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[7260397085903590160,{"persistent_metadata":{"reference":"Sample Polyline","display_name":"","input_properties":[{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{"unit":" px","is_integer":false,"blank_assist":true,"min":0.0,"mode":"Increment"},"widget_override":"number"},{"input_data":{"is_integer":true,"min":2.0,"blank_assist":true,"mode":"Increment"},"widget_override":"number"},{"input_data":{"blank_assist":true,"min":0.0,"unit":" px","is_integer":false,"mode":"Increment"},"widget_override":"number"},{"input_data":{"blank_assist":true,"is_integer":false,"unit":" px","mode":"Increment","min":0.0},"widget_override":"number"},{"input_data":{},"widget_override":null}],"output_names":["Vector"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-13,-3]}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"Subpath Segment Lengths","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,7]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Freeze Real Time","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[21,0]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"Sample Polyline","input_properties":[{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Memoize","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[14,0]}}},"network_metadata":null}}],[4,{"persistent_metadata":{"reference":null,"display_name":"Boundless Footprint","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[28,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[1791308547102433540,{"persistent_metadata":{"reference":"Fill","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Fill"},"widget_override":null},{"input_data":{"input_name":"Backup Color"},"widget_override":null},{"input_data":{"input_name":"Backup Gradient"},"widget_override":null}],"output_names":["Future>"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-20,-3]}}},"network_metadata":null}}],[11731553664207576737,{"persistent_metadata":{"reference":"Jitter Points","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Amount"},"widget_override":null},{"input_data":{"input_name":"Seed"},"widget_override":null}],"output_names":["Future>"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-6,-3]}}},"network_metadata":null}}],[640915213983348287,{"persistent_metadata":{"reference":"Rectangle","display_name":"","input_properties":[{"input_data":{"input_name":"Primary"},"widget_override":null},{"input_data":{"input_name":"Width"},"widget_override":null},{"input_data":{"input_name":"Height"},"widget_override":null},{"input_data":{"input_name":"Individual Corner Radii"},"widget_override":null},{"input_data":{"input_name":"Corner Radius"},"widget_override":null},{"input_data":{"input_name":"Clamped"},"widget_override":null}],"output_names":["Future>"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-27,-3]}}},"network_metadata":null}}],[16943732999059587742,{"persistent_metadata":{"reference":"Jitter Points","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Amount"},"widget_override":null},{"input_data":{"input_name":"Seed"},"widget_override":null}],"output_names":["Future>"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[8,-3]}}},"network_metadata":null}}],[7828034197076821310,{"persistent_metadata":{"reference":"To u32","display_name":"","input_properties":[{"input_data":{"input_name":"Value"},"widget_override":null}],"output_names":["Future"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-13,1]}}},"network_metadata":null}}],[14577956936089455769,{"persistent_metadata":{"reference":"Coordinate Value","display_name":"","input_properties":[{"input_data":{"input_name":"Primary"},"widget_override":null},{"input_data":{"input_name":"X"},"widget_override":null},{"input_data":{"input_name":"Y"},"widget_override":null}],"output_names":["Future"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[8,-1]}}},"network_metadata":null}}],[2288754089236120499,{"persistent_metadata":{"reference":"Spline","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null}],"output_names":["Future>"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[22,-3]}}},"network_metadata":null}}],[14158287945315818946,{"persistent_metadata":{"reference":"Transform","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Translation","unit":" px","x":"X","y":"Y"},"widget_override":"vec2"},{"input_data":{"input_name":"Rotation"},"widget_override":"transform_rotation"},{"input_data":{"input_name":"Scale","unit":"x","x":"W","y":"H"},"widget_override":"vec2"},{"input_data":{"input_name":"Skew"},"widget_override":"transform_skew"},{"input_data":{"input_name":"Pivot"},"widget_override":"hidden"}],"output_names":["Data"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[15,-3]}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"Transform","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[15937218612227302315,{"persistent_metadata":{"reference":"Sample Polyline","display_name":"","input_properties":[{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{"unit":" px","is_integer":false,"min":0.0,"blank_assist":true,"mode":"Increment"},"widget_override":"number"},{"input_data":{"mode":"Increment","blank_assist":true,"is_integer":true,"min":2.0},"widget_override":"number"},{"input_data":{"unit":" px","mode":"Increment","blank_assist":true,"is_integer":false,"min":0.0},"widget_override":"number"},{"input_data":{"is_integer":false,"mode":"Increment","min":0.0,"unit":" px","blank_assist":true},"widget_override":"number"},{"input_data":{},"widget_override":null}],"output_names":["Vector"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"Subpath Segment Lengths","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,7]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Freeze Real Time","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[21,0]}}},"network_metadata":null}}],[4,{"persistent_metadata":{"reference":null,"display_name":"Boundless Footprint","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[28,0]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Memoize","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[14,0]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"Sample Polyline","input_properties":[{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,991.0,581.0],"node_graph_top_right":[1980.796875,0.0]},"selection_undo_history":[[]],"selection_redo_history":[]}}}}],[7128559142392931896,{"persistent_metadata":{"reference":null,"display_name":"Dune","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":"Color"},"widget_override":null},{"input_data":{"input_name":"Height"},"widget_override":null},{"input_data":{"input_name":"Seed"},"widget_override":null}],"output_names":[""],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[10094915787292727725,{"persistent_metadata":{"reference":"Sample Polyline","display_name":"","input_properties":[{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{"blank_assist":true,"mode":"Increment","min":0.0,"unit":" px","is_integer":false},"widget_override":"number"},{"input_data":{"mode":"Increment","is_integer":true,"blank_assist":true,"min":2.0},"widget_override":"number"},{"input_data":{"min":0.0,"is_integer":false,"mode":"Increment","blank_assist":true,"unit":" px"},"widget_override":"number"},{"input_data":{"blank_assist":true,"unit":" px","is_integer":false,"min":0.0,"mode":"Increment"},"widget_override":"number"},{"input_data":{},"widget_override":null}],"output_names":["Vector"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-13,-3]}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[2,{"persistent_metadata":{"reference":null,"display_name":"Memoize","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[14,0]}}},"network_metadata":null}}],[4,{"persistent_metadata":{"reference":null,"display_name":"Boundless Footprint","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[28,0]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Freeze Real Time","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[21,0]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"Sample Polyline","input_properties":[{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"Subpath Segment Lengths","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,7]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[1791308547102433540,{"persistent_metadata":{"reference":"Fill","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Fill"},"widget_override":null},{"input_data":{"input_name":"Backup Color"},"widget_override":null},{"input_data":{"input_name":"Backup Gradient"},"widget_override":null}],"output_names":["Future>"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-20,-3]}}},"network_metadata":null}}],[2288754089236120499,{"persistent_metadata":{"reference":"Spline","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null}],"output_names":["Future>"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[22,-3]}}},"network_metadata":null}}],[14158287945315818946,{"persistent_metadata":{"reference":"Transform","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"y":"Y","input_name":"Translation","unit":" px","x":"X"},"widget_override":"vec2"},{"input_data":{"input_name":"Rotation"},"widget_override":"transform_rotation"},{"input_data":{"x":"W","input_name":"Scale","unit":"x","y":"H"},"widget_override":"vec2"},{"input_data":{"input_name":"Skew"},"widget_override":"transform_skew"},{"input_data":{"input_name":"Pivot"},"widget_override":"hidden"}],"output_names":["Data"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[15,-3]}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"Transform","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[16943732999059587742,{"persistent_metadata":{"reference":"Jitter Points","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Amount"},"widget_override":null},{"input_data":{"input_name":"Seed"},"widget_override":null}],"output_names":["Future>"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[8,-3]}}},"network_metadata":null}}],[7828034197076821310,{"persistent_metadata":{"reference":"To u32","display_name":"","input_properties":[{"input_data":{"input_name":"Value"},"widget_override":null}],"output_names":["Future"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-13,1]}}},"network_metadata":null}}],[11731553664207576737,{"persistent_metadata":{"reference":"Jitter Points","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Amount"},"widget_override":null},{"input_data":{"input_name":"Seed"},"widget_override":null}],"output_names":["Future>"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-6,-3]}}},"network_metadata":null}}],[640915213983348287,{"persistent_metadata":{"reference":"Rectangle","display_name":"","input_properties":[{"input_data":{"input_name":"Primary"},"widget_override":null},{"input_data":{"input_name":"Width"},"widget_override":null},{"input_data":{"input_name":"Height"},"widget_override":null},{"input_data":{"input_name":"Individual Corner Radii"},"widget_override":null},{"input_data":{"input_name":"Corner Radius"},"widget_override":null},{"input_data":{"input_name":"Clamped"},"widget_override":null}],"output_names":["Future>"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-27,-3]}}},"network_metadata":null}}],[18443039976647938912,{"persistent_metadata":{"reference":"Sample Polyline","display_name":"","input_properties":[{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{"is_integer":false,"blank_assist":true,"min":0.0,"mode":"Increment","unit":" px"},"widget_override":"number"},{"input_data":{"blank_assist":true,"is_integer":true,"mode":"Increment","min":2.0},"widget_override":"number"},{"input_data":{"mode":"Increment","is_integer":false,"blank_assist":true,"min":0.0,"unit":" px"},"widget_override":"number"},{"input_data":{"min":0.0,"is_integer":false,"blank_assist":true,"mode":"Increment","unit":" px"},"widget_override":"number"},{"input_data":{},"widget_override":null}],"output_names":["Vector"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"Subpath Segment Lengths","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,7]}}},"network_metadata":null}}],[4,{"persistent_metadata":{"reference":null,"display_name":"Boundless Footprint","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[28,0]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Freeze Real Time","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[21,0]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Memoize","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[14,0]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"Sample Polyline","input_properties":[{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[14577956936089455769,{"persistent_metadata":{"reference":"Coordinate Value","display_name":"","input_properties":[{"input_data":{"input_name":"Primary"},"widget_override":null},{"input_data":{"input_name":"X"},"widget_override":null},{"input_data":{"input_name":"Y"},"widget_override":null}],"output_names":["Future"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[8,-1]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.33333333333328596,-0.3333333333333428],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,991.0,580.0],"node_graph_top_right":[1980.796875,0.0]},"selection_undo_history":[[10094915787292727725]],"selection_redo_history":[]}}}}],[13323241418027154136,{"persistent_metadata":{"reference":null,"display_name":"Dune","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":"Color"},"widget_override":null},{"input_data":{"input_name":"Height"},"widget_override":null},{"input_data":{"input_name":"Seed"},"widget_override":null}],"output_names":[""],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[14158287945315818946,{"persistent_metadata":{"reference":"Transform","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"unit":" px","x":"X","y":"Y","input_name":"Translation"},"widget_override":"vec2"},{"input_data":{"input_name":"Rotation"},"widget_override":"transform_rotation"},{"input_data":{"y":"H","unit":"x","input_name":"Scale","x":"W"},"widget_override":"vec2"},{"input_data":{"input_name":"Skew"},"widget_override":"transform_skew"},{"input_data":{"input_name":"Pivot"},"widget_override":"hidden"}],"output_names":["Data"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[15,-3]}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"Transform","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[3434804841107735149,{"persistent_metadata":{"reference":"Sample Polyline","display_name":"","input_properties":[{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{"unit":" px","blank_assist":true,"min":0.0,"mode":"Increment","is_integer":false},"widget_override":"number"},{"input_data":{"blank_assist":true,"is_integer":true,"min":2.0,"mode":"Increment"},"widget_override":"number"},{"input_data":{"is_integer":false,"min":0.0,"mode":"Increment","blank_assist":true,"unit":" px"},"widget_override":"number"},{"input_data":{"min":0.0,"mode":"Increment","is_integer":false,"unit":" px","blank_assist":true},"widget_override":"number"},{"input_data":{},"widget_override":null}],"output_names":["Vector"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[2,{"persistent_metadata":{"reference":null,"display_name":"Memoize","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[14,0]}}},"network_metadata":null}}],[4,{"persistent_metadata":{"reference":null,"display_name":"Boundless Footprint","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[28,0]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"Sample Polyline","input_properties":[{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"Subpath Segment Lengths","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,7]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Freeze Real Time","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[21,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[11731553664207576737,{"persistent_metadata":{"reference":"Jitter Points","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Amount"},"widget_override":null},{"input_data":{"input_name":"Seed"},"widget_override":null}],"output_names":["Future>"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-6,-3]}}},"network_metadata":null}}],[640915213983348287,{"persistent_metadata":{"reference":"Rectangle","display_name":"","input_properties":[{"input_data":{"input_name":"Primary"},"widget_override":null},{"input_data":{"input_name":"Width"},"widget_override":null},{"input_data":{"input_name":"Height"},"widget_override":null},{"input_data":{"input_name":"Individual Corner Radii"},"widget_override":null},{"input_data":{"input_name":"Corner Radius"},"widget_override":null},{"input_data":{"input_name":"Clamped"},"widget_override":null}],"output_names":["Future>"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-27,-3]}}},"network_metadata":null}}],[16504069171520924548,{"persistent_metadata":{"reference":"Sample Polyline","display_name":"","input_properties":[{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{"is_integer":false,"min":0.0,"blank_assist":true,"mode":"Increment","unit":" px"},"widget_override":"number"},{"input_data":{"is_integer":true,"blank_assist":true,"min":2.0,"mode":"Increment"},"widget_override":"number"},{"input_data":{"blank_assist":true,"is_integer":false,"min":0.0,"mode":"Increment","unit":" px"},"widget_override":"number"},{"input_data":{"mode":"Increment","is_integer":false,"unit":" px","blank_assist":true,"min":0.0},"widget_override":"number"},{"input_data":{},"widget_override":null}],"output_names":["Vector"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-13,-3]}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[2,{"persistent_metadata":{"reference":null,"display_name":"Memoize","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[14,0]}}},"network_metadata":null}}],[4,{"persistent_metadata":{"reference":null,"display_name":"Boundless Footprint","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[28,0]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"Sample Polyline","input_properties":[{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Freeze Real Time","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[21,0]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"Subpath Segment Lengths","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,7]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[7828034197076821310,{"persistent_metadata":{"reference":"To u32","display_name":"","input_properties":[{"input_data":{"input_name":"Value"},"widget_override":null}],"output_names":["Future"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-13,1]}}},"network_metadata":null}}],[14577956936089455769,{"persistent_metadata":{"reference":"Coordinate Value","display_name":"","input_properties":[{"input_data":{"input_name":"Primary"},"widget_override":null},{"input_data":{"input_name":"X"},"widget_override":null},{"input_data":{"input_name":"Y"},"widget_override":null}],"output_names":["Future"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[8,-1]}}},"network_metadata":null}}],[16943732999059587742,{"persistent_metadata":{"reference":"Jitter Points","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Amount"},"widget_override":null},{"input_data":{"input_name":"Seed"},"widget_override":null}],"output_names":["Future>"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[8,-3]}}},"network_metadata":null}}],[1791308547102433540,{"persistent_metadata":{"reference":"Fill","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Fill"},"widget_override":null},{"input_data":{"input_name":"Backup Color"},"widget_override":null},{"input_data":{"input_name":"Backup Gradient"},"widget_override":null}],"output_names":["Future>"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-20,-3]}}},"network_metadata":null}}],[2288754089236120499,{"persistent_metadata":{"reference":"Spline","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null}],"output_names":["Future>"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[22,-3]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[26.0,-82.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,1017.0,499.0],"node_graph_top_right":[1980.796875,0.0]},"selection_undo_history":[[]],"selection_redo_history":[]}}}}],[239716716021064150,{"persistent_metadata":{"reference":"Merge","display_name":"Dune 2","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":["Out"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":0}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[13676600738025998635,{"persistent_metadata":{"reference":"Merge","display_name":"Background","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":["Out"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":10}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[3934928477288442109,{"persistent_metadata":{"reference":"Merge","display_name":"Dune 1","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":["Out"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":0}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[4445985685181725042,{"persistent_metadata":{"reference":"Artboard","display_name":"","input_properties":[{"input_data":{"input_name":"Artboards"},"widget_override":null},{"input_data":{"input_name":"Contents"},"widget_override":"hidden"},{"input_data":{"unit":" px","y":"Y","x":"X","input_name":"Location"},"widget_override":"vec2"},{"input_data":{"y":"H","unit":" px","x":"W","input_name":"Dimensions"},"widget_override":"vec2"},{"input_data":{"input_name":"Background"},"widget_override":"artboard_background"},{"input_data":{"input_name":"Clip"},"widget_override":null}],"output_names":["Out"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Absolute":[3,0]}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-2,-3]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"To Artboard","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-10,-3]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Append Artboards","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[6,-4]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[10806978668166337270,{"persistent_metadata":{"reference":null,"display_name":"Dune","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":"Color"},"widget_override":null},{"input_data":{"input_name":"Height"},"widget_override":null},{"input_data":{"input_name":"Seed"},"widget_override":null}],"output_names":[""],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[16943732999059587742,{"persistent_metadata":{"reference":"Jitter Points","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Amount"},"widget_override":null},{"input_data":{"input_name":"Seed"},"widget_override":null}],"output_names":["Future>"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[8,-3]}}},"network_metadata":null}}],[3765311973789472189,{"persistent_metadata":{"reference":"Sample Polyline","display_name":"","input_properties":[{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{"unit":" px","blank_assist":true,"mode":"Increment","is_integer":false,"min":0.0},"widget_override":"number"},{"input_data":{"blank_assist":true,"min":2.0,"mode":"Increment","is_integer":true},"widget_override":"number"},{"input_data":{"unit":" px","blank_assist":true,"min":0.0,"is_integer":false,"mode":"Increment"},"widget_override":"number"},{"input_data":{"mode":"Increment","min":0.0,"blank_assist":true,"unit":" px","is_integer":false},"widget_override":"number"},{"input_data":{},"widget_override":null}],"output_names":["Vector"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-13,-3]}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[3,{"persistent_metadata":{"reference":null,"display_name":"Freeze Real Time","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[21,0]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"Sample Polyline","input_properties":[{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}],[4,{"persistent_metadata":{"reference":null,"display_name":"Boundless Footprint","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[28,0]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"Subpath Segment Lengths","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,7]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Memoize","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[14,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[640915213983348287,{"persistent_metadata":{"reference":"Rectangle","display_name":"","input_properties":[{"input_data":{"input_name":"Primary"},"widget_override":null},{"input_data":{"input_name":"Width"},"widget_override":null},{"input_data":{"input_name":"Height"},"widget_override":null},{"input_data":{"input_name":"Individual Corner Radii"},"widget_override":null},{"input_data":{"input_name":"Corner Radius"},"widget_override":null},{"input_data":{"input_name":"Clamped"},"widget_override":null}],"output_names":["Future>"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-27,-3]}}},"network_metadata":null}}],[9133354469966676056,{"persistent_metadata":{"reference":"Sample Polyline","display_name":"","input_properties":[{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{"blank_assist":true,"mode":"Increment","unit":" px","min":0.0,"is_integer":false},"widget_override":"number"},{"input_data":{"is_integer":true,"blank_assist":true,"mode":"Increment","min":2.0},"widget_override":"number"},{"input_data":{"min":0.0,"unit":" px","blank_assist":true,"mode":"Increment","is_integer":false},"widget_override":"number"},{"input_data":{"blank_assist":true,"mode":"Increment","min":0.0,"unit":" px","is_integer":false},"widget_override":"number"},{"input_data":{},"widget_override":null}],"output_names":["Vector"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[3,{"persistent_metadata":{"reference":null,"display_name":"Freeze Real Time","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[21,0]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"Sample Polyline","input_properties":[{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Memoize","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[14,0]}}},"network_metadata":null}}],[4,{"persistent_metadata":{"reference":null,"display_name":"Boundless Footprint","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[28,0]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"Subpath Segment Lengths","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,7]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[7828034197076821310,{"persistent_metadata":{"reference":"To u32","display_name":"","input_properties":[{"input_data":{"input_name":"Value"},"widget_override":null}],"output_names":["Future"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-13,1]}}},"network_metadata":null}}],[14158287945315818946,{"persistent_metadata":{"reference":"Transform","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"y":"Y","input_name":"Translation","x":"X","unit":" px"},"widget_override":"vec2"},{"input_data":{"input_name":"Rotation"},"widget_override":"transform_rotation"},{"input_data":{"y":"H","x":"W","input_name":"Scale","unit":"x"},"widget_override":"vec2"},{"input_data":{"input_name":"Skew"},"widget_override":"transform_skew"},{"input_data":{"input_name":"Pivot"},"widget_override":"hidden"}],"output_names":["Data"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[15,-3]}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"Transform","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[2288754089236120499,{"persistent_metadata":{"reference":"Spline","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null}],"output_names":["Future>"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[22,-3]}}},"network_metadata":null}}],[14577956936089455769,{"persistent_metadata":{"reference":"Coordinate Value","display_name":"","input_properties":[{"input_data":{"input_name":"Primary"},"widget_override":null},{"input_data":{"input_name":"X"},"widget_override":null},{"input_data":{"input_name":"Y"},"widget_override":null}],"output_names":["Future"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[8,-1]}}},"network_metadata":null}}],[1791308547102433540,{"persistent_metadata":{"reference":"Fill","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Fill"},"widget_override":null},{"input_data":{"input_name":"Backup Color"},"widget_override":null},{"input_data":{"input_name":"Backup Gradient"},"widget_override":null}],"output_names":["Future>"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-20,-3]}}},"network_metadata":null}}],[11731553664207576737,{"persistent_metadata":{"reference":"Jitter Points","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Amount"},"widget_override":null},{"input_data":{"input_name":"Seed"},"widget_override":null}],"output_names":["Future>"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-6,-3]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,991.0,581.0],"node_graph_top_right":[1980.796875,0.0]},"selection_undo_history":[[]],"selection_redo_history":[]}}}}],[9069881382900058607,{"persistent_metadata":{"reference":"Merge","display_name":"Dune 5","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":["Out"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":0}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[4390668436091073484,{"persistent_metadata":{"reference":"Merge","display_name":"Midground in Shadow","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":["Out"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":18}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[17589660903986237301,{"persistent_metadata":{"reference":null,"display_name":"Dune","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":"Color"},"widget_override":null},{"input_data":{"input_name":"Height"},"widget_override":null},{"input_data":{"input_name":"Seed"},"widget_override":null}],"output_names":[""],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[11731553664207576737,{"persistent_metadata":{"reference":"Jitter Points","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Amount"},"widget_override":null},{"input_data":{"input_name":"Seed"},"widget_override":null}],"output_names":["Future>"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-6,-3]}}},"network_metadata":null}}],[1791308547102433540,{"persistent_metadata":{"reference":"Fill","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Fill"},"widget_override":null},{"input_data":{"input_name":"Backup Color"},"widget_override":null},{"input_data":{"input_name":"Backup Gradient"},"widget_override":null}],"output_names":["Future>"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-20,-3]}}},"network_metadata":null}}],[3289411516263327806,{"persistent_metadata":{"reference":"Sample Polyline","display_name":"","input_properties":[{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{"unit":" px","blank_assist":true,"is_integer":false,"mode":"Increment","min":0.0},"widget_override":"number"},{"input_data":{"mode":"Increment","min":2.0,"is_integer":true,"blank_assist":true},"widget_override":"number"},{"input_data":{"is_integer":false,"unit":" px","mode":"Increment","min":0.0,"blank_assist":true},"widget_override":"number"},{"input_data":{"blank_assist":true,"min":0.0,"is_integer":false,"mode":"Increment","unit":" px"},"widget_override":"number"},{"input_data":{},"widget_override":null}],"output_names":["Vector"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-13,-3]}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"Sample Polyline","input_properties":[{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Memoize","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[14,0]}}},"network_metadata":null}}],[4,{"persistent_metadata":{"reference":null,"display_name":"Boundless Footprint","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[28,0]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"Subpath Segment Lengths","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,7]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Freeze Real Time","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[21,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[7828034197076821310,{"persistent_metadata":{"reference":"To u32","display_name":"","input_properties":[{"input_data":{"input_name":"Value"},"widget_override":null}],"output_names":["Future"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-13,1]}}},"network_metadata":null}}],[16943732999059587742,{"persistent_metadata":{"reference":"Jitter Points","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Amount"},"widget_override":null},{"input_data":{"input_name":"Seed"},"widget_override":null}],"output_names":["Future>"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[8,-3]}}},"network_metadata":null}}],[14577956936089455769,{"persistent_metadata":{"reference":"Coordinate Value","display_name":"","input_properties":[{"input_data":{"input_name":"Primary"},"widget_override":null},{"input_data":{"input_name":"X"},"widget_override":null},{"input_data":{"input_name":"Y"},"widget_override":null}],"output_names":["Future"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[8,-1]}}},"network_metadata":null}}],[640915213983348287,{"persistent_metadata":{"reference":"Rectangle","display_name":"","input_properties":[{"input_data":{"input_name":"Primary"},"widget_override":null},{"input_data":{"input_name":"Width"},"widget_override":null},{"input_data":{"input_name":"Height"},"widget_override":null},{"input_data":{"input_name":"Individual Corner Radii"},"widget_override":null},{"input_data":{"input_name":"Corner Radius"},"widget_override":null},{"input_data":{"input_name":"Clamped"},"widget_override":null}],"output_names":["Future>"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-27,-3]}}},"network_metadata":null}}],[12029121808718862100,{"persistent_metadata":{"reference":"Sample Polyline","display_name":"","input_properties":[{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{"mode":"Increment","blank_assist":true,"unit":" px","min":0.0,"is_integer":false},"widget_override":"number"},{"input_data":{"mode":"Increment","is_integer":true,"blank_assist":true,"min":2.0},"widget_override":"number"},{"input_data":{"blank_assist":true,"mode":"Increment","unit":" px","min":0.0,"is_integer":false},"widget_override":"number"},{"input_data":{"blank_assist":true,"min":0.0,"mode":"Increment","unit":" px","is_integer":false},"widget_override":"number"},{"input_data":{},"widget_override":null}],"output_names":["Vector"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"Subpath Segment Lengths","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,7]}}},"network_metadata":null}}],[4,{"persistent_metadata":{"reference":null,"display_name":"Boundless Footprint","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[28,0]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"Sample Polyline","input_properties":[{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Memoize","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[14,0]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Freeze Real Time","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[21,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[14158287945315818946,{"persistent_metadata":{"reference":"Transform","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Translation","unit":" px","x":"X","y":"Y"},"widget_override":"vec2"},{"input_data":{"input_name":"Rotation"},"widget_override":"transform_rotation"},{"input_data":{"y":"H","unit":"x","x":"W","input_name":"Scale"},"widget_override":"vec2"},{"input_data":{"input_name":"Skew"},"widget_override":"transform_skew"},{"input_data":{"input_name":"Pivot"},"widget_override":"hidden"}],"output_names":["Data"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[15,-3]}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"Transform","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[2288754089236120499,{"persistent_metadata":{"reference":"Spline","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null}],"output_names":["Future>"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[22,-3]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,991.0,581.0],"node_graph_top_right":[1980.796875,0.0]},"selection_undo_history":[[]],"selection_redo_history":[]}}}}],[12639486733043466090,{"persistent_metadata":{"reference":"Merge","display_name":"Dune in Shadow 3","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":["Out"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":0}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[6523786079462141312,{"persistent_metadata":{"reference":null,"display_name":"Dune","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":"Color"},"widget_override":null},{"input_data":{"input_name":"Height"},"widget_override":null},{"input_data":{"input_name":"Seed"},"widget_override":null}],"output_names":[""],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[14577956936089455769,{"persistent_metadata":{"reference":"Coordinate Value","display_name":"","input_properties":[{"input_data":{"input_name":"Primary"},"widget_override":null},{"input_data":{"input_name":"X"},"widget_override":null},{"input_data":{"input_name":"Y"},"widget_override":null}],"output_names":["Future"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[8,-1]}}},"network_metadata":null}}],[7783268010546120518,{"persistent_metadata":{"reference":"Sample Polyline","display_name":"","input_properties":[{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{"min":0.0,"unit":" px","blank_assist":true,"is_integer":false,"mode":"Increment"},"widget_override":"number"},{"input_data":{"blank_assist":true,"is_integer":true,"mode":"Increment","min":2.0},"widget_override":"number"},{"input_data":{"blank_assist":true,"unit":" px","is_integer":false,"min":0.0,"mode":"Increment"},"widget_override":"number"},{"input_data":{"mode":"Increment","unit":" px","blank_assist":true,"is_integer":false,"min":0.0},"widget_override":"number"},{"input_data":{},"widget_override":null}],"output_names":["Vector"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"Sample Polyline","input_properties":[{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}],[4,{"persistent_metadata":{"reference":null,"display_name":"Boundless Footprint","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[28,0]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Freeze Real Time","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[21,0]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Memoize","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[14,0]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"Subpath Segment Lengths","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,7]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[7828034197076821310,{"persistent_metadata":{"reference":"To u32","display_name":"","input_properties":[{"input_data":{"input_name":"Value"},"widget_override":null}],"output_names":["Future"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-13,1]}}},"network_metadata":null}}],[1791308547102433540,{"persistent_metadata":{"reference":"Fill","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Fill"},"widget_override":null},{"input_data":{"input_name":"Backup Color"},"widget_override":null},{"input_data":{"input_name":"Backup Gradient"},"widget_override":null}],"output_names":["Future>"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-20,-3]}}},"network_metadata":null}}],[16009834030113172488,{"persistent_metadata":{"reference":"Sample Polyline","display_name":"","input_properties":[{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{"min":0.0,"mode":"Increment","blank_assist":true,"is_integer":false,"unit":" px"},"widget_override":"number"},{"input_data":{"min":2.0,"blank_assist":true,"mode":"Increment","is_integer":true},"widget_override":"number"},{"input_data":{"min":0.0,"unit":" px","blank_assist":true,"is_integer":false,"mode":"Increment"},"widget_override":"number"},{"input_data":{"is_integer":false,"unit":" px","min":0.0,"blank_assist":true,"mode":"Increment"},"widget_override":"number"},{"input_data":{},"widget_override":null}],"output_names":["Vector"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-13,-3]}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"Subpath Segment Lengths","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,7]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Freeze Real Time","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[21,0]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"Sample Polyline","input_properties":[{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Memoize","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[14,0]}}},"network_metadata":null}}],[4,{"persistent_metadata":{"reference":null,"display_name":"Boundless Footprint","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[28,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[2288754089236120499,{"persistent_metadata":{"reference":"Spline","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null}],"output_names":["Future>"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[22,-3]}}},"network_metadata":null}}],[11731553664207576737,{"persistent_metadata":{"reference":"Jitter Points","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Amount"},"widget_override":null},{"input_data":{"input_name":"Seed"},"widget_override":null}],"output_names":["Future>"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-6,-3]}}},"network_metadata":null}}],[640915213983348287,{"persistent_metadata":{"reference":"Rectangle","display_name":"","input_properties":[{"input_data":{"input_name":"Primary"},"widget_override":null},{"input_data":{"input_name":"Width"},"widget_override":null},{"input_data":{"input_name":"Height"},"widget_override":null},{"input_data":{"input_name":"Individual Corner Radii"},"widget_override":null},{"input_data":{"input_name":"Corner Radius"},"widget_override":null},{"input_data":{"input_name":"Clamped"},"widget_override":null}],"output_names":["Future>"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-27,-3]}}},"network_metadata":null}}],[14158287945315818946,{"persistent_metadata":{"reference":"Transform","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"unit":" px","y":"Y","input_name":"Translation","x":"X"},"widget_override":"vec2"},{"input_data":{"input_name":"Rotation"},"widget_override":"transform_rotation"},{"input_data":{"unit":"x","x":"W","y":"H","input_name":"Scale"},"widget_override":"vec2"},{"input_data":{"input_name":"Skew"},"widget_override":"transform_skew"},{"input_data":{"input_name":"Pivot"},"widget_override":"hidden"}],"output_names":["Data"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[15,-3]}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"Transform","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[16943732999059587742,{"persistent_metadata":{"reference":"Jitter Points","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Amount"},"widget_override":null},{"input_data":{"input_name":"Seed"},"widget_override":null}],"output_names":["Future>"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[8,-3]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,991.0,581.0],"node_graph_top_right":[1980.796875,0.0]},"selection_undo_history":[[]],"selection_redo_history":[]}}}}],[13132104524813958174,{"persistent_metadata":{"reference":"Merge","display_name":"Foreground","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":["Out"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Absolute":[-4,3]}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[16611856724057842399,{"persistent_metadata":{"reference":null,"display_name":"Dune","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":"Color"},"widget_override":null},{"input_data":{"input_name":"Height"},"widget_override":null},{"input_data":{"input_name":"Seed"},"widget_override":null}],"output_names":[""],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1791308547102433540,{"persistent_metadata":{"reference":"Fill","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Fill"},"widget_override":null},{"input_data":{"input_name":"Backup Color"},"widget_override":null},{"input_data":{"input_name":"Backup Gradient"},"widget_override":null}],"output_names":["Future>"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-20,-3]}}},"network_metadata":null}}],[11731553664207576737,{"persistent_metadata":{"reference":"Jitter Points","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Amount"},"widget_override":null},{"input_data":{"input_name":"Seed"},"widget_override":null}],"output_names":["Future>"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-6,-3]}}},"network_metadata":null}}],[14158287945315818946,{"persistent_metadata":{"reference":"Transform","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"unit":" px","input_name":"Translation","x":"X","y":"Y"},"widget_override":"vec2"},{"input_data":{"input_name":"Rotation"},"widget_override":"transform_rotation"},{"input_data":{"input_name":"Scale","x":"W","y":"H","unit":"x"},"widget_override":"vec2"},{"input_data":{"input_name":"Skew"},"widget_override":"transform_skew"},{"input_data":{"input_name":"Pivot"},"widget_override":"hidden"}],"output_names":["Data"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[15,-3]}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"Transform","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[16943732999059587742,{"persistent_metadata":{"reference":"Jitter Points","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Amount"},"widget_override":null},{"input_data":{"input_name":"Seed"},"widget_override":null}],"output_names":["Future>"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[8,-3]}}},"network_metadata":null}}],[17232801702996970986,{"persistent_metadata":{"reference":"Sample Polyline","display_name":"","input_properties":[{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{"blank_assist":true,"min":0.0,"is_integer":false,"unit":" px","mode":"Increment"},"widget_override":"number"},{"input_data":{"mode":"Increment","blank_assist":true,"min":2.0,"is_integer":true},"widget_override":"number"},{"input_data":{"unit":" px","is_integer":false,"min":0.0,"blank_assist":true,"mode":"Increment"},"widget_override":"number"},{"input_data":{"blank_assist":true,"is_integer":false,"min":0.0,"mode":"Increment","unit":" px"},"widget_override":"number"},{"input_data":{},"widget_override":null}],"output_names":["Vector"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-13,-3]}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"Sample Polyline","input_properties":[{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Freeze Real Time","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[21,0]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"Subpath Segment Lengths","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,7]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Memoize","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[14,0]}}},"network_metadata":null}}],[4,{"persistent_metadata":{"reference":null,"display_name":"Boundless Footprint","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[28,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[2288754089236120499,{"persistent_metadata":{"reference":"Spline","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null}],"output_names":["Future>"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[22,-3]}}},"network_metadata":null}}],[14577956936089455769,{"persistent_metadata":{"reference":"Coordinate Value","display_name":"","input_properties":[{"input_data":{"input_name":"Primary"},"widget_override":null},{"input_data":{"input_name":"X"},"widget_override":null},{"input_data":{"input_name":"Y"},"widget_override":null}],"output_names":["Future"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[8,-1]}}},"network_metadata":null}}],[9065988052616974602,{"persistent_metadata":{"reference":"Sample Polyline","display_name":"","input_properties":[{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{"min":0.0,"blank_assist":true,"mode":"Increment","unit":" px","is_integer":false},"widget_override":"number"},{"input_data":{"is_integer":true,"mode":"Increment","min":2.0,"blank_assist":true},"widget_override":"number"},{"input_data":{"min":0.0,"is_integer":false,"mode":"Increment","unit":" px","blank_assist":true},"widget_override":"number"},{"input_data":{"unit":" px","is_integer":false,"blank_assist":true,"min":0.0,"mode":"Increment"},"widget_override":"number"},{"input_data":{},"widget_override":null}],"output_names":["Vector"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"Sample Polyline","input_properties":[{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Freeze Real Time","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[21,0]}}},"network_metadata":null}}],[4,{"persistent_metadata":{"reference":null,"display_name":"Boundless Footprint","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[28,0]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"Subpath Segment Lengths","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,7]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Memoize","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[14,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[640915213983348287,{"persistent_metadata":{"reference":"Rectangle","display_name":"","input_properties":[{"input_data":{"input_name":"Primary"},"widget_override":null},{"input_data":{"input_name":"Width"},"widget_override":null},{"input_data":{"input_name":"Height"},"widget_override":null},{"input_data":{"input_name":"Individual Corner Radii"},"widget_override":null},{"input_data":{"input_name":"Corner Radius"},"widget_override":null},{"input_data":{"input_name":"Clamped"},"widget_override":null}],"output_names":["Future>"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-27,-3]}}},"network_metadata":null}}],[7828034197076821310,{"persistent_metadata":{"reference":"To u32","display_name":"","input_properties":[{"input_data":{"input_name":"Value"},"widget_override":null}],"output_names":["Future"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-13,1]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,991.0,581.0],"node_graph_top_right":[1980.796875,0.0]},"selection_undo_history":[[]],"selection_redo_history":[]}}}}],[17154757625902243313,{"persistent_metadata":{"reference":null,"display_name":"Dune","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":"Color"},"widget_override":null},{"input_data":{"input_name":"Height"},"widget_override":null},{"input_data":{"input_name":"Seed"},"widget_override":null}],"output_names":[""],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[2288754089236120499,{"persistent_metadata":{"reference":"Spline","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null}],"output_names":["Future>"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[22,-3]}}},"network_metadata":null}}],[1357621220363171879,{"persistent_metadata":{"reference":"Sample Polyline","display_name":"","input_properties":[{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{"mode":"Increment","min":0.0,"blank_assist":true,"unit":" px","is_integer":false},"widget_override":"number"},{"input_data":{"mode":"Increment","min":2.0,"blank_assist":true,"is_integer":true},"widget_override":"number"},{"input_data":{"min":0.0,"blank_assist":true,"mode":"Increment","is_integer":false,"unit":" px"},"widget_override":"number"},{"input_data":{"unit":" px","is_integer":false,"min":0.0,"mode":"Increment","blank_assist":true},"widget_override":"number"},{"input_data":{},"widget_override":null}],"output_names":["Vector"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"Sample Polyline","input_properties":[{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}],[4,{"persistent_metadata":{"reference":null,"display_name":"Boundless Footprint","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[28,0]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Memoize","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[14,0]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Freeze Real Time","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[21,0]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"Subpath Segment Lengths","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,7]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[640915213983348287,{"persistent_metadata":{"reference":"Rectangle","display_name":"","input_properties":[{"input_data":{"input_name":"Primary"},"widget_override":null},{"input_data":{"input_name":"Width"},"widget_override":null},{"input_data":{"input_name":"Height"},"widget_override":null},{"input_data":{"input_name":"Individual Corner Radii"},"widget_override":null},{"input_data":{"input_name":"Corner Radius"},"widget_override":null},{"input_data":{"input_name":"Clamped"},"widget_override":null}],"output_names":["Future>"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-27,-3]}}},"network_metadata":null}}],[14577956936089455769,{"persistent_metadata":{"reference":"Coordinate Value","display_name":"","input_properties":[{"input_data":{"input_name":"Primary"},"widget_override":null},{"input_data":{"input_name":"X"},"widget_override":null},{"input_data":{"input_name":"Y"},"widget_override":null}],"output_names":["Future"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[8,-1]}}},"network_metadata":null}}],[11731553664207576737,{"persistent_metadata":{"reference":"Jitter Points","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Amount"},"widget_override":null},{"input_data":{"input_name":"Seed"},"widget_override":null}],"output_names":["Future>"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-6,-3]}}},"network_metadata":null}}],[1791308547102433540,{"persistent_metadata":{"reference":"Fill","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Fill"},"widget_override":null},{"input_data":{"input_name":"Backup Color"},"widget_override":null},{"input_data":{"input_name":"Backup Gradient"},"widget_override":null}],"output_names":["Future>"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-20,-3]}}},"network_metadata":null}}],[7828034197076821310,{"persistent_metadata":{"reference":"To u32","display_name":"","input_properties":[{"input_data":{"input_name":"Value"},"widget_override":null}],"output_names":["Future"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-13,1]}}},"network_metadata":null}}],[14158287945315818946,{"persistent_metadata":{"reference":"Transform","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"x":"X","unit":" px","y":"Y","input_name":"Translation"},"widget_override":"vec2"},{"input_data":{"input_name":"Rotation"},"widget_override":"transform_rotation"},{"input_data":{"unit":"x","x":"W","y":"H","input_name":"Scale"},"widget_override":"vec2"},{"input_data":{"input_name":"Skew"},"widget_override":"transform_skew"},{"input_data":{"input_name":"Pivot"},"widget_override":"hidden"}],"output_names":["Data"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[15,-3]}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"Transform","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[757876048866560520,{"persistent_metadata":{"reference":"Sample Polyline","display_name":"","input_properties":[{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{"unit":" px","is_integer":false,"min":0.0,"mode":"Increment","blank_assist":true},"widget_override":"number"},{"input_data":{"mode":"Increment","blank_assist":true,"is_integer":true,"min":2.0},"widget_override":"number"},{"input_data":{"min":0.0,"blank_assist":true,"mode":"Increment","unit":" px","is_integer":false},"widget_override":"number"},{"input_data":{"is_integer":false,"min":0.0,"mode":"Increment","unit":" px","blank_assist":true},"widget_override":"number"},{"input_data":{},"widget_override":null}],"output_names":["Vector"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-13,-3]}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"Subpath Segment Lengths","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,7]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Memoize","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[14,0]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Freeze Real Time","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[21,0]}}},"network_metadata":null}}],[4,{"persistent_metadata":{"reference":null,"display_name":"Boundless Footprint","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[28,0]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"Sample Polyline","input_properties":[{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[16943732999059587742,{"persistent_metadata":{"reference":"Jitter Points","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Amount"},"widget_override":null},{"input_data":{"input_name":"Seed"},"widget_override":null}],"output_names":["Future>"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[8,-3]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,991.0,581.0],"node_graph_top_right":[1980.796875,0.0]},"selection_undo_history":[[]],"selection_redo_history":[]}}}}],[12110920487474373676,{"persistent_metadata":{"reference":"Merge","display_name":"Dune in Shadow 2","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":["Out"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":0}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[7711570794020903773,{"persistent_metadata":{"reference":null,"display_name":"Dune","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":"Color"},"widget_override":null},{"input_data":{"input_name":"Height"},"widget_override":null},{"input_data":{"input_name":"Seed"},"widget_override":null}],"output_names":[""],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[640915213983348287,{"persistent_metadata":{"reference":"Rectangle","display_name":"","input_properties":[{"input_data":{"input_name":"Primary"},"widget_override":null},{"input_data":{"input_name":"Width"},"widget_override":null},{"input_data":{"input_name":"Height"},"widget_override":null},{"input_data":{"input_name":"Individual Corner Radii"},"widget_override":null},{"input_data":{"input_name":"Corner Radius"},"widget_override":null},{"input_data":{"input_name":"Clamped"},"widget_override":null}],"output_names":["Future>"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-27,-3]}}},"network_metadata":null}}],[1791308547102433540,{"persistent_metadata":{"reference":"Fill","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Fill"},"widget_override":null},{"input_data":{"input_name":"Backup Color"},"widget_override":null},{"input_data":{"input_name":"Backup Gradient"},"widget_override":null}],"output_names":["Future>"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-20,-3]}}},"network_metadata":null}}],[14577956936089455769,{"persistent_metadata":{"reference":"Coordinate Value","display_name":"","input_properties":[{"input_data":{"input_name":"Primary"},"widget_override":null},{"input_data":{"input_name":"X"},"widget_override":null},{"input_data":{"input_name":"Y"},"widget_override":null}],"output_names":["Future"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[8,-1]}}},"network_metadata":null}}],[16943732999059587742,{"persistent_metadata":{"reference":"Jitter Points","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Amount"},"widget_override":null},{"input_data":{"input_name":"Seed"},"widget_override":null}],"output_names":["Future>"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[8,-3]}}},"network_metadata":null}}],[7828034197076821310,{"persistent_metadata":{"reference":"To u32","display_name":"","input_properties":[{"input_data":{"input_name":"Value"},"widget_override":null}],"output_names":["Future"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-13,1]}}},"network_metadata":null}}],[11731553664207576737,{"persistent_metadata":{"reference":"Jitter Points","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Amount"},"widget_override":null},{"input_data":{"input_name":"Seed"},"widget_override":null}],"output_names":["Future>"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-6,-3]}}},"network_metadata":null}}],[3025883099767376126,{"persistent_metadata":{"reference":"Sample Polyline","display_name":"","input_properties":[{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{"unit":" px","min":0.0,"mode":"Increment","is_integer":false,"blank_assist":true},"widget_override":"number"},{"input_data":{"is_integer":true,"blank_assist":true,"min":2.0,"mode":"Increment"},"widget_override":"number"},{"input_data":{"is_integer":false,"mode":"Increment","unit":" px","blank_assist":true,"min":0.0},"widget_override":"number"},{"input_data":{"min":0.0,"mode":"Increment","blank_assist":true,"unit":" px","is_integer":false},"widget_override":"number"},{"input_data":{},"widget_override":null}],"output_names":["Vector"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-13,-3]}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"Sample Polyline","input_properties":[{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Freeze Real Time","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[21,0]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"Subpath Segment Lengths","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,7]}}},"network_metadata":null}}],[4,{"persistent_metadata":{"reference":null,"display_name":"Boundless Footprint","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[28,0]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Memoize","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[14,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[14158287945315818946,{"persistent_metadata":{"reference":"Transform","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Translation","unit":" px","y":"Y","x":"X"},"widget_override":"vec2"},{"input_data":{"input_name":"Rotation"},"widget_override":"transform_rotation"},{"input_data":{"unit":"x","input_name":"Scale","y":"H","x":"W"},"widget_override":"vec2"},{"input_data":{"input_name":"Skew"},"widget_override":"transform_skew"},{"input_data":{"input_name":"Pivot"},"widget_override":"hidden"}],"output_names":["Data"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[15,-3]}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"Transform","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[2288754089236120499,{"persistent_metadata":{"reference":"Spline","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null}],"output_names":["Future>"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[22,-3]}}},"network_metadata":null}}],[1126802566044359983,{"persistent_metadata":{"reference":"Sample Polyline","display_name":"","input_properties":[{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{"mode":"Increment","blank_assist":true,"is_integer":false,"min":0.0,"unit":" px"},"widget_override":"number"},{"input_data":{"mode":"Increment","blank_assist":true,"min":2.0,"is_integer":true},"widget_override":"number"},{"input_data":{"min":0.0,"is_integer":false,"mode":"Increment","unit":" px","blank_assist":true},"widget_override":"number"},{"input_data":{"is_integer":false,"mode":"Increment","unit":" px","min":0.0,"blank_assist":true},"widget_override":"number"},{"input_data":{},"widget_override":null}],"output_names":["Vector"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"Sample Polyline","input_properties":[{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"Subpath Segment Lengths","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,7]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Memoize","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[14,0]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Freeze Real Time","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[21,0]}}},"network_metadata":null}}],[4,{"persistent_metadata":{"reference":null,"display_name":"Boundless Footprint","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[28,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,991.0,581.0],"node_graph_top_right":[1980.796875,0.0]},"selection_undo_history":[[]],"selection_redo_history":[]}}}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[393.8840949272409,-703.048313613491],"tilt":0.0,"zoom":0.7533811475409836,"flip":false},"node_graph_to_viewport":[0.7533811475409836,0.0,0.0,0.7533811475409836,1287.0,51.0],"node_graph_top_right":[1980.796875,0.0]},"selection_undo_history":[[6097807941755042226,15385259560644295534,17327221498641745184,12317719117993811200,9069881382900058607],[17327221498641745184],[6097807941755042226,15385259560644295534,17327221498641745184,12317719117993811200,9069881382900058607],[6097807941755042226,5883606306991910210,2128810469968776913,12416569579970107543,13644002059194136823,17437077810654043142,15002088321732485705],[6097807941755042226,15385259560644295534,17327221498641745184,12317719117993811200,9069881382900058607],[2128810469968776913],[6097807941755042226,15385259560644295534,17327221498641745184,12317719117993811200,9069881382900058607],[15385259560644295534],[6097807941755042226,15385259560644295534,17327221498641745184,12317719117993811200,9069881382900058607],[2128810469968776913,12416569579970107543,13644002059194136823,17437077810654043142,15002088321732485705],[6097807941755042226,15385259560644295534,17327221498641745184,12317719117993811200,9069881382900058607],[13676600738025998635],[2128810469968776913],[11435147660766496741],[15726496377243608372],[4390668436091073484],[11386926595254122633],[11435147660766496741],[15726496377243608372],[15726496377243608372,11435147660766496741,2163528024003768644,12110920487474373676,12639486733043466090,8804763001225416124],[11435147660766496741,2163528024003768644,12110920487474373676,12639486733043466090,8804763001225416124,15726496377243608372],[11435147660766496741],[11435147660766496741,2163528024003768644,12110920487474373676,12639486733043466090,8804763001225416124,15726496377243608372],[11435147660766496741,15726496377243608372,4390668436091073484,11386926595254122633,13676600738025998635,2128810469968776913],[11435147660766496741,2163528024003768644,12110920487474373676,12639486733043466090,8804763001225416124,15726496377243608372],[11435147660766496741],[11435147660766496741,2163528024003768644,12110920487474373676,12639486733043466090,8804763001225416124,15726496377243608372],[4390668436091073484,11386926595254122633,13676600738025998635,2128810469968776913],[11435147660766496741,2163528024003768644,12110920487474373676,12639486733043466090,8804763001225416124,15726496377243608372],[11435147660766496741,2163528024003768644,7128559142392931896,12110920487474373676,13323241418027154136,12639486733043466090,1801066723091712434,8804763001225416124,17154757625902243313,4390668436091073484,12122314434656187176,16611856724057842399,10686861494573327243,10806978668166337270,11386926595254122633,6523786079462141312,13676600738025998635,6097807941755042226,5883606306991910210,15385259560644295534,3726756269632080543,17327221498641745184,3683309254695891012,12317719117993811200,17239043462037837834,9069881382900058607,4037968351431607570,2128810469968776913,12416569579970107543,13644002059194136823,17437077810654043142,15002088321732485705],[11435147660766496741,2163528024003768644,12110920487474373676,12639486733043466090,8804763001225416124,15726496377243608372],[4390668436091073484,11386926595254122633,13676600738025998635,2128810469968776913],[11435147660766496741,2163528024003768644,12110920487474373676,12639486733043466090,8804763001225416124,15726496377243608372],[15726496377243608372],[11435147660766496741,2163528024003768644,12110920487474373676,12639486733043466090,8804763001225416124,15726496377243608372],[4390668436091073484,12122314434656187176,16611856724057842399,10686861494573327243,10806978668166337270,11386926595254122633,6523786079462141312,13676600738025998635,6097807941755042226,5883606306991910210,15385259560644295534,3726756269632080543,17327221498641745184,3683309254695891012,12317719117993811200,17239043462037837834,9069881382900058607,4037968351431607570,2128810469968776913,12416569579970107543,13644002059194136823,17437077810654043142,15002088321732485705],[11435147660766496741,2163528024003768644,12110920487474373676,12639486733043466090,8804763001225416124,15726496377243608372],[13132104524813958174],[11435147660766496741],[2163528024003768644],[12110920487474373676],[12639486733043466090],[8804763001225416124],[11435147660766496741],[15726496377243608372],[3934928477288442109],[239716716021064150],[15726496377243608372],[15726496377243608372,11435147660766496741],[239716716021064150],[239716716021064150,7711570794020903773],[239716716021064150,3934928477288442109],[4390668436091073484],[12122314434656187176],[10686861494573327243],[11386926595254122633],[4390668436091073484],[13676600738025998635,2128810469968776913],[13676600738025998635,6097807941755042226,5883606306991910210,15385259560644295534,3726756269632080543,17327221498641745184,3683309254695891012,12317719117993811200,17239043462037837834,9069881382900058607,4037968351431607570,2128810469968776913,12416569579970107543,13644002059194136823,17437077810654043142,15002088321732485705],[11386926595254122633],[13676600738025998635],[6097807941755042226],[15385259560644295534],[17327221498641745184],[12317719117993811200],[9069881382900058607],[2128810469968776913],[13132104524813958174],[2128810469968776913],[13132104524813958174],[2163528024003768644],[239716716021064150],[3934928477288442109],[8804763001225416124],[12639486733043466090],[12110920487474373676],[2163528024003768644],[4390668436091073484],[13676600738025998635],[2128810469968776913],[2163528024003768644],[9069881382900058607],[12317719117993811200,9069881382900058607],[17327221498641745184,12317719117993811200,9069881382900058607],[15385259560644295534,17327221498641745184,12317719117993811200,9069881382900058607],[12317719117993811200,15385259560644295534,9069881382900058607,17327221498641745184,6097807941755042226],[17327221498641745184,12317719117993811200,11386926595254122633,6097807941755042226,9069881382900058607,15385259560644295534],[9069881382900058607,6097807941755042226,10686861494573327243,15385259560644295534,11386926595254122633,12317719117993811200,17327221498641745184],[10686861494573327243,15385259560644295534,12122314434656187176,11386926595254122633,9069881382900058607,6097807941755042226,12317719117993811200,17327221498641745184],[12122314434656187176,6097807941755042226,11386926595254122633,12317719117993811200,17327221498641745184,10686861494573327243,239716716021064150,15385259560644295534,9069881382900058607],[9069881382900058607,239716716021064150,6097807941755042226,12122314434656187176,12317719117993811200,10686861494573327243,15385259560644295534,17327221498641745184,11386926595254122633,3934928477288442109],[9069881382900058607,13676600738025998635,3934928477288442109,12122314434656187176,6097807941755042226,15385259560644295534,4390668436091073484,10686861494573327243,17327221498641745184,11386926595254122633,12317719117993811200,239716716021064150],[6097807941755042226,3934928477288442109,4390668436091073484,9069881382900058607,13676600738025998635,11386926595254122633,15385259560644295534,12122314434656187176,8804763001225416124,10686861494573327243,239716716021064150,12317719117993811200,17327221498641745184],[9069881382900058607,12122314434656187176,13676600738025998635,10686861494573327243,12317719117993811200,6097807941755042226,15385259560644295534,239716716021064150,17327221498641745184,11386926595254122633,3934928477288442109,8804763001225416124,12639486733043466090,4390668436091073484],[10686861494573327243,15385259560644295534,17327221498641745184,239716716021064150,8804763001225416124,6097807941755042226,11386926595254122633,12317719117993811200,12122314434656187176,9069881382900058607,3934928477288442109,12639486733043466090],[10686861494573327243,17327221498641745184,12317719117993811200,11386926595254122633,12639486733043466090,12122314434656187176,9069881382900058607,6097807941755042226,12110920487474373676,3934928477288442109,15385259560644295534,8804763001225416124,239716716021064150],[12110920487474373676,10686861494573327243,11386926595254122633,12317719117993811200,8804763001225416124,3934928477288442109,9069881382900058607,15385259560644295534,2163528024003768644,17327221498641745184,239716716021064150,12639486733043466090,12122314434656187176,6097807941755042226],[2128810469968776913],[17327221498641745184],[]],"selection_redo_history":[]}}},"collapsed":[4390668436091073485,13676600738025998636,13132104524813958175],"name":"parametric-dunescape.graphite","commit_hash":"c4e16e1aac642bbcde72f41f86deed79e6e38006","document_ptz":{"pan":[-999.515765085624,-500.18277881031514],"tilt":0.0,"zoom":0.940975,"flip":false},"document_mode":"DesignMode","view_mode":"Normal","overlays_visibility_settings":{"all":true,"artboard_name":true,"compass_rose":true,"quick_measurement":true,"transform_measurement":true,"transform_cage":true,"hover_outline":true,"selection_outline":true,"pivot":true,"path":true,"anchors":true,"handles":true},"rulers_visible":true,"snapping_state":{"snapping_enabled":true,"grid_snapping":false,"artboards":true,"tolerance":8.0,"bounding_box":{"center_point":true,"corner_point":true,"edge_midpoint":true,"align_with_edges":true,"distribute_evenly":true},"path":{"anchor_point":true,"line_midpoint":true,"along_path":true,"normal_to_path":true,"tangent_to_path":true,"path_intersection_point":true,"align_with_anchor_point":true,"perpendicular_from_endpoint":true},"grid":{"origin":[0.0,0.0],"grid_type":{"Rectangular":{"spacing":[1.0,1.0]}},"rectangular_spacing":[1.0,1.0],"isometric_y_spacing":1.0,"isometric_angle_a":30.0,"isometric_angle_b":30.0,"grid_color":{"red":0.6038274,"green":0.6038274,"blue":0.6038274,"alpha":1.0},"dot_display":false}},"graph_view_overlay_open":false,"graph_fade_artwork_percentage":80.0} \ No newline at end of file diff --git a/demo-artwork/procedural-string-lights.graphite b/demo-artwork/procedural-string-lights.graphite new file mode 100644 index 0000000000000000000000000000000000000000..7a705914f5a85586a787436dfa283150229b1099 --- /dev/null +++ b/demo-artwork/procedural-string-lights.graphite @@ -0,0 +1 @@ +{"network_interface":{"network":{"exports":[{"Node":{"node_id":14972365039974885000,"output_index":0,"lambda":false}}],"nodes":[[183562335973647870,{"inputs":[{"Node":{"node_id":4248875763694880300,"output_index":0,"lambda":false}},{"Node":{"node_id":2181148486404191200,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[665049002420596400,{"inputs":[{"Value":{"tagged_value":{"VectorData":{"instance":[{"style":{"stroke":{"color":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0},"weight":0.0,"dash_lengths":[],"dash_offset":0.0,"cap":"Butt","join":"Miter","join_miter_limit":4.0,"align":"Center","transform":[1.0,0.0,0.0,1.0,0.0,0.0],"non_scaling":false,"paint_order":"StrokeAbove"},"fill":"None"},"colinear_manipulators":[],"point_domain":{"id":[],"position":[]},"segment_domain":{"id":[],"start_point":[],"end_point":[],"handles":[],"stroke":[]},"region_domain":{"id":[],"segment_range":[],"fill":[]},"upstream_graphic_group":null}],"transform":[[1.0,0.0,0.0,1.0,0.0,0.0]],"alpha_blending":[{"blend_mode":"Normal","opacity":1.0,"fill":1.0,"clip":false}],"source_node_id":[null]}},"exposed":true}},{"Value":{"tagged_value":{"VectorModification":{"points":{"add":[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34],"remove":[],"delta":[[1,[-103.55555555555554,126.66666666666664]],[22,[71.11111111111109,-201.7777777777778]],[3,[45.77777777777777,145.33333333333331]],[9,[156.4444444444444,97.33333333333331]],[6,[123.99999999999994,148.4444444444444]],[30,[-9.333333333333371,0.0]],[20,[128.4444444444444,-142.22222222222223]],[28,[39.111111111111086,-58.22222222222226]],[16,[159.5555555555555,-75.55555555555557]],[21,[76.0,-202.22222222222223]],[26,[22.66666666666663,-81.33333333333337]],[8,[252.4444444444444,124.88888888888886]],[24,[57.77777777777777,-129.33333333333334]],[33,[-78.22222222222223,75.55555555555554]],[18,[145.77777777777777,-97.7777777777778]],[13,[153.77777777777777,-1.3333333333333712]],[19,[90.66666666666664,-129.33333333333334]],[15,[111.11111111111114,-60.888888888888914]],[7,[229.33333333333331,152.4444444444444]],[17,[123.99999999999994,-84.00000000000003]],[4,[18.66666666666663,157.77777777777771]],[25,[0.8888888888888573,-94.66666666666669]],[10,[216.4444444444444,72.4444444444444]],[23,[19.555555555555543,-139.55555555555557]],[12,[199.5555555555555,10.666666666666629]],[5,[66.22222222222223,152.88888888888886]],[31,[-53.33333333333337,13.777777777777771]],[11,[136.88888888888886,39.111111111111086]],[29,[-32.888888888888914,-14.666666666666686]],[32,[9.333333333333314,38.66666666666663]],[27,[-11.111111111111144,-72.00000000000003]],[34,[-5.333333333333371,99.11111111111109]],[2,[-67.55555555555554,158.22222222222217]],[14,[183.11111111111103,-19.111111111111143]]]},"segments":{"add":[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34],"remove":[],"start_point":[[13,13],[9,9],[34,34],[18,18],[32,32],[28,28],[21,21],[12,12],[25,25],[3,3],[22,22],[29,29],[1,1],[20,20],[2,2],[10,10],[19,19],[6,6],[17,17],[30,30],[5,5],[8,8],[16,16],[33,33],[14,14],[11,11],[15,15],[26,26],[24,24],[7,7],[23,23],[27,27],[31,31],[4,4]],"end_point":[[30,31],[14,15],[20,21],[2,3],[26,27],[15,16],[24,25],[17,18],[22,23],[16,17],[5,6],[4,5],[11,12],[7,8],[1,2],[34,1],[21,22],[18,19],[29,30],[19,20],[32,33],[33,34],[31,32],[3,4],[8,9],[25,26],[9,10],[27,28],[6,7],[13,14],[28,29],[12,13],[23,24],[10,11]],"handle_primary":[[18,[0.0,0.0]],[7,[24.88888888888891,-15.111111111111086]],[32,[0.0,0.0]],[28,[0.0,0.0]],[2,[30.66666666666663,2.6666666666666856]],[9,[0.0,0.0]],[20,[0.0,0.0]],[29,[0.0,0.0]],[8,[0.0,0.0]],[11,[0.0,0.0]],[27,[0.0,0.0]],[10,[0.0,0.0]],[16,[0.0,0.0]],[31,[0.0,0.0]],[21,[0.0,0.0]],[15,[0.0,0.0]],[1,[0.0,0.0]],[5,[0.0,0.0]],[33,[0.0,0.0]],[6,[0.0,0.0]],[22,[0.0,0.0]],[14,[0.0,0.0]],[25,[0.0,0.0]],[26,[0.0,0.0]],[34,[0.0,0.0]],[4,[0.0,0.0]],[24,[0.0,0.0]],[19,[0.0,0.0]],[12,[0.0,0.0]],[13,[0.0,0.0]],[23,[0.0,0.0]],[30,[0.0,0.0]],[3,[0.0,0.0]],[17,[0.0,0.0]]],"handle_end":[[33,[-64.44444444444446,3.111111111111157]],[3,[8.4444444444444,-0.8888888888889142]],[31,[-42.22222222222223,5.333333333333314]],[13,[-13.333333333333371,14.222222222222229]],[9,[-34.222222222222285,36.0]],[23,[-35.55555555555554,11.1111111111111]],[27,[-39.55555555555554,12.444444444444429]],[1,[-30.666666666666615,-2.6666666666666856]],[34,[65.7777777777778,12.444444444444445]],[14,[29.33333333333337,57.77777777777777]],[8,[36.0,41.77777777777777]],[4,[-31.555555555555543,18.22222222222223]],[2,[-51.111111111111086,14.666666666666686]],[6,[-24.88888888888891,15.111111111111086]],[24,[47.55555555555554,4.888888888888886]],[16,[6.666666666666629,13.333333333333314]],[15,[-12.444444444444455,28.444444444444457]],[18,[13.3333333333333,41.33333333333334]],[21,[0.0,0.0]],[30,[35.111111111111086,1.333333333333373]],[26,[26.22222222222223,2.666666666666657]],[5,[-13.333333333333384,14.222222222222229]],[11,[-24.0,31.555555555555543]],[7,[0.0,0.0]],[20,[13.333333333333371,70.22222222222223]],[17,[-10.222222222222172,12.444444444444455]],[12,[18.66666666666663,16.0]],[25,[-11.111111111111144,-1.7777777777778]],[10,[26.66666666666663,44.44444444444446]],[22,[38.22222222222223,4.888888888888886]],[32,[55.111111111111086,9.777777777777771]],[28,[54.66666666666663,6.666666666666686]],[29,[-17.77777777777777,-3.555555555555543]],[19,[-9.777777777777844,23.55555555555557]]],"stroke":[[28,0],[14,0],[23,0],[2,0],[34,0],[11,0],[15,0],[31,0],[33,0],[9,0],[12,0],[1,0],[6,0],[21,0],[24,0],[3,0],[22,0],[25,0],[13,0],[18,0],[30,0],[10,0],[29,0],[27,0],[4,0],[16,0],[26,0],[17,0],[8,0],[19,0],[5,0],[20,0],[7,0],[32,0]]},"regions":{"add":[0],"remove":[],"segment_range":[[0,{"start":1,"end":34}]],"fill":[[0,0]]},"add_g1_continuous":[],"remove_g1_continuous":[]}},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::vector_data::modification::VectorModification","alias":null}},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::vector_data::modification::PathModifyNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[14972365039974885000,{"inputs":[{"Value":{"tagged_value":{"ArtboardGroup":{"instance":[],"transform":[],"alpha_blending":[],"source_node_id":[]}},"exposed":true}},{"Node":{"node_id":3471929742275053000,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"IVec2":[0,0]},"exposed":false}},{"Value":{"tagged_value":{"IVec2":[1000,1000]},"exposed":false}},{"Value":{"tagged_value":{"Color":{"red":1.0,"green":1.0,"blue":1.0,"alpha":1.0}},"exposed":false}},{"Value":{"tagged_value":{"Bool":false},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":2,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graph_craft::document::value::TaggedValue","alias":null}},"import_index":1}},{"Value":{"tagged_value":{"String":"Artboard"},"exposed":false}},{"Network":{"import_type":{"Concrete":{"name":"graph_craft::document::value::TaggedValue","alias":null}},"import_index":2}},{"Network":{"import_type":{"Concrete":{"name":"graph_craft::document::value::TaggedValue","alias":null}},"import_index":3}},{"Network":{"import_type":{"Concrete":{"name":"graph_craft::document::value::TaggedValue","alias":null}},"import_index":4}},{"Network":{"import_type":{"Concrete":{"name":"graph_craft::document::value::TaggedValue","alias":null}},"import_index":5}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToArtboardNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Network":{"import_type":{"Fn":[{"Concrete":{"name":"core::option::Option>","alias":null}},{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}}]},"import_index":0}},{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::AppendArtboardNode"}},"visible":true,"skip_deduplication":false}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[13394621587544123000,{"inputs":[{"Node":{"node_id":13907401402762847509,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"Fill":{"Solid":{"red":0.6484375,"green":0.6484375,"blue":0.6484375,"alpha":1.0}}},"exposed":false}},{"Value":{"tagged_value":{"OptionalColor":{"red":0.6484375,"green":0.6484375,"blue":0.6484375,"alpha":1.0}},"exposed":false}},{"Value":{"tagged_value":{"Gradient":{"stops":[[0.0,{"red":0.91796875,"green":0.68489075,"blue":0.68489075,"alpha":1.0}],[1.0,{"red":0.8862745,"green":0.16470589,"blue":0.16470589,"alpha":1.0}]],"gradient_type":"Radial","start":[0.4915209831246563,0.36613756613756576],"end":[0.49551110871305326,0.9947089947089944],"transform":[250.61867799546343,0.0,0.0,472.4999999999999,809.8156610022683,336.0000000000002]}},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::FillNode"}},"visible":true,"skip_deduplication":false}],[11411423299989983000,{"inputs":[{"Node":{"node_id":16877573495957869000,"output_index":0,"lambda":false}},{"Node":{"node_id":3958246774416220000,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[14631609508767818000,{"inputs":[{"Node":{"node_id":15889416971203222000,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"DVec2":[487.1243076693745,127.7443401649906]},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[25.393705016577044,25.003032631706716]},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[0.0,0.0]},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[0.5,0.5]},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":1}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":2}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":3}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":4}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":5}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::TransformNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[2908374490615384600,{"inputs":[{"Node":{"node_id":17339085479159577000,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"Fill":{"Solid":{"red":0.078431375,"green":0.14901961,"blue":0.20784314,"alpha":1.0}}},"exposed":false}},{"Value":{"tagged_value":{"OptionalColor":{"red":0.078431375,"green":0.14901961,"blue":0.20784314,"alpha":1.0}},"exposed":false}},{"Value":{"tagged_value":{"Gradient":{"stops":[[0.0,{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}],[1.0,{"red":1.0,"green":1.0,"blue":1.0,"alpha":1.0}]],"gradient_type":"Linear","start":[0.0,0.5],"end":[1.0,0.5],"transform":[1.0,0.0,0.0,1.0,0.0,0.0]}},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::FillNode"}},"visible":true,"skip_deduplication":false}],[16765094648901306000,{"inputs":[{"Value":{"tagged_value":{"GraphicGroup":{"instance":[],"transform":[],"alpha_blending":[],"source_node_id":[]}},"exposed":true}},{"Node":{"node_id":8147814087664910471,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[655907162126315400,{"inputs":[{"Value":{"tagged_value":{"VectorData":{"instance":[{"style":{"stroke":{"color":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0},"weight":0.0,"dash_lengths":[],"dash_offset":0.0,"cap":"Butt","join":"Miter","join_miter_limit":4.0,"align":"Center","transform":[1.0,0.0,0.0,1.0,0.0,0.0],"non_scaling":false,"paint_order":"StrokeAbove"},"fill":"None"},"colinear_manipulators":[],"point_domain":{"id":[],"position":[]},"segment_domain":{"id":[],"start_point":[],"end_point":[],"handles":[],"stroke":[]},"region_domain":{"id":[],"segment_range":[],"fill":[]},"upstream_graphic_group":null}],"transform":[[1.0,0.0,0.0,1.0,0.0,0.0]],"alpha_blending":[{"blend_mode":"Normal","opacity":1.0,"fill":1.0,"clip":false}],"source_node_id":[null]}},"exposed":true}},{"Value":{"tagged_value":{"VectorModification":{"points":{"add":[1,2,3,4,5,6,7,8,9,10,11],"remove":[],"delta":[[11,[186.0,824.9999999999999]],[9,[750.0,703.9999999999999]],[4,[484.0,446.9999999999999]],[6,[495.0,533.9999999999999]],[2,[587.0,291.9999999999999]],[10,[455.0,824.9999999999999]],[3,[373.0,372.9999999999999]],[1,[416.0,270.9999999999999]],[7,[304.0,611.9999999999999]],[8,[475.0,671.9999999999999]],[5,[639.0,438.9999999999999]]]},"segments":{"add":[1,2,3,4,5,6,7,8,9,10],"remove":[],"start_point":[[7,7],[9,9],[5,5],[4,4],[10,10],[8,8],[6,6],[3,3],[1,1],[2,2]],"end_point":[[2,3],[3,4],[4,5],[5,6],[8,9],[7,8],[6,7],[1,2],[9,10],[10,11]],"handle_primary":[[10,[0.0,0.0]],[6,[0.0,0.0]],[5,[0.0,0.0]],[8,[0.0,0.0]],[3,[0.0,0.0]],[9,[0.0,0.0]],[2,[0.0,0.0]],[4,[0.0,0.0]],[1,[0.0,0.0]],[7,[0.0,0.0]]],"handle_end":[[8,[0.0,0.0]],[10,[0.0,0.0]],[1,[0.0,0.0]],[9,[0.0,0.0]],[7,[0.0,0.0]],[3,[0.0,0.0]],[2,[0.0,0.0]],[4,[0.0,0.0]],[5,[0.0,0.0]],[6,[0.0,0.0]]],"stroke":[[8,0],[5,0],[10,0],[3,0],[2,0],[9,0],[4,0],[7,0],[6,0],[1,0]]},"regions":{"add":[],"remove":[],"segment_range":[],"fill":[]},"add_g1_continuous":[],"remove_g1_continuous":[]}},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::vector_data::modification::VectorModification","alias":null}},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::vector_data::modification::PathModifyNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[16877573495957869000,{"inputs":[{"Node":{"node_id":4534782777857480700,"output_index":0,"lambda":false}},{"Node":{"node_id":5737014828407011000,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[5737014828407011000,{"inputs":[{"Node":{"node_id":10504222558938851000,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"DVec2":[499.21344163872624,106.32837674079803]},"exposed":false}},{"Value":{"tagged_value":{"F64":3.141592653589793},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[55.110312549931045,55.110312549931045]},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[-1.921525468856923e-16,0.0]},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[0.5,0.5]},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":1}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":2}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":3}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":4}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":5}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::TransformNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[10504222558938851000,{"inputs":[{"Node":{"node_id":13571989088655643000,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"Fill":{"Gradient":{"stops":[[0.0,{"red":1.0,"green":0.94460994,"blue":0.79296875,"alpha":1.0}],[1.0,{"red":0.89411765,"green":0.654902,"blue":0.0,"alpha":1.0}]],"gradient_type":"Radial","start":[0.4703098217208352,0.4995258072961386],"end":[0.9924395932459462,0.5005395053456176],"transform":[237.34320332463173,-71.34811668265112,75.01984946235177,249.55741247555255,995.9008094918244,343.8953521035491]}}},"exposed":false}},{"Value":{"tagged_value":{"OptionalColor":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}},"exposed":false}},{"Value":{"tagged_value":{"Gradient":{"stops":[[0.0,{"red":1.0,"green":0.94460994,"blue":0.79296875,"alpha":1.0}],[1.0,{"red":0.89411765,"green":0.654902,"blue":0.0,"alpha":1.0}]],"gradient_type":"Radial","start":[0.4703098217208352,0.4995258072961386],"end":[0.9924395932459462,0.5005395053456176],"transform":[237.34320332463173,-71.34811668265112,75.01984946235177,249.55741247555255,995.9008094918244,343.8953521035491]}},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::FillNode"}},"visible":true,"skip_deduplication":false}],[4248875763694880300,{"inputs":[{"Value":{"tagged_value":{"GraphicGroup":{"instance":[],"transform":[],"alpha_blending":[],"source_node_id":[]}},"exposed":true}},{"Node":{"node_id":7297408968096180000,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[3471929742275053000,{"inputs":[{"Node":{"node_id":11411423299989983000,"output_index":0,"lambda":false}},{"Node":{"node_id":4217566479741824000,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[169695252050218443,{"inputs":[{"Node":{"node_id":6559102076450693000,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"Fill":{"Gradient":{"stops":[[0.0,{"red":1.0,"green":1.0,"blue":1.0,"alpha":0.75}],[1.0,{"red":1.0,"green":1.0,"blue":1.0,"alpha":0.01}]],"gradient_type":"Radial","start":[0.4915209831246563,0.36613756613756576],"end":[0.49551110871305326,0.9947089947089944],"transform":[250.61867799546343,0.0,0.0,472.4999999999999,809.8156610022683,336.0000000000002]}}},"exposed":false}},{"Value":{"tagged_value":{"OptionalColor":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}},"exposed":false}},{"Value":{"tagged_value":{"Gradient":{"stops":[[0.0,{"red":1.0,"green":1.0,"blue":1.0,"alpha":0.7734375}],[1.0,{"red":1.0,"green":1.0,"blue":1.0,"alpha":0.01}]],"gradient_type":"Radial","start":[0.4915209831246563,0.36613756613756576],"end":[0.49551110871305326,0.9947089947089944],"transform":[250.61867799546343,0.0,0.0,472.4999999999999,809.8156610022683,336.0000000000002]}},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::FillNode"}},"visible":true,"skip_deduplication":false}],[5250960114142560178,{"inputs":[{"Node":{"node_id":655907162126315400,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"OptionalColor":{"red":0.18629456,"green":0.18054199,"blue":0.2265625,"alpha":1.0}},"exposed":false}},{"Value":{"tagged_value":{"F64":8.0},"exposed":false}},{"Value":{"tagged_value":{"StrokeAlign":"Center"},"exposed":false}},{"Value":{"tagged_value":{"StrokeCap":"Round"},"exposed":false}},{"Value":{"tagged_value":{"StrokeJoin":"Miter"},"exposed":false}},{"Value":{"tagged_value":{"F64":4.0},"exposed":false}},{"Value":{"tagged_value":{"PaintOrder":"StrokeAbove"},"exposed":false}},{"Value":{"tagged_value":{"VecF64":[]},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::StrokeNode"}},"visible":true,"skip_deduplication":false}],[17339085479159577000,{"inputs":[{"Value":{"tagged_value":{"VectorData":{"instance":[{"style":{"stroke":{"color":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0},"weight":0.0,"dash_lengths":[],"dash_offset":0.0,"cap":"Butt","join":"Miter","join_miter_limit":4.0,"align":"Center","transform":[1.0,0.0,0.0,1.0,0.0,0.0],"non_scaling":false,"paint_order":"StrokeAbove"},"fill":"None"},"colinear_manipulators":[],"point_domain":{"id":[],"position":[]},"segment_domain":{"id":[],"start_point":[],"end_point":[],"handles":[],"stroke":[]},"region_domain":{"id":[],"segment_range":[],"fill":[]},"upstream_graphic_group":null}],"transform":[[1.0,0.0,0.0,1.0,0.0,0.0]],"alpha_blending":[{"blend_mode":"Normal","opacity":1.0,"fill":1.0,"clip":false}],"source_node_id":[null]}},"exposed":true}},{"Value":{"tagged_value":{"VectorModification":{"points":{"add":[1,2,3,4,5,6,7],"remove":[],"delta":[[2,[122.22222222222224,196.4444444444444]],[7,[66.51851851851853,147.1111111111111]],[6,[58.962962962962976,152.74074074074073]],[3,[123.55555555555554,199.1111111111111]],[4,[28.296296296296305,198.96296296296293]],[5,[28.296296296296305,197.33333333333331]],[1,[88.4444444444444,151.55555555555554]]]},"segments":{"add":[1,2,3,4,5,6,7],"remove":[],"start_point":[[5,5],[2,2],[7,7],[6,6],[3,3],[4,4],[1,1]],"end_point":[[4,5],[1,2],[7,1],[5,6],[3,4],[6,7],[2,3]],"handle_primary":[[7,[0.0,0.0]],[1,[0.0,0.0]],[6,[0.0,0.0]],[2,[0.0,0.0]],[5,[0.0,0.0]],[3,[0.0,0.0]],[4,[0.0,0.0]]],"handle_end":[[3,[0.0,0.0]],[4,[0.0,0.0]],[5,[5.92592592592591,45.77777777777786]],[2,[0.0,0.0]],[6,[0.0,0.0]],[1,[-32.0,-3.5555555555555145]],[7,[0.0,0.0]]],"stroke":[[6,0],[1,0],[7,0],[4,0],[3,0],[2,0],[5,0]]},"regions":{"add":[0],"remove":[],"segment_range":[[0,{"start":1,"end":7}]],"fill":[[0,0]]},"add_g1_continuous":[],"remove_g1_continuous":[]}},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::vector_data::modification::VectorModification","alias":null}},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::vector_data::modification::PathModifyNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[13571989088655643000,{"inputs":[{"Value":{"tagged_value":"None","exposed":false}},{"Value":{"tagged_value":{"U32":5},"exposed":false}},{"Value":{"tagged_value":{"F64":0.5},"exposed":false}},{"Value":{"tagged_value":{"F64":1.0},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::generator_nodes::StarNode"}},"visible":true,"skip_deduplication":false}],[8147814087664910471,{"inputs":[{"Node":{"node_id":2866788868013687300,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"Fill":{"Solid":{"red":0.3372549,"green":0.33333334,"blue":0.40784314,"alpha":1.0}}},"exposed":false}},{"Value":{"tagged_value":{"OptionalColor":{"red":0.3372549,"green":0.33333334,"blue":0.40784314,"alpha":1.0}},"exposed":false}},{"Value":{"tagged_value":{"Gradient":{"stops":[[0.0,{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}],[1.0,{"red":1.0,"green":1.0,"blue":1.0,"alpha":1.0}]],"gradient_type":"Linear","start":[0.0,0.5],"end":[1.0,0.5],"transform":[1.0,0.0,0.0,1.0,0.0,0.0]}},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::FillNode"}},"visible":true,"skip_deduplication":false}],[13907401402762847509,{"inputs":[{"Value":{"tagged_value":{"VectorData":{"instance":[{"style":{"stroke":{"color":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0},"weight":0.0,"dash_lengths":[],"dash_offset":0.0,"cap":"Butt","join":"Miter","join_miter_limit":4.0,"align":"Center","transform":[1.0,0.0,0.0,1.0,0.0,0.0],"non_scaling":false,"paint_order":"StrokeAbove"},"fill":"None"},"colinear_manipulators":[],"point_domain":{"id":[10666000720855117911,12291367210538906710,11079673538758176715,9852417284720842144,13528392218319754720],"position":[[0.0,16.600000381469727],[13.314000129699709,30.4060001373291],[0.0,66.8030014038086],[-13.314000129699709,30.4060001373291],[0.0,16.600000381469727]]},"segment_domain":{"id":[1,2,3,4,5],"start_point":[0,1,2,3,4],"end_point":[1,2,3,4,0],"handles":[{"Cubic":{"handle_start":[7.347000122070312,16.600000381469727],"handle_end":[13.314000129699709,22.788000106811523]}},{"Cubic":{"handle_start":[13.314000129699709,38.02399826049805],"handle_end":[4.480999946594238,66.8030014038086]}},{"Cubic":{"handle_start":[-4.480999946594238,66.8030014038086],"handle_end":[-13.314000129699709,38.02299880981445]}},{"Cubic":{"handle_start":[-13.314000129699709,22.788000106811523],"handle_end":[-7.347000122070312,16.600000381469727]}},{"Cubic":{"handle_start":[0.0,16.600000381469727],"handle_end":[0.0,16.600000381469727]}}],"stroke":[0,0,0,0,0]},"region_domain":{"id":[0],"segment_range":[{"start":1,"end":5}],"fill":[0]},"upstream_graphic_group":null}],"transform":[[1.0,0.0,0.0,1.0,0.0,0.0]],"alpha_blending":[{"blend_mode":"Normal","opacity":1.0,"fill":1.0,"clip":false}],"source_node_id":[null]}},"exposed":false}},{"Value":{"tagged_value":{"VectorModification":{"points":{"add":[],"remove":[13528392218319754720],"delta":[]},"segments":{"add":[4],"remove":[5],"start_point":[[4,9852417284720842144]],"end_point":[[4,10666000720855117911]],"handle_primary":[[4,[0.0,-7.618000030517578]]],"handle_end":[[4,[-7.34700012207,-3.552713678800501e-15]]],"stroke":[[4,0]]},"regions":{"add":[],"remove":[],"segment_range":[],"fill":[]},"add_g1_continuous":[],"remove_g1_continuous":[[{"ty":"End","segment":4},{"ty":"Primary","segment":1}],[{"ty":"End","segment":4},{"ty":"Primary","segment":5}]]}},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::vector_data::modification::VectorModification","alias":null}},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::vector_data::modification::PathModifyNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[6559102076450693000,{"inputs":[{"Node":{"node_id":13907401402762847509,"output_index":0,"lambda":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}],[2866788868013687300,{"inputs":[{"Node":{"node_id":8496292024993914696,"output_index":0,"lambda":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}],[4331062027851128000,{"inputs":[{"Node":{"node_id":665049002420596400,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"Fill":{"Gradient":{"stops":[[0.0,{"red":0.1764706,"green":0.25882354,"blue":0.32156864,"alpha":1.0}],[1.0,{"red":0.16577148,"green":0.37890625,"blue":0.36788198,"alpha":1.0}]],"gradient_type":"Linear","start":[0.3769992978075994,0.1888891278143931],"end":[0.9861902161192166,0.9200728483862376],"transform":[801.0625,0.0,0.0,820.5871973335948,698.0,185.0]}}},"exposed":false}},{"Value":{"tagged_value":{"OptionalColor":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}},"exposed":false}},{"Value":{"tagged_value":{"Gradient":{"stops":[[0.0,{"red":0.1764706,"green":0.25882354,"blue":0.32156864,"alpha":1.0}],[1.0,{"red":0.16577148,"green":0.37890625,"blue":0.36788198,"alpha":1.0}]],"gradient_type":"Linear","start":[0.3769992978075994,0.1888891278143931],"end":[0.9861902161192166,0.9200728483862376],"transform":[801.0625,0.0,0.0,820.5871973335948,698.0,185.0]}},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::FillNode"}},"visible":true,"skip_deduplication":false}],[11815560782623298000,{"inputs":[{"Node":{"node_id":16765094648901306000,"output_index":0,"lambda":false}},{"Node":{"node_id":13394621587544123000,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[13371003476981866000,{"inputs":[{"Node":{"node_id":11815560782623298000,"output_index":0,"lambda":false}},{"Node":{"node_id":169695252050218443,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[4534782777857480700,{"inputs":[{"Node":{"node_id":183562335973647870,"output_index":0,"lambda":false}},{"Node":{"node_id":14631609508767818000,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[17790961655412892000,{"inputs":[{"Node":{"node_id":12728151724950013388,"output_index":0,"lambda":false}},{"Node":{"node_id":13371003476981866000,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"F64":1.0},"exposed":false}},{"Value":{"tagged_value":{"F64":1.0},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"U32":0},"exposed":false}},{"Value":{"tagged_value":{"F64":10.0},"exposed":false}},{"Value":{"tagged_value":{"U32":0},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::CopyToPointsNode"}},"visible":true,"skip_deduplication":false}],[2181148486404191200,{"inputs":[{"Node":{"node_id":4331062027851128000,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"DVec2":[353.5143520436918,551.6238777493922]},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[1.9777789484064812,1.9777789484064812]},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[0.0,0.0]},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[0.5,0.5]},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":1}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":2}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":3}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":4}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":5}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::TransformNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[4217566479741824000,{"inputs":[{"Node":{"node_id":17790961655412892000,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"Bool":true},"exposed":false}},{"Value":{"tagged_value":{"Bool":false},"exposed":false}},{"Value":{"tagged_value":{"GradientStops":[[0.0,{"red":0.16470589,"green":0.8862745,"blue":0.4117647,"alpha":1.0}],[0.5,{"red":0.8862745,"green":0.16470589,"blue":0.16470589,"alpha":1.0}],[1.0,{"red":0.16470589,"green":0.54901963,"blue":0.8862745,"alpha":1.0}]]},"exposed":false}},{"Value":{"tagged_value":{"Bool":false},"exposed":false}},{"Value":{"tagged_value":{"Bool":false},"exposed":false}},{"Value":{"tagged_value":{"U32":0},"exposed":false}},{"Value":{"tagged_value":{"U32":3},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::AssignColorsNode"}},"visible":true,"skip_deduplication":false}],[3958246774416220000,{"inputs":[{"Node":{"node_id":5250960114142560178,"output_index":0,"lambda":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::SplineNode"}},"visible":true,"skip_deduplication":false}],[7297408968096180000,{"inputs":[{"Node":{"node_id":2908374490615384600,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"DVec2":[353.5143520436944,551.6238777493922]},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[1.9777789484064812,1.9777789484064812]},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[0.0,0.0]},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[0.5,0.5]},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":1}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":2}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":3}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":4}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":5}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::TransformNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[8309013977031955000,{"inputs":[{"Value":{"tagged_value":{"VectorData":{"instance":[{"style":{"stroke":{"color":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0},"weight":0.0,"dash_lengths":[],"dash_offset":0.0,"cap":"Butt","join":"Miter","join_miter_limit":4.0,"align":"Center","transform":[1.0,0.0,0.0,1.0,0.0,0.0],"non_scaling":false,"paint_order":"StrokeAbove"},"fill":"None"},"colinear_manipulators":[],"point_domain":{"id":[],"position":[]},"segment_domain":{"id":[],"start_point":[],"end_point":[],"handles":[],"stroke":[]},"region_domain":{"id":[],"segment_range":[],"fill":[]},"upstream_graphic_group":null}],"transform":[[1.0,0.0,0.0,1.0,0.0,0.0]],"alpha_blending":[{"blend_mode":"Normal","opacity":1.0,"fill":1.0,"clip":false}],"source_node_id":[null]}},"exposed":true}},{"Value":{"tagged_value":{"VectorModification":{"points":{"add":[1,2,3,4],"remove":[],"delta":[[1,[0.0,0.0]],[3,[1.0,1.0]],[4,[0.0,1.0]],[2,[1.0,0.0]]]},"segments":{"add":[1,2,3,4],"remove":[],"start_point":[[3,3],[2,2],[4,4],[1,1]],"end_point":[[2,3],[4,1],[3,4],[1,2]],"handle_primary":[[1,[0.0,0.0]],[2,[0.0,0.0]],[3,[0.0,0.0]],[4,[0.0,0.0]]],"handle_end":[[3,[0.0,0.0]],[1,[0.0,0.0]],[4,[0.0,0.0]],[2,[0.0,0.0]]],"stroke":[[2,0],[1,0],[3,0],[4,0]]},"regions":{"add":[0],"remove":[],"segment_range":[[0,{"start":1,"end":4}]],"fill":[[0,0]]},"add_g1_continuous":[],"remove_g1_continuous":[]}},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::vector_data::modification::VectorModification","alias":null}},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::vector_data::modification::PathModifyNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[8496292024993914696,{"inputs":[{"Value":{"tagged_value":{"VectorData":{"instance":[{"style":{"stroke":{"color":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0},"weight":0.0,"dash_lengths":[],"dash_offset":0.0,"cap":"Butt","join":"Miter","join_miter_limit":4.0,"align":"Center","transform":[1.0,0.0,0.0,1.0,0.0,0.0],"non_scaling":false,"paint_order":"StrokeAbove"},"fill":"None"},"colinear_manipulators":[],"point_domain":{"id":[8579252446942557840,5702904670777106146,6914816536199142761,17771770146045579307,4317718082554655671],"position":[[-5.75,-0.4000000059604645],[5.75,-0.4000000059604645],[10.0,21.600000381469727],[-10.0,21.600000381469727],[-5.75,-0.4000000059604645]]},"segment_domain":{"id":[1,2,3,4,5],"start_point":[0,1,2,3,4],"end_point":[1,2,3,4,0],"handles":[{"Cubic":{"handle_start":[-5.75,-0.4000000059604645],"handle_end":[5.75,-0.4000000059604645]}},{"Cubic":{"handle_start":[5.75,-0.4000000059604645],"handle_end":[10.0,21.600000381469727]}},{"Cubic":{"handle_start":[10.0,21.600000381469727],"handle_end":[-10.0,21.600000381469727]}},{"Cubic":{"handle_start":[-10.0,21.600000381469727],"handle_end":[-5.75,-0.4000000059604645]}},{"Cubic":{"handle_start":[-5.75,-0.4000000059604645],"handle_end":[-5.75,-0.4000000059604645]}}],"stroke":[0,0,0,0,0]},"region_domain":{"id":[0],"segment_range":[{"start":1,"end":5}],"fill":[0]},"upstream_graphic_group":null}],"transform":[[1.0,0.0,0.0,1.0,0.0,0.0]],"alpha_blending":[{"blend_mode":"Normal","opacity":1.0,"fill":1.0,"clip":false}],"source_node_id":[null]}},"exposed":false}},{"Value":{"tagged_value":{"VectorModification":{"points":{"add":[],"remove":[4317718082554655671],"delta":[]},"segments":{"add":[4],"remove":[5],"start_point":[[4,17771770146045579307]],"end_point":[[4,8579252446942557840]],"handle_primary":[[4,[0.0,0.0]]],"handle_end":[[4,[0.0,0.0]]],"stroke":[[4,0]]},"regions":{"add":[],"remove":[],"segment_range":[],"fill":[]},"add_g1_continuous":[],"remove_g1_continuous":[]}},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::vector_data::modification::VectorModification","alias":null}},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::vector_data::modification::PathModifyNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[15889416971203222000,{"inputs":[{"Node":{"node_id":8309013977031955000,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"Fill":{"Solid":{"red":0.89411765,"green":0.654902,"blue":0.0,"alpha":1.0}}},"exposed":false}},{"Value":{"tagged_value":{"OptionalColor":{"red":0.89411765,"green":0.654902,"blue":0.0,"alpha":1.0}},"exposed":false}},{"Value":{"tagged_value":{"Gradient":{"stops":[[0.0,{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}],[1.0,{"red":1.0,"green":1.0,"blue":1.0,"alpha":1.0}]],"gradient_type":"Linear","start":[0.0,0.5],"end":[1.0,0.5],"transform":[1.0,0.0,0.0,1.0,0.0,0.0]}},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::FillNode"}},"visible":true,"skip_deduplication":false}],[12728151724950013388,{"inputs":[{"Node":{"node_id":3958246774416220000,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"PointSpacingType":"Separation"},"exposed":false}},{"Value":{"tagged_value":{"F64":105.0},"exposed":false}},{"Value":{"tagged_value":{"U32":100},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"Bool":true},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":4,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::SubpathSegmentLengthsNode"}},"visible":true,"skip_deduplication":false}],[4,{"inputs":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::BoundlessFootprintNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":2,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::FreezeRealTimeNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MemoNode"}},"visible":true,"skip_deduplication":false}],[1,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::misc::PointSpacingType","alias":null}},"import_index":1}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":2}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":3}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":4}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":5}},{"Network":{"import_type":{"Concrete":{"name":"bool","alias":null}},"import_index":6}},{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::SamplePolylineNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]},"network_metadata":{"persistent_metadata":{"node_metadata":[[11411423299989983000,{"persistent_metadata":{"reference":"Merge","display_name":"Wire (Use Path Tool to Reshape This!)","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":0}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[13394621587544123000,{"persistent_metadata":{"reference":"Fill","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Fill"},"widget_override":null},{"input_data":{"input_name":"Backup Color"},"widget_override":null},{"input_data":{"input_name":"Backup Gradient"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[4331062027851128000,{"persistent_metadata":{"reference":"Fill","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Fill"},"widget_override":null},{"input_data":{"input_name":"Backup Color"},"widget_override":null},{"input_data":{"input_name":"Backup Gradient"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[655907162126315400,{"persistent_metadata":{"reference":"Path","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Modification"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-50,15]}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"Path Modify","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[12728151724950013388,{"persistent_metadata":{"reference":"Sample Polyline","display_name":"","input_properties":[{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{"blank_assist":true,"is_integer":false,"unit":" px","min":0.0,"mode":"Increment"},"widget_override":"number"},{"input_data":{"mode":"Increment","blank_assist":true,"is_integer":true,"min":2.0},"widget_override":"number"},{"input_data":{"is_integer":false,"min":0.0,"mode":"Increment","blank_assist":true,"unit":" px"},"widget_override":"number"},{"input_data":{"min":0.0,"mode":"Increment","is_integer":false,"unit":" px","blank_assist":true},"widget_override":"number"},{"input_data":{},"widget_override":null}],"output_names":["Vector"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[3,{"persistent_metadata":{"reference":null,"display_name":"Freeze Real Time","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[21,0]}}},"network_metadata":null}}],[4,{"persistent_metadata":{"reference":null,"display_name":"Boundless Footprint","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[28,0]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"Subpath Segment Lengths","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,7]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Memoize","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[14,0]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"Sample Polyline","input_properties":[{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[665049002420596400,{"persistent_metadata":{"reference":"Path","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Modification"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"Path Modify","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[14972365039974885000,{"persistent_metadata":{"reference":"Artboard","display_name":"","input_properties":[{"input_data":{"input_name":"Artboards"},"widget_override":null},{"input_data":{"input_name":"Contents"},"widget_override":"hidden"},{"input_data":{"input_name":"Location","x":"X","y":"Y","unit":" px"},"widget_override":"vec2"},{"input_data":{"x":"W","y":"H","unit":" px","input_name":"Dimensions"},"widget_override":"vec2"},{"input_data":{"input_name":"Background"},"widget_override":"artboard_background"},{"input_data":{"input_name":"Clip"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Absolute":[-4,9]}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[2,{"persistent_metadata":{"reference":null,"display_name":"Append Artboards","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[6,-4]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-2,-3]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"To Artboard","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-10,-3]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[15889416971203222000,{"persistent_metadata":{"reference":"Fill","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Fill"},"widget_override":null},{"input_data":{"input_name":"Backup Color"},"widget_override":null},{"input_data":{"input_name":"Backup Gradient"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[13907401402762847509,{"persistent_metadata":{"reference":"Path","display_name":"","input_properties":[{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null}],"output_names":["Vector Data"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-50,21]}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"Path Modify","input_properties":[{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[11815560782623298000,{"persistent_metadata":{"reference":"Merge","display_name":"Bulb Shape","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":0}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[2908374490615384600,{"persistent_metadata":{"reference":"Fill","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Fill"},"widget_override":null},{"input_data":{"input_name":"Backup Color"},"widget_override":null},{"input_data":{"input_name":"Backup Gradient"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[4534782777857480700,{"persistent_metadata":{"reference":"Merge","display_name":"Star Base","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":0}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[13371003476981866000,{"persistent_metadata":{"reference":"Merge","display_name":"Bulb Glow Gradient","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Absolute":[-29,18]}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[2866788868013687300,{"persistent_metadata":{"reference":"To Group","display_name":"","input_properties":[{"input_data":{"input_name":"Element"},"widget_override":null}],"output_names":["Instances"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[17790961655412892000,{"persistent_metadata":{"reference":"Copy to Points","display_name":"","input_properties":[{"input_data":{"input_name":"Points"},"widget_override":null},{"input_data":{"tooltip":"Artwork to be copied and placed at each point","input_name":"Instance"},"widget_override":null},{"input_data":{"unit":"x","input_name":"Random Scale Min","range_max":2,"mode":"Range","range_min":0,"min":0,"tooltip":"Minimum range of randomized sizes given to each instance","is_integer":false,"blank_assist":true},"widget_override":"number"},{"input_data":{"unit":"x","range_max":2,"tooltip":"Minimum range of randomized sizes given to each instance","blank_assist":true,"range_min":0,"input_name":"Random Scale Max","is_integer":false,"min":0,"mode":"Range"},"widget_override":"number"},{"input_data":{"range_max":50,"range_min":-50,"input_name":"Random Scale Bias","is_integer":false,"tooltip":"Bias for the probability distribution of randomized sizes (0 is uniform, negatives favor more of small sizes, positives favor more of large sizes)","mode":"Range","blank_assist":true},"widget_override":"number"},{"input_data":{"blank_assist":true,"mode":"Increment","tooltip":"Seed to determine unique variations on all the randomized instance sizes","input_name":"Random Scale Seed","min":0,"is_integer":true},"widget_override":"number"},{"input_data":{"is_integer":false,"max":360,"min":0,"blank_assist":true,"input_name":"Random Rotation","mode":"Range","unit":"°","tooltip":"Range of randomized angles given to each instance, in degrees ranging from furthest clockwise to counterclockwise"},"widget_override":"number"},{"input_data":{"mode":"Increment","tooltip":"Seed to determine unique variations on all the randomized instance angles","input_name":"Random Rotation Seed","blank_assist":true,"is_integer":true,"min":0},"widget_override":"number"}],"output_names":["Vector"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[3471929742275053000,{"persistent_metadata":{"reference":"Merge","display_name":"Lights","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Absolute":[-8,12]}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[5737014828407011000,{"persistent_metadata":{"reference":"Transform","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"y":"Y","unit":" px","x":"X","input_name":"Translation"},"widget_override":"vec2"},{"input_data":{"input_name":"Rotation"},"widget_override":"transform_rotation"},{"input_data":{"y":"H","input_name":"Scale","unit":"x","x":"W"},"widget_override":"vec2"},{"input_data":{"input_name":"Skew"},"widget_override":"hidden"},{"input_data":{"input_name":"Pivot"},"widget_override":"hidden"}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"Transform","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[8147814087664910471,{"persistent_metadata":{"reference":"Fill","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Fill"},"widget_override":null},{"input_data":{"input_name":"Backup Color"},"widget_override":null},{"input_data":{"input_name":"Backup Gradient"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[5250960114142560178,{"persistent_metadata":{"reference":"Stroke","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Color"},"widget_override":null},{"input_data":{"input_name":"Weight"},"widget_override":null},{"input_data":{"input_name":"Dash Lengths"},"widget_override":null},{"input_data":{"input_name":"Dash Offset"},"widget_override":null},{"input_data":{"input_name":"Line Cap"},"widget_override":null},{"input_data":{"input_name":"Line Join"},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{"input_name":"Miter Limit"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-43,15]}}},"network_metadata":null}}],[17339085479159577000,{"persistent_metadata":{"reference":"Path","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Modification"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"Path Modify","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[183562335973647870,{"persistent_metadata":{"reference":"Merge","display_name":"Tree","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":0}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[13571989088655643000,{"persistent_metadata":{"reference":"Star","display_name":"","input_properties":[{"input_data":{"input_name":"Primary"},"widget_override":null},{"input_data":{"input_name":"Sides"},"widget_override":null},{"input_data":{"input_name":"Radius"},"widget_override":null},{"input_data":{"input_name":"Inner Radius"},"widget_override":null}],"output_names":["Vector"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[14631609508767818000,{"persistent_metadata":{"reference":"Transform","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"y":"Y","input_name":"Translation","unit":" px","x":"X"},"widget_override":"vec2"},{"input_data":{"input_name":"Rotation"},"widget_override":"transform_rotation"},{"input_data":{"unit":"x","x":"W","y":"H","input_name":"Scale"},"widget_override":"vec2"},{"input_data":{"input_name":"Skew"},"widget_override":"hidden"},{"input_data":{"input_name":"Pivot"},"widget_override":"hidden"}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"Transform","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[3958246774416220000,{"persistent_metadata":{"reference":"Spline","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-36,15]}}},"network_metadata":null}}],[6559102076450693000,{"persistent_metadata":{"reference":"To Group","display_name":"","input_properties":[{"input_data":{"input_name":"Element"},"widget_override":null}],"output_names":["Instances"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[169695252050218443,{"persistent_metadata":{"reference":"Fill","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Fill"},"widget_override":null},{"input_data":{"input_name":"Backup Color"},"widget_override":null},{"input_data":{"input_name":"Backup Gradient"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[16877573495957869000,{"persistent_metadata":{"reference":"Merge","display_name":"Star","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":10}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[8309013977031955000,{"persistent_metadata":{"reference":"Path","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Modification"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"Path Modify","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[4248875763694880300,{"persistent_metadata":{"reference":"Merge","display_name":"Tree Stump","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":0}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[10504222558938851000,{"persistent_metadata":{"reference":"Fill","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Fill"},"widget_override":null},{"input_data":{"input_name":"Backup Color"},"widget_override":null},{"input_data":{"input_name":"Backup Gradient"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[8496292024993914696,{"persistent_metadata":{"reference":"Path","display_name":"","input_properties":[{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null}],"output_names":["Vector Data"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"Path Modify","input_properties":[{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[2181148486404191200,{"persistent_metadata":{"reference":"Transform","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"unit":" px","x":"X","y":"Y","input_name":"Translation"},"widget_override":"vec2"},{"input_data":{"input_name":"Rotation"},"widget_override":"transform_rotation"},{"input_data":{"input_name":"Scale","y":"H","unit":"x","x":"W"},"widget_override":"vec2"},{"input_data":{"input_name":"Skew"},"widget_override":"hidden"},{"input_data":{"input_name":"Pivot"},"widget_override":"hidden"}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"Transform","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[16765094648901306000,{"persistent_metadata":{"reference":"Merge","display_name":"Bulb Housing","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":0}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[4217566479741824000,{"persistent_metadata":{"reference":"Assign Colors","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Group"},"widget_override":"hidden"},{"input_data":{"input_name":"Fill"},"widget_override":null},{"input_data":{"input_name":"Stroke"},"widget_override":null},{"input_data":{"input_name":"Gradient"},"widget_override":"assign_colors_gradient"},{"input_data":{"input_name":"Reverse"},"widget_override":null},{"input_data":{"input_name":"Randomize"},"widget_override":null},{"input_data":{"input_name":"Seed"},"widget_override":null},{"input_data":{"input_name":"Repeat Every"},"widget_override":"assign_colors_repeat_every"}],"output_names":["Vector Group"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[7297408968096180000,{"persistent_metadata":{"reference":"Transform","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"unit":" px","x":"X","y":"Y","input_name":"Translation"},"widget_override":"vec2"},{"input_data":{"input_name":"Rotation"},"widget_override":"transform_rotation"},{"input_data":{"input_name":"Scale","x":"W","unit":"x","y":"H"},"widget_override":"vec2"},{"input_data":{"input_name":"Skew"},"widget_override":"hidden"},{"input_data":{"input_name":"Pivot"},"widget_override":"hidden"}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"Transform","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[527.9166666666665,-576.1833333333332],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,1518.0,4.0],"node_graph_top_right":[1980.796875,0.0]},"selection_undo_history":[[],[2866788868013687300],[],[4352028121261571600],[],[2866788868013687300],[6559102076450693000],[6559102076450693000],[10775791528628074000],[],[6559102076450693000],[],[],[],[],[],[15084833709935380000],[],[16765094648901306000],[16765094648901306000,11815560782623298000],[16765094648901306000,13371003476981866000,11815560782623298000],[6559102076450693000,16765094648901306000,13394621587544123000,11815560782623298000,2866788868013687300,13371003476981866000],[3958246774416220000],[],[],[3958246774416220000],[3958246774416220000,655907162126315400],[],[3958246774416220000],[],[3958246774416220000],[655907162126315400,3958246774416220000],[],[],[3958246774416220000],[655907162126315400,3958246774416220000],[],[14631609508767818000],[],[5737014828407011000],[],[10118219203151733000],[],[],[],[],[],[],[655907162126315400],[],[],[655907162126315400,3958246774416220000],[],[],[16877573495957869000],[11411423299989983000],[16877573495957869000],[3471929742275053000],[11411423299989983000],[11411423299989983000,15209576944107258000],[15209576944107258000,3287844738046380000,11411423299989983000],[15209576944107258000,3287844738046380000,11411423299989983000,3958246774416220000],[3958246774416220000,655907162126315400,15209576944107258000,11411423299989983000,3287844738046380000],[4248875763694880300],[11411423299989983000],[3471929742275053000],[11411423299989983000],[15223368326030279287],[11815560782623298000],[11815560782623298000,16765094648901306000],[11815560782623298000],[13371003476981866000],[16765094648901306000],[15223368326030279287],[13371003476981866000],[13371003476981866000,16765094648901306000,11815560782623298000],[13371003476981866000],[11815560782623298000],[16765094648901306000],[13371003476981866000],[16765094648901306000],[11815560782623298000],[13371003476981866000],[11815560782623298000],[13371003476981866000],[16765094648901306000],[13371003476981866000],[16877573495957869000],[16765094648901306000],[13371003476981866000],[16765094648901306000],[11411423299989983000],[]],"selection_redo_history":[]}}},"collapsed":[],"name":"procedural-string-lights.graphite","commit_hash":"95bbc95606ba40ed7441fdf4e1b954d80b72e3dc","document_ptz":{"pan":[-500.157717622685,-499.8045823704831],"tilt":0.0,"zoom":1.0,"flip":false},"document_mode":"DesignMode","view_mode":"Normal","overlays_visibility_settings":{"all":true,"artboard_name":true,"compass_rose":true,"quick_measurement":true,"transform_measurement":true,"transform_cage":true,"hover_outline":true,"selection_outline":true,"pivot":true,"path":true,"anchors":true,"handles":true},"rulers_visible":true,"snapping_state":{"snapping_enabled":true,"grid_snapping":false,"artboards":true,"tolerance":8.0,"bounding_box":{"center_point":true,"corner_point":true,"edge_midpoint":true,"align_with_edges":true,"distribute_evenly":true},"path":{"anchor_point":true,"line_midpoint":true,"along_path":true,"normal_to_path":true,"tangent_to_path":true,"path_intersection_point":true,"align_with_anchor_point":true,"perpendicular_from_endpoint":true},"grid":{"origin":[0.0,0.0],"grid_type":{"Rectangular":{"spacing":[1.0,1.0]}},"rectangular_spacing":[1.0,1.0],"isometric_y_spacing":1.0,"isometric_angle_a":30.0,"isometric_angle_b":30.0,"grid_color":{"red":0.6038274,"green":0.6038274,"blue":0.6038274,"alpha":1.0},"dot_display":false}},"graph_view_overlay_open":false,"graph_fade_artwork_percentage":80.0} \ No newline at end of file diff --git a/demo-artwork/red-dress.graphite b/demo-artwork/red-dress.graphite new file mode 100644 index 0000000000000000000000000000000000000000..68f34ea4ed9ea8b07f9640b5915884afdd6775f5 --- /dev/null +++ b/demo-artwork/red-dress.graphite @@ -0,0 +1 @@ +{"network_interface":{"network":{"exports":[{"Node":{"node_id":2394762731964337494,"output_index":0,"lambda":false}}],"nodes":[[10127467043900015225,{"inputs":[{"Value":{"tagged_value":{"VectorData":{"instance":[{"style":{"stroke":{"color":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0},"weight":0.0,"dash_lengths":[],"dash_offset":0.0,"cap":"Butt","join":"Miter","join_miter_limit":4.0,"align":"Center","transform":[1.0,0.0,0.0,1.0,0.0,0.0],"non_scaling":false,"paint_order":"StrokeAbove"},"fill":"None"},"colinear_manipulators":[],"point_domain":{"id":[],"position":[]},"segment_domain":{"id":[],"start_point":[],"end_point":[],"handles":[],"stroke":[]},"region_domain":{"id":[],"segment_range":[],"fill":[]},"upstream_graphic_group":null}],"transform":[[1.0,0.0,0.0,1.0,0.0,0.0]],"alpha_blending":[{"blend_mode":"Normal","opacity":1.0,"fill":1.0,"clip":false}],"source_node_id":[null]}},"exposed":true}},{"Value":{"tagged_value":{"VectorModification":{"points":{"add":[1,2],"remove":[],"delta":[[1,[258.00000000000006,994.6666666666664]],[2,[644.0,726.6666666666666]]]},"segments":{"add":[1],"remove":[],"start_point":[[1,1]],"end_point":[[1,2]],"handle_primary":[[1,[0.0,0.0]]],"handle_end":[[1,[-328.66666666666674,129.33333333333337]]],"stroke":[[1,0]]},"regions":{"add":[],"remove":[],"segment_range":[],"fill":[]},"add_g1_continuous":[],"remove_g1_continuous":[]}},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::vector_data::modification::VectorModification","alias":null}},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::vector_data::modification::PathModifyNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[15961046538654083626,{"inputs":[{"Node":{"node_id":1889157037801767612,"output_index":0,"lambda":false}},{"Node":{"node_id":4332145463108161926,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"F64":0.5},"exposed":false}},{"Value":{"tagged_value":{"F64":10.0},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"U32":0},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"U32":0},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::CopyToPointsNode"}},"visible":true,"skip_deduplication":false}],[17378885078543074499,{"inputs":[{"Value":{"tagged_value":{"VectorData":{"instance":[{"style":{"stroke":{"color":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0},"weight":0.0,"dash_lengths":[],"dash_offset":0.0,"cap":"Butt","join":"Miter","join_miter_limit":4.0,"align":"Center","transform":[1.0,0.0,0.0,1.0,0.0,0.0],"non_scaling":false,"paint_order":"StrokeAbove"},"fill":"None"},"colinear_manipulators":[],"point_domain":{"id":[],"position":[]},"segment_domain":{"id":[],"start_point":[],"end_point":[],"handles":[],"stroke":[]},"region_domain":{"id":[],"segment_range":[],"fill":[]},"upstream_graphic_group":null}],"transform":[[1.0,0.0,0.0,1.0,0.0,0.0]],"alpha_blending":[{"blend_mode":"Normal","opacity":1.0,"fill":1.0,"clip":false}],"source_node_id":[null]}},"exposed":true}},{"Value":{"tagged_value":{"VectorModification":{"points":{"add":[1,2,3,4,5,6,7,8],"remove":[],"delta":[[7,[727.5555555555554,1026.6666666666663]],[3,[707.5,1026.5]],[4,[709.5555555555554,1026.6666666666667]],[8,[746.0000000000001,842.9999999999999]],[1,[823.2222222222221,660.4444444444445]],[6,[725.7777777777779,1026.370370370371]],[2,[745.5,826.0]],[5,[740.4444444444443,857.1111111111111]]]},"segments":{"add":[1,2,3,4,5,6,7,8],"remove":[],"start_point":[[4,4],[2,2],[3,3],[6,6],[8,8],[5,5],[1,1],[7,7]],"end_point":[[2,3],[8,1],[7,8],[4,5],[1,2],[3,4],[5,6],[6,7]],"handle_primary":[[3,[0.0,0.0]],[1,[0.0,0.0]],[8,[17.33333333333337,-84.99999999999989]],[5,[0.0,0.0]],[7,[0.0,0.0]],[4,[0.0,0.0]],[6,[0.0,0.0]],[2,[-24.5,85.0]]],"handle_end":[[1,[24.5,-85.0]],[3,[0.0,0.0]],[8,[1.772016460905547,0.9591220850479658]],[2,[0.0,0.0]],[4,[-23.11111111111109,90.44444444444456]],[6,[0.0,0.0]],[7,[-26.8034437596026,131.4399645903585]],[5,[-7.555555555555884,-59.25925925925992]]],"stroke":[[3,0],[2,0],[7,0],[6,0],[1,0],[4,0],[5,0],[8,0]]},"regions":{"add":[0],"remove":[],"segment_range":[[0,{"start":1,"end":8}]],"fill":[[0,0]]},"add_g1_continuous":[],"remove_g1_continuous":[]}},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::vector_data::modification::VectorModification","alias":null}},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::vector_data::modification::PathModifyNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[14537754528543289381,{"inputs":[{"Node":{"node_id":1689789805659535712,"output_index":0,"lambda":false}},{"Node":{"node_id":17364155187784942740,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[11656581020969095354,{"inputs":[{"Node":{"node_id":8413863870096329943,"output_index":0,"lambda":false}},{"Node":{"node_id":9698363115186534174,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[4350324834849900949,{"inputs":[{"Node":{"node_id":6672826052605647592,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"Fill":{"Solid":{"red":0.8980392,"green":0.8,"blue":0.6117647,"alpha":1.0}}},"exposed":false}},{"Value":{"tagged_value":{"OptionalColor":{"red":0.8980392,"green":0.8,"blue":0.6117647,"alpha":1.0}},"exposed":false}},{"Value":{"tagged_value":{"Gradient":{"stops":[[0.0,{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}],[1.0,{"red":1.0,"green":1.0,"blue":1.0,"alpha":1.0}]],"gradient_type":"Linear","start":[0.0,0.5],"end":[1.0,0.5],"transform":[1.0,0.0,0.0,1.0,0.0,0.0]}},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::FillNode"}},"visible":true,"skip_deduplication":false}],[15857077552290328068,{"inputs":[{"Value":{"tagged_value":{"VectorData":{"instance":[{"style":{"stroke":{"color":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0},"weight":0.0,"dash_lengths":[],"dash_offset":0.0,"cap":"Butt","join":"Miter","join_miter_limit":4.0,"align":"Center","transform":[1.0,0.0,0.0,1.0,0.0,0.0],"non_scaling":false,"paint_order":"StrokeAbove"},"fill":"None"},"colinear_manipulators":[],"point_domain":{"id":[],"position":[]},"segment_domain":{"id":[],"start_point":[],"end_point":[],"handles":[],"stroke":[]},"region_domain":{"id":[],"segment_range":[],"fill":[]},"upstream_graphic_group":null}],"transform":[[1.0,0.0,0.0,1.0,0.0,0.0]],"alpha_blending":[{"blend_mode":"Normal","opacity":1.0,"fill":1.0,"clip":false}],"source_node_id":[null]}},"exposed":true}},{"Value":{"tagged_value":{"VectorModification":{"points":{"add":[1,2,3,4],"remove":[],"delta":[[3,[740.0,516.0]],[1,[848.8888888888889,330.66666666666663]],[4,[702.2222222222222,621.3333333333333]],[2,[820.8888888888889,395.55555555555554]]]},"segments":{"add":[1,2,3],"remove":[],"start_point":[[2,2],[3,3],[1,1]],"end_point":[[2,3],[1,2],[3,4]],"handle_primary":[[3,[-17.77777777777783,35.55555555555554]],[2,[-15.111111111111086,22.66666666666663]],[1,[0.0,0.0]]],"handle_end":[[3,[6.222222222222172,-38.66666666666674]],[2,[17.77777777777783,-35.55555555555554]],[1,[15.111111111111086,-22.66666666666663]]],"stroke":[[1,0],[3,0],[2,0]]},"regions":{"add":[],"remove":[],"segment_range":[],"fill":[]},"add_g1_continuous":[],"remove_g1_continuous":[]}},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::vector_data::modification::VectorModification","alias":null}},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::vector_data::modification::PathModifyNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[15735375935164094402,{"inputs":[{"Node":{"node_id":3414873131936208778,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"Fill":{"Solid":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}}},"exposed":false}},{"Value":{"tagged_value":{"OptionalColor":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}},"exposed":false}},{"Value":{"tagged_value":{"Gradient":{"stops":[[0.0,{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}],[1.0,{"red":1.0,"green":1.0,"blue":1.0,"alpha":1.0}]],"gradient_type":"Linear","start":[0.0,0.5],"end":[1.0,0.5],"transform":[1.0,0.0,0.0,1.0,0.0,0.0]}},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::FillNode"}},"visible":true,"skip_deduplication":false}],[15239301303367148581,{"inputs":[{"Node":{"node_id":11268046366284173800,"output_index":0,"lambda":false}},{"Node":{"node_id":5269304445610080925,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[615144098061106242,{"inputs":[{"Node":{"node_id":14675232891471617236,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"Fill":{"Solid":{"red":0.84705883,"green":0.5372549,"blue":0.38431373,"alpha":1.0}}},"exposed":false}},{"Value":{"tagged_value":{"OptionalColor":{"red":0.84705883,"green":0.5372549,"blue":0.38431373,"alpha":1.0}},"exposed":false}},{"Value":{"tagged_value":{"Gradient":{"stops":[[0.0,{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}],[1.0,{"red":1.0,"green":1.0,"blue":1.0,"alpha":1.0}]],"gradient_type":"Linear","start":[0.0,0.5],"end":[1.0,0.5],"transform":[1.0,0.0,0.0,1.0,0.0,0.0]}},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::FillNode"}},"visible":true,"skip_deduplication":false}],[11058365317860779469,{"inputs":[{"Value":{"tagged_value":{"VectorData":{"instance":[{"style":{"stroke":{"color":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0},"weight":0.0,"dash_lengths":[],"dash_offset":0.0,"cap":"Butt","join":"Miter","join_miter_limit":4.0,"align":"Center","transform":[1.0,0.0,0.0,1.0,0.0,0.0],"non_scaling":false,"paint_order":"StrokeAbove"},"fill":"None"},"colinear_manipulators":[],"point_domain":{"id":[],"position":[]},"segment_domain":{"id":[],"start_point":[],"end_point":[],"handles":[],"stroke":[]},"region_domain":{"id":[],"segment_range":[],"fill":[]},"upstream_graphic_group":null}],"transform":[[1.0,0.0,0.0,1.0,0.0,0.0]],"alpha_blending":[{"blend_mode":"Normal","opacity":1.0,"fill":1.0,"clip":false}],"source_node_id":[null]}},"exposed":true}},{"Value":{"tagged_value":{"VectorModification":{"points":{"add":[1,2,3,4,5,6,7],"remove":[],"delta":[[6,[368.0,902.6666666666669]],[1,[181.0,1023.0]],[4,[397.3333333333333,770.6666666666666]],[2,[242.0,917.0]],[7,[311.3333333333333,1018.6666666666666]],[5,[479.00000000000006,817.0]],[3,[352.0,833.0]]]},"segments":{"add":[1,2,3,4,5,6,7],"remove":[],"start_point":[[7,7],[2,2],[5,5],[6,6],[1,1],[3,3],[4,4]],"end_point":[[3,4],[2,3],[1,2],[4,5],[6,7],[5,6],[7,1]],"handle_primary":[[1,[0.0,0.0]],[6,[0.0,0.0]],[4,[0.0,0.0]],[7,[0.0,0.0]],[5,[-35.31654570364651,23.463149348287175]],[3,[37.4110841377784,-16.935189837826556]],[2,[40.0718943376238,-39.16116946631416]]],"handle_end":[[4,[35.31654570364611,-23.463149348286947]],[2,[-37.4110841377784,16.935189837826556]],[5,[45.99999999999994,-52.00000000000023]],[7,[0.0,1.3333333333337123]],[1,[-40.071894337623746,39.16116946631416]],[6,[18.0,-55.33333333333326]],[3,[0.0,0.0]]],"stroke":[[5,0],[1,0],[6,0],[3,0],[7,0],[2,0],[4,0]]},"regions":{"add":[0],"remove":[],"segment_range":[[0,{"start":1,"end":7}]],"fill":[[0,0]]},"add_g1_continuous":[],"remove_g1_continuous":[]}},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::vector_data::modification::VectorModification","alias":null}},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::vector_data::modification::PathModifyNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[14946189826912398678,{"inputs":[{"Node":{"node_id":10086073308516686449,"output_index":0,"lambda":false}},{"Node":{"node_id":12030171742672119253,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[11553850607251055696,{"inputs":[{"Value":{"tagged_value":{"VectorData":{"instance":[{"style":{"stroke":{"color":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0},"weight":0.0,"dash_lengths":[],"dash_offset":0.0,"cap":"Butt","join":"Miter","join_miter_limit":4.0,"align":"Center","transform":[1.0,0.0,0.0,1.0,0.0,0.0],"non_scaling":false,"paint_order":"StrokeAbove"},"fill":"None"},"colinear_manipulators":[],"point_domain":{"id":[],"position":[]},"segment_domain":{"id":[],"start_point":[],"end_point":[],"handles":[],"stroke":[]},"region_domain":{"id":[],"segment_range":[],"fill":[]},"upstream_graphic_group":null}],"transform":[[1.0,0.0,0.0,1.0,0.0,0.0]],"alpha_blending":[{"blend_mode":"Normal","opacity":1.0,"fill":1.0,"clip":false}],"source_node_id":[null]}},"exposed":true}},{"Value":{"tagged_value":{"VectorModification":{"points":{"add":[1,2,3,4,5,6,7,8],"remove":[],"delta":[[7,[591.5390946502059,128.7023319615912]],[4,[608.570644718793,131.2482853223594]],[3,[594.085048010974,128.61454046639233]],[5,[619.2812071330591,124.6639231824417]],[2,[596.631001371742,112.37311385459536]],[8,[594.962962962963,111.93415637860085]],[1,[597.5967078189302,96.04389574759946]],[6,[609.9753086419754,133.5308641975309]]]},"segments":{"add":[1,2,3,4,5,6,7,8],"remove":[],"start_point":[[1,1],[2,2],[3,3],[4,4],[5,5],[7,7],[8,8],[6,6]],"end_point":[[5,6],[7,8],[4,5],[2,3],[3,4],[1,2],[6,7],[8,1]],"handle_primary":[[2,[-4.126200274348321,7.1111111111111]],[7,[-2.3703703703704377,-6.057613168724245]],[3,[3.5534615822588194,4.6302681223374975]],[8,[4.1262002743484345,-6.935528120713329]],[1,[0.0,0.0]],[4,[4.038408779149563,-1.492455418381354]],[5,[0.0,0.0]],[6,[-7.286694101508829,3.0727023319615796]]],"handle_end":[[2,[-2.8971193415636662,-3.7750342935528063]],[1,[4.126200274348321,-7.111111111111114]],[7,[-4.1262002743484345,6.935528120713272]],[4,[0.0,0.0]],[8,[-0.0877914951989851,0.08779149519889984]],[6,[2.3703703703704377,6.057613168724259]],[5,[7.286694101508829,-3.0727023319615796]],[3,[-4.038408779149563,1.492455418381354]]],"stroke":[[8,0],[1,0],[5,0],[3,0],[7,0],[4,0],[6,0],[2,0]]},"regions":{"add":[0],"remove":[],"segment_range":[[0,{"start":1,"end":8}]],"fill":[[0,0]]},"add_g1_continuous":[],"remove_g1_continuous":[]}},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::vector_data::modification::VectorModification","alias":null}},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::vector_data::modification::PathModifyNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[4453139144069993994,{"inputs":[{"Node":{"node_id":11804065810513502701,"output_index":0,"lambda":false}},{"Node":{"node_id":3955326429435439190,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[5040278174920511484,{"inputs":[{"Node":{"node_id":14345191642063772510,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"Fill":{"Solid":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}}},"exposed":false}},{"Value":{"tagged_value":{"OptionalColor":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}},"exposed":false}},{"Value":{"tagged_value":{"Gradient":{"stops":[[0.0,{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}],[1.0,{"red":1.0,"green":1.0,"blue":1.0,"alpha":1.0}]],"gradient_type":"Linear","start":[0.0,0.5],"end":[1.0,0.5],"transform":[1.0,0.0,0.0,1.0,0.0,0.0]}},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::FillNode"}},"visible":true,"skip_deduplication":false}],[4577174813962563383,{"inputs":[{"Value":{"tagged_value":{"VectorData":{"instance":[{"style":{"stroke":{"color":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0},"weight":0.0,"dash_lengths":[],"dash_offset":0.0,"cap":"Butt","join":"Miter","join_miter_limit":4.0,"align":"Center","transform":[1.0,0.0,0.0,1.0,0.0,0.0],"non_scaling":false,"paint_order":"StrokeAbove"},"fill":"None"},"colinear_manipulators":[],"point_domain":{"id":[],"position":[]},"segment_domain":{"id":[],"start_point":[],"end_point":[],"handles":[],"stroke":[]},"region_domain":{"id":[],"segment_range":[],"fill":[]},"upstream_graphic_group":null}],"transform":[[1.0,0.0,0.0,1.0,0.0,0.0]],"alpha_blending":[{"blend_mode":"Normal","opacity":1.0,"fill":1.0,"clip":false}],"source_node_id":[null]}},"exposed":true}},{"Value":{"tagged_value":{"VectorModification":{"points":{"add":[1,2,3,4],"remove":[],"delta":[[4,[683.6813083078299,66.11925839089211]],[1,[681.3689965686843,65.32157692417977]],[2,[681.8346756482305,95.35045043533154]],[3,[682.7287205627164,97.04177207029592]]]},"segments":{"add":[1,2,3,4],"remove":[],"start_point":[[4,4],[1,1],[3,3],[2,2]],"end_point":[[3,4],[1,2],[4,1],[2,3]],"handle_primary":[[2,[0.0,0.0]],[4,[-1.0406539360374154,-1.1405457962673182]],[1,[0.0,0.0]],[3,[-1.544754703853414,-12.605862910106907]]],"handle_end":[[1,[-2.6406503472093164,-12.592334294499352]],[4,[-1.1368683772161605e-13,-1.4210854715202004e-14]],[3,null],[2,[-0.5302752037773644,-0.69223185792994]]],"stroke":[[3,0],[2,0],[1,0],[4,0]]},"regions":{"add":[0],"remove":[],"segment_range":[[0,{"start":1,"end":4}]],"fill":[[0,0]]},"add_g1_continuous":[],"remove_g1_continuous":[]}},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::vector_data::modification::VectorModification","alias":null}},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::vector_data::modification::PathModifyNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[14225285635863713990,{"inputs":[{"Node":{"node_id":8410534738018320047,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"DVec2":[25.333333333333485,12.641975308641918]},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[1.0,1.0]},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[0.0,0.0]},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[0.5,0.5]},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":1}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":2}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":3}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":4}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":5}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::TransformNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[11899713172487274471,{"inputs":[{"Node":{"node_id":9954843247420111867,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"Fill":{"Solid":{"red":0.7529412,"green":0.15686275,"blue":0.13333334,"alpha":1.0}}},"exposed":false}},{"Value":{"tagged_value":{"OptionalColor":{"red":0.7529412,"green":0.15686275,"blue":0.13333334,"alpha":1.0}},"exposed":false}},{"Value":{"tagged_value":{"Gradient":{"stops":[[0.0,{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}],[1.0,{"red":1.0,"green":1.0,"blue":1.0,"alpha":1.0}]],"gradient_type":"Linear","start":[0.0,0.5],"end":[1.0,0.5],"transform":[1.0,0.0,0.0,1.0,0.0,0.0]}},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::FillNode"}},"visible":true,"skip_deduplication":false}],[6580280438672662494,{"inputs":[{"Node":{"node_id":15395954548128560685,"output_index":0,"lambda":false}},{"Node":{"node_id":14598755603287563819,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[17967471489196302183,{"inputs":[{"Value":{"tagged_value":{"VectorData":{"instance":[{"style":{"stroke":{"color":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0},"weight":0.0,"dash_lengths":[],"dash_offset":0.0,"cap":"Butt","join":"Miter","join_miter_limit":4.0,"align":"Center","transform":[1.0,0.0,0.0,1.0,0.0,0.0],"non_scaling":false,"paint_order":"StrokeAbove"},"fill":"None"},"colinear_manipulators":[],"point_domain":{"id":[],"position":[]},"segment_domain":{"id":[],"start_point":[],"end_point":[],"handles":[],"stroke":[]},"region_domain":{"id":[],"segment_range":[],"fill":[]},"upstream_graphic_group":null}],"transform":[[1.0,0.0,0.0,1.0,0.0,0.0]],"alpha_blending":[{"blend_mode":"Normal","opacity":1.0,"fill":1.0,"clip":false}],"source_node_id":[null]}},"exposed":true}},{"Value":{"tagged_value":{"VectorModification":{"points":{"add":[1,2,3],"remove":[],"delta":[[3,[334.8148148148148,1025.4814814814813]],[2,[568.8888888888889,785.4814814814813]],[1,[339.25925925925924,1025.185185185185]]]},"segments":{"add":[1,2,3],"remove":[],"start_point":[[2,2],[1,1],[3,3]],"end_point":[[3,1],[1,2],[2,3]],"handle_primary":[[2,[0.0,0.0]],[3,[0.0,0.0]],[1,[0.0,0.0]]],"handle_end":[[1,[-209.77777777777777,108.44444444444468]],[3,null],[2,[42.07407407407419,-157.6296296296293]]],"stroke":[[3,0],[2,0],[1,0]]},"regions":{"add":[0],"remove":[],"segment_range":[[0,{"start":1,"end":3}]],"fill":[[0,0]]},"add_g1_continuous":[],"remove_g1_continuous":[]}},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::vector_data::modification::VectorModification","alias":null}},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::vector_data::modification::PathModifyNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[10086073308516686449,{"inputs":[{"Value":{"tagged_value":{"GraphicGroup":{"instance":[],"transform":[],"alpha_blending":[],"source_node_id":[]}},"exposed":true}},{"Node":{"node_id":3971837674569123876,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[4222034829755771252,{"inputs":[{"Value":{"tagged_value":{"VectorData":{"instance":[{"style":{"stroke":{"color":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0},"weight":0.0,"dash_lengths":[],"dash_offset":0.0,"cap":"Butt","join":"Miter","join_miter_limit":4.0,"align":"Center","transform":[1.0,0.0,0.0,1.0,0.0,0.0],"non_scaling":false,"paint_order":"StrokeAbove"},"fill":"None"},"colinear_manipulators":[],"point_domain":{"id":[],"position":[]},"segment_domain":{"id":[],"start_point":[],"end_point":[],"handles":[],"stroke":[]},"region_domain":{"id":[],"segment_range":[],"fill":[]},"upstream_graphic_group":null}],"transform":[[1.0,0.0,0.0,1.0,0.0,0.0]],"alpha_blending":[{"blend_mode":"Normal","opacity":1.0,"fill":1.0,"clip":false}],"source_node_id":[null]}},"exposed":true}},{"Value":{"tagged_value":{"VectorModification":{"points":{"add":[1,2,3,4],"remove":[],"delta":[[2,[155.25925925925927,256.7901234567901]],[4,[161.6241426611797,258.3703703703704]],[3,[152.49382716049382,262.71604938271605]],[1,[165.5308641975309,250.07407407407408]]]},"segments":{"add":[1,2,3,4],"remove":[],"start_point":[[1,1],[4,4],[2,2],[3,3]],"end_point":[[2,3],[4,1],[1,2],[3,4]],"handle_primary":[[4,[2.7654320987654444,-3.950617283950635]],[1,[0.0,0.0]],[2,[-1.9753086419753176,0.790123456790127]],[3,[0.0,0.0]]],"handle_end":[[4,[0.0,0.0]],[3,[-2.7654320987654444,3.950617283950635]],[2,[-0.3950617283950919,-1.7777777777777717]],[1,[1.9753086419753176,-0.790123456790127]]],"stroke":[[2,0],[3,0],[1,0],[4,0]]},"regions":{"add":[0],"remove":[],"segment_range":[[0,{"start":1,"end":4}]],"fill":[[0,0]]},"add_g1_continuous":[],"remove_g1_continuous":[]}},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::vector_data::modification::VectorModification","alias":null}},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::vector_data::modification::PathModifyNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[4307303572241320716,{"inputs":[{"Node":{"node_id":4265165189651403984,"output_index":0,"lambda":false}},{"Node":{"node_id":4572557574846980832,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[2878992817082507910,{"inputs":[{"Value":{"tagged_value":{"VectorData":{"instance":[{"style":{"stroke":{"color":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0},"weight":0.0,"dash_lengths":[],"dash_offset":0.0,"cap":"Butt","join":"Miter","join_miter_limit":4.0,"align":"Center","transform":[1.0,0.0,0.0,1.0,0.0,0.0],"non_scaling":false,"paint_order":"StrokeAbove"},"fill":"None"},"colinear_manipulators":[],"point_domain":{"id":[],"position":[]},"segment_domain":{"id":[],"start_point":[],"end_point":[],"handles":[],"stroke":[]},"region_domain":{"id":[],"segment_range":[],"fill":[]},"upstream_graphic_group":null}],"transform":[[1.0,0.0,0.0,1.0,0.0,0.0]],"alpha_blending":[{"blend_mode":"Normal","opacity":1.0,"fill":1.0,"clip":false}],"source_node_id":[null]}},"exposed":true}},{"Value":{"tagged_value":{"VectorModification":{"points":{"add":[1,2,3],"remove":[],"delta":[[2,[738.074074074074,1027.2592592592591]],[3,[741.6296296296296,1027.5555555555557]],[1,[777.4814814814814,867.5555555555555]]]},"segments":{"add":[1,2,3],"remove":[],"start_point":[[3,3],[1,1],[2,2]],"end_point":[[2,3],[1,2],[3,1]],"handle_primary":[[2,[0.0,0.0]],[3,[0.0,0.0]],[1,[0.0,0.0]]],"handle_end":[[2,[0.0,0.0]],[3,[-25.185185185185105,132.14814814814804]],[1,[0.0,0.0]]],"stroke":[[1,0],[3,0],[2,0]]},"regions":{"add":[0],"remove":[],"segment_range":[[0,{"start":1,"end":3}]],"fill":[[0,0]]},"add_g1_continuous":[],"remove_g1_continuous":[]}},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::vector_data::modification::VectorModification","alias":null}},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::vector_data::modification::PathModifyNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[9863310024364795214,{"inputs":[{"Node":{"node_id":5278509881589546420,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"Fill":{"Solid":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}}},"exposed":false}},{"Value":{"tagged_value":{"OptionalColor":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}},"exposed":false}},{"Value":{"tagged_value":{"Gradient":{"stops":[[0.0,{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}],[1.0,{"red":1.0,"green":1.0,"blue":1.0,"alpha":1.0}]],"gradient_type":"Linear","start":[0.0,0.5],"end":[1.0,0.5],"transform":[1.0,0.0,0.0,1.0,0.0,0.0]}},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::FillNode"}},"visible":true,"skip_deduplication":false}],[11025165626998987360,{"inputs":[{"Node":{"node_id":5326536612985524219,"output_index":0,"lambda":false}},{"Node":{"node_id":4332145463108161926,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"F64":2.0},"exposed":false}},{"Value":{"tagged_value":{"F64":40.0},"exposed":false}},{"Value":{"tagged_value":{"F64":-15.0},"exposed":false}},{"Value":{"tagged_value":{"U32":0},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"U32":0},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::CopyToPointsNode"}},"visible":true,"skip_deduplication":false}],[15982852655074258238,{"inputs":[{"Value":{"tagged_value":{"VectorData":{"instance":[{"style":{"stroke":{"color":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0},"weight":0.0,"dash_lengths":[],"dash_offset":0.0,"cap":"Butt","join":"Miter","join_miter_limit":4.0,"align":"Center","transform":[1.0,0.0,0.0,1.0,0.0,0.0],"non_scaling":false,"paint_order":"StrokeAbove"},"fill":"None"},"colinear_manipulators":[],"point_domain":{"id":[],"position":[]},"segment_domain":{"id":[],"start_point":[],"end_point":[],"handles":[],"stroke":[]},"region_domain":{"id":[],"segment_range":[],"fill":[]},"upstream_graphic_group":null}],"transform":[[1.0,0.0,0.0,1.0,0.0,0.0]],"alpha_blending":[{"blend_mode":"Normal","opacity":1.0,"fill":1.0,"clip":false}],"source_node_id":[null]}},"exposed":true}},{"Value":{"tagged_value":{"VectorModification":{"points":{"add":[1,2],"remove":[],"delta":[[2,[798.222222222222,639.8024691358025]],[1,[837.9999999999998,535.8024691358025]]]},"segments":{"add":[1,2],"remove":[],"start_point":[[1,1],[2,2]],"end_point":[[2,1],[1,2]],"handle_primary":[[1,[0.0,0.0]],[2,[31.037037037037067,-61.11111111111131]]],"handle_end":[[1,[34.000000000000114,-59.77777777777783]],[2,null]],"stroke":[[2,0],[1,0]]},"regions":{"add":[0],"remove":[],"segment_range":[[0,{"start":1,"end":2}]],"fill":[[0,0]]},"add_g1_continuous":[],"remove_g1_continuous":[]}},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::vector_data::modification::VectorModification","alias":null}},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::vector_data::modification::PathModifyNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[17699121037850769131,{"inputs":[{"Value":{"tagged_value":{"VectorData":{"instance":[{"style":{"stroke":{"color":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0},"weight":0.0,"dash_lengths":[],"dash_offset":0.0,"cap":"Butt","join":"Miter","join_miter_limit":4.0,"align":"Center","transform":[1.0,0.0,0.0,1.0,0.0,0.0],"non_scaling":false,"paint_order":"StrokeAbove"},"fill":"None"},"colinear_manipulators":[],"point_domain":{"id":[],"position":[]},"segment_domain":{"id":[],"start_point":[],"end_point":[],"handles":[],"stroke":[]},"region_domain":{"id":[],"segment_range":[],"fill":[]},"upstream_graphic_group":null}],"transform":[[1.0,0.0,0.0,1.0,0.0,0.0]],"alpha_blending":[{"blend_mode":"Normal","opacity":1.0,"fill":1.0,"clip":false}],"source_node_id":[null]}},"exposed":true}},{"Value":{"tagged_value":{"VectorModification":{"points":{"add":[1,2,3,4],"remove":[],"delta":[[4,[158.22222222222223,332.0]],[2,[429.33333333333326,295.1111111111111]],[1,[531.1111111111111,364.0]],[3,[282.2222222222222,277.3333333333333]]]},"segments":{"add":[1,2,3],"remove":[],"start_point":[[2,2],[1,1],[3,3]],"end_point":[[2,3],[3,4],[1,2]],"handle_primary":[[2,[-56.8888888888888,-24.0]],[1,[0.0,0.0]],[3,[-33.333333333333286,6.666666666666686]]],"handle_end":[[3,[60.0,-41.77777777777777]],[2,[33.333333333333314,-6.666666666666686]],[1,[56.8888888888888,24.0]]],"stroke":[[3,0],[1,0],[2,0]]},"regions":{"add":[],"remove":[],"segment_range":[],"fill":[]},"add_g1_continuous":[],"remove_g1_continuous":[]}},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::vector_data::modification::VectorModification","alias":null}},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::vector_data::modification::PathModifyNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[5174744389209053970,{"inputs":[{"Node":{"node_id":12385950900718181935,"output_index":0,"lambda":false}},{"Node":{"node_id":5040278174920511484,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[1689789805659535712,{"inputs":[{"Node":{"node_id":15637103575662751567,"output_index":0,"lambda":false}},{"Node":{"node_id":11590691579869262546,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[9778375740427894463,{"inputs":[{"Node":{"node_id":16137033772363318157,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"Fill":{"Solid":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}}},"exposed":false}},{"Value":{"tagged_value":{"OptionalColor":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}},"exposed":false}},{"Value":{"tagged_value":{"Gradient":{"stops":[[0.0,{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}],[1.0,{"red":1.0,"green":1.0,"blue":1.0,"alpha":1.0}]],"gradient_type":"Linear","start":[0.0,0.5],"end":[1.0,0.5],"transform":[1.0,0.0,0.0,1.0,0.0,0.0]}},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::FillNode"}},"visible":true,"skip_deduplication":false}],[5002654561220917457,{"inputs":[{"Node":{"node_id":11632506522064533635,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"F64":35.0},"exposed":false}},{"Value":{"tagged_value":{"U32":206},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":1}},{"Network":{"import_type":{"Concrete":{"name":"u32","alias":null}},"import_index":2}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::PoissonDiskPointsNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":2,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::BoundlessFootprintNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::FreezeRealTimeNode"}},"visible":true,"skip_deduplication":false}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MemoNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[8699675339613677057,{"inputs":[{"Node":{"node_id":15982852655074258238,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"DVec2":[40.2222222222224,-10.469135802469168]},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[1.0,1.0]},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[0.0,0.0]},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[0.5,0.5]},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":1}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":2}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":3}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":4}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":5}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::TransformNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[18207065424980079673,{"inputs":[{"Node":{"node_id":13035777574951374461,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"PointSpacingType":"Separation"},"exposed":false}},{"Value":{"tagged_value":{"F64":5.0},"exposed":false}},{"Value":{"tagged_value":{"U32":100},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"Bool":false},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":4,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::SubpathSegmentLengthsNode"}},"visible":true,"skip_deduplication":false}],[4,{"inputs":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::BoundlessFootprintNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":2,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::FreezeRealTimeNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MemoNode"}},"visible":true,"skip_deduplication":false}],[1,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::misc::PointSpacingType","alias":null}},"import_index":1}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":2}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":3}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":4}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":5}},{"Network":{"import_type":{"Concrete":{"name":"bool","alias":null}},"import_index":6}},{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::SamplePolylineNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[2660652185019504730,{"inputs":[{"Node":{"node_id":1806828617441445250,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"PointSpacingType":"Separation"},"exposed":false}},{"Value":{"tagged_value":{"F64":8.0},"exposed":false}},{"Value":{"tagged_value":{"U32":100},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"Bool":false},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":4,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::SubpathSegmentLengthsNode"}},"visible":true,"skip_deduplication":false}],[4,{"inputs":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::BoundlessFootprintNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":2,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::FreezeRealTimeNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MemoNode"}},"visible":true,"skip_deduplication":false}],[1,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::misc::PointSpacingType","alias":null}},"import_index":1}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":2}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":3}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":4}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":5}},{"Network":{"import_type":{"Concrete":{"name":"bool","alias":null}},"import_index":6}},{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::SamplePolylineNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[2959546142916532439,{"inputs":[{"Value":{"tagged_value":{"VectorData":{"instance":[{"style":{"stroke":{"color":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0},"weight":0.0,"dash_lengths":[],"dash_offset":0.0,"cap":"Butt","join":"Miter","join_miter_limit":4.0,"align":"Center","transform":[1.0,0.0,0.0,1.0,0.0,0.0],"non_scaling":false,"paint_order":"StrokeAbove"},"fill":"None"},"colinear_manipulators":[],"point_domain":{"id":[],"position":[]},"segment_domain":{"id":[],"start_point":[],"end_point":[],"handles":[],"stroke":[]},"region_domain":{"id":[],"segment_range":[],"fill":[]},"upstream_graphic_group":null}],"transform":[[1.0,0.0,0.0,1.0,0.0,0.0]],"alpha_blending":[{"blend_mode":"Normal","opacity":1.0,"fill":1.0,"clip":false}],"source_node_id":[null]}},"exposed":true}},{"Value":{"tagged_value":{"VectorModification":{"points":{"add":[1,2,3,4],"remove":[],"delta":[[3,[0.5,1.0]],[4,[0.0,0.5]],[2,[1.0,0.5]],[1,[0.5,0.0]]]},"segments":{"add":[1,2,3,4],"remove":[],"start_point":[[3,3],[4,4],[1,1],[2,2]],"end_point":[[1,2],[4,1],[3,4],[2,3]],"handle_primary":[[1,[0.27589238888950707,0.0]],[3,[-0.275892388889507,0.0]],[2,[0.0,0.27589238888950707]],[4,[0.0,-0.275892388889507]]],"handle_end":[[4,[-0.275892388889507,0.0]],[2,[0.27589238888950707,0.0]],[1,[0.0,-0.275892388889507]],[3,[0.0,0.27589238888950707]]],"stroke":[[2,0],[3,0],[1,0],[4,0]]},"regions":{"add":[0],"remove":[],"segment_range":[[0,{"start":1,"end":4}]],"fill":[[0,0]]},"add_g1_continuous":[],"remove_g1_continuous":[]}},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::vector_data::modification::VectorModification","alias":null}},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::vector_data::modification::PathModifyNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[11479098559726891734,{"inputs":[{"Value":{"tagged_value":{"VectorData":{"instance":[{"style":{"stroke":{"color":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0},"weight":0.0,"dash_lengths":[],"dash_offset":0.0,"cap":"Butt","join":"Miter","join_miter_limit":4.0,"align":"Center","transform":[1.0,0.0,0.0,1.0,0.0,0.0],"non_scaling":false,"paint_order":"StrokeAbove"},"fill":"None"},"colinear_manipulators":[],"point_domain":{"id":[],"position":[]},"segment_domain":{"id":[],"start_point":[],"end_point":[],"handles":[],"stroke":[]},"region_domain":{"id":[],"segment_range":[],"fill":[]},"upstream_graphic_group":null}],"transform":[[1.0,0.0,0.0,1.0,0.0,0.0]],"alpha_blending":[{"blend_mode":"Normal","opacity":1.0,"fill":1.0,"clip":false}],"source_node_id":[null]}},"exposed":true}},{"Value":{"tagged_value":{"VectorModification":{"points":{"add":[1,2,3,4,5,6,7,8,9,10,11,12],"remove":[],"delta":[[9,[717.5491540923639,95.80978509373573]],[6,[717.9588477366254,99.32144490169182]],[7,[710.5648529187624,103.39887212315196]],[1,[660.660265203475,61.39551897576588]],[10,[712.047553726566,86.56241426611797]],[2,[669.2053040695015,63.20987654320987]],[4,[704.5560128029263,81.29492455418381]],[11,[694.9574759945133,76.78829446730683]],[3,[686.5294924554183,63.38545953360767]],[8,[709.979576284103,102.93065081542449]],[12,[683.3104709647919,64.0877914951989]],[5,[718.310013717421,90.01554641060812]]]},"segments":{"add":[1,2,3,4,5,6,7,8,9,10,11,12],"remove":[],"start_point":[[8,8],[2,2],[3,3],[12,12],[11,11],[6,6],[4,4],[9,9],[10,10],[5,5],[7,7],[1,1]],"end_point":[[9,10],[3,4],[11,12],[1,2],[10,11],[6,7],[12,1],[4,5],[2,3],[7,8],[8,9],[5,6]],"handle_primary":[[4,[8.369455875628773,2.867855509830818]],[8,[0.0,0.0]],[9,[0.17558299039785652,-3.5116598079561214]],[12,[-12.8760859625055,-0.4682213077274682]],[6,[-1.9184335509834227,1.995170893022717]],[2,[5.4430727023319605,-0.6438042981252892]],[1,[0.0,0.0]],[5,[1.1120256058526363,1.9314128943758817]],[3,[3.4531321444902687,2.1655235482396193]],[7,[-0.585276634659408,-0.4682213077274753]],[10,[-4.096936442615174,-1.872885230909901]],[11,[-5.618655692729931,-7.257430269775952]]],"handle_end":[[6,[1.706505264591101,-0.4025776799149554]],[5,[2.926383173296813,-3.043438500228561]],[8,[-0.17558299039785652,3.511659807956093]],[7,null],[9,[4.0931309699032,1.8711455862415676]],[11,[4.036165212980222,0.14676964410837456]],[10,[5.464020763447934,7.057693486120044]],[1,[-5.4430727023319605,0.6438042981252892]],[3,[-8.369455875628773,-2.867855509830818]],[2,[-3.4853769593560173,-2.1857448728164144]],[12,[4.9748513946045705,5.91129401005945]],[4,[-1.8416562954789697,-3.1986661974113133]]],"stroke":[[11,0],[2,0],[10,0],[9,0],[8,0],[1,0],[5,0],[4,0],[7,0],[3,0],[12,0],[6,0]]},"regions":{"add":[0],"remove":[],"segment_range":[[0,{"start":1,"end":12}]],"fill":[[0,0]]},"add_g1_continuous":[],"remove_g1_continuous":[]}},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::vector_data::modification::VectorModification","alias":null}},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::vector_data::modification::PathModifyNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[6282972142629473139,{"inputs":[{"Node":{"node_id":15815816861435910950,"output_index":0,"lambda":false}},{"Node":{"node_id":15578929303912288394,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[3406722917122601552,{"inputs":[{"Value":{"tagged_value":"None","exposed":false}},{"Value":{"tagged_value":{"F64":1.0},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::generator_nodes::CircleNode"}},"visible":true,"skip_deduplication":false}],[16530658574540156160,{"inputs":[{"Node":{"node_id":11666664915283969027,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"DVec2":[23.70370370370381,12.641975308641918]},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[1.0,1.0]},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[0.0,0.0]},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[0.5,0.5]},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":1}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":2}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":3}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":4}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":5}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::TransformNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[1167210731467447244,{"inputs":[{"Node":{"node_id":16551385471328831128,"output_index":0,"lambda":false}},{"Node":{"node_id":10432831427187785843,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[4248321400839848160,{"inputs":[{"Value":{"tagged_value":{"GraphicGroup":{"instance":[],"transform":[],"alpha_blending":[],"source_node_id":[]}},"exposed":true}},{"Node":{"node_id":13231685386999438557,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[907841922684377912,{"inputs":[{"Node":{"node_id":17336535036064625290,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"Fill":{"Solid":{"red":0.7529412,"green":0.15686275,"blue":0.13333334,"alpha":1.0}}},"exposed":false}},{"Value":{"tagged_value":{"OptionalColor":{"red":0.7529412,"green":0.15686275,"blue":0.13333334,"alpha":1.0}},"exposed":false}},{"Value":{"tagged_value":{"Gradient":{"stops":[[0.0,{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}],[1.0,{"red":1.0,"green":1.0,"blue":1.0,"alpha":1.0}]],"gradient_type":"Linear","start":[0.0,0.5],"end":[1.0,0.5],"transform":[1.0,0.0,0.0,1.0,0.0,0.0]}},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::FillNode"}},"visible":true,"skip_deduplication":false}],[12219771677493189964,{"inputs":[{"Value":{"tagged_value":{"GraphicGroup":{"instance":[],"transform":[],"alpha_blending":[],"source_node_id":[]}},"exposed":true}},{"Node":{"node_id":5140869461760168364,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[9954843247420111867,{"inputs":[{"Node":{"node_id":6988349135757634271,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"DVec2":[0.14046639231827385,0.1473642955124319]},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[1.0,1.0]},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[0.0,0.0]},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[0.5,0.5]},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":1}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":2}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":3}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":4}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":5}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::TransformNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[10619788176782820865,{"inputs":[{"Node":{"node_id":2397243911096708995,"output_index":0,"lambda":false}},{"Node":{"node_id":1157261387411722141,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[14285767317419627814,{"inputs":[{"Node":{"node_id":6749771744300551215,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"Fill":{"Solid":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}}},"exposed":false}},{"Value":{"tagged_value":{"OptionalColor":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}},"exposed":false}},{"Value":{"tagged_value":{"Gradient":{"stops":[[0.0,{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}],[1.0,{"red":1.0,"green":1.0,"blue":1.0,"alpha":1.0}]],"gradient_type":"Linear","start":[0.0,0.5],"end":[1.0,0.5],"transform":[1.0,0.0,0.0,1.0,0.0,0.0]}},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::FillNode"}},"visible":true,"skip_deduplication":false}],[12049041947382267086,{"inputs":[{"Node":{"node_id":2959546142916532439,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"DVec2":[25.77777777777777,508.44444444444446]},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[8.0,8.0]},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[0.0,0.0]},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[0.5,0.5]},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":1}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":2}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":3}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":4}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":5}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::TransformNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[11573595155909211511,{"inputs":[{"Node":{"node_id":10127467043900015225,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"PointSpacingType":"Separation"},"exposed":false}},{"Value":{"tagged_value":{"F64":5.0},"exposed":false}},{"Value":{"tagged_value":{"U32":100},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"Bool":false},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":4,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::SubpathSegmentLengthsNode"}},"visible":true,"skip_deduplication":false}],[4,{"inputs":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::BoundlessFootprintNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":2,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::FreezeRealTimeNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MemoNode"}},"visible":true,"skip_deduplication":false}],[1,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::misc::PointSpacingType","alias":null}},"import_index":1}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":2}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":3}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":4}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":5}},{"Network":{"import_type":{"Concrete":{"name":"bool","alias":null}},"import_index":6}},{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::SamplePolylineNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[17891208858820401648,{"inputs":[{"Node":{"node_id":1204243038352113866,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"DVec2":[-7.407407407407391,4.740740740740762]},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[1.0,1.0]},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[0.0,0.0]},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[0.5,0.5]},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":1}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":2}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":3}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":4}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":5}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::TransformNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[15949658764632267703,{"inputs":[{"Node":{"node_id":14012583111791538162,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"PointSpacingType":"Separation"},"exposed":false}},{"Value":{"tagged_value":{"F64":5.0},"exposed":false}},{"Value":{"tagged_value":{"U32":100},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"Bool":false},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":4,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::SubpathSegmentLengthsNode"}},"visible":true,"skip_deduplication":false}],[4,{"inputs":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::BoundlessFootprintNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":2,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::FreezeRealTimeNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MemoNode"}},"visible":true,"skip_deduplication":false}],[1,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::misc::PointSpacingType","alias":null}},"import_index":1}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":2}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":3}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":4}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":5}},{"Network":{"import_type":{"Concrete":{"name":"bool","alias":null}},"import_index":6}},{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::SamplePolylineNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[13352561089252322209,{"inputs":[{"Value":{"tagged_value":{"VectorData":{"instance":[{"style":{"stroke":{"color":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0},"weight":0.0,"dash_lengths":[],"dash_offset":0.0,"cap":"Butt","join":"Miter","join_miter_limit":4.0,"align":"Center","transform":[1.0,0.0,0.0,1.0,0.0,0.0],"non_scaling":false,"paint_order":"StrokeAbove"},"fill":"None"},"colinear_manipulators":[],"point_domain":{"id":[],"position":[]},"segment_domain":{"id":[],"start_point":[],"end_point":[],"handles":[],"stroke":[]},"region_domain":{"id":[],"segment_range":[],"fill":[]},"upstream_graphic_group":null}],"transform":[[1.0,0.0,0.0,1.0,0.0,0.0]],"alpha_blending":[{"blend_mode":"Normal","opacity":1.0,"fill":1.0,"clip":false}],"source_node_id":[null]}},"exposed":true}},{"Value":{"tagged_value":{"VectorModification":{"points":{"add":[1,2,3,4],"remove":[],"delta":[[3,[752.4444444444443,739.1111111111111]],[1,[612.0,1025.3333333333333]],[2,[749.7777777777777,741.7777777777778]],[4,[615.5555555555555,1025.7777777777778]]]},"segments":{"add":[1,2,3,4],"remove":[],"start_point":[[1,1],[4,4],[3,3],[2,2]],"end_point":[[3,4],[1,2],[4,1],[2,3]],"handle_primary":[[1,[0.0,0.0]],[2,[0.0,0.0]],[3,[0.0,0.0]],[4,[0.0,0.0]]],"handle_end":[[2,[0.0,0.0]],[3,[28.000000000000114,-107.55555555555544]],[1,[-112.0,179.55555555555577]],[4,[-0.4444444444444571,0.0]]],"stroke":[[2,0],[4,0],[1,0],[3,0]]},"regions":{"add":[0],"remove":[],"segment_range":[[0,{"start":1,"end":4}]],"fill":[[0,0]]},"add_g1_continuous":[],"remove_g1_continuous":[]}},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::vector_data::modification::VectorModification","alias":null}},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::vector_data::modification::PathModifyNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[10689298484366290551,{"inputs":[{"Value":{"tagged_value":{"VectorData":{"instance":[{"style":{"stroke":{"color":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0},"weight":0.0,"dash_lengths":[],"dash_offset":0.0,"cap":"Butt","join":"Miter","join_miter_limit":4.0,"align":"Center","transform":[1.0,0.0,0.0,1.0,0.0,0.0],"non_scaling":false,"paint_order":"StrokeAbove"},"fill":"None"},"colinear_manipulators":[],"point_domain":{"id":[],"position":[]},"segment_domain":{"id":[],"start_point":[],"end_point":[],"handles":[],"stroke":[]},"region_domain":{"id":[],"segment_range":[],"fill":[]},"upstream_graphic_group":null}],"transform":[[1.0,0.0,0.0,1.0,0.0,0.0]],"alpha_blending":[{"blend_mode":"Normal","opacity":1.0,"fill":1.0,"clip":false}],"source_node_id":[null]}},"exposed":true}},{"Value":{"tagged_value":{"VectorModification":{"points":{"add":[1,2,3],"remove":[],"delta":[[2,[151.22962962962964,252.1283950617284]],[1,[156.93571992954355,246.07901729349]],[3,[155.85185185185185,253.03703703703707]]]},"segments":{"add":[1,2,3],"remove":[],"start_point":[[3,3],[2,2],[1,1]],"end_point":[[3,1],[2,3],[1,2]],"handle_primary":[[1,[-2.071522398679349,1.8617234472507391]],[2,[-0.4744436253241133,1.2651830008642833]],[3,[1.0949818244169762,-0.3546380887060252]]],"handle_end":[[3,[1.9215307714004553,1.0902372408288272]],[1,[0.9481481481481068,-2.5283950617284177]],[2,[-1.0949818244169762,0.3546380887060252]]],"stroke":[[1,0],[2,0],[3,0]]},"regions":{"add":[0],"remove":[],"segment_range":[[0,{"start":1,"end":3}]],"fill":[[0,0]]},"add_g1_continuous":[],"remove_g1_continuous":[]}},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::vector_data::modification::VectorModification","alias":null}},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::vector_data::modification::PathModifyNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[1785173043494067496,{"inputs":[{"Value":{"tagged_value":{"VectorData":{"instance":[{"style":{"stroke":{"color":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0},"weight":0.0,"dash_lengths":[],"dash_offset":0.0,"cap":"Butt","join":"Miter","join_miter_limit":4.0,"align":"Center","transform":[1.0,0.0,0.0,1.0,0.0,0.0],"non_scaling":false,"paint_order":"StrokeAbove"},"fill":"None"},"colinear_manipulators":[],"point_domain":{"id":[],"position":[]},"segment_domain":{"id":[],"start_point":[],"end_point":[],"handles":[],"stroke":[]},"region_domain":{"id":[],"segment_range":[],"fill":[]},"upstream_graphic_group":null}],"transform":[[1.0,0.0,0.0,1.0,0.0,0.0]],"alpha_blending":[{"blend_mode":"Normal","opacity":1.0,"fill":1.0,"clip":false}],"source_node_id":[null]}},"exposed":true}},{"Value":{"tagged_value":{"VectorModification":{"points":{"add":[1,2,3,4],"remove":[],"delta":[[2,[636.4444444444443,579.5555555555555]],[4,[770.2222222222222,459.1111111111111]],[1,[566.6666666666666,576.0]],[3,[712.0,519.1111111111111]]]},"segments":{"add":[1,2,3],"remove":[],"start_point":[[1,1],[2,2],[3,3]],"end_point":[[1,2],[3,4],[2,3]],"handle_primary":[[2,[31.1111111111112,-17.33333333333337]],[1,[0.0,0.0]],[3,[18.22222222222217,-21.777777777777715]]],"handle_end":[[3,[0.0,0.0]],[2,[-18.22222222222217,21.777777777777715]],[1,[-31.1111111111112,17.33333333333337]]],"stroke":[[3,0],[1,0],[2,0]]},"regions":{"add":[],"remove":[],"segment_range":[],"fill":[]},"add_g1_continuous":[],"remove_g1_continuous":[]}},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::vector_data::modification::VectorModification","alias":null}},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::vector_data::modification::PathModifyNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[12554368619682347699,{"inputs":[{"Node":{"node_id":2594533001540454577,"output_index":0,"lambda":false}},{"Node":{"node_id":17078740291337047697,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"F64":2.0},"exposed":false}},{"Value":{"tagged_value":{"F64":3.0},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"U32":0},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"U32":0},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::CopyToPointsNode"}},"visible":true,"skip_deduplication":false}],[13261814586176172586,{"inputs":[{"Value":{"tagged_value":{"VectorData":{"instance":[{"style":{"stroke":{"color":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0},"weight":0.0,"dash_lengths":[],"dash_offset":0.0,"cap":"Butt","join":"Miter","join_miter_limit":4.0,"align":"Center","transform":[1.0,0.0,0.0,1.0,0.0,0.0],"non_scaling":false,"paint_order":"StrokeAbove"},"fill":"None"},"colinear_manipulators":[],"point_domain":{"id":[],"position":[]},"segment_domain":{"id":[],"start_point":[],"end_point":[],"handles":[],"stroke":[]},"region_domain":{"id":[],"segment_range":[],"fill":[]},"upstream_graphic_group":null}],"transform":[[1.0,0.0,0.0,1.0,0.0,0.0]],"alpha_blending":[{"blend_mode":"Normal","opacity":1.0,"fill":1.0,"clip":false}],"source_node_id":[null]}},"exposed":true}},{"Value":{"tagged_value":{"VectorModification":{"points":{"add":[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16],"remove":[],"delta":[[13,[736.8888888888889,432.2962962962963]],[8,[686.5302034429451,490.6109861193811]],[14,[782.8148148148148,378.96296296296293]],[16,[809.1851851851852,207.1111111111111]],[12,[715.8518518518517,452.14814814814815]],[3,[851.1111111111111,237.7777777777778]],[4,[858.6666666666666,268.88888888888886]],[11,[719.9999999999999,460.8395061728396]],[5,[829.8271604938273,345.08641975308643]],[1,[799.1111111111112,188.14814814814815]],[7,[680.4331323644109,506.0568995183343]],[15,[817.4814814814815,272.2962962962963]],[6,[775.5061728395061,429.23456790123464]],[9,[758.716049382716,441.8765432098765]],[10,[755.3580246913581,432.5925925925926]],[2,[827.2592592592594,206.41975308641975]]]},"segments":{"add":[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16],"remove":[],"start_point":[[9,9],[11,11],[12,12],[2,2],[8,8],[6,6],[10,10],[3,3],[16,16],[13,13],[14,14],[15,15],[4,4],[1,1],[7,7],[5,5]],"end_point":[[1,2],[6,7],[3,4],[4,5],[8,9],[15,16],[14,15],[16,1],[2,3],[7,8],[9,10],[13,14],[5,6],[11,12],[10,11],[12,13]],"handle_primary":[[6,[-36.541158121167314,42.67873357730855]],[10,[0.0,0.0]],[5,[-31.06481223802939,48.93526760703577]],[7,null],[16,[0.0,0.0]],[8,[37.39536928167615,-11.787670751832536]],[14,[20.148148148148152,-33.481481481481524]],[12,[0.0,0.0]],[11,[0.0,0.0]],[9,[0.0,0.0]],[1,[0.0,0.0]],[4,[-2.5679012345678984,17.77777777777777]],[15,[5.925925925925867,-34.96296296296299]],[2,[0.0,0.0]],[13,[0.0,0.0]],[3,[9.086419753086489,9.086419753086432]]],"handle_end":[[15,[6.51851851851859,11.851851851851848]],[3,[2.5679012345678984,-17.77777777777777]],[16,[0.0,0.0]],[9,[0.0,0.0]],[8,[-11.555555555555657,17.18518518518522]],[1,[0.0,0.0]],[13,[-20.148148148148152,33.481481481481524]],[6,[22.320987654321016,-14.222222222222342]],[14,[-5.925925925925867,34.96296296296299]],[7,null],[2,[-9.086419753086489,-9.086419753086432]],[12,[0.0,0.0]],[11,[0.0,0.0]],[5,[18.3855550289378,-21.473654506216747]],[10,[0.0,0.0]],[4,[31.06481223802939,-48.93526760703571]]],"stroke":[[9,0],[13,0],[1,0],[12,0],[6,0],[14,0],[4,0],[15,0],[3,0],[7,0],[8,0],[10,0],[5,0],[16,0],[2,0],[11,0]]},"regions":{"add":[0],"remove":[],"segment_range":[[0,{"start":1,"end":16}]],"fill":[[0,0]]},"add_g1_continuous":[],"remove_g1_continuous":[]}},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::vector_data::modification::VectorModification","alias":null}},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::vector_data::modification::PathModifyNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[11616089678400336955,{"inputs":[{"Node":{"node_id":2660652185019504730,"output_index":0,"lambda":false}},{"Node":{"node_id":17078740291337047697,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"F64":1.8},"exposed":false}},{"Value":{"tagged_value":{"F64":3.0},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"U32":0},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"U32":0},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::CopyToPointsNode"}},"visible":true,"skip_deduplication":false}],[17336535036064625290,{"inputs":[{"Node":{"node_id":10421722418968896452,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"DVec2":[49.47996245659249,5.913900401382151]},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[0.9277405532359332,0.9277405532359332]},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[0.0,0.0]},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[0.5,0.5]},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":1}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":2}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":3}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":4}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":5}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::TransformNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[1621196991038859321,{"inputs":[{"Node":{"node_id":15857077552290328068,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"PointSpacingType":"Separation"},"exposed":false}},{"Value":{"tagged_value":{"F64":5.0},"exposed":false}},{"Value":{"tagged_value":{"U32":100},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"Bool":false},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":4,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::SubpathSegmentLengthsNode"}},"visible":true,"skip_deduplication":false}],[4,{"inputs":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::BoundlessFootprintNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":2,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::FreezeRealTimeNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MemoNode"}},"visible":true,"skip_deduplication":false}],[1,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::misc::PointSpacingType","alias":null}},"import_index":1}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":2}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":3}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":4}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":5}},{"Network":{"import_type":{"Concrete":{"name":"bool","alias":null}},"import_index":6}},{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::SamplePolylineNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[3150436463719911922,{"inputs":[{"Node":{"node_id":18214377096178867498,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"DVec2":[0.0,0.0]},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[1.0,1.0]},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[0.0,0.0]},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[0.5,0.5]},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":1}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":2}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":3}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":4}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":5}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::TransformNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[5455777299776842371,{"inputs":[{"Node":{"node_id":9470742171134780193,"output_index":0,"lambda":false}},{"Node":{"node_id":7385465194555106679,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[13045580349734858212,{"inputs":[{"Node":{"node_id":10795820039540504703,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"F64":5.0},"exposed":false}},{"Value":{"tagged_value":{"U32":0},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":1}},{"Network":{"import_type":{"Concrete":{"name":"u32","alias":null}},"import_index":2}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::PoissonDiskPointsNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":2,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::BoundlessFootprintNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::FreezeRealTimeNode"}},"visible":true,"skip_deduplication":false}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MemoNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[10432831427187785843,{"inputs":[{"Node":{"node_id":2087303479944421366,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"Fill":{"Solid":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}}},"exposed":false}},{"Value":{"tagged_value":{"OptionalColor":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}},"exposed":false}},{"Value":{"tagged_value":{"Gradient":{"stops":[[0.0,{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}],[1.0,{"red":1.0,"green":1.0,"blue":1.0,"alpha":1.0}]],"gradient_type":"Linear","start":[0.0,0.5],"end":[1.0,0.5],"transform":[1.0,0.0,0.0,1.0,0.0,0.0]}},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::FillNode"}},"visible":true,"skip_deduplication":false}],[14209241002058525241,{"inputs":[{"Node":{"node_id":16290933138334939444,"output_index":0,"lambda":false}},{"Node":{"node_id":10918055532782314571,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[9374264173303233490,{"inputs":[{"Node":{"node_id":1713644030979611623,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"PointSpacingType":"Separation"},"exposed":false}},{"Value":{"tagged_value":{"F64":5.0},"exposed":false}},{"Value":{"tagged_value":{"U32":100},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"Bool":false},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":4,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::SubpathSegmentLengthsNode"}},"visible":true,"skip_deduplication":false}],[4,{"inputs":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::BoundlessFootprintNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":2,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::FreezeRealTimeNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MemoNode"}},"visible":true,"skip_deduplication":false}],[1,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::misc::PointSpacingType","alias":null}},"import_index":1}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":2}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":3}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":4}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":5}},{"Network":{"import_type":{"Concrete":{"name":"bool","alias":null}},"import_index":6}},{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::SamplePolylineNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[8934999452649011837,{"inputs":[{"Node":{"node_id":16796171662855500935,"output_index":0,"lambda":false}},{"Node":{"node_id":16756940771483104467,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[4787732047489141819,{"inputs":[{"Node":{"node_id":12062649793560663566,"output_index":0,"lambda":false}},{"Node":{"node_id":4248321400839848160,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[16614450796751955858,{"inputs":[{"Value":{"tagged_value":{"VectorData":{"instance":[{"style":{"stroke":{"color":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0},"weight":0.0,"dash_lengths":[],"dash_offset":0.0,"cap":"Butt","join":"Miter","join_miter_limit":4.0,"align":"Center","transform":[1.0,0.0,0.0,1.0,0.0,0.0],"non_scaling":false,"paint_order":"StrokeAbove"},"fill":"None"},"colinear_manipulators":[],"point_domain":{"id":[],"position":[]},"segment_domain":{"id":[],"start_point":[],"end_point":[],"handles":[],"stroke":[]},"region_domain":{"id":[],"segment_range":[],"fill":[]},"upstream_graphic_group":null}],"transform":[[1.0,0.0,0.0,1.0,0.0,0.0]],"alpha_blending":[{"blend_mode":"Normal","opacity":1.0,"fill":1.0,"clip":false}],"source_node_id":[null]}},"exposed":true}},{"Value":{"tagged_value":{"VectorModification":{"points":{"add":[1,2,3,4,5,6,7],"remove":[],"delta":[[6,[845.3333333333333,842.0000000000001]],[5,[807.3333333333334,1026.0]],[4,[327.3333333333333,1024.6666666666663]],[1,[902.6666666666666,446.6666666666667]],[7,[918.6666666666664,604.6666666666666]],[2,[757.1358024691358,661.5308641975308]],[3,[481.33333333333337,826.6666666666666]]]},"segments":{"add":[1,2,3,4,5,6,7],"remove":[],"start_point":[[5,5],[3,3],[6,6],[7,7],[1,1],[2,2],[4,4]],"end_point":[[7,1],[2,3],[4,5],[3,4],[5,6],[6,7],[1,2]],"handle_primary":[[6,[49.4943341398548,-116.98660796692934]],[2,[-138.41983388553547,108.26897897977506]],[4,[0.0,0.0]],[5,[0.0,0.0]],[3,[-131.33333333333337,78.66666666666652]],[7,[16.000000000000227,-89.99999999999989]],[1,[0.0,0.0]]],"handle_end":[[4,[0.0,0.0]],[7,[3.3333333333333712,32.00000000000006]],[1,[134.66666666666686,-105.33333333333326]],[6,[-16.71260304301461,94.00839211695676]],[3,[0.0,0.0]],[5,[-36.66666666666663,86.66666666666652]],[2,[143.2366194125077,-85.79655375977609]]],"stroke":[[7,0],[3,0],[4,0],[2,0],[5,0],[1,0],[6,0]]},"regions":{"add":[0],"remove":[],"segment_range":[[0,{"start":1,"end":7}]],"fill":[[0,0]]},"add_g1_continuous":[],"remove_g1_continuous":[]}},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::vector_data::modification::VectorModification","alias":null}},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::vector_data::modification::PathModifyNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[6666260895482068061,{"inputs":[{"Value":{"tagged_value":{"VectorData":{"instance":[{"style":{"stroke":{"color":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0},"weight":0.0,"dash_lengths":[],"dash_offset":0.0,"cap":"Butt","join":"Miter","join_miter_limit":4.0,"align":"Center","transform":[1.0,0.0,0.0,1.0,0.0,0.0],"non_scaling":false,"paint_order":"StrokeAbove"},"fill":"None"},"colinear_manipulators":[],"point_domain":{"id":[],"position":[]},"segment_domain":{"id":[],"start_point":[],"end_point":[],"handles":[],"stroke":[]},"region_domain":{"id":[],"segment_range":[],"fill":[]},"upstream_graphic_group":null}],"transform":[[1.0,0.0,0.0,1.0,0.0,0.0]],"alpha_blending":[{"blend_mode":"Normal","opacity":1.0,"fill":1.0,"clip":false}],"source_node_id":[null]}},"exposed":true}},{"Value":{"tagged_value":{"VectorModification":{"points":{"add":[1,2,3,4],"remove":[],"delta":[[3,[646.4033730994855,154.80329633678198]],[1,[643.0921942512911,135.30336230847865]],[2,[645.6821893629258,155.3850506865855]],[4,[645.3845450388659,135.9012345679012]]]},"segments":{"add":[1,2,3,4],"remove":[],"start_point":[[2,2],[3,3],[4,4],[1,1]],"end_point":[[4,1],[1,2],[2,3],[3,4]],"handle_primary":[[4,[0.0,0.0]],[3,[-0.2558402858584259,-10.083527774255913]],[1,[0.0,0.0]],[2,[0.0,0.0]]],"handle_end":[[3,[0.0,0.0]],[4,[1.68322954928135,-0.022087435068414152]],[1,[-0.05703059647760256,-13.444628325495556]],[2,[-0.3446760851414865,0.611494768909921]]],"stroke":[[4,0],[3,0],[2,0],[1,0]]},"regions":{"add":[0],"remove":[],"segment_range":[[0,{"start":1,"end":4}]],"fill":[[0,0]]},"add_g1_continuous":[],"remove_g1_continuous":[]}},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::vector_data::modification::VectorModification","alias":null}},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::vector_data::modification::PathModifyNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[7893851488963635918,{"inputs":[{"Value":{"tagged_value":{"VectorData":{"instance":[{"style":{"stroke":{"color":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0},"weight":0.0,"dash_lengths":[],"dash_offset":0.0,"cap":"Butt","join":"Miter","join_miter_limit":4.0,"align":"Center","transform":[1.0,0.0,0.0,1.0,0.0,0.0],"non_scaling":false,"paint_order":"StrokeAbove"},"fill":"None"},"colinear_manipulators":[],"point_domain":{"id":[],"position":[]},"segment_domain":{"id":[],"start_point":[],"end_point":[],"handles":[],"stroke":[]},"region_domain":{"id":[],"segment_range":[],"fill":[]},"upstream_graphic_group":null}],"transform":[[1.0,0.0,0.0,1.0,0.0,0.0]],"alpha_blending":[{"blend_mode":"Normal","opacity":1.0,"fill":1.0,"clip":false}],"source_node_id":[null]}},"exposed":true}},{"Value":{"tagged_value":{"VectorModification":{"points":{"add":[1,2],"remove":[],"delta":[[2,[24.0,486.0]],[1,[125.0,420.0]]]},"segments":{"add":[1],"remove":[],"start_point":[[1,1]],"end_point":[[1,2]],"handle_primary":[[1,[0.0,0.0]]],"handle_end":[[1,[23.0,-70.0]]],"stroke":[[1,0]]},"regions":{"add":[],"remove":[],"segment_range":[],"fill":[]},"add_g1_continuous":[],"remove_g1_continuous":[]}},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::vector_data::modification::VectorModification","alias":null}},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::vector_data::modification::PathModifyNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[3802858053991775169,{"inputs":[{"Node":{"node_id":11058365317860779469,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"F64":25.0},"exposed":false}},{"Value":{"tagged_value":{"U32":0},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":1}},{"Network":{"import_type":{"Concrete":{"name":"u32","alias":null}},"import_index":2}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::PoissonDiskPointsNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":2,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::BoundlessFootprintNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::FreezeRealTimeNode"}},"visible":true,"skip_deduplication":false}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MemoNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[11199691961479466803,{"inputs":[{"Node":{"node_id":7141088190930752823,"output_index":0,"lambda":false}},{"Node":{"node_id":17078740291337047697,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"F64":1.2},"exposed":false}},{"Value":{"tagged_value":{"F64":2.0},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"U32":0},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"U32":0},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::CopyToPointsNode"}},"visible":true,"skip_deduplication":false}],[7141088190930752823,{"inputs":[{"Node":{"node_id":541002100261582638,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"PointSpacingType":"Separation"},"exposed":false}},{"Value":{"tagged_value":{"F64":5.0},"exposed":false}},{"Value":{"tagged_value":{"U32":100},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"Bool":false},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":4,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::SubpathSegmentLengthsNode"}},"visible":true,"skip_deduplication":false}],[4,{"inputs":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::BoundlessFootprintNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":2,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::FreezeRealTimeNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MemoNode"}},"visible":true,"skip_deduplication":false}],[1,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::misc::PointSpacingType","alias":null}},"import_index":1}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":2}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":3}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":4}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":5}},{"Network":{"import_type":{"Concrete":{"name":"bool","alias":null}},"import_index":6}},{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::SamplePolylineNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[18319784717194273926,{"inputs":[{"Value":{"tagged_value":{"VectorData":{"instance":[{"style":{"stroke":{"color":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0},"weight":0.0,"dash_lengths":[],"dash_offset":0.0,"cap":"Butt","join":"Miter","join_miter_limit":4.0,"align":"Center","transform":[1.0,0.0,0.0,1.0,0.0,0.0],"non_scaling":false,"paint_order":"StrokeAbove"},"fill":"None"},"colinear_manipulators":[],"point_domain":{"id":[],"position":[]},"segment_domain":{"id":[],"start_point":[],"end_point":[],"handles":[],"stroke":[]},"region_domain":{"id":[],"segment_range":[],"fill":[]},"upstream_graphic_group":null}],"transform":[[1.0,0.0,0.0,1.0,0.0,0.0]],"alpha_blending":[{"blend_mode":"Normal","opacity":1.0,"fill":1.0,"clip":false}],"source_node_id":[null]}},"exposed":true}},{"Value":{"tagged_value":{"VectorModification":{"points":{"add":[1,2,3,4,5,6,7,8,9,10,11,12],"remove":[],"delta":[[3,[167.0,691.0]],[10,[610.6666666666666,712.4444444444443]],[7,[558.6666666666666,749.7777777777778]],[8,[706.6666666666666,687.5555555555554]],[5,[418.2222222222222,754.6666666666666]],[2,[150.22222222222223,568.4444444444445]],[11,[595.0,690.0]],[6,[443.1111111111111,783.1111111111111]],[9,[828.0,570.2222222222221]],[4,[574.6666666666666,712.4444444444443]],[12,[437.99999999999994,690.0]],[1,[172.22222222222217,564.7777777777779]]]},"segments":{"add":[1,2,3,4,5,6,7,8,9,10,11,12],"remove":[],"start_point":[[3,3],[11,11],[5,5],[1,1],[12,12],[7,7],[4,4],[6,6],[9,9],[8,8],[2,2],[10,10]],"end_point":[[8,9],[11,12],[5,6],[6,7],[1,2],[9,10],[10,11],[4,5],[12,1],[3,4],[7,8],[2,3]],"handle_primary":[[8,[60.44444444444446,-39.55555555555566]],[5,[0.0,0.0]],[12,[-98.22222222222224,-28.0]],[6,[0.0,0.0]],[7,[32.888888888888914,-13.333333333333483]],[10,[0.0,0.0]],[3,[0.0,0.0]],[1,[0.0,0.0]],[2,[18.111111111111057,85.22222222222229]],[9,[0.0,0.0]],[4,[0.0,0.0]],[11,[0.0,0.0]]],"handle_end":[[10,[-1.3333333333333712,21.77777777777783]],[5,[-18.66666666666663,-4.888888888888914]],[9,[145.77777777777771,-61.777777777777715]],[7,[-60.44444444444446,39.55555555555566]],[4,[54.22222222222223,-9.333333333333371]],[6,[-32.888888888888914,13.333333333333483]],[1,null],[8,[0.0,0.0]],[12,[161.33333333333337,34.66666666666674]],[3,[-128.44444444444446,26.22222222222217]],[2,null],[11,[98.22222222222224,28.0]]],"stroke":[[4,0],[10,0],[9,0],[3,0],[8,0],[5,0],[6,0],[11,0],[7,0],[12,0],[2,0],[1,0]]},"regions":{"add":[0],"remove":[],"segment_range":[[0,{"start":1,"end":12}]],"fill":[[0,0]]},"add_g1_continuous":[],"remove_g1_continuous":[]}},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::vector_data::modification::VectorModification","alias":null}},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::vector_data::modification::PathModifyNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[4479074488343511985,{"inputs":[{"Node":{"node_id":11479098559726891734,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"Fill":{"Solid":{"red":0.8980392,"green":0.8,"blue":0.6156863,"alpha":1.0}}},"exposed":false}},{"Value":{"tagged_value":{"OptionalColor":{"red":0.8980392,"green":0.8,"blue":0.6156863,"alpha":1.0}},"exposed":false}},{"Value":{"tagged_value":{"Gradient":{"stops":[[0.0,{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}],[1.0,{"red":1.0,"green":1.0,"blue":1.0,"alpha":1.0}]],"gradient_type":"Linear","start":[0.0,0.5],"end":[1.0,0.5],"transform":[1.0,0.0,0.0,1.0,0.0,0.0]}},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::FillNode"}},"visible":true,"skip_deduplication":false}],[16137033772363318157,{"inputs":[{"Value":{"tagged_value":{"VectorData":{"instance":[{"style":{"stroke":{"color":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0},"weight":0.0,"dash_lengths":[],"dash_offset":0.0,"cap":"Butt","join":"Miter","join_miter_limit":4.0,"align":"Center","transform":[1.0,0.0,0.0,1.0,0.0,0.0],"non_scaling":false,"paint_order":"StrokeAbove"},"fill":"None"},"colinear_manipulators":[],"point_domain":{"id":[],"position":[]},"segment_domain":{"id":[],"start_point":[],"end_point":[],"handles":[],"stroke":[]},"region_domain":{"id":[],"segment_range":[],"fill":[]},"upstream_graphic_group":null}],"transform":[[1.0,0.0,0.0,1.0,0.0,0.0]],"alpha_blending":[{"blend_mode":"Normal","opacity":1.0,"fill":1.0,"clip":false}],"source_node_id":[null]}},"exposed":true}},{"Value":{"tagged_value":{"VectorModification":{"points":{"add":[1,2,3],"remove":[],"delta":[[2,[720.417009602195,178.00603566529497]],[1,[688.566255144033,175.3371742112483]],[3,[720.1360768175583,181.58792866941016]]]},"segments":{"add":[1,2,3],"remove":[],"start_point":[[2,2],[3,3],[1,1]],"end_point":[[1,2],[3,1],[2,3]],"handle_primary":[[1,[29.423007364946784,-0.024697364703285984]],[3,[-1.1237311385458495,-3.125377229080982]],[2,[1.8041152263373303,2.00164609053499]]],"handle_end":[[3,[12.04499314128941,0.8076817558298615]],[1,null],[2,null]],"stroke":[[3,0],[1,0],[2,0]]},"regions":{"add":[0],"remove":[],"segment_range":[[0,{"start":1,"end":3}]],"fill":[[0,0]]},"add_g1_continuous":[],"remove_g1_continuous":[]}},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::vector_data::modification::VectorModification","alias":null}},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::vector_data::modification::PathModifyNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[3170924135668664007,{"inputs":[{"Node":{"node_id":4787732047489141819,"output_index":0,"lambda":false}},{"Node":{"node_id":13444661581815146533,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[16051539163551573193,{"inputs":[{"Value":{"tagged_value":{"VectorData":{"instance":[{"style":{"stroke":{"color":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0},"weight":0.0,"dash_lengths":[],"dash_offset":0.0,"cap":"Butt","join":"Miter","join_miter_limit":4.0,"align":"Center","transform":[1.0,0.0,0.0,1.0,0.0,0.0],"non_scaling":false,"paint_order":"StrokeAbove"},"fill":"None"},"colinear_manipulators":[],"point_domain":{"id":[],"position":[]},"segment_domain":{"id":[],"start_point":[],"end_point":[],"handles":[],"stroke":[]},"region_domain":{"id":[],"segment_range":[],"fill":[]},"upstream_graphic_group":null}],"transform":[[1.0,0.0,0.0,1.0,0.0,0.0]],"alpha_blending":[{"blend_mode":"Normal","opacity":1.0,"fill":1.0,"clip":false}],"source_node_id":[null]}},"exposed":true}},{"Value":{"tagged_value":{"VectorModification":{"points":{"add":[1,2,3,4,5],"remove":[],"delta":[[4,[519.1111111111111,1026.2222222222222]],[1,[708.0000000000001,769.3333333333333]],[2,[609.7777777777777,896.0]],[3,[514.6666666666666,1025.7777777777778]],[5,[588.0,930.6666666666666]]]},"segments":{"add":[1,2,3,4,5],"remove":[],"start_point":[[5,5],[2,2],[3,3],[1,1],[4,4]],"end_point":[[3,4],[5,1],[4,5],[1,2],[2,3]],"handle_primary":[[3,[0.0,0.0]],[1,[0.0,0.0]],[4,[0.0,0.0]],[5,[24.0,-29.77777777777783]],[2,[-54.66666666666663,69.33333333333314]]],"handle_end":[[2,[0.0,0.0]],[1,[54.66666666666663,-69.33333333333326]],[5,[-28.44444444444457,47.111111111111086]],[4,[-24.0,29.777777777777715]],[3,[0.0,0.0]]],"stroke":[[1,0],[4,0],[5,0],[2,0],[3,0]]},"regions":{"add":[0],"remove":[],"segment_range":[[0,{"start":1,"end":5}]],"fill":[[0,0]]},"add_g1_continuous":[],"remove_g1_continuous":[]}},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::vector_data::modification::VectorModification","alias":null}},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::vector_data::modification::PathModifyNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[6292009934909381201,{"inputs":[{"Node":{"node_id":10424806499648491677,"output_index":0,"lambda":false}},{"Node":{"node_id":9778375740427894463,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[1204243038352113866,{"inputs":[{"Value":{"tagged_value":{"VectorData":{"instance":[{"style":{"stroke":{"color":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0},"weight":0.0,"dash_lengths":[],"dash_offset":0.0,"cap":"Butt","join":"Miter","join_miter_limit":4.0,"align":"Center","transform":[1.0,0.0,0.0,1.0,0.0,0.0],"non_scaling":false,"paint_order":"StrokeAbove"},"fill":"None"},"colinear_manipulators":[],"point_domain":{"id":[],"position":[]},"segment_domain":{"id":[],"start_point":[],"end_point":[],"handles":[],"stroke":[]},"region_domain":{"id":[],"segment_range":[],"fill":[]},"upstream_graphic_group":null}],"transform":[[1.0,0.0,0.0,1.0,0.0,0.0]],"alpha_blending":[{"blend_mode":"Normal","opacity":1.0,"fill":1.0,"clip":false}],"source_node_id":[null]}},"exposed":true}},{"Value":{"tagged_value":{"VectorModification":{"points":{"add":[1,2],"remove":[],"delta":[[1,[808.8888888888889,832.2962962962965]],[2,[837.3333333333334,653.6296296296296]]]},"segments":{"add":[1,2],"remove":[],"start_point":[[1,1],[2,2]],"end_point":[[2,1],[1,2]],"handle_primary":[[2,[-26.22222222222217,80.29629629629608]],[1,[0.0,0.0]]],"handle_end":[[2,[0.0,-0.4444444444443434]],[1,[-22.22222222222217,79.40740740740739]]],"stroke":[[2,0],[1,0]]},"regions":{"add":[0],"remove":[],"segment_range":[[0,{"start":1,"end":2}]],"fill":[[0,0]]},"add_g1_continuous":[],"remove_g1_continuous":[]}},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::vector_data::modification::VectorModification","alias":null}},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::vector_data::modification::PathModifyNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[12062649793560663566,{"inputs":[{"Node":{"node_id":5455777299776842371,"output_index":0,"lambda":false}},{"Node":{"node_id":8934999452649011837,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[17494926338451345058,{"inputs":[{"Node":{"node_id":1167210731467447244,"output_index":0,"lambda":false}},{"Node":{"node_id":9529195152569434392,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[14098374807212007572,{"inputs":[{"Node":{"node_id":17494926338451345058,"output_index":0,"lambda":false}},{"Node":{"node_id":10336592647221792772,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[4572557574846980832,{"inputs":[{"Node":{"node_id":13014916927589286309,"output_index":0,"lambda":false}},{"Node":{"node_id":4332145463108161926,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"F64":0.5},"exposed":false}},{"Value":{"tagged_value":{"F64":30.0},"exposed":false}},{"Value":{"tagged_value":{"F64":-60.0},"exposed":false}},{"Value":{"tagged_value":{"U32":0},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"U32":0},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::CopyToPointsNode"}},"visible":true,"skip_deduplication":false}],[3992858139802231032,{"inputs":[{"Value":{"tagged_value":{"VectorData":{"instance":[{"style":{"stroke":{"color":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0},"weight":0.0,"dash_lengths":[],"dash_offset":0.0,"cap":"Butt","join":"Miter","join_miter_limit":4.0,"align":"Center","transform":[1.0,0.0,0.0,1.0,0.0,0.0],"non_scaling":false,"paint_order":"StrokeAbove"},"fill":"None"},"colinear_manipulators":[],"point_domain":{"id":[],"position":[]},"segment_domain":{"id":[],"start_point":[],"end_point":[],"handles":[],"stroke":[]},"region_domain":{"id":[],"segment_range":[],"fill":[]},"upstream_graphic_group":null}],"transform":[[1.0,0.0,0.0,1.0,0.0,0.0]],"alpha_blending":[{"blend_mode":"Normal","opacity":1.0,"fill":1.0,"clip":false}],"source_node_id":[null]}},"exposed":true}},{"Value":{"tagged_value":{"VectorModification":{"points":{"add":[1,2,3,4],"remove":[],"delta":[[2,[635.8445358939186,153.225422953818]],[1,[634.615454961134,135.08184727937814]],[4,[645.384545038866,135.90123456790124]],[3,[648.9547325102881,151.8792866941015]]]},"segments":{"add":[1,2,3,4],"remove":[],"start_point":[[4,4],[3,3],[2,2],[1,1]],"end_point":[[2,3],[4,1],[3,4],[1,2]],"handle_primary":[[4,[0.0,0.0]],[3,[1.8143575674440624,-2.575217192501128]],[1,[0.0,0.0]],[2,[6.203932327389111,7.491540923639718]]],"handle_end":[[1,[-6.203932327389111,-7.491540923639718]],[4,[9.247370827617717,-0.3511659807956278]],[3,[6.730681298582454,7.257430269775966]],[2,[-1.8143575674440624,2.575217192501128]]],"stroke":[[4,0],[2,0],[1,0],[3,0]]},"regions":{"add":[0],"remove":[],"segment_range":[[0,{"start":1,"end":4}]],"fill":[[0,0]]},"add_g1_continuous":[],"remove_g1_continuous":[]}},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::vector_data::modification::VectorModification","alias":null}},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::vector_data::modification::PathModifyNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[8091904580702893317,{"inputs":[{"Node":{"node_id":15446793500614592278,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"Fill":{"Solid":{"red":0.8980392,"green":0.8,"blue":0.6117647,"alpha":1.0}}},"exposed":false}},{"Value":{"tagged_value":{"OptionalColor":{"red":0.8980392,"green":0.8,"blue":0.6117647,"alpha":1.0}},"exposed":false}},{"Value":{"tagged_value":{"Gradient":{"stops":[[0.0,{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}],[1.0,{"red":1.0,"green":1.0,"blue":1.0,"alpha":1.0}]],"gradient_type":"Linear","start":[0.0,0.5],"end":[1.0,0.5],"transform":[1.0,0.0,0.0,1.0,0.0,0.0]}},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::FillNode"}},"visible":true,"skip_deduplication":false}],[15492651270767932214,{"inputs":[{"Node":{"node_id":6580280438672662494,"output_index":0,"lambda":false}},{"Node":{"node_id":2698266912167150713,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[10918055532782314571,{"inputs":[{"Node":{"node_id":7447657690776686262,"output_index":0,"lambda":false}},{"Node":{"node_id":17078740291337047697,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"F64":1.2},"exposed":false}},{"Value":{"tagged_value":{"F64":2.0},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"U32":0},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"U32":0},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::CopyToPointsNode"}},"visible":true,"skip_deduplication":false}],[18067513817508158001,{"inputs":[{"Node":{"node_id":16649851742084147477,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"PointSpacingType":"Separation"},"exposed":false}},{"Value":{"tagged_value":{"F64":5.0},"exposed":false}},{"Value":{"tagged_value":{"U32":100},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"Bool":false},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":4,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::SubpathSegmentLengthsNode"}},"visible":true,"skip_deduplication":false}],[4,{"inputs":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::BoundlessFootprintNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":2,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::FreezeRealTimeNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MemoNode"}},"visible":true,"skip_deduplication":false}],[1,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::misc::PointSpacingType","alias":null}},"import_index":1}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":2}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":3}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":4}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":5}},{"Network":{"import_type":{"Concrete":{"name":"bool","alias":null}},"import_index":6}},{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::SamplePolylineNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[1661691009086487874,{"inputs":[{"Node":{"node_id":14797986717815207528,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"PointSpacingType":"Separation"},"exposed":false}},{"Value":{"tagged_value":{"F64":5.0},"exposed":false}},{"Value":{"tagged_value":{"U32":100},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"Bool":false},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":4,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::SubpathSegmentLengthsNode"}},"visible":true,"skip_deduplication":false}],[4,{"inputs":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::BoundlessFootprintNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":2,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::FreezeRealTimeNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MemoNode"}},"visible":true,"skip_deduplication":false}],[1,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::misc::PointSpacingType","alias":null}},"import_index":1}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":2}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":3}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":4}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":5}},{"Network":{"import_type":{"Concrete":{"name":"bool","alias":null}},"import_index":6}},{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::SamplePolylineNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[14029368390543839187,{"inputs":[{"Value":{"tagged_value":{"VectorData":{"instance":[{"style":{"stroke":{"color":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0},"weight":0.0,"dash_lengths":[],"dash_offset":0.0,"cap":"Butt","join":"Miter","join_miter_limit":4.0,"align":"Center","transform":[1.0,0.0,0.0,1.0,0.0,0.0],"non_scaling":false,"paint_order":"StrokeAbove"},"fill":"None"},"colinear_manipulators":[],"point_domain":{"id":[],"position":[]},"segment_domain":{"id":[],"start_point":[],"end_point":[],"handles":[],"stroke":[]},"region_domain":{"id":[],"segment_range":[],"fill":[]},"upstream_graphic_group":null}],"transform":[[1.0,0.0,0.0,1.0,0.0,0.0]],"alpha_blending":[{"blend_mode":"Normal","opacity":1.0,"fill":1.0,"clip":false}],"source_node_id":[null]}},"exposed":true}},{"Value":{"tagged_value":{"VectorModification":{"points":{"add":[1,2,3],"remove":[],"delta":[[2,[668.4444444444445,516.4444444444443]],[3,[808.0,413.33333333333337]],[1,[604.8888888888889,523.5555555555557]]]},"segments":{"add":[1,2],"remove":[],"start_point":[[2,2],[1,1]],"end_point":[[1,2],[2,3]],"handle_primary":[[1,[0.0,0.0]],[2,[23.1111111111112,-9.7777777777776]]],"handle_end":[[2,[-59.111111111111086,58.22222222222223]],[1,[-23.1111111111112,9.7777777777776]]],"stroke":[[1,0],[2,0]]},"regions":{"add":[],"remove":[],"segment_range":[],"fill":[]},"add_g1_continuous":[],"remove_g1_continuous":[]}},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::vector_data::modification::VectorModification","alias":null}},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::vector_data::modification::PathModifyNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[15896921950407486754,{"inputs":[{"Node":{"node_id":13163272246010991228,"output_index":0,"lambda":false}},{"Node":{"node_id":11199691961479466803,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[15466714490303763249,{"inputs":[{"Node":{"node_id":10514847656270897393,"output_index":0,"lambda":false}},{"Node":{"node_id":11659756061767599421,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[2659768650911099730,{"inputs":[{"Node":{"node_id":13045087323693407920,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"PointSpacingType":"Separation"},"exposed":false}},{"Value":{"tagged_value":{"F64":6.0},"exposed":false}},{"Value":{"tagged_value":{"U32":100},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"Bool":false},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":4,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::SubpathSegmentLengthsNode"}},"visible":true,"skip_deduplication":false}],[4,{"inputs":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::BoundlessFootprintNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":2,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::FreezeRealTimeNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MemoNode"}},"visible":true,"skip_deduplication":false}],[1,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::misc::PointSpacingType","alias":null}},"import_index":1}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":2}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":3}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":4}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":5}},{"Network":{"import_type":{"Concrete":{"name":"bool","alias":null}},"import_index":6}},{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::SamplePolylineNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[12224498203743157414,{"inputs":[{"Node":{"node_id":2878992817082507910,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"Fill":{"Solid":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}}},"exposed":false}},{"Value":{"tagged_value":{"OptionalColor":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}},"exposed":false}},{"Value":{"tagged_value":{"Gradient":{"stops":[[0.0,{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}],[1.0,{"red":1.0,"green":1.0,"blue":1.0,"alpha":1.0}]],"gradient_type":"Linear","start":[0.0,0.5],"end":[1.0,0.5],"transform":[1.0,0.0,0.0,1.0,0.0,0.0]}},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::FillNode"}},"visible":true,"skip_deduplication":false}],[13045087323693407920,{"inputs":[{"Value":{"tagged_value":{"VectorData":{"instance":[{"style":{"stroke":{"color":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0},"weight":0.0,"dash_lengths":[],"dash_offset":0.0,"cap":"Butt","join":"Miter","join_miter_limit":4.0,"align":"Center","transform":[1.0,0.0,0.0,1.0,0.0,0.0],"non_scaling":false,"paint_order":"StrokeAbove"},"fill":"None"},"colinear_manipulators":[],"point_domain":{"id":[],"position":[]},"segment_domain":{"id":[],"start_point":[],"end_point":[],"handles":[],"stroke":[]},"region_domain":{"id":[],"segment_range":[],"fill":[]},"upstream_graphic_group":null}],"transform":[[1.0,0.0,0.0,1.0,0.0,0.0]],"alpha_blending":[{"blend_mode":"Normal","opacity":1.0,"fill":1.0,"clip":false}],"source_node_id":[null]}},"exposed":true}},{"Value":{"tagged_value":{"VectorModification":{"points":{"add":[1,2],"remove":[],"delta":[[1,[19.0,494.0]],[2,[227.0,496.0]]]},"segments":{"add":[1],"remove":[],"start_point":[[1,1]],"end_point":[[1,2]],"handle_primary":[[1,[0.0,0.0]]],"handle_end":[[1,[-98.0,-55.0]]],"stroke":[[1,0]]},"regions":{"add":[],"remove":[],"segment_range":[],"fill":[]},"add_g1_continuous":[],"remove_g1_continuous":[]}},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::vector_data::modification::VectorModification","alias":null}},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::vector_data::modification::PathModifyNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[8240895922641772563,{"inputs":[{"Node":{"node_id":16530658574540156160,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"Fill":{"Solid":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}}},"exposed":false}},{"Value":{"tagged_value":{"OptionalColor":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}},"exposed":false}},{"Value":{"tagged_value":{"Gradient":{"stops":[[0.0,{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}],[1.0,{"red":1.0,"green":1.0,"blue":1.0,"alpha":1.0}]],"gradient_type":"Linear","start":[0.0,0.5],"end":[1.0,0.5],"transform":[1.0,0.0,0.0,1.0,0.0,0.0]}},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::FillNode"}},"visible":true,"skip_deduplication":false}],[13644138583806412631,{"inputs":[{"Node":{"node_id":2641530639940889619,"output_index":0,"lambda":false}},{"Node":{"node_id":12473080738469616517,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[11021243031011826737,{"inputs":[{"Node":{"node_id":16446146761452576438,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"Fill":{"Solid":{"red":0.8980392,"green":0.8,"blue":0.6117647,"alpha":1.0}}},"exposed":false}},{"Value":{"tagged_value":{"OptionalColor":{"red":0.8980392,"green":0.8,"blue":0.6117647,"alpha":1.0}},"exposed":false}},{"Value":{"tagged_value":{"Gradient":{"stops":[[0.0,{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}],[1.0,{"red":1.0,"green":1.0,"blue":1.0,"alpha":1.0}]],"gradient_type":"Linear","start":[0.0,0.5],"end":[1.0,0.5],"transform":[1.0,0.0,0.0,1.0,0.0,0.0]}},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::FillNode"}},"visible":true,"skip_deduplication":false}],[17064046832210629373,{"inputs":[{"Node":{"node_id":12219771677493189964,"output_index":0,"lambda":false}},{"Node":{"node_id":11677503666435782605,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[10420981328998103391,{"inputs":[{"Value":{"tagged_value":{"VectorData":{"instance":[{"style":{"stroke":{"color":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0},"weight":0.0,"dash_lengths":[],"dash_offset":0.0,"cap":"Butt","join":"Miter","join_miter_limit":4.0,"align":"Center","transform":[1.0,0.0,0.0,1.0,0.0,0.0],"non_scaling":false,"paint_order":"StrokeAbove"},"fill":"None"},"colinear_manipulators":[],"point_domain":{"id":[],"position":[]},"segment_domain":{"id":[],"start_point":[],"end_point":[],"handles":[],"stroke":[]},"region_domain":{"id":[],"segment_range":[],"fill":[]},"upstream_graphic_group":null}],"transform":[[1.0,0.0,0.0,1.0,0.0,0.0]],"alpha_blending":[{"blend_mode":"Normal","opacity":1.0,"fill":1.0,"clip":false}],"source_node_id":[null]}},"exposed":true}},{"Value":{"tagged_value":{"VectorModification":{"points":{"add":[1,2,3],"remove":[],"delta":[[3,[694.2222222222222,623.5555555555554]],[1,[859.5555555555554,375.1111111111111]],[2,[844.4444444444443,460.44444444444434]]]},"segments":{"add":[1,2],"remove":[],"start_point":[[1,1],[2,2]],"end_point":[[2,3],[1,2]],"handle_primary":[[1,[0.0,0.0]],[2,[-11.999999999999886,30.6666666666668]]],"handle_end":[[1,[11.055745483535702,-28.253571791258253]],[2,[76.88888888888891,-30.666666666666742]]],"stroke":[[1,0],[2,0]]},"regions":{"add":[],"remove":[],"segment_range":[],"fill":[]},"add_g1_continuous":[],"remove_g1_continuous":[]}},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::vector_data::modification::VectorModification","alias":null}},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::vector_data::modification::PathModifyNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[15460109068588328521,{"inputs":[{"Node":{"node_id":5185036609290210853,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"Fill":{"Solid":{"red":0.9019608,"green":0.8,"blue":0.6,"alpha":1.0}}},"exposed":false}},{"Value":{"tagged_value":{"OptionalColor":{"red":0.9019608,"green":0.8,"blue":0.6,"alpha":1.0}},"exposed":false}},{"Value":{"tagged_value":{"Gradient":{"stops":[[0.0,{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}],[1.0,{"red":1.0,"green":1.0,"blue":1.0,"alpha":1.0}]],"gradient_type":"Linear","start":[0.0,0.5],"end":[1.0,0.5],"transform":[1.0,0.0,0.0,1.0,0.0,0.0]}},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::FillNode"}},"visible":true,"skip_deduplication":false}],[17815494794630739611,{"inputs":[{"Node":{"node_id":14079496619264986678,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"Fill":{"Solid":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}}},"exposed":false}},{"Value":{"tagged_value":{"OptionalColor":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}},"exposed":false}},{"Value":{"tagged_value":{"Gradient":{"stops":[[0.0,{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}],[1.0,{"red":1.0,"green":1.0,"blue":1.0,"alpha":1.0}]],"gradient_type":"Linear","start":[0.0,0.5],"end":[1.0,0.5],"transform":[1.0,0.0,0.0,1.0,0.0,0.0]}},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::FillNode"}},"visible":true,"skip_deduplication":false}],[4131094614457622424,{"inputs":[{"Node":{"node_id":11356586238302409958,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"PointSpacingType":"Separation"},"exposed":false}},{"Value":{"tagged_value":{"F64":5.0},"exposed":false}},{"Value":{"tagged_value":{"U32":100},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"Bool":false},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":4,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::SubpathSegmentLengthsNode"}},"visible":true,"skip_deduplication":false}],[4,{"inputs":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::BoundlessFootprintNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":2,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::FreezeRealTimeNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MemoNode"}},"visible":true,"skip_deduplication":false}],[1,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::misc::PointSpacingType","alias":null}},"import_index":1}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":2}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":3}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":4}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":5}},{"Network":{"import_type":{"Concrete":{"name":"bool","alias":null}},"import_index":6}},{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::SamplePolylineNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[10860592954464951000,{"inputs":[{"Node":{"node_id":4236845268521674740,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"Fill":{"Solid":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}}},"exposed":false}},{"Value":{"tagged_value":{"OptionalColor":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}},"exposed":false}},{"Value":{"tagged_value":{"Gradient":{"stops":[[0.0,{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}],[1.0,{"red":1.0,"green":1.0,"blue":1.0,"alpha":1.0}]],"gradient_type":"Linear","start":[0.0,0.5],"end":[1.0,0.5],"transform":[1.0,0.0,0.0,1.0,0.0,0.0]}},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::FillNode"}},"visible":true,"skip_deduplication":false}],[12387541320114693418,{"inputs":[{"Node":{"node_id":5471152581000334146,"output_index":0,"lambda":false}},{"Node":{"node_id":15460109068588328521,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[9182448229950585507,{"inputs":[{"Node":{"node_id":12496143061817048445,"output_index":0,"lambda":false}},{"Node":{"node_id":7320676248579211727,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[431994205232245356,{"inputs":[{"Node":{"node_id":12387541320114693418,"output_index":0,"lambda":false}},{"Node":{"node_id":14894569344576297448,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[12594527670567285670,{"inputs":[{"Node":{"node_id":4663768795652429571,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"Fill":{"Solid":{"red":0.8980392,"green":0.8,"blue":0.6117647,"alpha":1.0}}},"exposed":false}},{"Value":{"tagged_value":{"OptionalColor":{"red":0.8980392,"green":0.8,"blue":0.6117647,"alpha":1.0}},"exposed":false}},{"Value":{"tagged_value":{"Gradient":{"stops":[[0.0,{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}],[1.0,{"red":1.0,"green":1.0,"blue":1.0,"alpha":1.0}]],"gradient_type":"Linear","start":[0.0,0.5],"end":[1.0,0.5],"transform":[1.0,0.0,0.0,1.0,0.0,0.0]}},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::FillNode"}},"visible":true,"skip_deduplication":false}],[14345191642063772510,{"inputs":[{"Value":{"tagged_value":{"VectorData":{"instance":[{"style":{"stroke":{"color":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0},"weight":0.0,"dash_lengths":[],"dash_offset":0.0,"cap":"Butt","join":"Miter","join_miter_limit":4.0,"align":"Center","transform":[1.0,0.0,0.0,1.0,0.0,0.0],"non_scaling":false,"paint_order":"StrokeAbove"},"fill":"None"},"colinear_manipulators":[],"point_domain":{"id":[],"position":[]},"segment_domain":{"id":[],"start_point":[],"end_point":[],"handles":[],"stroke":[]},"region_domain":{"id":[],"segment_range":[],"fill":[]},"upstream_graphic_group":null}],"transform":[[1.0,0.0,0.0,1.0,0.0,0.0]],"alpha_blending":[{"blend_mode":"Normal","opacity":1.0,"fill":1.0,"clip":false}],"source_node_id":[null]}},"exposed":true}},{"Value":{"tagged_value":{"VectorModification":{"points":{"add":[1,2,3,4],"remove":[],"delta":[[4,[838.2222222222222,766.6666666666669]],[2,[833.7777777777777,780.4444444444443]],[1,[880.8888888888888,556.4444444444443]],[3,[813.3557395833334,961.1454375]]]},"segments":{"add":[1,2,3,4],"remove":[],"start_point":[[4,4],[2,2],[3,3],[1,1]],"end_point":[[1,2],[4,1],[3,4],[2,3]],"handle_primary":[[4,[10.643023589139377,-58.51588472312813]],[1,[0.0,0.0]],[3,[0.0,0.0]],[2,[-9.333333333333371,54.66666666666674]]],"handle_end":[[3,[-10.643023589139377,58.51588472312813]],[2,[0.0,0.0]],[4,[-0.4444444444444571,-0.8888888888888005]],[1,[9.333333333333371,-54.66666666666674]]],"stroke":[[4,0],[3,0],[2,0],[1,0]]},"regions":{"add":[0],"remove":[],"segment_range":[[0,{"start":1,"end":4}]],"fill":[[0,0]]},"add_g1_continuous":[],"remove_g1_continuous":[]}},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::vector_data::modification::VectorModification","alias":null}},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::vector_data::modification::PathModifyNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[12531351117929704587,{"inputs":[{"Node":{"node_id":11194653561109699287,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"Fill":{"Solid":{"red":0.7529412,"green":0.15686275,"blue":0.13333334,"alpha":1.0}}},"exposed":false}},{"Value":{"tagged_value":{"OptionalColor":{"red":0.7529412,"green":0.15686275,"blue":0.13333334,"alpha":1.0}},"exposed":false}},{"Value":{"tagged_value":{"Gradient":{"stops":[[0.0,{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}],[1.0,{"red":1.0,"green":1.0,"blue":1.0,"alpha":1.0}]],"gradient_type":"Linear","start":[0.0,0.5],"end":[1.0,0.5],"transform":[1.0,0.0,0.0,1.0,0.0,0.0]}},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::FillNode"}},"visible":true,"skip_deduplication":false}],[12801133692316734622,{"inputs":[{"Node":{"node_id":17699121037850769131,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"PointSpacingType":"Separation"},"exposed":false}},{"Value":{"tagged_value":{"F64":5.0},"exposed":false}},{"Value":{"tagged_value":{"U32":100},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"Bool":false},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":4,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::SubpathSegmentLengthsNode"}},"visible":true,"skip_deduplication":false}],[4,{"inputs":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::BoundlessFootprintNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":2,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::FreezeRealTimeNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MemoNode"}},"visible":true,"skip_deduplication":false}],[1,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::misc::PointSpacingType","alias":null}},"import_index":1}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":2}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":3}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":4}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":5}},{"Network":{"import_type":{"Concrete":{"name":"bool","alias":null}},"import_index":6}},{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::SamplePolylineNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[12385950900718181935,{"inputs":[{"Node":{"node_id":4372998635946271235,"output_index":0,"lambda":false}},{"Node":{"node_id":615144098061106242,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[1713644030979611623,{"inputs":[{"Value":{"tagged_value":{"VectorData":{"instance":[{"style":{"stroke":{"color":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0},"weight":0.0,"dash_lengths":[],"dash_offset":0.0,"cap":"Butt","join":"Miter","join_miter_limit":4.0,"align":"Center","transform":[1.0,0.0,0.0,1.0,0.0,0.0],"non_scaling":false,"paint_order":"StrokeAbove"},"fill":"None"},"colinear_manipulators":[],"point_domain":{"id":[],"position":[]},"segment_domain":{"id":[],"start_point":[],"end_point":[],"handles":[],"stroke":[]},"region_domain":{"id":[],"segment_range":[],"fill":[]},"upstream_graphic_group":null}],"transform":[[1.0,0.0,0.0,1.0,0.0,0.0]],"alpha_blending":[{"blend_mode":"Normal","opacity":1.0,"fill":1.0,"clip":false}],"source_node_id":[null]}},"exposed":true}},{"Value":{"tagged_value":{"VectorModification":{"points":{"add":[1,2],"remove":[],"delta":[[1,[404.0,882.6666666666666]],[2,[321.33333333333326,1022.0]]]},"segments":{"add":[1],"remove":[],"start_point":[[1,1]],"end_point":[[1,2]],"handle_primary":[[1,[0.0,0.0]]],"handle_end":[[1,[30.96296296296316,-100.2222222222224]]],"stroke":[[1,0]]},"regions":{"add":[],"remove":[],"segment_range":[],"fill":[]},"add_g1_continuous":[],"remove_g1_continuous":[]}},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::vector_data::modification::VectorModification","alias":null}},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::vector_data::modification::PathModifyNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[3649809135741361946,{"inputs":[{"Value":{"tagged_value":{"VectorData":{"instance":[{"style":{"stroke":{"color":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0},"weight":0.0,"dash_lengths":[],"dash_offset":0.0,"cap":"Butt","join":"Miter","join_miter_limit":4.0,"align":"Center","transform":[1.0,0.0,0.0,1.0,0.0,0.0],"non_scaling":false,"paint_order":"StrokeAbove"},"fill":"None"},"colinear_manipulators":[],"point_domain":{"id":[],"position":[]},"segment_domain":{"id":[],"start_point":[],"end_point":[],"handles":[],"stroke":[]},"region_domain":{"id":[],"segment_range":[],"fill":[]},"upstream_graphic_group":null}],"transform":[[1.0,0.0,0.0,1.0,0.0,0.0]],"alpha_blending":[{"blend_mode":"Normal","opacity":1.0,"fill":1.0,"clip":false}],"source_node_id":[null]}},"exposed":true}},{"Value":{"tagged_value":{"VectorModification":{"points":{"add":[1,2],"remove":[],"delta":[[1,[787.1111111111111,414.66666666666663]],[2,[841.3333333333333,336.8888888888889]]]},"segments":{"add":[1],"remove":[],"start_point":[[1,1]],"end_point":[[1,2]],"handle_primary":[[1,[0.0,0.0]]],"handle_end":[[1,[-21.333333333333258,48.888888888888914]]],"stroke":[[1,0]]},"regions":{"add":[],"remove":[],"segment_range":[],"fill":[]},"add_g1_continuous":[],"remove_g1_continuous":[]}},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::vector_data::modification::VectorModification","alias":null}},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::vector_data::modification::PathModifyNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[5213978458941436169,{"inputs":[{"Node":{"node_id":13261814586176172586,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"F64":7.0},"exposed":false}},{"Value":{"tagged_value":{"U32":10},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":1}},{"Network":{"import_type":{"Concrete":{"name":"u32","alias":null}},"import_index":2}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::PoissonDiskPointsNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":2,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::BoundlessFootprintNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::FreezeRealTimeNode"}},"visible":true,"skip_deduplication":false}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MemoNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[4663768795652429571,{"inputs":[{"Value":{"tagged_value":{"VectorData":{"instance":[{"style":{"stroke":{"color":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0},"weight":0.0,"dash_lengths":[],"dash_offset":0.0,"cap":"Butt","join":"Miter","join_miter_limit":4.0,"align":"Center","transform":[1.0,0.0,0.0,1.0,0.0,0.0],"non_scaling":false,"paint_order":"StrokeAbove"},"fill":"None"},"colinear_manipulators":[],"point_domain":{"id":[],"position":[]},"segment_domain":{"id":[],"start_point":[],"end_point":[],"handles":[],"stroke":[]},"region_domain":{"id":[],"segment_range":[],"fill":[]},"upstream_graphic_group":null}],"transform":[[1.0,0.0,0.0,1.0,0.0,0.0]],"alpha_blending":[{"blend_mode":"Normal","opacity":1.0,"fill":1.0,"clip":false}],"source_node_id":[null]}},"exposed":true}},{"Value":{"tagged_value":{"VectorModification":{"points":{"add":[1,2,3,4,5,6],"remove":[],"delta":[[6,[706.633744855967,98.10699588477364]],[3,[708.8285322359397,101.48696844993144]],[2,[696.6255144032922,96.92181069958846]],[5,[710.8379820149368,102.96966925773508]],[1,[691.7530864197531,86.91358024691357]],[4,[713.0620332266423,107.3007163542143]]]},"segments":{"add":[1,2,3,4,5,6],"remove":[],"start_point":[[5,5],[4,4],[6,6],[3,3],[2,2],[1,1]],"end_point":[[3,4],[2,3],[1,2],[4,5],[5,6],[6,1]],"handle_primary":[[5,[-0.8974241731443726,-2.770309404054231]],[3,[1.7753391251332005,4.7992684042066]],[4,[0.0,0.0]],[1,[0.0,0.0]],[6,[-6.847736625514244,-2.3703703703703525]],[2,[6.057613168724288,1.9753086419753032]]],"handle_end":[[4,[0.786301337230384,2.4272780410153985]],[1,[-6.057613168724288,-1.9753086419753032]],[5,[2.9051419934493197,1.005626074655538]],[2,[-0.7886938944185431,-2.1320736046921525]],[6,[1.1851851851849915,8.823045267489718]],[3,[-0.9218106995884908,-0.3950617283950635]]],"stroke":[[5,0],[1,0],[3,0],[2,0],[4,0],[6,0]]},"regions":{"add":[0],"remove":[],"segment_range":[[0,{"start":1,"end":6}]],"fill":[[0,0]]},"add_g1_continuous":[],"remove_g1_continuous":[]}},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::vector_data::modification::VectorModification","alias":null}},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::vector_data::modification::PathModifyNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[10599660455959346550,{"inputs":[{"Value":{"tagged_value":{"VectorData":{"instance":[{"style":{"stroke":{"color":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0},"weight":0.0,"dash_lengths":[],"dash_offset":0.0,"cap":"Butt","join":"Miter","join_miter_limit":4.0,"align":"Center","transform":[1.0,0.0,0.0,1.0,0.0,0.0],"non_scaling":false,"paint_order":"StrokeAbove"},"fill":"None"},"colinear_manipulators":[],"point_domain":{"id":[],"position":[]},"segment_domain":{"id":[],"start_point":[],"end_point":[],"handles":[],"stroke":[]},"region_domain":{"id":[],"segment_range":[],"fill":[]},"upstream_graphic_group":null}],"transform":[[1.0,0.0,0.0,1.0,0.0,0.0]],"alpha_blending":[{"blend_mode":"Normal","opacity":1.0,"fill":1.0,"clip":false}],"source_node_id":[null]}},"exposed":true}},{"Value":{"tagged_value":{"VectorModification":{"points":{"add":[1,2,3,4],"remove":[],"delta":[[1,[478.2222222222222,515.1111111111111]],[2,[572.0,570.2222222222222]],[4,[745.3333333333333,471.55555555555554]],[3,[654.6666666666666,546.6666666666666]]]},"segments":{"add":[1,2,3],"remove":[],"start_point":[[1,1],[2,2],[3,3]],"end_point":[[2,3],[1,2],[3,4]],"handle_primary":[[1,[0.0,0.0]],[3,[26.222222222222285,-16.0]],[2,[31.555555555555543,7.555555555555543]]],"handle_end":[[3,[0.0,0.0]],[2,[-26.222222222222285,16.0]],[1,[-31.555555555555543,-7.555555555555543]]],"stroke":[[3,0],[2,0],[1,0]]},"regions":{"add":[],"remove":[],"segment_range":[],"fill":[]},"add_g1_continuous":[],"remove_g1_continuous":[]}},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::vector_data::modification::VectorModification","alias":null}},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::vector_data::modification::PathModifyNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[16756940771483104467,{"inputs":[{"Node":{"node_id":13975451746581400000,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"Fill":{"Solid":{"red":0.84705883,"green":0.5372549,"blue":0.38431373,"alpha":1.0}}},"exposed":false}},{"Value":{"tagged_value":{"OptionalColor":{"red":0.84705883,"green":0.5372549,"blue":0.38431373,"alpha":1.0}},"exposed":false}},{"Value":{"tagged_value":{"Gradient":{"stops":[[0.0,{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}],[1.0,{"red":1.0,"green":1.0,"blue":1.0,"alpha":1.0}]],"gradient_type":"Linear","start":[0.0,0.5],"end":[1.0,0.5],"transform":[1.0,0.0,0.0,1.0,0.0,0.0]}},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::FillNode"}},"visible":true,"skip_deduplication":false}],[17207895962122263432,{"inputs":[{"Node":{"node_id":11573595155909211511,"output_index":0,"lambda":false}},{"Node":{"node_id":17078740291337047697,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"F64":1.2},"exposed":false}},{"Value":{"tagged_value":{"F64":2.0},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"U32":0},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"U32":0},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::CopyToPointsNode"}},"visible":true,"skip_deduplication":false}],[2175432926627256613,{"inputs":[{"Value":{"tagged_value":{"GraphicGroup":{"instance":[],"transform":[],"alpha_blending":[],"source_node_id":[]}},"exposed":true}},{"Node":{"node_id":14982414026754548178,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[17945736750161448391,{"inputs":[{"Value":{"tagged_value":{"VectorData":{"instance":[{"style":{"stroke":{"color":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0},"weight":0.0,"dash_lengths":[],"dash_offset":0.0,"cap":"Butt","join":"Miter","join_miter_limit":4.0,"align":"Center","transform":[1.0,0.0,0.0,1.0,0.0,0.0],"non_scaling":false,"paint_order":"StrokeAbove"},"fill":"None"},"colinear_manipulators":[],"point_domain":{"id":[],"position":[]},"segment_domain":{"id":[],"start_point":[],"end_point":[],"handles":[],"stroke":[]},"region_domain":{"id":[],"segment_range":[],"fill":[]},"upstream_graphic_group":null}],"transform":[[1.0,0.0,0.0,1.0,0.0,0.0]],"alpha_blending":[{"blend_mode":"Normal","opacity":1.0,"fill":1.0,"clip":false}],"source_node_id":[null]}},"exposed":true}},{"Value":{"tagged_value":{"VectorModification":{"points":{"add":[1,2,3,4],"remove":[],"delta":[[2,[688.3433248095167,92.67923984990472]],[4,[687.6968543916372,70.6398816184091]],[1,[689.4327280262556,73.68042956754955]],[3,[687.4660700953133,94.52064202140812]]]},"segments":{"add":[1,2,3,4],"remove":[],"start_point":[[4,4],[2,2],[1,1],[3,3]],"end_point":[[2,3],[1,2],[3,4],[4,1]],"handle_primary":[[3,[-0.975596082205584,-10.16276974584038]],[1,[-1.460603632035259,12.298077567102167]],[2,[0.0,0.0]],[4,[0.0,0.0]]],"handle_end":[[2,[0.6631784948407358,-0.4471776104951459]],[4,[-0.3670368206467174,-1.6914035044494111]],[1,null],[3,[0.0,0.0]]],"stroke":[[2,0],[3,0],[1,0],[4,0]]},"regions":{"add":[0],"remove":[],"segment_range":[[0,{"start":1,"end":4}]],"fill":[[0,0]]},"add_g1_continuous":[],"remove_g1_continuous":[]}},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::vector_data::modification::VectorModification","alias":null}},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::vector_data::modification::PathModifyNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[16324258033206362312,{"inputs":[{"Node":{"node_id":16732130236852371275,"output_index":0,"lambda":false}},{"Node":{"node_id":17078740291337047697,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"F64":1.0},"exposed":false}},{"Value":{"tagged_value":{"F64":2.0},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"U32":0},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"U32":0},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::CopyToPointsNode"}},"visible":true,"skip_deduplication":false}],[14079496619264986678,{"inputs":[{"Value":{"tagged_value":{"VectorData":{"instance":[{"style":{"stroke":{"color":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0},"weight":0.0,"dash_lengths":[],"dash_offset":0.0,"cap":"Butt","join":"Miter","join_miter_limit":4.0,"align":"Center","transform":[1.0,0.0,0.0,1.0,0.0,0.0],"non_scaling":false,"paint_order":"StrokeAbove"},"fill":"None"},"colinear_manipulators":[],"point_domain":{"id":[],"position":[]},"segment_domain":{"id":[],"start_point":[],"end_point":[],"handles":[],"stroke":[]},"region_domain":{"id":[],"segment_range":[],"fill":[]},"upstream_graphic_group":null}],"transform":[[1.0,0.0,0.0,1.0,0.0,0.0]],"alpha_blending":[{"blend_mode":"Normal","opacity":1.0,"fill":1.0,"clip":false}],"source_node_id":[null]}},"exposed":true}},{"Value":{"tagged_value":{"VectorModification":{"points":{"add":[1,2,3],"remove":[],"delta":[[2,[608.9876543209878,75.25925925925925]],[1,[597.2345679012346,77.92592592592592]],[3,[609.2839506172841,76.74074074074073]]]},"segments":{"add":[1,2,3],"remove":[],"start_point":[[1,1],[3,3],[2,2]],"end_point":[[3,1],[1,2],[2,3]],"handle_primary":[[2,[0.0,0.0]],[1,[0.0,0.0]],[3,[0.0,0.0]]],"handle_end":[[3,[8.09876543209873,0.2962962962962763]],[2,[0.0,0.0]],[1,[-6.222222222222172,-0.9876543209876588]]],"stroke":[[3,0],[1,0],[2,0]]},"regions":{"add":[0],"remove":[],"segment_range":[[0,{"start":1,"end":3}]],"fill":[[0,0]]},"add_g1_continuous":[],"remove_g1_continuous":[]}},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::vector_data::modification::VectorModification","alias":null}},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::vector_data::modification::PathModifyNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[10253927692147706615,{"inputs":[{"Node":{"node_id":7262199696924786895,"output_index":0,"lambda":false}},{"Node":{"node_id":17078740291337047697,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"F64":1.2},"exposed":false}},{"Value":{"tagged_value":{"F64":2.0},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"U32":0},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"U32":0},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::CopyToPointsNode"}},"visible":true,"skip_deduplication":false}],[9529195152569434392,{"inputs":[{"Node":{"node_id":3121275823460307102,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"Fill":{"Solid":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}}},"exposed":false}},{"Value":{"tagged_value":{"OptionalColor":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}},"exposed":false}},{"Value":{"tagged_value":{"Gradient":{"stops":[[0.0,{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}],[1.0,{"red":1.0,"green":1.0,"blue":1.0,"alpha":1.0}]],"gradient_type":"Linear","start":[0.0,0.5],"end":[1.0,0.5],"transform":[1.0,0.0,0.0,1.0,0.0,0.0]}},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::FillNode"}},"visible":true,"skip_deduplication":false}],[12876462860151722087,{"inputs":[{"Node":{"node_id":10619788176782820865,"output_index":0,"lambda":false}},{"Node":{"node_id":10415872992231003638,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[11268046366284173800,{"inputs":[{"Node":{"node_id":4453139144069993994,"output_index":0,"lambda":false}},{"Node":{"node_id":11616089678400336955,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[15303587427289959766,{"inputs":[{"Value":{"tagged_value":{"VectorData":{"instance":[{"style":{"stroke":{"color":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0},"weight":0.0,"dash_lengths":[],"dash_offset":0.0,"cap":"Butt","join":"Miter","join_miter_limit":4.0,"align":"Center","transform":[1.0,0.0,0.0,1.0,0.0,0.0],"non_scaling":false,"paint_order":"StrokeAbove"},"fill":"None"},"colinear_manipulators":[],"point_domain":{"id":[],"position":[]},"segment_domain":{"id":[],"start_point":[],"end_point":[],"handles":[],"stroke":[]},"region_domain":{"id":[],"segment_range":[],"fill":[]},"upstream_graphic_group":null}],"transform":[[1.0,0.0,0.0,1.0,0.0,0.0]],"alpha_blending":[{"blend_mode":"Normal","opacity":1.0,"fill":1.0,"clip":false}],"source_node_id":[null]}},"exposed":true}},{"Value":{"tagged_value":{"VectorModification":{"points":{"add":[1,2],"remove":[],"delta":[[1,[610.6666666666666,706.6666666666666]],[2,[818.2222222222222,566.2222222222222]]]},"segments":{"add":[1],"remove":[],"start_point":[[1,1]],"end_point":[[1,2]],"handle_primary":[[1,[0.0,0.0]]],"handle_end":[[1,[-82.66666666666674,97.77777777777771]]],"stroke":[[1,0]]},"regions":{"add":[],"remove":[],"segment_range":[],"fill":[]},"add_g1_continuous":[],"remove_g1_continuous":[]}},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::vector_data::modification::VectorModification","alias":null}},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::vector_data::modification::PathModifyNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[12761901161949743155,{"inputs":[{"Node":{"node_id":7659717355245331967,"output_index":0,"lambda":false}},{"Node":{"node_id":8091904580702893317,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[14887821801874852671,{"inputs":[{"Node":{"node_id":8230694129617719636,"output_index":0,"lambda":false}},{"Node":{"node_id":18279507457571359732,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[6416452251137958677,{"inputs":[{"Node":{"node_id":9374264173303233490,"output_index":0,"lambda":false}},{"Node":{"node_id":17078740291337047697,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"F64":1.2},"exposed":false}},{"Value":{"tagged_value":{"F64":2.0},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"U32":0},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"U32":0},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::CopyToPointsNode"}},"visible":true,"skip_deduplication":false}],[11194653561109699287,{"inputs":[{"Value":{"tagged_value":{"VectorData":{"instance":[{"style":{"stroke":{"color":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0},"weight":0.0,"dash_lengths":[],"dash_offset":0.0,"cap":"Butt","join":"Miter","join_miter_limit":4.0,"align":"Center","transform":[1.0,0.0,0.0,1.0,0.0,0.0],"non_scaling":false,"paint_order":"StrokeAbove"},"fill":"None"},"colinear_manipulators":[],"point_domain":{"id":[],"position":[]},"segment_domain":{"id":[],"start_point":[],"end_point":[],"handles":[],"stroke":[]},"region_domain":{"id":[],"segment_range":[],"fill":[]},"upstream_graphic_group":null}],"transform":[[1.0,0.0,0.0,1.0,0.0,0.0]],"alpha_blending":[{"blend_mode":"Normal","opacity":1.0,"fill":1.0,"clip":false}],"source_node_id":[null]}},"exposed":true}},{"Value":{"tagged_value":{"VectorModification":{"points":{"add":[1,2,3,4,5,6],"remove":[],"delta":[[6,[603.4567901234567,92.83950617283948]],[2,[607.4000914494741,86.85505258344766]],[4,[605.761316872428,82.28989483310471]],[1,[604.3716161316235,95.4260819221956]],[3,[623.4951989026065,81.23639689071788]],[5,[602.0316509633005,90.5516059992284]]]},"segments":{"add":[1,2,3,4,5,6],"remove":[],"start_point":[[6,6],[2,2],[4,4],[3,3],[5,5],[1,1]],"end_point":[[4,5],[5,6],[2,3],[3,4],[1,2],[6,1]],"handle_primary":[[6,[0.3965701826469967,0.8240731861035471]],[5,[0.0,0.0]],[4,[-3.2460274482192517,2.85650415443304]],[2,[3.687242798354191,-3.4531321444901835]],[1,[0.0,0.0]],[3,[-0.7803688462123546,-2.7117817405883216]]],"handle_end":[[3,[4.389574759945049,-3.862825788751721]],[1,[-3.3249738510837687,3.113864400221118]],[6,[-2.273736754432321e-13,-4.263256414560601e-14]],[4,[-0.10095077423932251,-1.27829797882373]],[2,[-1.0144795000761633,1.6192653558908745]],[5,[-0.3896135191956773,-0.8096172333722365]]],"stroke":[[3,0],[5,0],[1,0],[4,0],[2,0],[6,0]]},"regions":{"add":[0],"remove":[],"segment_range":[[0,{"start":1,"end":6}]],"fill":[[0,0]]},"add_g1_continuous":[],"remove_g1_continuous":[]}},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::vector_data::modification::VectorModification","alias":null}},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::vector_data::modification::PathModifyNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[7747398671834040298,{"inputs":[{"Node":{"node_id":18319784717194273926,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"F64":30.0},"exposed":false}},{"Value":{"tagged_value":{"U32":47},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":1}},{"Network":{"import_type":{"Concrete":{"name":"u32","alias":null}},"import_index":2}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::PoissonDiskPointsNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":2,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::BoundlessFootprintNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::FreezeRealTimeNode"}},"visible":true,"skip_deduplication":false}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MemoNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[1869448627329502330,{"inputs":[{"Node":{"node_id":3827449344952693766,"output_index":0,"lambda":false}},{"Node":{"node_id":17078740291337047697,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"F64":1.2},"exposed":false}},{"Value":{"tagged_value":{"F64":2.0},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"U32":0},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"U32":0},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::CopyToPointsNode"}},"visible":true,"skip_deduplication":false}],[16796171662855500935,{"inputs":[{"Node":{"node_id":14993053984267866751,"output_index":0,"lambda":false}},{"Node":{"node_id":9371909264427723282,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[14012648643507848353,{"inputs":[{"Value":{"tagged_value":{"VectorData":{"instance":[{"style":{"stroke":{"color":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0},"weight":0.0,"dash_lengths":[],"dash_offset":0.0,"cap":"Butt","join":"Miter","join_miter_limit":4.0,"align":"Center","transform":[1.0,0.0,0.0,1.0,0.0,0.0],"non_scaling":false,"paint_order":"StrokeAbove"},"fill":"None"},"colinear_manipulators":[],"point_domain":{"id":[],"position":[]},"segment_domain":{"id":[],"start_point":[],"end_point":[],"handles":[],"stroke":[]},"region_domain":{"id":[],"segment_range":[],"fill":[]},"upstream_graphic_group":null}],"transform":[[1.0,0.0,0.0,1.0,0.0,0.0]],"alpha_blending":[{"blend_mode":"Normal","opacity":1.0,"fill":1.0,"clip":false}],"source_node_id":[null]}},"exposed":true}},{"Value":{"tagged_value":{"VectorModification":{"points":{"add":[1,2,3,4],"remove":[],"delta":[[3,[615.7168724279835,33.05349794238683]],[2,[613.7152263374486,29.076543209876547]],[4,[613.6098765432099,30.393415637860084]],[1,[610.080658436214,28.760493827160495]]]},"segments":{"add":[1,2,3,4],"remove":[],"start_point":[[1,1],[4,4],[2,2],[3,3]],"end_point":[[1,2],[4,1],[3,4],[2,3]],"handle_primary":[[2,[1.5990193552247547,1.4582133097558128]],[3,[0.0,0.0]],[1,[0.0,0.0]],[4,[-1.3168724279836397,-1.343209876543213]]],"handle_end":[[4,[0.05267489711934559,0.02633744855966924]],[3,[0.7962610294339356,0.812186250022549]],[2,[-0.05267489711934559,-0.9218106995884768]],[1,[-1.447323438899616,-1.3198753943965968]]],"stroke":[[4,0],[3,0],[1,0],[2,0]]},"regions":{"add":[0],"remove":[],"segment_range":[[0,{"start":1,"end":4}]],"fill":[[0,0]]},"add_g1_continuous":[],"remove_g1_continuous":[]}},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::vector_data::modification::VectorModification","alias":null}},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::vector_data::modification::PathModifyNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[7525593029671097583,{"inputs":[{"Node":{"node_id":16175421708184657649,"output_index":0,"lambda":false}},{"Node":{"node_id":15735375935164094402,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[14894569344576297448,{"inputs":[{"Node":{"node_id":5555007473125503522,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"Fill":{"Solid":{"red":0.8980392,"green":0.8,"blue":0.6117647,"alpha":1.0}}},"exposed":false}},{"Value":{"tagged_value":{"OptionalColor":{"red":0.8980392,"green":0.8,"blue":0.6117647,"alpha":1.0}},"exposed":false}},{"Value":{"tagged_value":{"Gradient":{"stops":[[0.0,{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}],[1.0,{"red":1.0,"green":1.0,"blue":1.0,"alpha":1.0}]],"gradient_type":"Linear","start":[0.0,0.5],"end":[1.0,0.5],"transform":[1.0,0.0,0.0,1.0,0.0,0.0]}},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::FillNode"}},"visible":true,"skip_deduplication":false}],[15578929303912288394,{"inputs":[{"Node":{"node_id":10770443343193024138,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"Fill":{"Solid":{"red":0.8980392,"green":0.8,"blue":0.6117647,"alpha":1.0}}},"exposed":false}},{"Value":{"tagged_value":{"OptionalColor":{"red":0.8980392,"green":0.8,"blue":0.6117647,"alpha":1.0}},"exposed":false}},{"Value":{"tagged_value":{"Gradient":{"stops":[[0.0,{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}],[1.0,{"red":1.0,"green":1.0,"blue":1.0,"alpha":1.0}]],"gradient_type":"Linear","start":[0.0,0.5],"end":[1.0,0.5],"transform":[1.0,0.0,0.0,1.0,0.0,0.0]}},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::FillNode"}},"visible":true,"skip_deduplication":false}],[10133176481349663495,{"inputs":[{"Node":{"node_id":12876462860151722087,"output_index":0,"lambda":false}},{"Node":{"node_id":11021243031011826737,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[4332145463108161926,{"inputs":[{"Node":{"node_id":3406722917122601552,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"Fill":{"Solid":{"red":0.7529412,"green":0.15686275,"blue":0.13333334,"alpha":1.0}}},"exposed":false}},{"Value":{"tagged_value":{"OptionalColor":{"red":0.7529412,"green":0.15686275,"blue":0.13333334,"alpha":1.0}},"exposed":false}},{"Value":{"tagged_value":{"Gradient":{"stops":[[0.0,{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}],[1.0,{"red":1.0,"green":1.0,"blue":1.0,"alpha":1.0}]],"gradient_type":"Linear","start":[0.0,0.5],"end":[1.0,0.5],"transform":[1.0,0.0,0.0,1.0,0.0,0.0]}},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::FillNode"}},"visible":true,"skip_deduplication":false}],[9740500978584792725,{"inputs":[{"Node":{"node_id":14946189826912398678,"output_index":0,"lambda":false}},{"Node":{"node_id":10586744777717861556,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[10421722418968896452,{"inputs":[{"Value":{"tagged_value":{"VectorData":{"instance":[{"style":{"stroke":{"color":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0},"weight":0.0,"dash_lengths":[],"dash_offset":0.0,"cap":"Butt","join":"Miter","join_miter_limit":4.0,"align":"Center","transform":[1.0,0.0,0.0,1.0,0.0,0.0],"non_scaling":false,"paint_order":"StrokeAbove"},"fill":"None"},"colinear_manipulators":[],"point_domain":{"id":[],"position":[]},"segment_domain":{"id":[],"start_point":[],"end_point":[],"handles":[],"stroke":[]},"region_domain":{"id":[],"segment_range":[],"fill":[]},"upstream_graphic_group":null}],"transform":[[1.0,0.0,0.0,1.0,0.0,0.0]],"alpha_blending":[{"blend_mode":"Normal","opacity":1.0,"fill":1.0,"clip":false}],"source_node_id":[null]}},"exposed":true}},{"Value":{"tagged_value":{"VectorModification":{"points":{"add":[1,2,3],"remove":[],"delta":[[2,[683.3689986282578,99.49702789208962]],[3,[691.7384545038866,78.07590306355738]],[1,[677.8673982624599,66.19478737997257]]]},"segments":{"add":[1,2,3],"remove":[],"start_point":[[2,2],[3,3],[1,1]],"end_point":[[1,2],[3,1],[2,3]],"handle_primary":[[3,[0.12630166293718048,-1.7247569518707309]],[1,[-0.49434169374126213,0.7369041683249975]],[2,[0.34676700844204333,0.512429191350904]]],"handle_end":[[2,[-1.4537474229852023,19.852161212683583]],[1,[-7.636184307015128,-11.284244620129414]],[3,[5.6142033131263815,-8.368968014727507]]],"stroke":[[1,0],[2,0],[3,0]]},"regions":{"add":[0],"remove":[],"segment_range":[[0,{"start":1,"end":3}]],"fill":[[0,0]]},"add_g1_continuous":[],"remove_g1_continuous":[]}},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::vector_data::modification::VectorModification","alias":null}},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::vector_data::modification::PathModifyNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[16551385471328831128,{"inputs":[{"Node":{"node_id":14991324592500870173,"output_index":0,"lambda":false}},{"Node":{"node_id":17207349373429328029,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[6532401937876437300,{"inputs":[{"Node":{"node_id":3992858139802231032,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"DVec2":[0.0,0.0]},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[1.0,1.0]},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[0.0,0.0]},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[0.5,0.5]},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":1}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":2}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":3}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":4}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":5}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::TransformNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[3971837674569123876,{"inputs":[{"Node":{"node_id":4131094614457622424,"output_index":0,"lambda":false}},{"Node":{"node_id":17078740291337047697,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"F64":1.2},"exposed":false}},{"Value":{"tagged_value":{"F64":2.0},"exposed":false}},{"Value":{"tagged_value":{"F64":3.3528},"exposed":false}},{"Value":{"tagged_value":{"U32":0},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"U32":0},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::CopyToPointsNode"}},"visible":true,"skip_deduplication":false}],[6988349135757634271,{"inputs":[{"Value":{"tagged_value":{"VectorData":{"instance":[{"style":{"stroke":{"color":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0},"weight":0.0,"dash_lengths":[],"dash_offset":0.0,"cap":"Butt","join":"Miter","join_miter_limit":4.0,"align":"Center","transform":[1.0,0.0,0.0,1.0,0.0,0.0],"non_scaling":false,"paint_order":"StrokeAbove"},"fill":"None"},"colinear_manipulators":[],"point_domain":{"id":[],"position":[]},"segment_domain":{"id":[],"start_point":[],"end_point":[],"handles":[],"stroke":[]},"region_domain":{"id":[],"segment_range":[],"fill":[]},"upstream_graphic_group":null}],"transform":[[1.0,0.0,0.0,1.0,0.0,0.0]],"alpha_blending":[{"blend_mode":"Normal","opacity":1.0,"fill":1.0,"clip":false}],"source_node_id":[null]}},"exposed":true}},{"Value":{"tagged_value":{"VectorModification":{"points":{"add":[1,2,3,4],"remove":[],"delta":[[2,[188.0493827160494,269.116049382716]],[3,[183.0891632373113,268.771154223006]],[1,[189.14614932392712,263.9984322947286]],[4,[184.5962505715592,263.55006858710567]]]},"segments":{"add":[1,2,3,4],"remove":[],"start_point":[[3,3],[4,4],[2,2],[1,1]],"end_point":[[4,1],[2,3],[3,4],[1,2]],"handle_primary":[[3,[-0.9800640224909783,-1.3570273385153655]],[2,[-1.9972565157751203,0.9588085439937686]],[4,[1.697261300324044,-1.9917992948792855]],[1,[1.552958476004363,1.9059035841873424]]],"handle_end":[[3,[-1.5959762231368018,1.872937487752267]],[1,[3.459421910557637,-1.6607397492127802]],[2,[1.0091841400482906,1.3973479652491392]],[4,[-1.464617942413156,-1.7974856565980986]]],"stroke":[[1,0],[4,0],[2,0],[3,0]]},"regions":{"add":[0],"remove":[],"segment_range":[[0,{"start":1,"end":4}]],"fill":[[0,0]]},"add_g1_continuous":[],"remove_g1_continuous":[]}},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::vector_data::modification::VectorModification","alias":null}},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::vector_data::modification::PathModifyNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[1384427686127078856,{"inputs":[{"Node":{"node_id":17064046832210629373,"output_index":0,"lambda":false}},{"Node":{"node_id":17529660518597229229,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[14057307926677215422,{"inputs":[{"Node":{"node_id":5861306074868809692,"output_index":0,"lambda":false}},{"Node":{"node_id":7450965328305122110,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[4832236468224231783,{"inputs":[{"Value":{"tagged_value":{"VectorData":{"instance":[{"style":{"stroke":{"color":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0},"weight":0.0,"dash_lengths":[],"dash_offset":0.0,"cap":"Butt","join":"Miter","join_miter_limit":4.0,"align":"Center","transform":[1.0,0.0,0.0,1.0,0.0,0.0],"non_scaling":false,"paint_order":"StrokeAbove"},"fill":"None"},"colinear_manipulators":[],"point_domain":{"id":[],"position":[]},"segment_domain":{"id":[],"start_point":[],"end_point":[],"handles":[],"stroke":[]},"region_domain":{"id":[],"segment_range":[],"fill":[]},"upstream_graphic_group":null}],"transform":[[1.0,0.0,0.0,1.0,0.0,0.0]],"alpha_blending":[{"blend_mode":"Normal","opacity":1.0,"fill":1.0,"clip":false}],"source_node_id":[null]}},"exposed":true}},{"Value":{"tagged_value":{"VectorModification":{"points":{"add":[1,2],"remove":[],"delta":[[1,[232.44444444444443,332.8888888888889]],[2,[369.77777777777777,381.7777777777778]]]},"segments":{"add":[1],"remove":[],"start_point":[[1,1]],"end_point":[[1,2]],"handle_primary":[[1,[0.0,0.0]]],"handle_end":[[1,[-73.77777777777777,-53.77777777777777]]],"stroke":[[1,0]]},"regions":{"add":[],"remove":[],"segment_range":[],"fill":[]},"add_g1_continuous":[],"remove_g1_continuous":[]}},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::vector_data::modification::VectorModification","alias":null}},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::vector_data::modification::PathModifyNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[14991324592500870173,{"inputs":[{"Node":{"node_id":542361600097372754,"output_index":0,"lambda":false}},{"Node":{"node_id":10860592954464951000,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[11630078441485655672,{"inputs":[{"Value":{"tagged_value":{"VectorData":{"instance":[{"style":{"stroke":{"color":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0},"weight":0.0,"dash_lengths":[],"dash_offset":0.0,"cap":"Butt","join":"Miter","join_miter_limit":4.0,"align":"Center","transform":[1.0,0.0,0.0,1.0,0.0,0.0],"non_scaling":false,"paint_order":"StrokeAbove"},"fill":"None"},"colinear_manipulators":[],"point_domain":{"id":[],"position":[]},"segment_domain":{"id":[],"start_point":[],"end_point":[],"handles":[],"stroke":[]},"region_domain":{"id":[],"segment_range":[],"fill":[]},"upstream_graphic_group":null}],"transform":[[1.0,0.0,0.0,1.0,0.0,0.0]],"alpha_blending":[{"blend_mode":"Normal","opacity":1.0,"fill":1.0,"clip":false}],"source_node_id":[null]}},"exposed":true}},{"Value":{"tagged_value":{"VectorModification":{"points":{"add":[1,2],"remove":[],"delta":[[2,[751.4074074074075,685.0370370370371]],[1,[760.6913580246915,657.5802469135803]]]},"segments":{"add":[1,2],"remove":[],"start_point":[[2,2],[1,1]],"end_point":[[1,2],[2,1]],"handle_primary":[[1,[0.0,0.0]],[2,[4.543209876543187,-10.271604938271594]]],"handle_end":[[2,null],[1,[7.111111111110972,-8.44444444444457]]],"stroke":[[1,0],[2,0]]},"regions":{"add":[0],"remove":[],"segment_range":[[0,{"start":1,"end":2}]],"fill":[[0,0]]},"add_g1_continuous":[],"remove_g1_continuous":[]}},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::vector_data::modification::VectorModification","alias":null}},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::vector_data::modification::PathModifyNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[3970516859959908758,{"inputs":[{"Value":{"tagged_value":{"VectorData":{"instance":[{"style":{"stroke":{"color":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0},"weight":0.0,"dash_lengths":[],"dash_offset":0.0,"cap":"Butt","join":"Miter","join_miter_limit":4.0,"align":"Center","transform":[1.0,0.0,0.0,1.0,0.0,0.0],"non_scaling":false,"paint_order":"StrokeAbove"},"fill":"None"},"colinear_manipulators":[],"point_domain":{"id":[],"position":[]},"segment_domain":{"id":[],"start_point":[],"end_point":[],"handles":[],"stroke":[]},"region_domain":{"id":[],"segment_range":[],"fill":[]},"upstream_graphic_group":null}],"transform":[[1.0,0.0,0.0,1.0,0.0,0.0]],"alpha_blending":[{"blend_mode":"Normal","opacity":1.0,"fill":1.0,"clip":false}],"source_node_id":[null]}},"exposed":true}},{"Value":{"tagged_value":{"VectorModification":{"points":{"add":[1,2,3],"remove":[],"delta":[[2,[78.22222222222219,579.2592592592591]],[1,[49.77777777777773,636.148148148148]],[3,[170.96296296296293,544.5925925925925]]]},"segments":{"add":[1,2],"remove":[],"start_point":[[2,2],[1,1]],"end_point":[[2,3],[1,2]],"handle_primary":[[1,[0.0,0.0]],[2,[27.259259259259252,-24.88888888888891]]],"handle_end":[[1,[-27.259259259259267,24.88888888888891]],[2,[-21.62962962962962,-2.0740740740740193]]],"stroke":[[2,0],[1,0]]},"regions":{"add":[],"remove":[],"segment_range":[],"fill":[]},"add_g1_continuous":[],"remove_g1_continuous":[]}},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::vector_data::modification::VectorModification","alias":null}},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::vector_data::modification::PathModifyNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[13302269488061286120,{"inputs":[{"Value":{"tagged_value":{"VectorData":{"instance":[{"style":{"stroke":{"color":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0},"weight":0.0,"dash_lengths":[],"dash_offset":0.0,"cap":"Butt","join":"Miter","join_miter_limit":4.0,"align":"Center","transform":[1.0,0.0,0.0,1.0,0.0,0.0],"non_scaling":false,"paint_order":"StrokeAbove"},"fill":"None"},"colinear_manipulators":[],"point_domain":{"id":[],"position":[]},"segment_domain":{"id":[],"start_point":[],"end_point":[],"handles":[],"stroke":[]},"region_domain":{"id":[],"segment_range":[],"fill":[]},"upstream_graphic_group":null}],"transform":[[1.0,0.0,0.0,1.0,0.0,0.0]],"alpha_blending":[{"blend_mode":"Normal","opacity":1.0,"fill":1.0,"clip":false}],"source_node_id":[null]}},"exposed":true}},{"Value":{"tagged_value":{"VectorModification":{"points":{"add":[1,2],"remove":[],"delta":[[1,[262.66666666666674,903.3333333333331]],[2,[565.3333333333335,756.6666666666666]]]},"segments":{"add":[1],"remove":[],"start_point":[[1,1]],"end_point":[[1,2]],"handle_primary":[[1,[0.0,0.0]]],"handle_end":[[1,[-200.66666666666652,64.66666666666663]]],"stroke":[[1,0]]},"regions":{"add":[],"remove":[],"segment_range":[],"fill":[]},"add_g1_continuous":[],"remove_g1_continuous":[]}},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::vector_data::modification::VectorModification","alias":null}},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::vector_data::modification::PathModifyNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[1889157037801767612,{"inputs":[{"Node":{"node_id":17324767436949538365,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"F64":30.0},"exposed":false}},{"Value":{"tagged_value":{"U32":18},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":1}},{"Network":{"import_type":{"Concrete":{"name":"u32","alias":null}},"import_index":2}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::PoissonDiskPointsNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":2,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::BoundlessFootprintNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::FreezeRealTimeNode"}},"visible":true,"skip_deduplication":false}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MemoNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[10270446074640675342,{"inputs":[{"Node":{"node_id":14883504161508594099,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"DVec2":[0.0,0.0]},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[1.0,1.0]},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[0.0,0.0]},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[0.5,0.5]},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":1}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":2}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":3}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":4}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":5}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::TransformNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[4078100635676202528,{"inputs":[{"Value":{"tagged_value":{"VectorData":{"instance":[{"style":{"stroke":{"color":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0},"weight":0.0,"dash_lengths":[],"dash_offset":0.0,"cap":"Butt","join":"Miter","join_miter_limit":4.0,"align":"Center","transform":[1.0,0.0,0.0,1.0,0.0,0.0],"non_scaling":false,"paint_order":"StrokeAbove"},"fill":"None"},"colinear_manipulators":[],"point_domain":{"id":[],"position":[]},"segment_domain":{"id":[],"start_point":[],"end_point":[],"handles":[],"stroke":[]},"region_domain":{"id":[],"segment_range":[],"fill":[]},"upstream_graphic_group":null}],"transform":[[1.0,0.0,0.0,1.0,0.0,0.0]],"alpha_blending":[{"blend_mode":"Normal","opacity":1.0,"fill":1.0,"clip":false}],"source_node_id":[null]}},"exposed":true}},{"Value":{"tagged_value":{"VectorModification":{"points":{"add":[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26],"remove":[],"delta":[[4,[627.9111111111112,43.73333333333333]],[16,[661.0962962962963,35.792592592592584]],[3,[613.4518518518519,35.43703703703703]],[18,[621.2740740740741,37.21481481481481]],[15,[677.925925925926,46.222222222222214]],[7,[684.4444444444445,46.1037037037037]],[17,[639.762962962963,37.45185185185185]],[14,[698.3111111111111,43.61481481481481]],[6,[676.2666666666667,48.47407407407407]],[20,[601.2444444444444,36.859259259259254]],[26,[607.3152263374486,46.38024691358025]],[1,[606.3407407407408,47.76296296296296]],[9,[642.4888888888889,44.44444444444444]],[21,[605.3925925925926,49.42222222222222]],[13,[707.0814814814814,53.33333333333333]],[23,[608.5794238683127,44.82633744855967]],[11,[665.4814814814815,56.05925925925925]],[10,[653.1555555555556,49.89629629629629]],[22,[607.6312757201646,47.64444444444445]],[24,[605.998353909465,33.79094650205761]],[12,[683.3777777777777,50.48888888888889]],[19,[613.4518518518519,26.429629629629623]],[8,[667.2592592592594,52.029629629629625]],[2,[603.4962962962964,36.977777777777774]],[25,[604.6288065843622,39.321810699588475]],[5,[653.9851851851852,38.99259259259259]]]},"segments":{"add":[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26],"remove":[],"start_point":[[22,22],[18,18],[14,14],[2,2],[20,20],[7,7],[25,25],[6,6],[3,3],[17,17],[10,10],[19,19],[13,13],[9,9],[5,5],[24,24],[16,16],[11,11],[4,4],[26,26],[21,21],[1,1],[12,12],[8,8],[23,23],[15,15]],"end_point":[[6,7],[10,11],[8,9],[11,12],[5,6],[22,23],[13,14],[21,22],[1,2],[14,15],[26,1],[12,13],[18,19],[7,8],[3,4],[23,24],[15,16],[25,26],[4,5],[20,21],[24,25],[16,17],[9,10],[17,18],[19,20],[2,3]],"handle_primary":[[22,[0.0,0.0]],[10,[2.251851851851825,2.2518518518518533]],[2,[2.1333333333333258,-5.68888888888889]],[25,[0.18814026836287212,2.510418336797158]],[6,[4.5037037037037635,1.1851851851851831]],[26,[0.0,0.0]],[8,[-10.666666666666629,-0.7111111111111157]],[16,[-5.214814814814758,-1.3037037037037038]],[19,[-3.3185185185185446,-1.1851851851851831]],[23,[-2.2123456790121736,-2.3967078189300537]],[7,[0.0,0.0]],[20,[-1.5407407407407163,8.651851851851852]],[13,[0.0,0.0]],[17,[-6.992592592592587,2.962962962962962]],[14,[-10.90370370370374,-2.6074074074074076]],[3,[2.9629629629629335,4.385185185185186]],[1,[0.0,0.0]],[18,[-3.437037037037044,-4.148148148148145]],[12,[6.9925925925927,-4.740740740740748]],[5,[10.311111111111131,0.5925925925925952]],[11,[3.318518518518431,-0.11851851851851336]],[4,[6.992592592592587,-0.23703703703703383]],[9,[0.0,0.0]],[24,[0.0,0.0]],[21,[0.0,0.0]],[15,[-2.844444444444548,-0.829629629629629]]],"handle_end":[[4,[-10.311111111111131,-0.5925925925925952]],[19,[1.5407407407407163,-8.651851851851855]],[26,[0.0,0.0]],[5,[-4.5037037037037635,-1.1851851851851904]],[21,[0.0,0.0]],[1,[-2.1333333333333258,5.68888888888889]],[12,[-3.0814814814815463,-9.48148148148148]],[13,[10.90370370370374,2.6074074074074076]],[15,[5.214814814814758,1.3037037037037038]],[23,[0.0,0.0]],[8,[9.36296296296291,-2.4888888888888943]],[20,[0.0,0.0]],[3,[-6.992592592592587,0.23703703703703383]],[9,[-2.251851851851825,-2.2518518518518533]],[17,[3.437037037037044,4.148148148148145]],[2,[-2.9629629629629335,-4.385185185185186]],[25,[0.0,0.0]],[22,null],[24,[-0.13898543393838736,-1.8545289902200464]],[18,[3.3185185185185446,1.1851851851851831]],[11,[-6.9925925925927,4.740740740740748]],[14,[2.844444444444548,0.829629629629629]],[7,[10.666666666666629,0.7111111111111086]],[6,[0.0,0.0]],[16,[6.992592592592587,-2.962962962962962]],[10,[-3.318518518518431,0.11851851851851336]]],"stroke":[[21,0],[16,0],[24,0],[18,0],[3,0],[20,0],[15,0],[12,0],[14,0],[23,0],[26,0],[5,0],[2,0],[17,0],[22,0],[11,0],[6,0],[10,0],[19,0],[1,0],[4,0],[9,0],[7,0],[25,0],[8,0],[13,0]]},"regions":{"add":[0],"remove":[],"segment_range":[[0,{"start":1,"end":26}]],"fill":[[0,0]]},"add_g1_continuous":[],"remove_g1_continuous":[]}},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::vector_data::modification::VectorModification","alias":null}},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::vector_data::modification::PathModifyNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[2422139482859833437,{"inputs":[{"Node":{"node_id":14537754528543289381,"output_index":0,"lambda":false}},{"Node":{"node_id":172538270105470471,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[4372998635946271235,{"inputs":[{"Node":{"node_id":13481022631108980683,"output_index":0,"lambda":false}},{"Node":{"node_id":2126710823743005151,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[542361600097372754,{"inputs":[{"Node":{"node_id":17971411534648521628,"output_index":0,"lambda":false}},{"Node":{"node_id":6867142265138950838,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[14888395629683671889,{"inputs":[{"Node":{"node_id":4341772758799935306,"output_index":0,"lambda":false}},{"Node":{"node_id":17078740291337047697,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"F64":1.2},"exposed":false}},{"Value":{"tagged_value":{"F64":2.0},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"U32":0},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"U32":0},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::CopyToPointsNode"}},"visible":true,"skip_deduplication":false}],[2698266912167150713,{"inputs":[{"Node":{"node_id":3165571685352930240,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"Fill":{"Solid":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}}},"exposed":false}},{"Value":{"tagged_value":{"OptionalColor":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}},"exposed":false}},{"Value":{"tagged_value":{"Gradient":{"stops":[[0.0,{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}],[1.0,{"red":1.0,"green":1.0,"blue":1.0,"alpha":1.0}]],"gradient_type":"Linear","start":[0.0,0.5],"end":[1.0,0.5],"transform":[1.0,0.0,0.0,1.0,0.0,0.0]}},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::FillNode"}},"visible":true,"skip_deduplication":false}],[17324767436949538365,{"inputs":[{"Value":{"tagged_value":{"VectorData":{"instance":[{"style":{"stroke":{"color":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0},"weight":0.0,"dash_lengths":[],"dash_offset":0.0,"cap":"Butt","join":"Miter","join_miter_limit":4.0,"align":"Center","transform":[1.0,0.0,0.0,1.0,0.0,0.0],"non_scaling":false,"paint_order":"StrokeAbove"},"fill":"None"},"colinear_manipulators":[],"point_domain":{"id":[],"position":[]},"segment_domain":{"id":[],"start_point":[],"end_point":[],"handles":[],"stroke":[]},"region_domain":{"id":[],"segment_range":[],"fill":[]},"upstream_graphic_group":null}],"transform":[[1.0,0.0,0.0,1.0,0.0,0.0]],"alpha_blending":[{"blend_mode":"Normal","opacity":1.0,"fill":1.0,"clip":false}],"source_node_id":[null]}},"exposed":true}},{"Value":{"tagged_value":{"VectorModification":{"points":{"add":[1,2,3,4,5,6],"remove":[],"delta":[[2,[362.22222222222223,512.0]],[1,[503.11111111111114,614.6666666666666]],[3,[158.66666666666669,419.55555555555554]],[5,[119.1111111111111,456.44444444444446]],[6,[289.7777777777778,503.1111111111111]],[4,[150.22222222222223,429.3333333333333]]]},"segments":{"add":[1,2,3,4,5,6],"remove":[],"start_point":[[1,1],[4,4],[6,6],[3,3],[5,5],[2,2]],"end_point":[[4,5],[6,1],[1,2],[3,4],[5,6],[2,3]],"handle_primary":[[5,[0.0,0.0]],[3,[0.0,0.0]],[1,[0.0,0.0]],[6,[89.85096850895411,61.20347364650138]],[4,[0.0,0.0]],[2,[-52.888888888888914,-48.44444444444446]]],"handle_end":[[6,[0.8888888888888005,-0.4444444444444571]],[4,[7.1111111111111,-35.55555555555554]],[2,[76.0,-1.7777777777777717]],[3,[0.0,0.0]],[5,[-89.85096850895414,-61.20347364650138]],[1,[52.888888888888914,48.44444444444446]]],"stroke":[[4,0],[5,0],[2,0],[3,0],[6,0],[1,0]]},"regions":{"add":[0],"remove":[],"segment_range":[[0,{"start":1,"end":6}]],"fill":[[0,0]]},"add_g1_continuous":[],"remove_g1_continuous":[]}},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::vector_data::modification::VectorModification","alias":null}},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::vector_data::modification::PathModifyNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[1659518581611333812,{"inputs":[{"Value":{"tagged_value":{"VectorData":{"instance":[{"style":{"stroke":{"color":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0},"weight":0.0,"dash_lengths":[],"dash_offset":0.0,"cap":"Butt","join":"Miter","join_miter_limit":4.0,"align":"Center","transform":[1.0,0.0,0.0,1.0,0.0,0.0],"non_scaling":false,"paint_order":"StrokeAbove"},"fill":"None"},"colinear_manipulators":[],"point_domain":{"id":[],"position":[]},"segment_domain":{"id":[],"start_point":[],"end_point":[],"handles":[],"stroke":[]},"region_domain":{"id":[],"segment_range":[],"fill":[]},"upstream_graphic_group":null}],"transform":[[1.0,0.0,0.0,1.0,0.0,0.0]],"alpha_blending":[{"blend_mode":"Normal","opacity":1.0,"fill":1.0,"clip":false}],"source_node_id":[null]}},"exposed":true}},{"Value":{"tagged_value":{"VectorModification":{"points":{"add":[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17],"remove":[],"delta":[[3,[917.991769547325,333.4320987654321]],[7,[773.7942386831274,177.119341563786]],[8,[809.349794238683,192.0]],[5,[838.3209876543208,205.6954732510288]],[2,[913.2510288065844,355.55555555555554]],[13,[872.1207133058986,331.2373113854595]],[4,[869.1358024691356,247.17695473251027]],[9,[838.4526748971191,213.46502057613168]],[12,[858.1618655692731,310.6063100137174]],[1,[889.8106995884773,368.4609053497942]],[11,[865.1851851851853,248.6255144032922]],[16,[854.5185185185187,346.46913580246917]],[17,[866.172839506173,375.11111111111114]],[10,[856.2304526748969,234.40329218106996]],[15,[872.9108367626887,333.08093278463645]],[6,[812.2469135802468,182.5185185185185]],[14,[885.9039780521264,331.0617283950617]]]},"segments":{"add":[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17],"remove":[],"start_point":[[4,4],[5,5],[14,14],[8,8],[13,13],[7,7],[16,16],[12,12],[2,2],[1,1],[6,6],[17,17],[3,3],[15,15],[11,11],[9,9],[10,10]],"end_point":[[11,12],[5,6],[9,10],[13,14],[14,15],[10,11],[4,5],[3,4],[6,7],[16,17],[12,13],[2,3],[1,2],[7,8],[17,1],[15,16],[8,9]],"handle_primary":[[14,[-5.267489711934104,0.0]],[7,[6.584362139917744,1.0534979423868265]],[15,[-5.267489711934104,1.4924554183813257]],[12,[6.935528120713343,13.080932784636502]],[10,[7.506172839506121,6.452674897119351]],[8,[14.748971193415628,7.242798353909478]],[13,[7.111111111111086,-2.72153635116598]],[3,[-10.72985850116538,-29.20905925317203]],[17,[4.279835390946232,0.32921810699582466]],[5,[-6.320987654321016,-8.164609053497912]],[11,[1.9314128943758533,32.395061728395035]],[4,[-8.03292181069969,-10.008230452674894]],[1,[9.349794238683105,-4.213991769547306]],[16,[0.0,0.0]],[9,[6.189300411522595,6.97942386831275]],[2,[7.637860082304428,-3.423868312757179]],[6,[-10.930041152263357,-4.213991769547334]]],"handle_end":[[1,[-7.637860082304542,3.423868312757179]],[7,[-14.748971193415628,-7.242798353909478]],[6,[0.0,0.0]],[9,[-7.506172839506121,-6.452674897119351]],[14,[5.267489711934104,-1.4924554183813257]],[13,[0.0,0.0]],[4,[6.320987654321016,8.164609053497912]],[5,[10.930041152263357,4.213991769547334]],[8,[-6.189300411522595,-6.97942386831275]],[17,[-9.349794238683105,4.213991769547306]],[2,[7.1111111111111995,19.35802469135808]],[12,[0.0,0.0]],[11,[0.0,0.0]],[16,[-8.098765432098958,-2.1728395061728634]],[15,[0.0,0.0]],[10,[0.0,0.0]],[3,[8.03292181069969,10.008230452674894]]],"stroke":[[9,0],[6,0],[11,0],[3,0],[13,0],[10,0],[8,0],[5,0],[7,0],[14,0],[17,0],[4,0],[15,0],[12,0],[1,0],[2,0],[16,0]]},"regions":{"add":[0],"remove":[],"segment_range":[[0,{"start":1,"end":17}]],"fill":[[0,0]]},"add_g1_continuous":[],"remove_g1_continuous":[]}},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::vector_data::modification::VectorModification","alias":null}},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::vector_data::modification::PathModifyNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[11481949351661484921,{"inputs":[{"Node":{"node_id":15303587427289959766,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"PointSpacingType":"Separation"},"exposed":false}},{"Value":{"tagged_value":{"F64":5.0},"exposed":false}},{"Value":{"tagged_value":{"U32":100},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"Bool":false},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":4,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::SubpathSegmentLengthsNode"}},"visible":true,"skip_deduplication":false}],[4,{"inputs":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::BoundlessFootprintNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":2,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::FreezeRealTimeNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MemoNode"}},"visible":true,"skip_deduplication":false}],[1,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::misc::PointSpacingType","alias":null}},"import_index":1}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":2}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":3}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":4}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":5}},{"Network":{"import_type":{"Concrete":{"name":"bool","alias":null}},"import_index":6}},{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::SamplePolylineNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[4105711298139980122,{"inputs":[{"Node":{"node_id":1162381870526064378,"output_index":0,"lambda":false}},{"Node":{"node_id":1272070255512697108,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[10415872992231003638,{"inputs":[{"Node":{"node_id":8375495949882478840,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"Fill":{"Solid":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}}},"exposed":false}},{"Value":{"tagged_value":{"OptionalColor":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}},"exposed":false}},{"Value":{"tagged_value":{"Gradient":{"stops":[[0.0,{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}],[1.0,{"red":1.0,"green":1.0,"blue":1.0,"alpha":1.0}]],"gradient_type":"Linear","start":[0.0,0.5],"end":[1.0,0.5],"transform":[1.0,0.0,0.0,1.0,0.0,0.0]}},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::FillNode"}},"visible":true,"skip_deduplication":false}],[10587073897090054035,{"inputs":[{"Node":{"node_id":8814059393325469059,"output_index":0,"lambda":false}},{"Node":{"node_id":907841922684377912,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[4422453582814483232,{"inputs":[{"Node":{"node_id":4577638792388493935,"output_index":0,"lambda":false}},{"Node":{"node_id":431994205232245356,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[14817659161913199655,{"inputs":[{"Value":{"tagged_value":{"VectorData":{"instance":[{"style":{"stroke":{"color":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0},"weight":0.0,"dash_lengths":[],"dash_offset":0.0,"cap":"Butt","join":"Miter","join_miter_limit":4.0,"align":"Center","transform":[1.0,0.0,0.0,1.0,0.0,0.0],"non_scaling":false,"paint_order":"StrokeAbove"},"fill":"None"},"colinear_manipulators":[],"point_domain":{"id":[],"position":[]},"segment_domain":{"id":[],"start_point":[],"end_point":[],"handles":[],"stroke":[]},"region_domain":{"id":[],"segment_range":[],"fill":[]},"upstream_graphic_group":null}],"transform":[[1.0,0.0,0.0,1.0,0.0,0.0]],"alpha_blending":[{"blend_mode":"Normal","opacity":1.0,"fill":1.0,"clip":false}],"source_node_id":[null]}},"exposed":true}},{"Value":{"tagged_value":{"VectorModification":{"points":{"add":[1,2,3],"remove":[],"delta":[[3,[726.8148148148148,1023.9999999999998]],[2,[725.3333333333333,985.7777777777776]],[1,[796.148148148148,723.8518518518517]]]},"segments":{"add":[1,2,3],"remove":[],"start_point":[[2,2],[3,3],[1,1]],"end_point":[[3,1],[1,2],[2,3]],"handle_primary":[[1,[0.0,0.0]],[2,[0.0,0.0]],[3,[0.0,0.0]]],"handle_end":[[1,[9.777777777777828,-73.18518518518522]],[2,[0.0,0.0]],[3,[-75.55555555555566,240.59259259259304]]],"stroke":[[1,0],[2,0],[3,0]]},"regions":{"add":[0],"remove":[],"segment_range":[[0,{"start":1,"end":3}]],"fill":[[0,0]]},"add_g1_continuous":[],"remove_g1_continuous":[]}},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::vector_data::modification::VectorModification","alias":null}},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::vector_data::modification::PathModifyNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[7505360855062237520,{"inputs":[{"Node":{"node_id":17945736750161448391,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"Fill":{"Solid":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}}},"exposed":false}},{"Value":{"tagged_value":{"OptionalColor":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}},"exposed":false}},{"Value":{"tagged_value":{"Gradient":{"stops":[[0.0,{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}],[1.0,{"red":1.0,"green":1.0,"blue":1.0,"alpha":1.0}]],"gradient_type":"Linear","start":[0.0,0.5],"end":[1.0,0.5],"transform":[1.0,0.0,0.0,1.0,0.0,0.0]}},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::FillNode"}},"visible":true,"skip_deduplication":false}],[8766106989344197438,{"inputs":[{"Value":{"tagged_value":{"VectorData":{"instance":[{"style":{"stroke":{"color":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0},"weight":0.0,"dash_lengths":[],"dash_offset":0.0,"cap":"Butt","join":"Miter","join_miter_limit":4.0,"align":"Center","transform":[1.0,0.0,0.0,1.0,0.0,0.0],"non_scaling":false,"paint_order":"StrokeAbove"},"fill":"None"},"colinear_manipulators":[],"point_domain":{"id":[],"position":[]},"segment_domain":{"id":[],"start_point":[],"end_point":[],"handles":[],"stroke":[]},"region_domain":{"id":[],"segment_range":[],"fill":[]},"upstream_graphic_group":null}],"transform":[[1.0,0.0,0.0,1.0,0.0,0.0]],"alpha_blending":[{"blend_mode":"Normal","opacity":1.0,"fill":1.0,"clip":false}],"source_node_id":[null]}},"exposed":true}},{"Value":{"tagged_value":{"VectorModification":{"points":{"add":[1,2,3,4,5,6],"remove":[],"delta":[[1,[197.33333333333337,212.5432098765432]],[6,[184.49382716049385,218.2716049382716]],[2,[172.64197530864195,208.98765432098767]],[3,[153.58712172411558,204.8434307274338]],[5,[155.85185185185185,211.55555555555557]],[4,[146.5679012345679,204.44444444444449]]]},"segments":{"add":[1,2,3,4,5,6],"remove":[],"start_point":[[5,5],[6,6],[3,3],[2,2],[1,1],[4,4]],"end_point":[[1,2],[3,4],[6,1],[5,6],[4,5],[2,3]],"handle_primary":[[2,[-7.703703703703667,-1.1851851851851904]],[1,[0.0,0.0]],[3,[-5.834035304362487,0.7861989021958493]],[5,[8.493827160493822,2.3703703703703525]],[6,[3.160493827160479,-0.9876543209876444]],[4,[0.0,0.0]]],"handle_end":[[5,[-3.1604938271605363,0.9876543209877012]],[4,[-8.493827160493794,-2.370370370370381]],[3,[0.0,0.0]],[6,[-3.160493827160479,1.9753086419753456]],[1,[7.703703703703724,1.1851851851852189]],[2,[5.834035304362487,-0.7861989021958493]]],"stroke":[[6,0],[3,0],[1,0],[2,0],[4,0],[5,0]]},"regions":{"add":[0],"remove":[],"segment_range":[[0,{"start":1,"end":6}]],"fill":[[0,0]]},"add_g1_continuous":[],"remove_g1_continuous":[]}},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::vector_data::modification::VectorModification","alias":null}},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::vector_data::modification::PathModifyNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[14831840560430171946,{"inputs":[{"Value":{"tagged_value":{"VectorData":{"instance":[{"style":{"stroke":{"color":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0},"weight":0.0,"dash_lengths":[],"dash_offset":0.0,"cap":"Butt","join":"Miter","join_miter_limit":4.0,"align":"Center","transform":[1.0,0.0,0.0,1.0,0.0,0.0],"non_scaling":false,"paint_order":"StrokeAbove"},"fill":"None"},"colinear_manipulators":[],"point_domain":{"id":[],"position":[]},"segment_domain":{"id":[],"start_point":[],"end_point":[],"handles":[],"stroke":[]},"region_domain":{"id":[],"segment_range":[],"fill":[]},"upstream_graphic_group":null}],"transform":[[1.0,0.0,0.0,1.0,0.0,0.0]],"alpha_blending":[{"blend_mode":"Normal","opacity":1.0,"fill":1.0,"clip":false}],"source_node_id":[null]}},"exposed":true}},{"Value":{"tagged_value":{"VectorModification":{"points":{"add":[1,2,3,4,5,6],"remove":[],"delta":[[2,[831.5555555555555,737.3333333333334]],[1,[791.5555555555555,1026.6666666666663]],[3,[889.7777777777777,516.8888888888889]],[4,[893.7613168724276,509.6296296296296]],[5,[833.4814814814815,746.3703703703703]],[6,[793.7777777777777,1027.2592592592591]]]},"segments":{"add":[1,2,3,4,5,6],"remove":[],"start_point":[[1,1],[4,4],[5,5],[3,3],[2,2],[6,6]],"end_point":[[2,3],[3,4],[1,2],[6,1],[4,5],[5,6]],"handle_primary":[[6,[0.0,0.0]],[3,[0.0,0.0]],[5,[-24.0,92.44444444444446]],[2,[19.555555555555543,-74.66666666666674]],[1,[0.0,0.0]],[4,[0.0,0.0]]],"handle_end":[[3,[0.0,0.0]],[4,[24.0,-92.44444444444446]],[6,[-0.14814814814815236,0.29629629629675946]],[1,[-26.4188207246807,100.8718609487812]],[5,[0.0,0.0]],[2,[-22.22222222222217,89.77777777777783]]],"stroke":[[1,0],[2,0],[4,0],[6,0],[5,0],[3,0]]},"regions":{"add":[0],"remove":[],"segment_range":[[0,{"start":1,"end":6}]],"fill":[[0,0]]},"add_g1_continuous":[],"remove_g1_continuous":[]}},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::vector_data::modification::VectorModification","alias":null}},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::vector_data::modification::PathModifyNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[7466034304713056391,{"inputs":[{"Value":{"tagged_value":{"VectorData":{"instance":[{"style":{"stroke":{"color":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0},"weight":0.0,"dash_lengths":[],"dash_offset":0.0,"cap":"Butt","join":"Miter","join_miter_limit":4.0,"align":"Center","transform":[1.0,0.0,0.0,1.0,0.0,0.0],"non_scaling":false,"paint_order":"StrokeAbove"},"fill":"None"},"colinear_manipulators":[],"point_domain":{"id":[],"position":[]},"segment_domain":{"id":[],"start_point":[],"end_point":[],"handles":[],"stroke":[]},"region_domain":{"id":[],"segment_range":[],"fill":[]},"upstream_graphic_group":null}],"transform":[[1.0,0.0,0.0,1.0,0.0,0.0]],"alpha_blending":[{"blend_mode":"Normal","opacity":1.0,"fill":1.0,"clip":false}],"source_node_id":[null]}},"exposed":true}},{"Value":{"tagged_value":{"VectorModification":{"points":{"add":[1,2,3,4],"remove":[],"delta":[[2,[635.5072483424783,152.80078149291265]],[1,[635.2478000597847,135.0597939750059]],[3,[636.4372010299622,153.9035515500083]],[4,[637.4252384335797,135.01742888696126]]]},"segments":{"add":[1,2,3,4],"remove":[],"start_point":[[4,4],[1,1],[2,2],[3,3]],"end_point":[[3,4],[1,2],[4,1],[2,3]],"handle_primary":[[1,[0.0,0.0]],[3,[1.020097146128478,-12.422679731687992]],[2,[0.0,0.0]],[4,[0.0,0.0]]],"handle_end":[[4,[1.1169817316086892,-0.21205734949143107]],[3,null],[1,[0.4153244360613826,-11.397946559213551]],[2,[-0.5579820762119425,-0.504231587867622]]],"stroke":[[1,0],[4,0],[2,0],[3,0]]},"regions":{"add":[0],"remove":[],"segment_range":[[0,{"start":1,"end":4}]],"fill":[[0,0]]},"add_g1_continuous":[],"remove_g1_continuous":[]}},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::vector_data::modification::VectorModification","alias":null}},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::vector_data::modification::PathModifyNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[3636653585682494814,{"inputs":[{"Node":{"node_id":11565160497886435388,"output_index":0,"lambda":false}},{"Node":{"node_id":17078740291337047697,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"F64":1.2},"exposed":false}},{"Value":{"tagged_value":{"F64":2.5},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"U32":0},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"U32":0},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::CopyToPointsNode"}},"visible":true,"skip_deduplication":false}],[172538270105470471,{"inputs":[{"Node":{"node_id":9276497172451351253,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"Fill":{"Solid":{"red":0.8980392,"green":0.8,"blue":0.6117647,"alpha":1.0}}},"exposed":false}},{"Value":{"tagged_value":{"OptionalColor":{"red":0.8980392,"green":0.8,"blue":0.6117647,"alpha":1.0}},"exposed":false}},{"Value":{"tagged_value":{"Gradient":{"stops":[[0.0,{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}],[1.0,{"red":1.0,"green":1.0,"blue":1.0,"alpha":1.0}]],"gradient_type":"Linear","start":[0.0,0.5],"end":[1.0,0.5],"transform":[1.0,0.0,0.0,1.0,0.0,0.0]}},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::FillNode"}},"visible":true,"skip_deduplication":false}],[9470742171134780193,{"inputs":[{"Node":{"node_id":15126865253122550765,"output_index":0,"lambda":false}},{"Node":{"node_id":10270446074640675342,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[10795820039540504703,{"inputs":[{"Value":{"tagged_value":{"VectorData":{"instance":[{"style":{"stroke":{"color":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0},"weight":0.0,"dash_lengths":[],"dash_offset":0.0,"cap":"Butt","join":"Miter","join_miter_limit":4.0,"align":"Center","transform":[1.0,0.0,0.0,1.0,0.0,0.0],"non_scaling":false,"paint_order":"StrokeAbove"},"fill":"None"},"colinear_manipulators":[],"point_domain":{"id":[],"position":[]},"segment_domain":{"id":[],"start_point":[],"end_point":[],"handles":[],"stroke":[]},"region_domain":{"id":[],"segment_range":[],"fill":[]},"upstream_graphic_group":null}],"transform":[[1.0,0.0,0.0,1.0,0.0,0.0]],"alpha_blending":[{"blend_mode":"Normal","opacity":1.0,"fill":1.0,"clip":false}],"source_node_id":[null]}},"exposed":true}},{"Value":{"tagged_value":{"VectorModification":{"points":{"add":[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19],"remove":[],"delta":[[4,[604.4444444444445,138.96296296296293]],[10,[396.14814814814815,88.29629629629629]],[5,[574.5185185185185,169.18518518518516]],[14,[418.0913936876638,12.121582398270874]],[3,[590.2222222222222,113.18518518518518]],[13,[376.7623479921926,0.4130988647245317]],[12,[332.131357712622,16.970215357579164]],[6,[518.2222222222222,175.7037037037037]],[17,[478.3481748953775,55.407407407407405]],[11,[350.8679463145693,59.25925925925925]],[1,[569.1851851851852,61.629629629629605]],[8,[447.7037037037037,131.25925925925924]],[2,[591.1111111111111,92.44444444444444]],[7,[485.6296296296296,153.48148148148147]],[19,[540.4444444444445,70.22222222222221]],[15,[432.1308820290171,20.740740740740748]],[18,[498.66666666666663,63.70370370370368]],[9,[418.074074074074,116.14814814814814]],[16,[451.9827338808689,43.25925925925927]]]},"segments":{"add":[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19],"remove":[],"start_point":[[12,12],[8,8],[4,4],[5,5],[16,16],[1,1],[19,19],[18,18],[2,2],[3,3],[7,7],[13,13],[9,9],[17,17],[14,14],[15,15],[10,10],[6,6],[11,11]],"end_point":[[4,5],[7,8],[3,4],[11,12],[16,17],[8,9],[5,6],[12,13],[18,19],[1,2],[10,11],[13,14],[9,10],[17,18],[15,16],[19,1],[2,3],[14,15],[6,7]],"handle_primary":[[3,[-6.518518518518476,13.3333333333333]],[10,[-13.333333333333371,-8.59259259259261]],[17,[10.962962962963047,12.148148148148124]],[16,[7.703703703703695,6.814814814814817]],[15,[20.148148148148152,6.8148148148148096]],[8,[-9.481481481481524,-12.740740740740762]],[12,[4.019883543587866,-14.744727738229416]],[11,[-11.259259259259125,-10.962962962962962]],[5,[-13.629629629629562,5.925925925925924]],[19,[11.555555555555545,-3.851851851851848]],[6,[-14.222222222222172,-11.851851851851848]],[9,[-13.629629629629562,-7.407407407407419]],[14,[0.0,0.0]],[13,[41.32904569547122,11.708483533546342]],[1,[12.848891737595522,5.11227609582204]],[2,[0.0,0.0]],[7,[-15.407407407407447,4.444444444444457]],[4,[18.370370370370324,0.2962962962963047]],[18,[13.333333333333371,4.148148148148152]]],"handle_end":[[18,[-11.555555555555545,3.851851851851848]],[5,[14.222222222222172,11.85185185185182]],[9,[13.333333333333371,8.59259259259261]],[13,null],[17,[-13.333333333333371,-4.148148148148152]],[3,[-18.370370370370324,-0.2962962962963047]],[10,[11.259259259259238,10.962962962963076]],[6,[15.407407407407334,-4.444444444444457]],[2,[6.518518518518476,-13.333333333333314]],[12,null],[7,[9.481481481481524,12.740740740740762]],[14,[-20.14814814814821,-6.814814814814827]],[11,[-2.7704748413796665,10.16196036497552]],[19,[-12.030418259761518,-4.786624476892754]],[1,[-24.88888888888891,-10.666666666666655]],[15,[-7.703703703703695,-6.8148148148148096]],[4,[13.629629629629562,-5.925925925925924]],[8,[13.629629629629562,7.407407407407419]],[16,[-10.96296296296299,-12.148148148148188]]],"stroke":[[3,0],[4,0],[9,0],[7,0],[1,0],[13,0],[17,0],[18,0],[14,0],[8,0],[12,0],[11,0],[2,0],[10,0],[6,0],[16,0],[19,0],[15,0],[5,0]]},"regions":{"add":[0],"remove":[],"segment_range":[[0,{"start":1,"end":19}]],"fill":[[0,0]]},"add_g1_continuous":[],"remove_g1_continuous":[]}},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::vector_data::modification::VectorModification","alias":null}},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::vector_data::modification::PathModifyNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[10928540355449103287,{"inputs":[{"Node":{"node_id":18190631752493248867,"output_index":0,"lambda":false}},{"Node":{"node_id":12554368619682347699,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[12313564802550122052,{"inputs":[{"Node":{"node_id":13557369662261607646,"output_index":0,"lambda":false}},{"Node":{"node_id":9684857454501250999,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[8413863870096329943,{"inputs":[{"Node":{"node_id":16195626650123806176,"output_index":0,"lambda":false}},{"Node":{"node_id":5302437193964714993,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[9847383247226990698,{"inputs":[{"Node":{"node_id":3627710206997006419,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"Fill":{"Solid":{"red":0.7529412,"green":0.15686275,"blue":0.13333334,"alpha":1.0}}},"exposed":false}},{"Value":{"tagged_value":{"OptionalColor":{"red":0.7529412,"green":0.15686275,"blue":0.13333334,"alpha":1.0}},"exposed":false}},{"Value":{"tagged_value":{"Gradient":{"stops":[[0.0,{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}],[1.0,{"red":1.0,"green":1.0,"blue":1.0,"alpha":1.0}]],"gradient_type":"Linear","start":[0.0,0.5],"end":[1.0,0.5],"transform":[1.0,0.0,0.0,1.0,0.0,0.0]}},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::FillNode"}},"visible":true,"skip_deduplication":false}],[11632506522064533635,{"inputs":[{"Value":{"tagged_value":{"VectorData":{"instance":[{"style":{"stroke":{"color":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0},"weight":0.0,"dash_lengths":[],"dash_offset":0.0,"cap":"Butt","join":"Miter","join_miter_limit":4.0,"align":"Center","transform":[1.0,0.0,0.0,1.0,0.0,0.0],"non_scaling":false,"paint_order":"StrokeAbove"},"fill":"None"},"colinear_manipulators":[],"point_domain":{"id":[],"position":[]},"segment_domain":{"id":[],"start_point":[],"end_point":[],"handles":[],"stroke":[]},"region_domain":{"id":[],"segment_range":[],"fill":[]},"upstream_graphic_group":null}],"transform":[[1.0,0.0,0.0,1.0,0.0,0.0]],"alpha_blending":[{"blend_mode":"Normal","opacity":1.0,"fill":1.0,"clip":false}],"source_node_id":[null]}},"exposed":true}},{"Value":{"tagged_value":{"VectorModification":{"points":{"add":[1,2,3,4,5,6,7],"remove":[],"delta":[[7,[145.33333333333331,1022.6666666666666]],[5,[336.66666666666663,799.3333333333334]],[1,[40.66666666666663,1022.6666666666666]],[2,[113.33333333333331,859.3333333333333]],[6,[208.0,903.0]],[4,[397.3333333333333,770.6666666666666]],[3,[299.33333333333326,775.3333333333333]]]},"segments":{"add":[1,2,3,4,5,6,7],"remove":[],"start_point":[[7,7],[1,1],[4,4],[2,2],[3,3],[6,6],[5,5]],"end_point":[[5,6],[2,3],[6,7],[1,2],[3,4],[7,1],[4,5]],"handle_primary":[[4,[0.0,0.0]],[1,[0.0,0.0]],[6,[0.0,0.0]],[5,[-40.66666666666663,12.0]],[2,[58.666666666666686,-57.33333333333326]],[7,[0.0,0.0]],[3,[65.33333333333337,-6.0]]],"handle_end":[[6,[18.00000000000003,-55.33333333333326]],[2,[-65.33333333333337,6.0]],[3,[0.0,0.0]],[7,[0.0,1.3333333333333712]],[1,[-58.666666666666686,57.333333333333144]],[5,[35.666666666666686,-46.66666666666674]],[4,[40.66666666666663,-12.0]]],"stroke":[[5,0],[4,0],[3,0],[6,0],[1,0],[2,0],[7,0]]},"regions":{"add":[0],"remove":[],"segment_range":[[0,{"start":1,"end":7}]],"fill":[[0,0]]},"add_g1_continuous":[],"remove_g1_continuous":[]}},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::vector_data::modification::VectorModification","alias":null}},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::vector_data::modification::PathModifyNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[15498700602024283966,{"inputs":[{"Node":{"node_id":15466714490303763249,"output_index":0,"lambda":false}},{"Node":{"node_id":9847383247226990698,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[12473080738469616517,{"inputs":[{"Node":{"node_id":17891208858820401648,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"Fill":{"Solid":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}}},"exposed":false}},{"Value":{"tagged_value":{"OptionalColor":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}},"exposed":false}},{"Value":{"tagged_value":{"Gradient":{"stops":[[0.0,{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}],[1.0,{"red":1.0,"green":1.0,"blue":1.0,"alpha":1.0}]],"gradient_type":"Linear","start":[0.0,0.5],"end":[1.0,0.5],"transform":[1.0,0.0,0.0,1.0,0.0,0.0]}},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::FillNode"}},"visible":true,"skip_deduplication":false}],[17133591775058457007,{"inputs":[{"Node":{"node_id":18067513817508158001,"output_index":0,"lambda":false}},{"Node":{"node_id":17078740291337047697,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"F64":1.2},"exposed":false}},{"Value":{"tagged_value":{"F64":2.0},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"U32":0},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"U32":0},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::CopyToPointsNode"}},"visible":true,"skip_deduplication":false}],[13163272246010991228,{"inputs":[{"Node":{"node_id":9740500978584792725,"output_index":0,"lambda":false}},{"Node":{"node_id":10253927692147706615,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[15286091228862934481,{"inputs":[{"Value":{"tagged_value":{"VectorData":{"instance":[{"style":{"stroke":{"color":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0},"weight":0.0,"dash_lengths":[],"dash_offset":0.0,"cap":"Butt","join":"Miter","join_miter_limit":4.0,"align":"Center","transform":[1.0,0.0,0.0,1.0,0.0,0.0],"non_scaling":false,"paint_order":"StrokeAbove"},"fill":"None"},"colinear_manipulators":[],"point_domain":{"id":[],"position":[]},"segment_domain":{"id":[],"start_point":[],"end_point":[],"handles":[],"stroke":[]},"region_domain":{"id":[],"segment_range":[],"fill":[]},"upstream_graphic_group":null}],"transform":[[1.0,0.0,0.0,1.0,0.0,0.0]],"alpha_blending":[{"blend_mode":"Normal","opacity":1.0,"fill":1.0,"clip":false}],"source_node_id":[null]}},"exposed":true}},{"Value":{"tagged_value":{"VectorModification":{"points":{"add":[1,2,3,4,5,6,7],"remove":[],"delta":[[4,[665.7229080932784,23.79149519890261]],[2,[627.0946502057614,23.00137174211249]],[1,[623.1001371742112,22.694101508916333]],[3,[638.5953360768175,27.56652949245542]],[7,[637.0589849108368,29.980795610425247]],[5,[684.554183813443,27.654320987654327]],[6,[661.2894375857338,26.381344307270236]]]},"segments":{"add":[1,2,3,4,5,6,7],"remove":[],"start_point":[[3,3],[2,2],[4,4],[5,5],[6,6],[1,1],[7,7]],"end_point":[[6,7],[3,4],[2,3],[4,5],[7,1],[1,2],[5,6]],"handle_primary":[[5,[0.0,0.0]],[6,[-11.456790123456813,0.9657064471879302]],[1,[0.0,0.0]],[2,[2.150891632373032,1.5802469135802468]],[7,[-6.089851956901498,-0.48236451143773706]],[4,[6.672153635116501,-0.35116598079560646]],[3,[5.3991769547326385,0.13168724279836042]]],"handle_end":[[7,[2.194787379972581,3.906721536351163]],[1,[-2.150891632373032,-1.5802469135802468]],[6,[4.433470507544598,0.35116598079561]],[3,[-6.672153635116501,0.35116598079560646]],[4,[-0.9218106995884908,-1.0534979423868336]],[2,[-5.486565700800156,-0.13381867562927496]],[5,[11.456790123456813,-0.9657064471879336]]],"stroke":[[5,0],[7,0],[4,0],[1,0],[3,0],[6,0],[2,0]]},"regions":{"add":[0],"remove":[],"segment_range":[[0,{"start":1,"end":7}]],"fill":[[0,0]]},"add_g1_continuous":[],"remove_g1_continuous":[]}},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::vector_data::modification::VectorModification","alias":null}},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::vector_data::modification::PathModifyNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[3165571685352930240,{"inputs":[{"Value":{"tagged_value":{"VectorData":{"instance":[{"style":{"stroke":{"color":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0},"weight":0.0,"dash_lengths":[],"dash_offset":0.0,"cap":"Butt","join":"Miter","join_miter_limit":4.0,"align":"Center","transform":[1.0,0.0,0.0,1.0,0.0,0.0],"non_scaling":false,"paint_order":"StrokeAbove"},"fill":"None"},"colinear_manipulators":[],"point_domain":{"id":[],"position":[]},"segment_domain":{"id":[],"start_point":[],"end_point":[],"handles":[],"stroke":[]},"region_domain":{"id":[],"segment_range":[],"fill":[]},"upstream_graphic_group":null}],"transform":[[1.0,0.0,0.0,1.0,0.0,0.0]],"alpha_blending":[{"blend_mode":"Normal","opacity":1.0,"fill":1.0,"clip":false}],"source_node_id":[null]}},"exposed":true}},{"Value":{"tagged_value":{"VectorModification":{"points":{"add":[1,2,3,4],"remove":[],"delta":[[2,[641.3926773385256,156.76403071818197]],[3,[642.0732703685807,156.78028060137643]],[1,[639.0431812985823,135.02706332876082]],[4,[641.1783537148203,135.11412115589184]]]},"segments":{"add":[1,2,3,4],"remove":[],"start_point":[[3,3],[4,4],[2,2],[1,1]],"end_point":[[1,2],[2,3],[3,4],[4,1]],"handle_primary":[[4,[0.0,0.0]],[2,[0.0,0.0]],[3,[-0.4020858660272779,-10.361367902183218]],[1,[0.0,0.0]]],"handle_end":[[4,[1.0850699611588652,-0.2123114466060372]],[3,null],[1,[-0.08991158554488266,-10.211393405397416]],[2,[-0.29793124344723765,0.12588207707705124]]],"stroke":[[4,0],[1,0],[2,0],[3,0]]},"regions":{"add":[0],"remove":[],"segment_range":[[0,{"start":1,"end":4}]],"fill":[[0,0]]},"add_g1_continuous":[],"remove_g1_continuous":[]}},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::vector_data::modification::VectorModification","alias":null}},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::vector_data::modification::PathModifyNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[13014916927589286309,{"inputs":[{"Node":{"node_id":2044103368441997753,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"F64":5.0},"exposed":false}},{"Value":{"tagged_value":{"U32":0},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":1}},{"Network":{"import_type":{"Concrete":{"name":"u32","alias":null}},"import_index":2}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::PoissonDiskPointsNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":2,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::BoundlessFootprintNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::FreezeRealTimeNode"}},"visible":true,"skip_deduplication":false}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MemoNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[15815816861435910950,{"inputs":[{"Node":{"node_id":4105711298139980122,"output_index":0,"lambda":false}},{"Node":{"node_id":17815494794630739611,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[15798070933198867970,{"inputs":[{"Value":{"tagged_value":{"VectorData":{"instance":[{"style":{"stroke":{"color":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0},"weight":0.0,"dash_lengths":[],"dash_offset":0.0,"cap":"Butt","join":"Miter","join_miter_limit":4.0,"align":"Center","transform":[1.0,0.0,0.0,1.0,0.0,0.0],"non_scaling":false,"paint_order":"StrokeAbove"},"fill":"None"},"colinear_manipulators":[],"point_domain":{"id":[],"position":[]},"segment_domain":{"id":[],"start_point":[],"end_point":[],"handles":[],"stroke":[]},"region_domain":{"id":[],"segment_range":[],"fill":[]},"upstream_graphic_group":null}],"transform":[[1.0,0.0,0.0,1.0,0.0,0.0]],"alpha_blending":[{"blend_mode":"Normal","opacity":1.0,"fill":1.0,"clip":false}],"source_node_id":[null]}},"exposed":true}},{"Value":{"tagged_value":{"VectorModification":{"points":{"add":[1,2,3,4,5,6,7,8,9,10,11,12],"remove":[],"delta":[[1,[595.1111111111111,513.3333333333333]],[10,[508.88888888888886,389.33333333333337]],[3,[598.6666666666666,547.1111111111111]],[4,[536.0,522.2222222222221]],[2,[642.2222222222222,536.8888888888889]],[11,[588.6666666666665,453.3333333333333]],[12,[660.0,500.66666666666663]],[9,[424.44444444444446,340.0]],[5,[449.99999999999994,445.3333333333333]],[8,[350.6666666666667,340.0]],[6,[438.18064449587104,508.2403828865154]],[7,[384.7140020398532,440.0243218219409]]]},"segments":{"add":[1,2,3,4,5,6,7,8,9,10,11,12],"remove":[],"start_point":[[8,8],[11,11],[3,3],[2,2],[7,7],[12,12],[5,5],[1,1],[9,9],[10,10],[6,6],[4,4]],"end_point":[[4,5],[11,12],[6,7],[10,11],[5,6],[3,4],[8,9],[12,1],[1,2],[9,10],[7,8],[2,3]],"handle_primary":[[11,[22.666666666666856,18.0]],[6,[0.0,0.0]],[2,[0.0,0.0]],[1,[0.0,0.0]],[8,[-46.969945387028645,-26.215783471829923]],[7,[5.531031978208716,-44.24825582567013]],[4,[-25.28395061728401,-13.827160493827025]],[3,[-18.370370370370324,2.1728395061728634]],[12,[-31.999999999999886,10.666666666666686]],[9,[24.0,8.0]],[5,[0.0,0.0]],[10,[25.481481481481467,20.4444444444444]]],"handle_end":[[12,null],[9,[-25.481481481481467,-20.4444444444444]],[3,[25.283950617284063,13.827160493827025]],[6,[-4.764895727801786,38.11916582241446]],[1,[-58.22222222222217,-1.3333333333332575]],[11,[-17.185185185185105,5.925925925925867]],[4,[0.0,0.0]],[5,[0.0,0.0]],[8,[-24.0,-8.0]],[2,[18.370370370370324,-2.1728395061728634]],[7,[28.6666666666668,16.000000000000057]],[10,[-23.199803616588156,-18.42337346023163]]],"stroke":[[6,0],[9,0],[4,0],[5,0],[8,0],[10,0],[3,0],[2,0],[7,0],[1,0],[11,0],[12,0]]},"regions":{"add":[0],"remove":[],"segment_range":[[0,{"start":1,"end":12}]],"fill":[[0,0]]},"add_g1_continuous":[],"remove_g1_continuous":[]}},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::vector_data::modification::VectorModification","alias":null}},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::vector_data::modification::PathModifyNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[6672826052605647592,{"inputs":[{"Value":{"tagged_value":{"VectorData":{"instance":[{"style":{"stroke":{"color":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0},"weight":0.0,"dash_lengths":[],"dash_offset":0.0,"cap":"Butt","join":"Miter","join_miter_limit":4.0,"align":"Center","transform":[1.0,0.0,0.0,1.0,0.0,0.0],"non_scaling":false,"paint_order":"StrokeAbove"},"fill":"None"},"colinear_manipulators":[],"point_domain":{"id":[],"position":[]},"segment_domain":{"id":[],"start_point":[],"end_point":[],"handles":[],"stroke":[]},"region_domain":{"id":[],"segment_range":[],"fill":[]},"upstream_graphic_group":null}],"transform":[[1.0,0.0,0.0,1.0,0.0,0.0]],"alpha_blending":[{"blend_mode":"Normal","opacity":1.0,"fill":1.0,"clip":false}],"source_node_id":[null]}},"exposed":true}},{"Value":{"tagged_value":{"VectorModification":{"points":{"add":[1,2,3,4,5,6,7,8,9,10,11,12],"remove":[],"delta":[[6,[594.172839506173,82.87517146776406]],[5,[603.127572016461,99.64334705075449]],[1,[617.5253772290811,122.03017832647464]],[3,[605.4979423868314,125.19067215363512]],[4,[600.0548696844994,115.53360768175584]],[8,[585.8326474622772,72.60356652949247]],[9,[593.3827160493829,85.77229080932784]],[7,[591.0123456790125,60.40054869684499]],[10,[599.4403292181071,108.68587105624144]],[12,[613.7991159884164,125.99055022100288]],[2,[614.2716726786227,123.52371759047573]],[11,[599.381801554641,127.00502972107913]]]},"segments":{"add":[1,2,3,4,5,6,7,8,9,10,11,12],"remove":[],"start_point":[[12,12],[3,3],[10,10],[9,9],[6,6],[1,1],[4,4],[5,5],[8,8],[2,2],[7,7],[11,11]],"end_point":[[9,10],[8,9],[6,7],[5,6],[4,5],[2,3],[11,12],[7,8],[12,1],[10,11],[3,4],[1,2]],"handle_primary":[[11,[3.960543177125487,4.094798878044912]],[6,[-6.145404663923159,-8.076817558299041]],[2,[-1.2820759681926577,0.7008681959453185]],[7,[0.0,0.0]],[4,[0.8779149519890552,-4.477366255144034]],[5,[-0.8779149519890552,-4.477366255144048]],[3,[-4.594421582076166,-1.1705532693187024]],[8,[0.6346981736430735,5.019885555177211]],[10,[-2.575217192501441,8.77914951989024]],[12,[2.3801249809480396,-1.7168114616673904]],[9,[3.599451303154978,4.477366255144034]],[1,[0.0,0.0]]],"handle_end":[[7,[-0.9657064471879266,-7.637860082304528]],[8,[-3.599451303154978,-4.477366255144034]],[4,[0.8779149519890552,4.47736625514402]],[5,[6.145404663923159,8.076817558299041]],[11,[-2.036412917146322,1.4688880058104417]],[10,[-4.118548609866821,-4.258160427150372]],[6,[-6.057613168724288,9.305898491083669]],[12,[0.0,0.0]],[3,[-0.8779149519890552,4.477366255144034]],[1,[1.3006147436874471,-0.7110027265491681]],[2,[3.396564570446685,0.8653667695405147]],[9,[3.3684073442221916,-11.48320685530176]]],"stroke":[[12,0],[11,0],[5,0],[1,0],[9,0],[10,0],[3,0],[7,0],[8,0],[2,0],[6,0],[4,0]]},"regions":{"add":[0],"remove":[],"segment_range":[[0,{"start":1,"end":12}]],"fill":[[0,0]]},"add_g1_continuous":[],"remove_g1_continuous":[]}},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::vector_data::modification::VectorModification","alias":null}},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::vector_data::modification::PathModifyNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[7385465194555106679,{"inputs":[{"Node":{"node_id":5009664118231399060,"output_index":0,"lambda":false}},{"Node":{"node_id":6416452251137958677,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[9425359632144678256,{"inputs":[{"Value":{"tagged_value":{"VectorData":{"instance":[{"style":{"stroke":{"color":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0},"weight":0.0,"dash_lengths":[],"dash_offset":0.0,"cap":"Butt","join":"Miter","join_miter_limit":4.0,"align":"Center","transform":[1.0,0.0,0.0,1.0,0.0,0.0],"non_scaling":false,"paint_order":"StrokeAbove"},"fill":"None"},"colinear_manipulators":[],"point_domain":{"id":[],"position":[]},"segment_domain":{"id":[],"start_point":[],"end_point":[],"handles":[],"stroke":[]},"region_domain":{"id":[],"segment_range":[],"fill":[]},"upstream_graphic_group":null}],"transform":[[1.0,0.0,0.0,1.0,0.0,0.0]],"alpha_blending":[{"blend_mode":"Normal","opacity":1.0,"fill":1.0,"clip":false}],"source_node_id":[null]}},"exposed":true}},{"Value":{"tagged_value":{"VectorModification":{"points":{"add":[1,2,3,4,5],"remove":[],"delta":[[5,[606.9918024691358,101.68414814814815]],[3,[622.6042778031804,84.90413046791649]],[2,[615.0086877000457,93.76131687242795]],[4,[612.3749428440786,88.61088248742568]],[1,[610.2608816540582,107.73159867034722]]]},"segments":{"add":[1,2,3,4,5],"remove":[],"start_point":[[4,4],[3,3],[2,2],[5,5],[1,1]],"end_point":[[2,3],[4,5],[3,4],[5,1],[1,2]],"handle_primary":[[1,[0.0,0.0]],[4,[-3.0889600162577153,2.952395468170536]],[5,[0.0,0.0]],[3,[-0.6242950769699291,-0.9364426154549648]],[2,[3.21902149062646,-3.511659807956093]]],"handle_end":[[5,[-2.1454520955559246,-3.1101486881290583]],[4,[-0.5623782142248501,-6.258066225952547]],[3,[2.992367941940074,-2.86007378029646]],[1,[-3.21902149062646,3.5116598079561214]],[2,[0.15607376924265282,0.7543565513387165]]],"stroke":[[2,0],[5,0],[3,0],[4,0],[1,0]]},"regions":{"add":[0],"remove":[],"segment_range":[[0,{"start":1,"end":5}]],"fill":[[0,0]]},"add_g1_continuous":[],"remove_g1_continuous":[]}},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::vector_data::modification::VectorModification","alias":null}},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::vector_data::modification::PathModifyNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[15177845878727456758,{"inputs":[{"Node":{"node_id":14225285635863713990,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"Fill":{"Solid":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}}},"exposed":false}},{"Value":{"tagged_value":{"OptionalColor":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}},"exposed":false}},{"Value":{"tagged_value":{"Gradient":{"stops":[[0.0,{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}],[1.0,{"red":1.0,"green":1.0,"blue":1.0,"alpha":1.0}]],"gradient_type":"Linear","start":[0.0,0.5],"end":[1.0,0.5],"transform":[1.0,0.0,0.0,1.0,0.0,0.0]}},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::FillNode"}},"visible":true,"skip_deduplication":false}],[5555007473125503522,{"inputs":[{"Value":{"tagged_value":{"VectorData":{"instance":[{"style":{"stroke":{"color":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0},"weight":0.0,"dash_lengths":[],"dash_offset":0.0,"cap":"Butt","join":"Miter","join_miter_limit":4.0,"align":"Center","transform":[1.0,0.0,0.0,1.0,0.0,0.0],"non_scaling":false,"paint_order":"StrokeAbove"},"fill":"None"},"colinear_manipulators":[],"point_domain":{"id":[],"position":[]},"segment_domain":{"id":[],"start_point":[],"end_point":[],"handles":[],"stroke":[]},"region_domain":{"id":[],"segment_range":[],"fill":[]},"upstream_graphic_group":null}],"transform":[[1.0,0.0,0.0,1.0,0.0,0.0]],"alpha_blending":[{"blend_mode":"Normal","opacity":1.0,"fill":1.0,"clip":false}],"source_node_id":[null]}},"exposed":true}},{"Value":{"tagged_value":{"VectorModification":{"points":{"add":[1,2,3,4,5,6,7],"remove":[],"delta":[[6,[724.0262155159273,62.468526139308025]],[7,[722.6215515927449,59.58116140832189]],[1,[721.7241274196006,63.248894985520494]],[4,[725.0797134583142,72.96448712086573]],[5,[726.0551745160798,67.30681298582532]],[2,[724.7285474775185,66.64349946654472]],[3,[723.7140679774425,72.106081390032]]]},"segments":{"add":[1,2,3,4,5,6,7],"remove":[],"start_point":[[2,2],[5,5],[3,3],[4,4],[1,1],[7,7],[6,6]],"end_point":[[6,7],[5,6],[3,4],[1,2],[4,5],[7,1],[2,3]],"handle_primary":[[1,[0.0,0.0]],[6,[-0.03901844231063478,-1.2485901539399509]],[5,[-0.585276634659408,-3.8628257887517066]],[4,[0.6633135192806776,-0.8584057308337094]],[7,[-1.014479500076277,0.3901844231062413]],[3,[-1.287608596250493,1.7558299039780536]],[2,[0.546258192348887,2.106995884773667]]],"handle_end":[[1,[-0.501794076076294,-1.9354914362939013]],[5,[0.03901844231063478,1.2485901539399509]],[7,[0.07803688462126956,-0.03901844231062768]],[2,[1.852405339488314,-2.526007281120613]],[3,[-0.6633135192806776,0.8584057308337094]],[6,[1.014479500076277,-0.39018442310623414]],[4,[0.585276634659408,3.8628257887517066]]],"stroke":[[5,0],[7,0],[1,0],[6,0],[4,0],[2,0],[3,0]]},"regions":{"add":[0],"remove":[],"segment_range":[[0,{"start":1,"end":7}]],"fill":[[0,0]]},"add_g1_continuous":[],"remove_g1_continuous":[]}},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::vector_data::modification::VectorModification","alias":null}},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::vector_data::modification::PathModifyNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[17529660518597229229,{"inputs":[{"Node":{"node_id":3802858053991775169,"output_index":0,"lambda":false}},{"Node":{"node_id":4332145463108161926,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"F64":4.0},"exposed":false}},{"Value":{"tagged_value":{"F64":40.0},"exposed":false}},{"Value":{"tagged_value":{"F64":-30.0},"exposed":false}},{"Value":{"tagged_value":{"U32":0},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"U32":0},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::CopyToPointsNode"}},"visible":true,"skip_deduplication":false}],[16446146761452576438,{"inputs":[{"Node":{"node_id":12131058586835568367,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"DVec2":[619.1444612416404,54.266956717585614]},"exposed":false}},{"Value":{"tagged_value":{"F64":-0.6118784},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[5.617278800347149,2.5068847538738956]},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[1.1858656806102035e-16,0.0]},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[0.5,0.5]},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":1}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":2}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":3}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":4}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":5}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::TransformNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[454416440369338250,{"inputs":[{"Value":{"tagged_value":{"VectorData":{"instance":[{"style":{"stroke":{"color":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0},"weight":0.0,"dash_lengths":[],"dash_offset":0.0,"cap":"Butt","join":"Miter","join_miter_limit":4.0,"align":"Center","transform":[1.0,0.0,0.0,1.0,0.0,0.0],"non_scaling":false,"paint_order":"StrokeAbove"},"fill":"None"},"colinear_manipulators":[],"point_domain":{"id":[],"position":[]},"segment_domain":{"id":[],"start_point":[],"end_point":[],"handles":[],"stroke":[]},"region_domain":{"id":[],"segment_range":[],"fill":[]},"upstream_graphic_group":null}],"transform":[[1.0,0.0,0.0,1.0,0.0,0.0]],"alpha_blending":[{"blend_mode":"Normal","opacity":1.0,"fill":1.0,"clip":false}],"source_node_id":[null]}},"exposed":true}},{"Value":{"tagged_value":{"VectorModification":{"points":{"add":[1,2],"remove":[],"delta":[[2,[733.7777777777778,518.6666666666666]],[1,[696.0,593.3333333333333]]]},"segments":{"add":[1],"remove":[],"start_point":[[1,1]],"end_point":[[1,2]],"handle_primary":[[1,[0.0,0.0]]],"handle_end":[[1,[-18.666666666666515,26.66666666666663]]],"stroke":[[1,0]]},"regions":{"add":[],"remove":[],"segment_range":[],"fill":[]},"add_g1_continuous":[],"remove_g1_continuous":[]}},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::vector_data::modification::VectorModification","alias":null}},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::vector_data::modification::PathModifyNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[15038739378867834454,{"inputs":[{"Value":{"tagged_value":{"VectorData":{"instance":[{"style":{"stroke":{"color":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0},"weight":0.0,"dash_lengths":[],"dash_offset":0.0,"cap":"Butt","join":"Miter","join_miter_limit":4.0,"align":"Center","transform":[1.0,0.0,0.0,1.0,0.0,0.0],"non_scaling":false,"paint_order":"StrokeAbove"},"fill":"None"},"colinear_manipulators":[],"point_domain":{"id":[],"position":[]},"segment_domain":{"id":[],"start_point":[],"end_point":[],"handles":[],"stroke":[]},"region_domain":{"id":[],"segment_range":[],"fill":[]},"upstream_graphic_group":null}],"transform":[[1.0,0.0,0.0,1.0,0.0,0.0]],"alpha_blending":[{"blend_mode":"Normal","opacity":1.0,"fill":1.0,"clip":false}],"source_node_id":[null]}},"exposed":true}},{"Value":{"tagged_value":{"VectorModification":{"points":{"add":[1,2,3,4,5,6,7],"remove":[],"delta":[[2,[667.4787379972565,58.20576131687244]],[5,[704.6145404663924,55.39643347050756]],[1,[654.3978052126201,51.621399176954746]],[7,[662.3868312757203,59.61042524005489]],[3,[691.5336076817558,52.14814814814816]],[4,[704.965706447188,54.25514403292181]],[6,[687.4951989026064,54.518518518518526]]]},"segments":{"add":[1,2,3,4,5,6,7],"remove":[],"start_point":[[2,2],[7,7],[4,4],[1,1],[5,5],[3,3],[6,6]],"end_point":[[1,2],[4,5],[5,6],[2,3],[3,4],[6,7],[7,1]],"handle_primary":[[3,[7.723134415788309,-0.2640387834457485]],[4,[0.0,0.0]],[5,[0.0,0.0]],[1,[0.0,0.0]],[7,[-4.546573253919632,-2.2347563451469625]],[6,[-10.156808190486911,1.6663513437517778]],[2,[6.145404663923159,-1.0534979423868336]]],"handle_end":[[6,[5.179698216735233,2.5459533607681664]],[7,[0.0,0.08779149519890694]],[3,null],[1,[-5.875074923313605,1.0071557011394745]],[2,[-10.271604938271594,0.35116598079560646]],[5,[11.237311385459408,-1.8436213991769537]],[4,[0.0,0.0]]],"stroke":[[4,0],[2,0],[6,0],[5,0],[7,0],[1,0],[3,0]]},"regions":{"add":[0],"remove":[],"segment_range":[[0,{"start":1,"end":7}]],"fill":[[0,0]]},"add_g1_continuous":[],"remove_g1_continuous":[]}},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::vector_data::modification::VectorModification","alias":null}},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::vector_data::modification::PathModifyNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[14982414026754548178,{"inputs":[{"Node":{"node_id":13045580349734858212,"output_index":0,"lambda":false}},{"Node":{"node_id":4332145463108161926,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"F64":10.0},"exposed":false}},{"Value":{"tagged_value":{"F64":-25.0},"exposed":false}},{"Value":{"tagged_value":{"U32":0},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"U32":0},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::CopyToPointsNode"}},"visible":true,"skip_deduplication":false}],[4493274523708782092,{"inputs":[{"Node":{"node_id":15239301303367148581,"output_index":0,"lambda":false}},{"Node":{"node_id":12880230498984021417,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[6973438081601736688,{"inputs":[{"Node":{"node_id":11630078441485655672,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"Fill":{"Solid":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}}},"exposed":false}},{"Value":{"tagged_value":{"OptionalColor":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}},"exposed":false}},{"Value":{"tagged_value":{"Gradient":{"stops":[[0.0,{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}],[1.0,{"red":1.0,"green":1.0,"blue":1.0,"alpha":1.0}]],"gradient_type":"Linear","start":[0.0,0.5],"end":[1.0,0.5],"transform":[1.0,0.0,0.0,1.0,0.0,0.0]}},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::FillNode"}},"visible":true,"skip_deduplication":false}],[4577638792388493935,{"inputs":[{"Node":{"node_id":3170924135668664007,"output_index":0,"lambda":false}},{"Node":{"node_id":6292009934909381201,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[12131058586835568367,{"inputs":[{"Value":{"tagged_value":{"VectorData":{"instance":[{"style":{"stroke":{"color":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0},"weight":0.0,"dash_lengths":[],"dash_offset":0.0,"cap":"Butt","join":"Miter","join_miter_limit":4.0,"align":"Center","transform":[1.0,0.0,0.0,1.0,0.0,0.0],"non_scaling":false,"paint_order":"StrokeAbove"},"fill":"None"},"colinear_manipulators":[],"point_domain":{"id":[],"position":[]},"segment_domain":{"id":[],"start_point":[],"end_point":[],"handles":[],"stroke":[]},"region_domain":{"id":[],"segment_range":[],"fill":[]},"upstream_graphic_group":null}],"transform":[[1.0,0.0,0.0,1.0,0.0,0.0]],"alpha_blending":[{"blend_mode":"Normal","opacity":1.0,"fill":1.0,"clip":false}],"source_node_id":[null]}},"exposed":true}},{"Value":{"tagged_value":{"VectorModification":{"points":{"add":[1,2,3,4],"remove":[],"delta":[[3,[0.443655685420585,0.8388279058567918]],[2,[1.0389965338526328,0.5311836299154763]],[4,[0.022131022857413415,0.4190687668825941]],[1,[0.6081211287919952,-0.2081641356766983]]]},"segments":{"add":[1,2,3,4],"remove":[],"start_point":[[3,3],[2,2],[4,4],[1,1]],"end_point":[[3,4],[2,3],[4,1],[1,2]],"handle_primary":[[1,[0.297407817404018,0.05174926937677715]],[3,[-0.29501938196342326,-0.04735956037402645]],[2,[-0.06483434986356718,0.26682960488486684]],[4,[0.021131345375600137,-0.27179882337964756]]],"handle_end":[[2,[0.2950193819634199,0.04735956037402589]],[4,[-0.38805268271111915,-0.0675215701634326]],[3,[-0.02113134537560013,0.27179882337964756]],[1,[0.07365905854782184,-0.30314821587423946]]],"stroke":[[4,0],[2,0],[3,0],[1,0]]},"regions":{"add":[0],"remove":[],"segment_range":[[0,{"start":1,"end":4}]],"fill":[[0,0]]},"add_g1_continuous":[],"remove_g1_continuous":[]}},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::vector_data::modification::VectorModification","alias":null}},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::vector_data::modification::PathModifyNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[1157261387411722141,{"inputs":[{"Node":{"node_id":4577174813962563383,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"Fill":{"Solid":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}}},"exposed":false}},{"Value":{"tagged_value":{"OptionalColor":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}},"exposed":false}},{"Value":{"tagged_value":{"Gradient":{"stops":[[0.0,{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}],[1.0,{"red":1.0,"green":1.0,"blue":1.0,"alpha":1.0}]],"gradient_type":"Linear","start":[0.0,0.5],"end":[1.0,0.5],"transform":[1.0,0.0,0.0,1.0,0.0,0.0]}},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::FillNode"}},"visible":true,"skip_deduplication":false}],[11659756061767599421,{"inputs":[{"Node":{"node_id":8766106989344197438,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"Fill":{"Solid":{"red":0.8980392,"green":0.8,"blue":0.6117647,"alpha":1.0}}},"exposed":false}},{"Value":{"tagged_value":{"OptionalColor":{"red":0.8980392,"green":0.8,"blue":0.6117647,"alpha":1.0}},"exposed":false}},{"Value":{"tagged_value":{"Gradient":{"stops":[[0.0,{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}],[1.0,{"red":1.0,"green":1.0,"blue":1.0,"alpha":1.0}]],"gradient_type":"Linear","start":[0.0,0.5],"end":[1.0,0.5],"transform":[1.0,0.0,0.0,1.0,0.0,0.0]}},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::FillNode"}},"visible":true,"skip_deduplication":false}],[5140869461760168364,{"inputs":[{"Node":{"node_id":17118107476414252025,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"Fill":{"Solid":{"red":0.7529412,"green":0.15686275,"blue":0.13333334,"alpha":1.0}}},"exposed":false}},{"Value":{"tagged_value":{"OptionalColor":{"red":0.7529412,"green":0.15686275,"blue":0.13333334,"alpha":1.0}},"exposed":false}},{"Value":{"tagged_value":{"Gradient":{"stops":[[0.0,{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}],[1.0,{"red":1.0,"green":1.0,"blue":1.0,"alpha":1.0}]],"gradient_type":"Linear","start":[0.0,0.5],"end":[1.0,0.5],"transform":[1.0,0.0,0.0,1.0,0.0,0.0]}},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::FillNode"}},"visible":true,"skip_deduplication":false}],[8543051864256131356,{"inputs":[{"Node":{"node_id":5002654561220917457,"output_index":0,"lambda":false}},{"Node":{"node_id":4332145463108161926,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"F64":5.0},"exposed":false}},{"Value":{"tagged_value":{"F64":300.0},"exposed":false}},{"Value":{"tagged_value":{"F64":-100.0},"exposed":false}},{"Value":{"tagged_value":{"U32":0},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"U32":0},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::CopyToPointsNode"}},"visible":true,"skip_deduplication":false}],[16732130236852371275,{"inputs":[{"Node":{"node_id":4832236468224231783,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"PointSpacingType":"Separation"},"exposed":false}},{"Value":{"tagged_value":{"F64":6.0},"exposed":false}},{"Value":{"tagged_value":{"U32":100},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"Bool":false},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":4,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::SubpathSegmentLengthsNode"}},"visible":true,"skip_deduplication":false}],[4,{"inputs":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::BoundlessFootprintNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":2,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::FreezeRealTimeNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MemoNode"}},"visible":true,"skip_deduplication":false}],[1,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::misc::PointSpacingType","alias":null}},"import_index":1}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":2}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":3}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":4}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":5}},{"Network":{"import_type":{"Concrete":{"name":"bool","alias":null}},"import_index":6}},{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::SamplePolylineNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[5185036609290210853,{"inputs":[{"Value":{"tagged_value":{"VectorData":{"instance":[{"style":{"stroke":{"color":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0},"weight":0.0,"dash_lengths":[],"dash_offset":0.0,"cap":"Butt","join":"Miter","join_miter_limit":4.0,"align":"Center","transform":[1.0,0.0,0.0,1.0,0.0,0.0],"non_scaling":false,"paint_order":"StrokeAbove"},"fill":"None"},"colinear_manipulators":[],"point_domain":{"id":[],"position":[]},"segment_domain":{"id":[],"start_point":[],"end_point":[],"handles":[],"stroke":[]},"region_domain":{"id":[],"segment_range":[],"fill":[]},"upstream_graphic_group":null}],"transform":[[1.0,0.0,0.0,1.0,0.0,0.0]],"alpha_blending":[{"blend_mode":"Normal","opacity":1.0,"fill":1.0,"clip":false}],"source_node_id":[null]}},"exposed":true}},{"Value":{"tagged_value":{"VectorModification":{"points":{"add":[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29],"remove":[],"delta":[[1,[687.846364883402,65.58024691358025]],[6,[695.152568206066,67.34583142813594]],[4,[704.9657064471878,54.25514403292179]],[26,[722.5825331504344,57.31809175430575]],[24,[719.0123456790122,66.6337448559671]],[5,[705.102270995275,59.269013869836904]],[19,[705.9094650205762,70.25514403292182]],[7,[701.785703398872,67.26779454351473]],[8,[709.8600823045268,50.83127572016461]],[29,[694.0600518213687,74.40816948635879]],[17,[713.3351623228167,47.46593507087334]],[2,[697.9423868312758,64.79012345679013]],[14,[711.9695168419447,48.57796067672611]],[25,[719.8512421886905,54.19661636945587]],[23,[711.5061728395062,69.99176954732509]],[11,[697.7283950617284,31.30864197530864]],[27,[718.680688919372,68.71147690900777]],[9,[702.2222222222223,38.38683127572017]],[18,[716.7736625514402,54.9135802469136]],[20,[716.6907483615302,62.66361835086114]],[22,[719.6171315348269,59.659198292943145]],[15,[703.604938271605,68.21399176954733]],[3,[703.7366255144034,54.694101508916326]],[13,[706.9556470050298,39.272062185642426]],[12,[698.2935528120714,34.35573845450388]],[28,[702.2539247065995,73.00350556317633]],[21,[716.1444901691814,49.82655083066605]],[16,[713.7448559670781,60.37860082304528]],[10,[696.5925925925927,33.728395061728385]]]},"segments":{"add":[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29],"remove":[],"start_point":[[3,3],[9,9],[10,10],[27,27],[24,24],[26,26],[25,25],[8,8],[21,21],[1,1],[28,28],[4,4],[14,14],[29,29],[12,12],[22,22],[19,19],[5,5],[13,13],[2,2],[20,20],[11,11],[6,6],[15,15],[17,17],[7,7],[23,23],[18,18],[16,16]],"end_point":[[19,20],[2,3],[23,24],[5,6],[10,11],[14,15],[3,4],[21,22],[29,1],[9,10],[12,13],[7,8],[11,12],[1,2],[22,23],[15,16],[20,21],[8,9],[26,27],[16,17],[18,19],[6,7],[17,18],[28,29],[13,14],[4,5],[24,25],[27,28],[25,26]],"handle_primary":[[6,[0.0,0.0]],[9,[-3.823807346440958,-1.6387745770461848]],[22,[-1.7948483462886315,6.047858558146615]],[11,[0.0,0.0]],[19,[0.0,0.0]],[21,[0.0,0.0]],[5,[-1.1705532693187024,3.0044200579180043]],[1,[0.0,0.0]],[13,[2.1939750755697105,1.3128956217623369]],[3,[0.0,0.0]],[29,[0.0,0.0]],[15,[0.0,0.0]],[25,[0.0,0.0]],[26,[0.8664211612748431,3.3573819999397045]],[8,[1.1368683772161605e-13,-7.4135040390184415]],[28,[-7.920532726374063,-0.13055823175342596]],[7,[3.3946044810244302,-1.8728852309099435]],[24,[2.106995884773596,-3.0044200579180256]],[18,[-0.7242798353908029,5.860082304526735]],[12,[1.5089163237310004,2.3850022862368547]],[17,[0.0,0.0]],[4,[0.0,0.0]],[23,[0.0,0.0]],[27,[-4.128769232802142,3.294230770852593]],[14,[0.9193720469440904,5.347965249199831]],[16,[2.9207548934437,-5.774876595401999]],[10,[-0.04481007342064913,-1.8372595419893116]],[2,[1.5646505637769224,-1.2302214356413188]],[20,[2.536198750190465,-6.516079865874104]]],"handle_end":[[21,[1.7948483462886315,-6.047858558146615]],[26,[3.66773357719876,-2.926383173296756]],[25,[-0.6242950769700428,-2.419143423258646]],[5,[6.516079865874076,-2.4581618655692807]],[15,[-3.84819387288519,7.608596250571544]],[23,[-2.1028230213785264,2.9984698638176326]],[16,[1.1705532693187024,1.8728852309099224]],[19,[-2.536198750190465,6.516079865874104]],[24,[2.980033531474078,4.338363054412447]],[11,[-0.8654907204776237,-1.3679998781853442]],[22,[2.731290961743639,-1.326627038561199]],[9,[0.04481007342064913,1.837259541989333]],[7,[-1.1368683772161605e-13,8.389895136005812]],[17,[0.667740598959881,-5.402628482494777]],[27,[7.101356500533598,0.11705532693187592]],[10,[0.0,0.0]],[6,[-3.208476806721251,1.7701941002599142]],[28,[0.0,0.0]],[12,[-3.679926840420876,-2.202103337905797]],[8,[5.150019007352512,2.2071510031511608]],[29,[0.009754610577488164,0.048773052888265056]],[4,[1.1705532693187024,-3.0044200579180043]],[1,[-2.555707971345896,2.0094497789970944]],[3,[0.0,0.0]],[18,[9.169333942996444,-4.409083981100437]],[13,[-0.7923207898123792,-4.608911119518574]],[14,[7.30864197530866,-5.333333333333336]],[20,[1.638774577046206,1.5607376924249363]],[2,[0.5267489711934559,6.320987654320987]]],"stroke":[[7,0],[22,0],[24,0],[18,0],[17,0],[13,0],[16,0],[10,0],[12,0],[3,0],[6,0],[28,0],[20,0],[21,0],[23,0],[1,0],[14,0],[4,0],[9,0],[8,0],[5,0],[2,0],[19,0],[26,0],[15,0],[25,0],[27,0],[11,0],[29,0]]},"regions":{"add":[0],"remove":[],"segment_range":[[0,{"start":1,"end":29}]],"fill":[[0,0]]},"add_g1_continuous":[],"remove_g1_continuous":[]}},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::vector_data::modification::VectorModification","alias":null}},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::vector_data::modification::PathModifyNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[18190631752493248867,{"inputs":[{"Node":{"node_id":12428327489525325219,"output_index":0,"lambda":false}},{"Node":{"node_id":10375238420217738812,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[8644924780109919177,{"inputs":[{"Node":{"node_id":10599660455959346550,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"PointSpacingType":"Separation"},"exposed":false}},{"Value":{"tagged_value":{"F64":5.0},"exposed":false}},{"Value":{"tagged_value":{"U32":100},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"Bool":false},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":4,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::SubpathSegmentLengthsNode"}},"visible":true,"skip_deduplication":false}],[4,{"inputs":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::BoundlessFootprintNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":2,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::FreezeRealTimeNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MemoNode"}},"visible":true,"skip_deduplication":false}],[1,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::misc::PointSpacingType","alias":null}},"import_index":1}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":2}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":3}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":4}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":5}},{"Network":{"import_type":{"Concrete":{"name":"bool","alias":null}},"import_index":6}},{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::SamplePolylineNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[5020096817747898028,{"inputs":[{"Node":{"node_id":15286091228862934481,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"Fill":{"Solid":{"red":0.8980392,"green":0.8,"blue":0.6117647,"alpha":1.0}}},"exposed":false}},{"Value":{"tagged_value":{"OptionalColor":{"red":0.8980392,"green":0.8,"blue":0.6117647,"alpha":1.0}},"exposed":false}},{"Value":{"tagged_value":{"Gradient":{"stops":[[0.0,{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}],[1.0,{"red":1.0,"green":1.0,"blue":1.0,"alpha":1.0}]],"gradient_type":"Linear","start":[0.0,0.5],"end":[1.0,0.5],"transform":[1.0,0.0,0.0,1.0,0.0,0.0]}},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::FillNode"}},"visible":true,"skip_deduplication":false}],[2641530639940889619,{"inputs":[{"Node":{"node_id":5174744389209053970,"output_index":0,"lambda":false}},{"Node":{"node_id":14539627480594383748,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[5326536612985524219,{"inputs":[{"Node":{"node_id":15798070933198867970,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"F64":27.0},"exposed":false}},{"Value":{"tagged_value":{"U32":9},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":1}},{"Network":{"import_type":{"Concrete":{"name":"u32","alias":null}},"import_index":2}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::PoissonDiskPointsNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":2,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::BoundlessFootprintNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::FreezeRealTimeNode"}},"visible":true,"skip_deduplication":false}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MemoNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[11666664915283969027,{"inputs":[{"Value":{"tagged_value":{"VectorData":{"instance":[{"style":{"stroke":{"color":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0},"weight":0.0,"dash_lengths":[],"dash_offset":0.0,"cap":"Butt","join":"Miter","join_miter_limit":4.0,"align":"Center","transform":[1.0,0.0,0.0,1.0,0.0,0.0],"non_scaling":false,"paint_order":"StrokeAbove"},"fill":"None"},"colinear_manipulators":[],"point_domain":{"id":[],"position":[]},"segment_domain":{"id":[],"start_point":[],"end_point":[],"handles":[],"stroke":[]},"region_domain":{"id":[],"segment_range":[],"fill":[]},"upstream_graphic_group":null}],"transform":[[1.0,0.0,0.0,1.0,0.0,0.0]],"alpha_blending":[{"blend_mode":"Normal","opacity":1.0,"fill":1.0,"clip":false}],"source_node_id":[null]}},"exposed":true}},{"Value":{"tagged_value":{"VectorModification":{"points":{"add":[1,2],"remove":[],"delta":[[2,[751.4074074074075,685.0370370370371]],[1,[802.3703703703703,580.9382716049382]]]},"segments":{"add":[1,2],"remove":[],"start_point":[[1,1],[2,2]],"end_point":[[1,2],[2,1]],"handle_primary":[[1,[0.0,0.0]],[2,[20.740740740740534,-42.469135802469054]]],"handle_end":[[1,[27.259259259259125,-48.79012345678995]],[2,null]],"stroke":[[1,0],[2,0]]},"regions":{"add":[0],"remove":[],"segment_range":[[0,{"start":1,"end":2}]],"fill":[[0,0]]},"add_g1_continuous":[],"remove_g1_continuous":[]}},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::vector_data::modification::VectorModification","alias":null}},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::vector_data::modification::PathModifyNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[3414873131936208778,{"inputs":[{"Value":{"tagged_value":{"VectorData":{"instance":[{"style":{"stroke":{"color":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0},"weight":0.0,"dash_lengths":[],"dash_offset":0.0,"cap":"Butt","join":"Miter","join_miter_limit":4.0,"align":"Center","transform":[1.0,0.0,0.0,1.0,0.0,0.0],"non_scaling":false,"paint_order":"StrokeAbove"},"fill":"None"},"colinear_manipulators":[],"point_domain":{"id":[],"position":[]},"segment_domain":{"id":[],"start_point":[],"end_point":[],"handles":[],"stroke":[]},"region_domain":{"id":[],"segment_range":[],"fill":[]},"upstream_graphic_group":null}],"transform":[[1.0,0.0,0.0,1.0,0.0,0.0]],"alpha_blending":[{"blend_mode":"Normal","opacity":1.0,"fill":1.0,"clip":false}],"source_node_id":[null]}},"exposed":true}},{"Value":{"tagged_value":{"VectorModification":{"points":{"add":[1,2],"remove":[],"delta":[[2,[697.7777777777777,954.2222222222222]],[1,[761.7777777777777,737.3333333333333]]]},"segments":{"add":[1,2],"remove":[],"start_point":[[2,2],[1,1]],"end_point":[[2,1],[1,2]],"handle_primary":[[1,[0.0,0.0]],[2,[0.0,0.0]]],"handle_end":[[2,[-40.0,81.33333333333326]],[1,[26.22222222222217,-158.66666666666652]]],"stroke":[[1,0],[2,0]]},"regions":{"add":[0],"remove":[],"segment_range":[[0,{"start":1,"end":2}]],"fill":[[0,0]]},"add_g1_continuous":[],"remove_g1_continuous":[]}},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::vector_data::modification::VectorModification","alias":null}},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::vector_data::modification::PathModifyNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[3686761601672683183,{"inputs":[{"Node":{"node_id":4859656512650360562,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"PointSpacingType":"Separation"},"exposed":false}},{"Value":{"tagged_value":{"F64":5.0},"exposed":false}},{"Value":{"tagged_value":{"U32":100},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"Bool":false},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":4,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::SubpathSegmentLengthsNode"}},"visible":true,"skip_deduplication":false}],[4,{"inputs":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::BoundlessFootprintNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":2,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::FreezeRealTimeNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MemoNode"}},"visible":true,"skip_deduplication":false}],[1,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::misc::PointSpacingType","alias":null}},"import_index":1}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":2}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":3}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":4}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":5}},{"Network":{"import_type":{"Concrete":{"name":"bool","alias":null}},"import_index":6}},{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::SamplePolylineNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[16805628435335819723,{"inputs":[{"Node":{"node_id":10689298484366290551,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"Fill":{"Solid":{"red":0.7529412,"green":0.15686275,"blue":0.13333334,"alpha":1.0}}},"exposed":false}},{"Value":{"tagged_value":{"OptionalColor":{"red":0.7529412,"green":0.15686275,"blue":0.13333334,"alpha":1.0}},"exposed":false}},{"Value":{"tagged_value":{"Gradient":{"stops":[[0.0,{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}],[1.0,{"red":1.0,"green":1.0,"blue":1.0,"alpha":1.0}]],"gradient_type":"Linear","start":[0.0,0.5],"end":[1.0,0.5],"transform":[1.0,0.0,0.0,1.0,0.0,0.0]}},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::FillNode"}},"visible":true,"skip_deduplication":false}],[13557369662261607646,{"inputs":[{"Node":{"node_id":3535178979443201645,"output_index":0,"lambda":false}},{"Node":{"node_id":15177845878727456758,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[16339345235172368839,{"inputs":[{"Node":{"node_id":14778750092903591172,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"Fill":{"Solid":{"red":0.7529412,"green":0.15686275,"blue":0.13333334,"alpha":1.0}}},"exposed":false}},{"Value":{"tagged_value":{"OptionalColor":{"red":0.7529412,"green":0.15686275,"blue":0.13333334,"alpha":1.0}},"exposed":false}},{"Value":{"tagged_value":{"Gradient":{"stops":[[0.0,{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}],[1.0,{"red":1.0,"green":1.0,"blue":1.0,"alpha":1.0}]],"gradient_type":"Linear","start":[0.0,0.5],"end":[1.0,0.5],"transform":[1.0,0.0,0.0,1.0,0.0,0.0]}},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::FillNode"}},"visible":true,"skip_deduplication":false}],[18214377096178867498,{"inputs":[{"Node":{"node_id":7747398671834040298,"output_index":0,"lambda":false}},{"Node":{"node_id":4332145463108161926,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"F64":2.0},"exposed":false}},{"Value":{"tagged_value":{"F64":300.0},"exposed":false}},{"Value":{"tagged_value":{"F64":-100.0},"exposed":false}},{"Value":{"tagged_value":{"U32":0},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"U32":0},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::CopyToPointsNode"}},"visible":true,"skip_deduplication":false}],[3955326429435439190,{"inputs":[{"Node":{"node_id":18207065424980079673,"output_index":0,"lambda":false}},{"Node":{"node_id":17078740291337047697,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"F64":1.2},"exposed":false}},{"Value":{"tagged_value":{"F64":2.0},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"U32":0},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"U32":0},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::CopyToPointsNode"}},"visible":true,"skip_deduplication":false}],[2126710823743005151,{"inputs":[{"Node":{"node_id":14831840560430171946,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"Fill":{"Solid":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}}},"exposed":false}},{"Value":{"tagged_value":{"OptionalColor":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}},"exposed":false}},{"Value":{"tagged_value":{"Gradient":{"stops":[[0.0,{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}],[1.0,{"red":1.0,"green":1.0,"blue":1.0,"alpha":1.0}]],"gradient_type":"Linear","start":[0.0,0.5],"end":[1.0,0.5],"transform":[1.0,0.0,0.0,1.0,0.0,0.0]}},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::FillNode"}},"visible":true,"skip_deduplication":false}],[11804065810513502701,{"inputs":[{"Node":{"node_id":9782123335421401489,"output_index":0,"lambda":false}},{"Node":{"node_id":17133591775058457007,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[7320676248579211727,{"inputs":[{"Node":{"node_id":14817659161913199655,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"Fill":{"Solid":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}}},"exposed":false}},{"Value":{"tagged_value":{"OptionalColor":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}},"exposed":false}},{"Value":{"tagged_value":{"Gradient":{"stops":[[0.0,{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}],[1.0,{"red":1.0,"green":1.0,"blue":1.0,"alpha":1.0}]],"gradient_type":"Linear","start":[0.0,0.5],"end":[1.0,0.5],"transform":[1.0,0.0,0.0,1.0,0.0,0.0]}},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::FillNode"}},"visible":true,"skip_deduplication":false}],[7654665057468818389,{"inputs":[{"Node":{"node_id":17378885078543074499,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"Fill":{"Solid":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}}},"exposed":false}},{"Value":{"tagged_value":{"OptionalColor":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}},"exposed":false}},{"Value":{"tagged_value":{"Gradient":{"stops":[[0.0,{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}],[1.0,{"red":1.0,"green":1.0,"blue":1.0,"alpha":1.0}]],"gradient_type":"Linear","start":[0.0,0.5],"end":[1.0,0.5],"transform":[1.0,0.0,0.0,1.0,0.0,0.0]}},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::FillNode"}},"visible":true,"skip_deduplication":false}],[10514847656270897393,{"inputs":[{"Value":{"tagged_value":{"GraphicGroup":{"instance":[],"transform":[],"alpha_blending":[],"source_node_id":[]}},"exposed":true}},{"Node":{"node_id":16339345235172368839,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[16434255153991868080,{"inputs":[{"Node":{"node_id":6124821161363551058,"output_index":0,"lambda":false}},{"Node":{"node_id":17078740291337047697,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"F64":1.2},"exposed":false}},{"Value":{"tagged_value":{"F64":2.0},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"U32":0},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"U32":0},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::CopyToPointsNode"}},"visible":true,"skip_deduplication":false}],[17207349373429328029,{"inputs":[{"Node":{"node_id":17967471489196302183,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"Fill":{"Solid":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}}},"exposed":false}},{"Value":{"tagged_value":{"OptionalColor":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}},"exposed":false}},{"Value":{"tagged_value":{"Gradient":{"stops":[[0.0,{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}],[1.0,{"red":1.0,"green":1.0,"blue":1.0,"alpha":1.0}]],"gradient_type":"Linear","start":[0.0,0.5],"end":[1.0,0.5],"transform":[1.0,0.0,0.0,1.0,0.0,0.0]}},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::FillNode"}},"visible":true,"skip_deduplication":false}],[6867142265138950838,{"inputs":[{"Node":{"node_id":4784708315242877950,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"Fill":{"Solid":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}}},"exposed":false}},{"Value":{"tagged_value":{"OptionalColor":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}},"exposed":false}},{"Value":{"tagged_value":{"Gradient":{"stops":[[0.0,{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}],[1.0,{"red":1.0,"green":1.0,"blue":1.0,"alpha":1.0}]],"gradient_type":"Linear","start":[0.0,0.5],"end":[1.0,0.5],"transform":[1.0,0.0,0.0,1.0,0.0,0.0]}},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::FillNode"}},"visible":true,"skip_deduplication":false}],[14862049226133442027,{"inputs":[{"Node":{"node_id":16614450796751955858,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"Fill":{"Solid":{"red":0.7529412,"green":0.15686275,"blue":0.13333334,"alpha":1.0}}},"exposed":false}},{"Value":{"tagged_value":{"OptionalColor":{"red":0.7529412,"green":0.15686275,"blue":0.13333334,"alpha":1.0}},"exposed":false}},{"Value":{"tagged_value":{"Gradient":{"stops":[[0.0,{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}],[1.0,{"red":1.0,"green":1.0,"blue":1.0,"alpha":1.0}]],"gradient_type":"Linear","start":[0.0,0.5],"end":[1.0,0.5],"transform":[1.0,0.0,0.0,1.0,0.0,0.0]}},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::FillNode"}},"visible":true,"skip_deduplication":false}],[8814059393325469059,{"inputs":[{"Node":{"node_id":15492651270767932214,"output_index":0,"lambda":false}},{"Node":{"node_id":14035980686649077716,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[17364155187784942740,{"inputs":[{"Node":{"node_id":1378578509112405,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"Fill":{"Solid":{"red":0.9019608,"green":0.8,"blue":0.6117647,"alpha":1.0}}},"exposed":false}},{"Value":{"tagged_value":{"OptionalColor":{"red":0.9019608,"green":0.8,"blue":0.6117647,"alpha":1.0}},"exposed":false}},{"Value":{"tagged_value":{"Gradient":{"stops":[[0.0,{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}],[1.0,{"red":1.0,"green":1.0,"blue":1.0,"alpha":1.0}]],"gradient_type":"Linear","start":[0.0,0.5],"end":[1.0,0.5],"transform":[1.0,0.0,0.0,1.0,0.0,0.0]}},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::FillNode"}},"visible":true,"skip_deduplication":false}],[10586744777717861556,{"inputs":[{"Node":{"node_id":11417901103965737900,"output_index":0,"lambda":false}},{"Node":{"node_id":17078740291337047697,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"F64":1.2},"exposed":false}},{"Value":{"tagged_value":{"F64":2.0},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"U32":0},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"U32":0},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::CopyToPointsNode"}},"visible":true,"skip_deduplication":false}],[15656854169166220905,{"inputs":[{"Node":{"node_id":7821977654068146599,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"DVec2":[-5.0,22.0]},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[1.0,1.0]},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[0.0,0.0]},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[0.5,0.5]},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":1}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":2}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":3}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":4}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":5}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::TransformNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[4909350123806022131,{"inputs":[{"Node":{"node_id":15498700602024283966,"output_index":0,"lambda":false}},{"Node":{"node_id":16536768589601337644,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[10190227675276560561,{"inputs":[{"Node":{"node_id":2682920349304670808,"output_index":0,"lambda":false}},{"Node":{"node_id":16434255153991868080,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[10424806499648491677,{"inputs":[{"Value":{"tagged_value":{"GraphicGroup":{"instance":[],"transform":[],"alpha_blending":[],"source_node_id":[]}},"exposed":true}},{"Node":{"node_id":17147975601187022720,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[14598755603287563819,{"inputs":[{"Node":{"node_id":7466034304713056391,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"Fill":{"Solid":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}}},"exposed":false}},{"Value":{"tagged_value":{"OptionalColor":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}},"exposed":false}},{"Value":{"tagged_value":{"Gradient":{"stops":[[0.0,{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}],[1.0,{"red":1.0,"green":1.0,"blue":1.0,"alpha":1.0}]],"gradient_type":"Linear","start":[0.0,0.5],"end":[1.0,0.5],"transform":[1.0,0.0,0.0,1.0,0.0,0.0]}},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::FillNode"}},"visible":true,"skip_deduplication":false}],[8230694129617719636,{"inputs":[{"Node":{"node_id":4909350123806022131,"output_index":0,"lambda":false}},{"Node":{"node_id":16805628435335819723,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[16175421708184657649,{"inputs":[{"Node":{"node_id":8698602280607307123,"output_index":0,"lambda":false}},{"Node":{"node_id":514796034658094296,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[18422317423856403288,{"inputs":[{"Node":{"node_id":10133176481349663495,"output_index":0,"lambda":false}},{"Node":{"node_id":12594527670567285670,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[15395954548128560685,{"inputs":[{"Node":{"node_id":13475705179546695973,"output_index":0,"lambda":false}},{"Node":{"node_id":16767482995096345179,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[11464423670065789907,{"inputs":[{"Node":{"node_id":8644924780109919177,"output_index":0,"lambda":false}},{"Node":{"node_id":17078740291337047697,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"F64":1.2},"exposed":false}},{"Value":{"tagged_value":{"F64":2.0},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"U32":0},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"U32":0},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::CopyToPointsNode"}},"visible":true,"skip_deduplication":false}],[5269304445610080925,{"inputs":[{"Node":{"node_id":3686761601672683183,"output_index":0,"lambda":false}},{"Node":{"node_id":17078740291337047697,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"F64":1.2},"exposed":false}},{"Value":{"tagged_value":{"F64":2.0},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"U32":0},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"U32":0},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::CopyToPointsNode"}},"visible":true,"skip_deduplication":false}],[14012583111791538162,{"inputs":[{"Value":{"tagged_value":{"VectorData":{"instance":[{"style":{"stroke":{"color":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0},"weight":0.0,"dash_lengths":[],"dash_offset":0.0,"cap":"Butt","join":"Miter","join_miter_limit":4.0,"align":"Center","transform":[1.0,0.0,0.0,1.0,0.0,0.0],"non_scaling":false,"paint_order":"StrokeAbove"},"fill":"None"},"colinear_manipulators":[],"point_domain":{"id":[],"position":[]},"segment_domain":{"id":[],"start_point":[],"end_point":[],"handles":[],"stroke":[]},"region_domain":{"id":[],"segment_range":[],"fill":[]},"upstream_graphic_group":null}],"transform":[[1.0,0.0,0.0,1.0,0.0,0.0]],"alpha_blending":[{"blend_mode":"Normal","opacity":1.0,"fill":1.0,"clip":false}],"source_node_id":[null]}},"exposed":true}},{"Value":{"tagged_value":{"VectorModification":{"points":{"add":[1,2,3],"remove":[],"delta":[[3,[603.3333333333335,744.6666666666666]],[2,[380.00000000000006,806.0]],[1,[248.00000000000009,884.0]]]},"segments":{"add":[1,2],"remove":[],"start_point":[[1,1],[2,2]],"end_point":[[1,2],[2,3]],"handle_primary":[[1,[0.0,0.0]],[2,[70.80694036316174,-19.49756328840681]]],"handle_end":[[1,[-92.00000000000006,25.333333333333258]],[2,[-71.33333333333326,24.0]]],"stroke":[[1,0],[2,0]]},"regions":{"add":[],"remove":[],"segment_range":[],"fill":[]},"add_g1_continuous":[],"remove_g1_continuous":[]}},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::vector_data::modification::VectorModification","alias":null}},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::vector_data::modification::PathModifyNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[4784708315242877950,{"inputs":[{"Value":{"tagged_value":{"VectorData":{"instance":[{"style":{"stroke":{"color":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0},"weight":0.0,"dash_lengths":[],"dash_offset":0.0,"cap":"Butt","join":"Miter","join_miter_limit":4.0,"align":"Center","transform":[1.0,0.0,0.0,1.0,0.0,0.0],"non_scaling":false,"paint_order":"StrokeAbove"},"fill":"None"},"colinear_manipulators":[],"point_domain":{"id":[],"position":[]},"segment_domain":{"id":[],"start_point":[],"end_point":[],"handles":[],"stroke":[]},"region_domain":{"id":[],"segment_range":[],"fill":[]},"upstream_graphic_group":null}],"transform":[[1.0,0.0,0.0,1.0,0.0,0.0]],"alpha_blending":[{"blend_mode":"Normal","opacity":1.0,"fill":1.0,"clip":false}],"source_node_id":[null]}},"exposed":true}},{"Value":{"tagged_value":{"VectorModification":{"points":{"add":[1,2,3,4,5,6,7],"remove":[],"delta":[[7,[807.0666666666666,680.1333333333332]],[5,[464.5925925925926,1025.382716049383]],[3,[592.4000000000001,852.3999999999999]],[2,[808.5333333333333,683.1555555555556]],[1,[902.6666666666669,446.66666666666674]],[6,[592.0,845.3333333333333]],[4,[468.14814814814815,1025.382716049383]]]},"segments":{"add":[1,2,3,4,5,6,7],"remove":[],"start_point":[[4,4],[2,2],[7,7],[6,6],[5,5],[1,1],[3,3]],"end_point":[[4,5],[3,4],[5,6],[6,7],[7,1],[2,3],[1,2]],"handle_primary":[[6,[93.94069526511169,-85.35957406301043]],[4,[0.0,0.0]],[1,[0.0,0.0]],[2,[-81.33333333333337,100.88888888888891]],[3,[-91.33798434535026,86.27035509501377]],[7,[62.39957279246403,-72.271586423759]],[5,[0.0,0.0]]],"handle_end":[[6,[-87.55555555555577,101.4074074074075]],[2,[85.857044886376,-81.09351003138556]],[3,[0.0,0.0]],[5,[-102.71604938271612,93.3333333333336]],[4,[0.0,0.0]],[1,[97.81027061870486,-121.32749415544254]],[7,[-3.466666666666697,51.33333333333326]]],"stroke":[[1,0],[5,0],[3,0],[7,0],[6,0],[4,0],[2,0]]},"regions":{"add":[0],"remove":[],"segment_range":[[0,{"start":1,"end":7}]],"fill":[[0,0]]},"add_g1_continuous":[],"remove_g1_continuous":[]}},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::vector_data::modification::VectorModification","alias":null}},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::vector_data::modification::PathModifyNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[8375495949882478840,{"inputs":[{"Value":{"tagged_value":{"VectorData":{"instance":[{"style":{"stroke":{"color":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0},"weight":0.0,"dash_lengths":[],"dash_offset":0.0,"cap":"Butt","join":"Miter","join_miter_limit":4.0,"align":"Center","transform":[1.0,0.0,0.0,1.0,0.0,0.0],"non_scaling":false,"paint_order":"StrokeAbove"},"fill":"None"},"colinear_manipulators":[],"point_domain":{"id":[],"position":[]},"segment_domain":{"id":[],"start_point":[],"end_point":[],"handles":[],"stroke":[]},"region_domain":{"id":[],"segment_range":[],"fill":[]},"upstream_graphic_group":null}],"transform":[[1.0,0.0,0.0,1.0,0.0,0.0]],"alpha_blending":[{"blend_mode":"Normal","opacity":1.0,"fill":1.0,"clip":false}],"source_node_id":[null]}},"exposed":true}},{"Value":{"tagged_value":{"VectorModification":{"points":{"add":[1,2,3,4,5,6,7,8,9,10,11],"remove":[],"delta":[[4,[642.6077325610934,47.29035208047554]],[2,[617.4278311233043,51.042625616013815]],[10,[650.9056546258192,56.62876594015139]],[9,[662.1234567901236,66.9849108367627]],[1,[616.0751917898693,61.31097901742621]],[7,[673.0096021947875,65.84362139917695]],[6,[662.1234567901236,64.96570644718793]],[3,[628.5871056241429,46.71808159325306]],[11,[641.3168724279836,48.02194787379973]],[8,[675.3580246913581,68.74074074074075]],[5,[650.6227709190673,52.93827160493828]]]},"segments":{"add":[1,2,3,4,5,6,7,8,9,10,11],"remove":[],"start_point":[[6,6],[2,2],[1,1],[5,5],[3,3],[9,9],[4,4],[7,7],[11,11],[10,10],[8,8]],"end_point":[[10,11],[4,5],[6,7],[8,9],[1,2],[9,10],[2,3],[7,8],[5,6],[3,4],[11,1]],"handle_primary":[[10,[-2.0025980353477735,-3.5689865976493422]],[5,[3.160493827160508,4.6529492455418335]],[4,[2.784561671457709,0.5265657466421629]],[8,[0.0,0.0]],[1,[-0.7315957933242316,0.01300614743686168]],[2,[2.1833209230284183,-3.0691100638496778]],[9,[-4.389574759945162,-2.106995884773667]],[11,[-8.252400548696869,-0.8779149519890339]],[7,[0.0,0.0]],[3,[4.873654303444027,-0.3091793289098348]],[6,[5.4430727023319605,2.545953360768181]]],"handle_end":[[5,[-5.4430727023319605,-2.545953360768181]],[6,[0.0,0.0]],[4,[-3.160493827160508,-4.6529492455418335]],[3,[-2.7845616714574817,-0.5265657466421203]],[10,[6.086554705109506,0.6475058196925048]],[2,[-5.145487535686698,0.32642413354457744]],[7,[0.0,0.0]],[9,[2.6272417822486887,4.682213077274824]],[1,[-2.4595700304455477,3.4574354386312436]],[11,[2.0257074632933154,-0.6893258141543512]],[8,[4.389574759945162,2.106995884773667]]],"stroke":[[11,0],[3,0],[5,0],[7,0],[2,0],[4,0],[9,0],[10,0],[1,0],[6,0],[8,0]]},"regions":{"add":[0],"remove":[],"segment_range":[[0,{"start":1,"end":11}]],"fill":[[0,0]]},"add_g1_continuous":[],"remove_g1_continuous":[]}},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::vector_data::modification::VectorModification","alias":null}},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::vector_data::modification::PathModifyNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[11677503666435782605,{"inputs":[{"Node":{"node_id":12049041947382267086,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"Fill":{"Solid":{"red":0.7529412,"green":0.15686275,"blue":0.13333334,"alpha":1.0}}},"exposed":false}},{"Value":{"tagged_value":{"OptionalColor":{"red":0.7529412,"green":0.15686275,"blue":0.13333334,"alpha":1.0}},"exposed":false}},{"Value":{"tagged_value":{"Gradient":{"stops":[[0.0,{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}],[1.0,{"red":1.0,"green":1.0,"blue":1.0,"alpha":1.0}]],"gradient_type":"Linear","start":[0.0,0.5],"end":[1.0,0.5],"transform":[1.0,0.0,0.0,1.0,0.0,0.0]}},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::FillNode"}},"visible":true,"skip_deduplication":false}],[16536768589601337644,{"inputs":[{"Node":{"node_id":4222034829755771252,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"Fill":{"Solid":{"red":0.8980392,"green":0.8,"blue":0.6117647,"alpha":1.0}}},"exposed":false}},{"Value":{"tagged_value":{"OptionalColor":{"red":0.8980392,"green":0.8,"blue":0.6117647,"alpha":1.0}},"exposed":false}},{"Value":{"tagged_value":{"Gradient":{"stops":[[0.0,{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}],[1.0,{"red":1.0,"green":1.0,"blue":1.0,"alpha":1.0}]],"gradient_type":"Linear","start":[0.0,0.5],"end":[1.0,0.5],"transform":[1.0,0.0,0.0,1.0,0.0,0.0]}},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::FillNode"}},"visible":true,"skip_deduplication":false}],[2087303479944421366,{"inputs":[{"Value":{"tagged_value":{"VectorData":{"instance":[{"style":{"stroke":{"color":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0},"weight":0.0,"dash_lengths":[],"dash_offset":0.0,"cap":"Butt","join":"Miter","join_miter_limit":4.0,"align":"Center","transform":[1.0,0.0,0.0,1.0,0.0,0.0],"non_scaling":false,"paint_order":"StrokeAbove"},"fill":"None"},"colinear_manipulators":[],"point_domain":{"id":[],"position":[]},"segment_domain":{"id":[],"start_point":[],"end_point":[],"handles":[],"stroke":[]},"region_domain":{"id":[],"segment_range":[],"fill":[]},"upstream_graphic_group":null}],"transform":[[1.0,0.0,0.0,1.0,0.0,0.0]],"alpha_blending":[{"blend_mode":"Normal","opacity":1.0,"fill":1.0,"clip":false}],"source_node_id":[null]}},"exposed":true}},{"Value":{"tagged_value":{"VectorModification":{"points":{"add":[1,2,3],"remove":[],"delta":[[2,[443.2592592592592,882.0740740740739]],[3,[368.59259259259255,1025.1851851851852]],[1,[365.6296296296296,1025.4814814814813]]]},"segments":{"add":[1,2],"remove":[],"start_point":[[2,2],[1,1]],"end_point":[[1,2],[2,3]],"handle_primary":[[1,[0.0,0.0]],[2,[0.0,0.0]]],"handle_end":[[2,[31.111111111111143,-96.29629629629642]],[1,[-48.59259259259255,50.07407407407413]]],"stroke":[[1,0],[2,0]]},"regions":{"add":[],"remove":[],"segment_range":[],"fill":[]},"add_g1_continuous":[],"remove_g1_continuous":[]}},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::vector_data::modification::VectorModification","alias":null}},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::vector_data::modification::PathModifyNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[17426609415699324395,{"inputs":[{"Node":{"node_id":15896921950407486754,"output_index":0,"lambda":false}},{"Node":{"node_id":11464423670065789907,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[16450742929146919960,{"inputs":[{"Node":{"node_id":14887821801874852671,"output_index":0,"lambda":false}},{"Node":{"node_id":11899713172487274471,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[8595304668947966919,{"inputs":[{"Value":{"tagged_value":{"VectorData":{"instance":[{"style":{"stroke":{"color":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0},"weight":0.0,"dash_lengths":[],"dash_offset":0.0,"cap":"Butt","join":"Miter","join_miter_limit":4.0,"align":"Center","transform":[1.0,0.0,0.0,1.0,0.0,0.0],"non_scaling":false,"paint_order":"StrokeAbove"},"fill":"None"},"colinear_manipulators":[],"point_domain":{"id":[],"position":[]},"segment_domain":{"id":[],"start_point":[],"end_point":[],"handles":[],"stroke":[]},"region_domain":{"id":[],"segment_range":[],"fill":[]},"upstream_graphic_group":null}],"transform":[[1.0,0.0,0.0,1.0,0.0,0.0]],"alpha_blending":[{"blend_mode":"Normal","opacity":1.0,"fill":1.0,"clip":false}],"source_node_id":[null]}},"exposed":true}},{"Value":{"tagged_value":{"VectorModification":{"points":{"add":[1,2],"remove":[],"delta":[[1,[810.1333333333333,731.4666666666668]],[2,[798.4000000000001,879.4666666666668]]]},"segments":{"add":[1,2],"remove":[],"start_point":[[1,1],[2,2]],"end_point":[[1,2],[2,1]],"handle_primary":[[2,[0.0,0.0]],[1,[0.0,0.0]]],"handle_end":[[1,[-1.8666666666665608,-67.46666666666658]],[2,[-18.13333333333333,82.66666666666674]]],"stroke":[[1,0],[2,0]]},"regions":{"add":[0],"remove":[],"segment_range":[[0,{"start":1,"end":2}]],"fill":[[0,0]]},"add_g1_continuous":[],"remove_g1_continuous":[]}},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::vector_data::modification::VectorModification","alias":null}},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::vector_data::modification::PathModifyNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[11451028343967836482,{"inputs":[{"Node":{"node_id":2422139482859833437,"output_index":0,"lambda":false}},{"Node":{"node_id":12531351117929704587,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[314278016428495768,{"inputs":[{"Node":{"node_id":6282972142629473139,"output_index":0,"lambda":false}},{"Node":{"node_id":5020096817747898028,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[17971411534648521628,{"inputs":[{"Value":{"tagged_value":{"GraphicGroup":{"instance":[],"transform":[],"alpha_blending":[],"source_node_id":[]}},"exposed":true}},{"Node":{"node_id":14862049226133442027,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[13014628586360765651,{"inputs":[{"Value":{"tagged_value":{"GraphicGroup":{"instance":[],"transform":[],"alpha_blending":[],"source_node_id":[]}},"exposed":true}},{"Node":{"node_id":2175432926627256613,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[14778750092903591172,{"inputs":[{"Value":{"tagged_value":{"VectorData":{"instance":[{"style":{"stroke":{"color":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0},"weight":0.0,"dash_lengths":[],"dash_offset":0.0,"cap":"Butt","join":"Miter","join_miter_limit":4.0,"align":"Center","transform":[1.0,0.0,0.0,1.0,0.0,0.0],"non_scaling":false,"paint_order":"StrokeAbove"},"fill":"None"},"colinear_manipulators":[],"point_domain":{"id":[],"position":[]},"segment_domain":{"id":[],"start_point":[],"end_point":[],"handles":[],"stroke":[]},"region_domain":{"id":[],"segment_range":[],"fill":[]},"upstream_graphic_group":null}],"transform":[[1.0,0.0,0.0,1.0,0.0,0.0]],"alpha_blending":[{"blend_mode":"Normal","opacity":1.0,"fill":1.0,"clip":false}],"source_node_id":[null]}},"exposed":true}},{"Value":{"tagged_value":{"VectorModification":{"points":{"add":[1,2,3],"remove":[],"delta":[[2,[149.0793650793651,202.5537918871252]],[3,[146.5679012345679,204.44444444444449]],[1,[155.98219408731924,204.757705978404]]]},"segments":{"add":[1,2,3],"remove":[],"start_point":[[1,1],[3,3],[2,2]],"end_point":[[2,3],[1,2],[3,1]],"handle_primary":[[1,[-2.6135873853791907,-0.8494167367814498]],[3,[0.9278738161427498,1.2447087777524644]],[2,[-2.2695727277346123,-0.643804298125275]]],"handle_end":[[1,[1.7022700834823468,0.48287890620272833]],[2,[-1.156966490299823,-1.5520282186949146]],[3,[-0.32172621516085087,3.1233079488176827]]],"stroke":[[2,0],[1,0],[3,0]]},"regions":{"add":[0],"remove":[],"segment_range":[[0,{"start":1,"end":3}]],"fill":[[0,0]]},"add_g1_continuous":[],"remove_g1_continuous":[]}},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::vector_data::modification::VectorModification","alias":null}},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::vector_data::modification::PathModifyNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[18015048324114736039,{"inputs":[{"Value":{"tagged_value":{"VectorData":{"instance":[{"style":{"stroke":{"color":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0},"weight":0.0,"dash_lengths":[],"dash_offset":0.0,"cap":"Butt","join":"Miter","join_miter_limit":4.0,"align":"Center","transform":[1.0,0.0,0.0,1.0,0.0,0.0],"non_scaling":false,"paint_order":"StrokeAbove"},"fill":"None"},"colinear_manipulators":[],"point_domain":{"id":[],"position":[]},"segment_domain":{"id":[],"start_point":[],"end_point":[],"handles":[],"stroke":[]},"region_domain":{"id":[],"segment_range":[],"fill":[]},"upstream_graphic_group":null}],"transform":[[1.0,0.0,0.0,1.0,0.0,0.0]],"alpha_blending":[{"blend_mode":"Normal","opacity":1.0,"fill":1.0,"clip":false}],"source_node_id":[null]}},"exposed":true}},{"Value":{"tagged_value":{"VectorModification":{"points":{"add":[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29],"remove":[],"delta":[[26,[752.1975308641976,172.83950617283952]],[12,[603.4567901234568,92.8395061728395]],[6,[617.283950617284,44.641975308641975]],[10,[597.530864197531,73.08641975308642]],[1,[687.4074074074074,99.1604938271605]],[13,[616.2962962962963,115.16049382716052]],[16,[672.5925925925926,176.5925925925926]],[19,[797.8271604938273,246.1234567901235]],[3,[675.3580246913581,68.74074074074075]],[2,[683.0617283950618,104.2962962962963]],[29,[705.1851851851852,106.27160493827162]],[4,[654.4197530864197,54.91358024691358]],[20,[805.1358024691358,260.34567901234567]],[9,[609.3827160493827,43.65432098765433]],[22,[785.9753086419753,197.13580246913585]],[7,[607.2098765432099,55.308641975308646]],[11,[596.9382716049383,85.13580246913581]],[23,[760.8888888888889,175.80246913580248]],[15,[664.8888888888889,140.64197530864195]],[14,[630.716049382716,132.3456790123457]],[21,[805.925925925926,230.9135802469136]],[25,[737.7777777777778,170.07407407407408]],[27,[722.1728395061729,147.1604938271605]],[5,[639.8024691358025,44.24691358024691]],[28,[730.2716049382716,169.4814814814815]],[8,[613.3333333333334,44.24691358024691]],[24,[746.8641975308642,175.40740740740742]],[18,[799.2098765432099,253.23456790123456]],[17,[757.7283950617285,217.48148148148147]]]},"segments":{"add":[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29],"remove":[],"start_point":[[14,14],[28,28],[25,25],[22,22],[3,3],[5,5],[23,23],[18,18],[2,2],[9,9],[6,6],[10,10],[20,20],[26,26],[8,8],[12,12],[24,24],[21,21],[17,17],[4,4],[19,19],[16,16],[15,15],[29,29],[1,1],[7,7],[13,13],[27,27],[11,11]],"end_point":[[5,6],[24,25],[13,14],[3,4],[7,8],[28,29],[26,27],[4,5],[29,1],[27,28],[20,21],[1,2],[15,16],[14,15],[17,18],[2,3],[21,22],[22,23],[16,17],[19,20],[8,9],[6,7],[25,26],[11,12],[9,10],[10,11],[23,24],[12,13],[18,19]],"handle_primary":[[16,[29.23456790123464,10.666666666666686]],[1,[-2.1728395061728634,1.5802469135802255]],[13,[2.370370370370324,7.308641975308632]],[8,[-1.1851851851851052,-1.1851851851851904]],[26,[0.0,0.0]],[14,[5.728395061728293,2.370370370370381]],[12,[5.728395061728406,16.98765432098766]],[29,[-13.234567901234527,-3.3580246913580396]],[20,[0.0,0.0]],[6,[-8.09876543209873,4.740740740740733]],[23,[-2.5679012345678984,-0.592592592592581]],[10,[-6.320987654320902,4.740740740740733]],[11,[3.3580246913580822,1.9753086419753176]],[3,[-15.209876543209816,-1.7777777777777717]],[25,[0.0,0.0]],[7,[-0.9876543209876444,-4.740740740740733]],[27,[0.0,0.0]],[9,[-14.024691358024713,15.802469135802482]],[21,[-2.5679012345678984,-9.481481481481469]],[15,[6.913580246913625,9.87654320987656]],[5,[-9.48148148148141,0.9876543209876516]],[24,[-5.3333333333332575,-2.5679012345678984]],[22,[-7.506172839506121,-7.901234567901298]],[19,[4.543209876543187,5.925925925925952]],[18,[0.0,-2.172839506172835]],[4,[-2.3703703703704377,-3.555555555555557]],[28,[0.0,0.0]],[17,[20.594048174910657,8.937919170354007]],[2,[-8.120713305898448,-14.573388203017842]]],"handle_end":[[21,[7.506172839506121,7.901234567901213]],[26,[19.35802469135808,26.864197530864203]],[10,[-3.3580246913580822,-1.9753086419753176]],[27,[-3.7530864197531177,-7.506172839506178]],[22,[2.5679012345678984,0.592592592592581]],[6,[0.0,0.0]],[7,[0.0,0.0]],[12,[0.0,0.0]],[3,[2.3703703703704377,3.555555555555557]],[8,[0.0,0.0]],[9,[0.0,0.0]],[16,[-20.59404817491054,-8.937919170353979]],[15,[0.0,0.0]],[25,[-4.740740740740762,0.790123456790127]],[20,[2.5679012345678984,9.481481481481438]],[19,[0.0,0.0]],[2,[0.0,0.0]],[4,[9.48148148148141,-0.9876543209876444]],[24,[0.0,0.0]],[14,[-6.913580246913625,-9.876543209876502]],[29,[0.0,0.0]],[18,[0.0,0.0]],[1,[0.0,0.0]],[5,[0.0,0.0]],[23,[5.3333333333332575,2.5679012345678984]],[13,[-5.728395061728293,-2.370370370370381]],[28,[17.580246913580254,58.07407407407402]],[17,[0.0,0.0]],[11,[0.0,0.0]]],"stroke":[[18,0],[15,0],[5,0],[16,0],[21,0],[20,0],[3,0],[11,0],[4,0],[25,0],[1,0],[9,0],[26,0],[29,0],[12,0],[13,0],[17,0],[10,0],[19,0],[8,0],[23,0],[6,0],[22,0],[7,0],[24,0],[2,0],[14,0],[28,0],[27,0]]},"regions":{"add":[0],"remove":[],"segment_range":[[0,{"start":1,"end":29}]],"fill":[[0,0]]},"add_g1_continuous":[],"remove_g1_continuous":[]}},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::vector_data::modification::VectorModification","alias":null}},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::vector_data::modification::PathModifyNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[13975451746581400000,{"inputs":[{"Value":{"tagged_value":{"VectorData":{"instance":[{"style":{"stroke":{"color":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0},"weight":0.0,"dash_lengths":[],"dash_offset":0.0,"cap":"Butt","join":"Miter","join_miter_limit":4.0,"align":"Center","transform":[1.0,0.0,0.0,1.0,0.0,0.0],"non_scaling":false,"paint_order":"StrokeAbove"},"fill":"None"},"colinear_manipulators":[],"point_domain":{"id":[],"position":[]},"segment_domain":{"id":[],"start_point":[],"end_point":[],"handles":[],"stroke":[]},"region_domain":{"id":[],"segment_range":[],"fill":[]},"upstream_graphic_group":null}],"transform":[[1.0,0.0,0.0,1.0,0.0,0.0]],"alpha_blending":[{"blend_mode":"Normal","opacity":1.0,"fill":1.0,"clip":false}],"source_node_id":[null]}},"exposed":true}},{"Value":{"tagged_value":{"VectorModification":{"points":{"add":[1,2],"remove":[],"delta":[[1,[835.7333333333332,786.4000000000001]],[2,[901.6,572.8]]]},"segments":{"add":[1,2],"remove":[],"start_point":[[1,1],[2,2]],"end_point":[[1,2],[2,1]],"handle_primary":[[1,[0.0,0.0]],[2,[0.0,0.0]]],"handle_end":[[2,[47.4666666666667,-108.26666666666664]],[1,[-22.399999999999977,109.06666666666648]]],"stroke":[[2,0],[1,0]]},"regions":{"add":[0],"remove":[],"segment_range":[[0,{"start":1,"end":2}]],"fill":[[0,0]]},"add_g1_continuous":[],"remove_g1_continuous":[]}},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::vector_data::modification::VectorModification","alias":null}},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::vector_data::modification::PathModifyNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[13035777574951374461,{"inputs":[{"Value":{"tagged_value":{"VectorData":{"instance":[{"style":{"stroke":{"color":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0},"weight":0.0,"dash_lengths":[],"dash_offset":0.0,"cap":"Butt","join":"Miter","join_miter_limit":4.0,"align":"Center","transform":[1.0,0.0,0.0,1.0,0.0,0.0],"non_scaling":false,"paint_order":"StrokeAbove"},"fill":"None"},"colinear_manipulators":[],"point_domain":{"id":[],"position":[]},"segment_domain":{"id":[],"start_point":[],"end_point":[],"handles":[],"stroke":[]},"region_domain":{"id":[],"segment_range":[],"fill":[]},"upstream_graphic_group":null}],"transform":[[1.0,0.0,0.0,1.0,0.0,0.0]],"alpha_blending":[{"blend_mode":"Normal","opacity":1.0,"fill":1.0,"clip":false}],"source_node_id":[null]}},"exposed":true}},{"Value":{"tagged_value":{"VectorModification":{"points":{"add":[1,2,3],"remove":[],"delta":[[3,[696.8888888888889,697.3333333333333]],[2,[833.7777777777778,573.3333333333333]],[1,[896.0,440.44444444444446]]]},"segments":{"add":[1,2],"remove":[],"start_point":[[2,2],[1,1]],"end_point":[[2,3],[1,2]],"handle_primary":[[1,[0.0,0.0]],[2,[-68.0,92.88888888888891]]],"handle_end":[[2,[0.0,0.0]],[1,[68.0,-92.88888888888891]]],"stroke":[[1,0],[2,0]]},"regions":{"add":[],"remove":[],"segment_range":[],"fill":[]},"add_g1_continuous":[],"remove_g1_continuous":[]}},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::vector_data::modification::VectorModification","alias":null}},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::vector_data::modification::PathModifyNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[3827449344952693766,{"inputs":[{"Node":{"node_id":2440895173483452224,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"PointSpacingType":"Separation"},"exposed":false}},{"Value":{"tagged_value":{"F64":5.0},"exposed":false}},{"Value":{"tagged_value":{"U32":100},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"Bool":false},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":4,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::SubpathSegmentLengthsNode"}},"visible":true,"skip_deduplication":false}],[4,{"inputs":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::BoundlessFootprintNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":2,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::FreezeRealTimeNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MemoNode"}},"visible":true,"skip_deduplication":false}],[1,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::misc::PointSpacingType","alias":null}},"import_index":1}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":2}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":3}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":4}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":5}},{"Network":{"import_type":{"Concrete":{"name":"bool","alias":null}},"import_index":6}},{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::SamplePolylineNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[11565160497886435388,{"inputs":[{"Node":{"node_id":7893851488963635918,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"PointSpacingType":"Separation"},"exposed":false}},{"Value":{"tagged_value":{"F64":6.0},"exposed":false}},{"Value":{"tagged_value":{"U32":100},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"Bool":false},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":4,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::SubpathSegmentLengthsNode"}},"visible":true,"skip_deduplication":false}],[4,{"inputs":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::BoundlessFootprintNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":2,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::FreezeRealTimeNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MemoNode"}},"visible":true,"skip_deduplication":false}],[1,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::misc::PointSpacingType","alias":null}},"import_index":1}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":2}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":3}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":4}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":5}},{"Network":{"import_type":{"Concrete":{"name":"bool","alias":null}},"import_index":6}},{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::SamplePolylineNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[10336592647221792772,{"inputs":[{"Node":{"node_id":16051539163551573193,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"Fill":{"Solid":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}}},"exposed":false}},{"Value":{"tagged_value":{"OptionalColor":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}},"exposed":false}},{"Value":{"tagged_value":{"Gradient":{"stops":[[0.0,{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}],[1.0,{"red":1.0,"green":1.0,"blue":1.0,"alpha":1.0}]],"gradient_type":"Linear","start":[0.0,0.5],"end":[1.0,0.5],"transform":[1.0,0.0,0.0,1.0,0.0,0.0]}},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::FillNode"}},"visible":true,"skip_deduplication":false}],[3535178979443201645,{"inputs":[{"Node":{"node_id":12838133055063962839,"output_index":0,"lambda":false}},{"Node":{"node_id":8240895922641772563,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[14675232891471617236,{"inputs":[{"Value":{"tagged_value":{"VectorData":{"instance":[{"style":{"stroke":{"color":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0},"weight":0.0,"dash_lengths":[],"dash_offset":0.0,"cap":"Butt","join":"Miter","join_miter_limit":4.0,"align":"Center","transform":[1.0,0.0,0.0,1.0,0.0,0.0],"non_scaling":false,"paint_order":"StrokeAbove"},"fill":"None"},"colinear_manipulators":[],"point_domain":{"id":[],"position":[]},"segment_domain":{"id":[],"start_point":[],"end_point":[],"handles":[],"stroke":[]},"region_domain":{"id":[],"segment_range":[],"fill":[]},"upstream_graphic_group":null}],"transform":[[1.0,0.0,0.0,1.0,0.0,0.0]],"alpha_blending":[{"blend_mode":"Normal","opacity":1.0,"fill":1.0,"clip":false}],"source_node_id":[null]}},"exposed":true}},{"Value":{"tagged_value":{"VectorModification":{"points":{"add":[1,2,3],"remove":[],"delta":[[1,[652.8888888888889,822.6666666666666]],[3,[483.9506172839506,1026.7654320987656]],[2,[480.7407407407408,1026.6666666666663]]]},"segments":{"add":[1,2,3],"remove":[],"start_point":[[2,2],[1,1],[3,3]],"end_point":[[2,3],[3,1],[1,2]],"handle_primary":[[1,[0.0,0.0]],[3,[0.0,0.0]],[2,[0.0,0.0]]],"handle_end":[[2,[0.0,0.0]],[1,[26.66666666666669,-58.666666666666515]],[3,[-143.85185185185185,150.07407407407413]]],"stroke":[[1,0],[2,0],[3,0]]},"regions":{"add":[0],"remove":[],"segment_range":[[0,{"start":1,"end":3}]],"fill":[[0,0]]},"add_g1_continuous":[],"remove_g1_continuous":[]}},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::vector_data::modification::VectorModification","alias":null}},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::vector_data::modification::PathModifyNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[14035980686649077716,{"inputs":[{"Node":{"node_id":6666260895482068061,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"Fill":{"Solid":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}}},"exposed":false}},{"Value":{"tagged_value":{"OptionalColor":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}},"exposed":false}},{"Value":{"tagged_value":{"Gradient":{"stops":[[0.0,{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}],[1.0,{"red":1.0,"green":1.0,"blue":1.0,"alpha":1.0}]],"gradient_type":"Linear","start":[0.0,0.5],"end":[1.0,0.5],"transform":[1.0,0.0,0.0,1.0,0.0,0.0]}},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::FillNode"}},"visible":true,"skip_deduplication":false}],[421715625023770179,{"inputs":[{"Node":{"node_id":3670529450440935325,"output_index":0,"lambda":false}},{"Node":{"node_id":3150436463719911922,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[2044103368441997753,{"inputs":[{"Value":{"tagged_value":{"VectorData":{"instance":[{"style":{"stroke":{"color":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0},"weight":0.0,"dash_lengths":[],"dash_offset":0.0,"cap":"Butt","join":"Miter","join_miter_limit":4.0,"align":"Center","transform":[1.0,0.0,0.0,1.0,0.0,0.0],"non_scaling":false,"paint_order":"StrokeAbove"},"fill":"None"},"colinear_manipulators":[],"point_domain":{"id":[],"position":[]},"segment_domain":{"id":[],"start_point":[],"end_point":[],"handles":[],"stroke":[]},"region_domain":{"id":[],"segment_range":[],"fill":[]},"upstream_graphic_group":null}],"transform":[[1.0,0.0,0.0,1.0,0.0,0.0]],"alpha_blending":[{"blend_mode":"Normal","opacity":1.0,"fill":1.0,"clip":false}],"source_node_id":[null]}},"exposed":true}},{"Value":{"tagged_value":{"VectorModification":{"points":{"add":[1,2,3,4,5,6,7,8],"remove":[],"delta":[[4,[796.4444444444446,278.12345679012356]],[7,[710.7160493827162,200.09876543209884]],[1,[710.5185185185186,302.2222222222223]],[3,[747.6543209876543,394.6666666666667]],[2,[723.3580246913581,337.97530864197535]],[8,[694.5185185185187,204.8395061728396]],[5,[793.6790123456792,258.7654320987655]],[6,[756.7407407407409,223.40740740740748]]]},"segments":{"add":[1,2,3,4,5,6,7,8],"remove":[],"start_point":[[7,7],[8,8],[1,1],[6,6],[3,3],[5,5],[4,4],[2,2]],"end_point":[[7,8],[6,7],[2,3],[8,1],[1,2],[4,5],[5,6],[3,4]],"handle_primary":[[2,[0.0,0.0]],[1,[0.0,0.0]],[6,[-22.518518518518476,-12.641975308641976]],[5,[-5.135802469135797,-10.271604938271594]],[7,[0.0,0.0]],[4,[0.0,0.0]],[3,[0.0,0.0]],[8,[0.0,0.0]]],"handle_end":[[3,[-12.049382716049422,68.54320987654324]],[6,[0.0,0.0]],[8,[7.111111111110972,-82.76543209876547]],[1,[1.3827160493826796,-12.641975308641976]],[4,[5.135802469135797,10.271604938271594]],[7,[8.117474523314513,-0.7895812719984008]],[5,[22.518518518518476,12.641975308641976]],[2,[-10.864197530864203,-35.5555555555556]]],"stroke":[[4,0],[6,0],[1,0],[5,0],[2,0],[8,0],[3,0],[7,0]]},"regions":{"add":[0],"remove":[],"segment_range":[[0,{"start":1,"end":8}]],"fill":[[0,0]]},"add_g1_continuous":[],"remove_g1_continuous":[]}},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::vector_data::modification::VectorModification","alias":null}},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::vector_data::modification::PathModifyNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[6124821161363551058,{"inputs":[{"Node":{"node_id":10420981328998103391,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"PointSpacingType":"Separation"},"exposed":false}},{"Value":{"tagged_value":{"F64":5.0},"exposed":false}},{"Value":{"tagged_value":{"U32":100},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"Bool":false},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":4,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::SubpathSegmentLengthsNode"}},"visible":true,"skip_deduplication":false}],[4,{"inputs":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::BoundlessFootprintNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":2,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::FreezeRealTimeNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MemoNode"}},"visible":true,"skip_deduplication":false}],[1,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::misc::PointSpacingType","alias":null}},"import_index":1}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":2}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":3}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":4}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":5}},{"Network":{"import_type":{"Concrete":{"name":"bool","alias":null}},"import_index":6}},{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::SamplePolylineNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[6749771744300551215,{"inputs":[{"Value":{"tagged_value":{"VectorData":{"instance":[{"style":{"stroke":{"color":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0},"weight":0.0,"dash_lengths":[],"dash_offset":0.0,"cap":"Butt","join":"Miter","join_miter_limit":4.0,"align":"Center","transform":[1.0,0.0,0.0,1.0,0.0,0.0],"non_scaling":false,"paint_order":"StrokeAbove"},"fill":"None"},"colinear_manipulators":[],"point_domain":{"id":[],"position":[]},"segment_domain":{"id":[],"start_point":[],"end_point":[],"handles":[],"stroke":[]},"region_domain":{"id":[],"segment_range":[],"fill":[]},"upstream_graphic_group":null}],"transform":[[1.0,0.0,0.0,1.0,0.0,0.0]],"alpha_blending":[{"blend_mode":"Normal","opacity":1.0,"fill":1.0,"clip":false}],"source_node_id":[null]}},"exposed":true}},{"Value":{"tagged_value":{"VectorModification":{"points":{"add":[1,2,3,4,5],"remove":[],"delta":[[1,[589.3333333333333,1025.3333333333333]],[5,[585.3333333333333,1025.7777777777778]],[3,[726.6666666666666,765.3333333333333]],[2,[660.4444444444443,878.2222222222222]],[4,[620.8888888888888,943.5555555555557]]]},"segments":{"add":[1,2,3,4,5],"remove":[],"start_point":[[4,4],[1,1],[2,2],[5,5],[3,3]],"end_point":[[3,4],[2,3],[5,1],[1,2],[4,5]],"handle_primary":[[5,[0.0,0.0]],[1,[0.0,0.0]],[2,[31.11111111111109,-50.66666666666663]],[4,[-29.333333333333258,59.11111111111097]],[3,[0.0,0.0]]],"handle_end":[[5,[-0.4444444444443434,0.8888888888889142]],[2,[0.0,0.0]],[4,[0.0,0.0]],[3,[29.333333333333258,-59.1111111111112]],[1,[-31.863450886870623,51.89190573004646]]],"stroke":[[3,0],[1,0],[4,0],[2,0],[5,0]]},"regions":{"add":[0],"remove":[],"segment_range":[[0,{"start":1,"end":5}]],"fill":[[0,0]]},"add_g1_continuous":[],"remove_g1_continuous":[]}},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::vector_data::modification::VectorModification","alias":null}},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::vector_data::modification::PathModifyNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[2440895173483452224,{"inputs":[{"Value":{"tagged_value":{"VectorData":{"instance":[{"style":{"stroke":{"color":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0},"weight":0.0,"dash_lengths":[],"dash_offset":0.0,"cap":"Butt","join":"Miter","join_miter_limit":4.0,"align":"Center","transform":[1.0,0.0,0.0,1.0,0.0,0.0],"non_scaling":false,"paint_order":"StrokeAbove"},"fill":"None"},"colinear_manipulators":[],"point_domain":{"id":[],"position":[]},"segment_domain":{"id":[],"start_point":[],"end_point":[],"handles":[],"stroke":[]},"region_domain":{"id":[],"segment_range":[],"fill":[]},"upstream_graphic_group":null}],"transform":[[1.0,0.0,0.0,1.0,0.0,0.0]],"alpha_blending":[{"blend_mode":"Normal","opacity":1.0,"fill":1.0,"clip":false}],"source_node_id":[null]}},"exposed":true}},{"Value":{"tagged_value":{"VectorModification":{"points":{"add":[1,2,3],"remove":[],"delta":[[3,[33.18518518518515,636.148148148148]],[1,[93.037037037037,526.8148148148147]],[2,[30.814814814814767,578.0740740740739]]]},"segments":{"add":[1,2],"remove":[],"start_point":[[2,2],[1,1]],"end_point":[[1,2],[2,3]],"handle_primary":[[2,[-9.185185185185162,39.703703703703695]],[1,[0.0,0.0]]],"handle_end":[[1,[9.185185185185162,-39.703703703703695]],[2,[0.0,0.0]]],"stroke":[[1,0],[2,0]]},"regions":{"add":[],"remove":[],"segment_range":[],"fill":[]},"add_g1_continuous":[],"remove_g1_continuous":[]}},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::vector_data::modification::VectorModification","alias":null}},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::vector_data::modification::PathModifyNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[11356586238302409958,{"inputs":[{"Value":{"tagged_value":{"VectorData":{"instance":[{"style":{"stroke":{"color":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0},"weight":0.0,"dash_lengths":[],"dash_offset":0.0,"cap":"Butt","join":"Miter","join_miter_limit":4.0,"align":"Center","transform":[1.0,0.0,0.0,1.0,0.0,0.0],"non_scaling":false,"paint_order":"StrokeAbove"},"fill":"None"},"colinear_manipulators":[],"point_domain":{"id":[],"position":[]},"segment_domain":{"id":[],"start_point":[],"end_point":[],"handles":[],"stroke":[]},"region_domain":{"id":[],"segment_range":[],"fill":[]},"upstream_graphic_group":null}],"transform":[[1.0,0.0,0.0,1.0,0.0,0.0]],"alpha_blending":[{"blend_mode":"Normal","opacity":1.0,"fill":1.0,"clip":false}],"source_node_id":[null]}},"exposed":true}},{"Value":{"tagged_value":{"VectorModification":{"points":{"add":[1,2,3,4,5,6],"remove":[],"delta":[[3,[732.148148148148,432.2962962962963]],[5,[811.8518518518518,273.18518518518516]],[4,[777.7777777777778,375.7037037037037]],[6,[792.2962962962963,188.74074074074073]],[1,[811.5555555555555,250.96296296296296]],[2,[783.1111111111111,348.74074074074065]]]},"segments":{"add":[1,2,3,4,5],"remove":[],"start_point":[[2,2],[5,5],[1,1],[4,4],[3,3]],"end_point":[[1,2],[3,4],[2,3],[5,6],[4,5]],"handle_primary":[[3,[0.0,0.0]],[2,[-14.6604291210798,34.80924611318039]],[5,[3.7834358363461433,-27.565032521950258]],[1,[0.0,0.0]],[4,[10.310300340717504,-19.181954122264813]]],"handle_end":[[2,[26.666666666666515,-35.555555555555486]],[4,[-4.148148148148152,30.22222222222223]],[5,[26.074074074074133,33.18518518518516]],[1,[14.6604291210798,-34.809246113180336]],[3,[-12.740740740740875,23.703703703703695]]],"stroke":[[2,0],[5,0],[3,0],[1,0],[4,0]]},"regions":{"add":[],"remove":[],"segment_range":[],"fill":[]},"add_g1_continuous":[],"remove_g1_continuous":[]}},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::vector_data::modification::VectorModification","alias":null}},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::vector_data::modification::PathModifyNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[13231685386999438557,{"inputs":[{"Node":{"node_id":1659518581611333812,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"Fill":{"Solid":{"red":0.8980392,"green":0.8,"blue":0.6117647,"alpha":1.0}}},"exposed":false}},{"Value":{"tagged_value":{"OptionalColor":{"red":0.8980392,"green":0.8,"blue":0.6117647,"alpha":1.0}},"exposed":false}},{"Value":{"tagged_value":{"Gradient":{"stops":[[0.0,{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}],[1.0,{"red":1.0,"green":1.0,"blue":1.0,"alpha":1.0}]],"gradient_type":"Linear","start":[0.0,0.5],"end":[1.0,0.5],"transform":[1.0,0.0,0.0,1.0,0.0,0.0]}},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::FillNode"}},"visible":true,"skip_deduplication":false}],[9371909264427723282,{"inputs":[{"Node":{"node_id":8595304668947966919,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"Fill":{"Solid":{"red":0.84705883,"green":0.5372549,"blue":0.38431373,"alpha":1.0}}},"exposed":false}},{"Value":{"tagged_value":{"OptionalColor":{"red":0.84705883,"green":0.5372549,"blue":0.38431373,"alpha":1.0}},"exposed":false}},{"Value":{"tagged_value":{"Gradient":{"stops":[[0.0,{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}],[1.0,{"red":1.0,"green":1.0,"blue":1.0,"alpha":1.0}]],"gradient_type":"Linear","start":[0.0,0.5],"end":[1.0,0.5],"transform":[1.0,0.0,0.0,1.0,0.0,0.0]}},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::FillNode"}},"visible":true,"skip_deduplication":false}],[9782123335421401489,{"inputs":[{"Node":{"node_id":11656581020969095354,"output_index":0,"lambda":false}},{"Node":{"node_id":1019037285881657884,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[2780251074492832077,{"inputs":[{"Value":{"tagged_value":{"VectorData":{"instance":[{"style":{"stroke":{"color":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0},"weight":0.0,"dash_lengths":[],"dash_offset":0.0,"cap":"Butt","join":"Miter","join_miter_limit":4.0,"align":"Center","transform":[1.0,0.0,0.0,1.0,0.0,0.0],"non_scaling":false,"paint_order":"StrokeAbove"},"fill":"None"},"colinear_manipulators":[],"point_domain":{"id":[],"position":[]},"segment_domain":{"id":[],"start_point":[],"end_point":[],"handles":[],"stroke":[]},"region_domain":{"id":[],"segment_range":[],"fill":[]},"upstream_graphic_group":null}],"transform":[[1.0,0.0,0.0,1.0,0.0,0.0]],"alpha_blending":[{"blend_mode":"Normal","opacity":1.0,"fill":1.0,"clip":false}],"source_node_id":[null]}},"exposed":true}},{"Value":{"tagged_value":{"VectorModification":{"points":{"add":[1,2,3,4],"remove":[],"delta":[[2,[644.0435005900861,214.94345295604788]],[4,[654.5349442975197,224.51689533908117]],[3,[679.189837009989,239.99177480754585]],[1,[620.0443231093315,208.38630063890184]]]},"segments":{"add":[1,2,3,4],"remove":[],"start_point":[[4,4],[2,2],[3,3],[1,1]],"end_point":[[2,3],[1,2],[3,4],[4,1]],"handle_primary":[[2,[17.048596024579638,8.262011919603992]],[1,[0.0,0.0]],[4,[-14.688021190407198,-10.884872846462486]],[3,[0.0,0.0]]],"handle_end":[[2,[-15.868308607493532,-9.835728475719122]],[3,[13.4932102981968,9.999432631699392]],[1,[-9.660678057982182,-4.68171321271447]],[4,[0.1311430463429133,0.13114304634288487]]],"stroke":[[4,0],[3,0],[2,0],[1,0]]},"regions":{"add":[0],"remove":[],"segment_range":[[0,{"start":1,"end":4}]],"fill":[[0,0]]},"add_g1_continuous":[],"remove_g1_continuous":[]}},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::vector_data::modification::VectorModification","alias":null}},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::vector_data::modification::PathModifyNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[17118107476414252025,{"inputs":[{"Node":{"node_id":6645255982686652881,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"DVec2":[74.2222222222222,480.0]},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[40.0,40.0]},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[0.0,0.0]},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[0.5,0.5]},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":1}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":2}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":3}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":4}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":5}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::TransformNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[3627710206997006419,{"inputs":[{"Value":{"tagged_value":{"VectorData":{"instance":[{"style":{"stroke":{"color":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0},"weight":0.0,"dash_lengths":[],"dash_offset":0.0,"cap":"Butt","join":"Miter","join_miter_limit":4.0,"align":"Center","transform":[1.0,0.0,0.0,1.0,0.0,0.0],"non_scaling":false,"paint_order":"StrokeAbove"},"fill":"None"},"colinear_manipulators":[],"point_domain":{"id":[],"position":[]},"segment_domain":{"id":[],"start_point":[],"end_point":[],"handles":[],"stroke":[]},"region_domain":{"id":[],"segment_range":[],"fill":[]},"upstream_graphic_group":null}],"transform":[[1.0,0.0,0.0,1.0,0.0,0.0]],"alpha_blending":[{"blend_mode":"Normal","opacity":1.0,"fill":1.0,"clip":false}],"source_node_id":[null]}},"exposed":true}},{"Value":{"tagged_value":{"VectorModification":{"points":{"add":[1,2,3],"remove":[],"delta":[[1,[152.49382716049382,262.71604938271605]],[3,[154.2366898148148,257.4780574845679]],[2,[149.94787379972564,262.84773662551436]]]},"segments":{"add":[1,2,3],"remove":[],"start_point":[[3,3],[2,2],[1,1]],"end_point":[[3,1],[1,2],[2,3]],"handle_primary":[[2,[-0.2633744855966995,-0.4389574759944139]],[3,[4.31137018907981,-2.5386217986682027]],[1,[0.0,0.0]]],"handle_end":[[2,[-3.3775342902714556,1.988760370600971]],[1,[0.4650366425890411,0.7750610709815646]],[3,[2.8421709430404014e-14,0.0]]],"stroke":[[2,0],[3,0],[1,0]]},"regions":{"add":[0],"remove":[],"segment_range":[[0,{"start":1,"end":3}]],"fill":[[0,0]]},"add_g1_continuous":[],"remove_g1_continuous":[]}},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::vector_data::modification::VectorModification","alias":null}},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::vector_data::modification::PathModifyNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[12838133055063962839,{"inputs":[{"Node":{"node_id":13644138583806412631,"output_index":0,"lambda":false}},{"Node":{"node_id":6973438081601736688,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[7922156219537051964,{"inputs":[{"Node":{"node_id":13594670583065022897,"output_index":0,"lambda":false}},{"Node":{"node_id":17078740291337047697,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"F64":1.2},"exposed":false}},{"Value":{"tagged_value":{"F64":2.0},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"U32":0},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"U32":0},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::CopyToPointsNode"}},"visible":true,"skip_deduplication":false}],[15446793500614592278,{"inputs":[{"Value":{"tagged_value":{"VectorData":{"instance":[{"style":{"stroke":{"color":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0},"weight":0.0,"dash_lengths":[],"dash_offset":0.0,"cap":"Butt","join":"Miter","join_miter_limit":4.0,"align":"Center","transform":[1.0,0.0,0.0,1.0,0.0,0.0],"non_scaling":false,"paint_order":"StrokeAbove"},"fill":"None"},"colinear_manipulators":[],"point_domain":{"id":[],"position":[]},"segment_domain":{"id":[],"start_point":[],"end_point":[],"handles":[],"stroke":[]},"region_domain":{"id":[],"segment_range":[],"fill":[]},"upstream_graphic_group":null}],"transform":[[1.0,0.0,0.0,1.0,0.0,0.0]],"alpha_blending":[{"blend_mode":"Normal","opacity":1.0,"fill":1.0,"clip":false}],"source_node_id":[null]}},"exposed":true}},{"Value":{"tagged_value":{"VectorModification":{"points":{"add":[1,2,3,4,5,6,7,8],"remove":[],"delta":[[3,[722.3484224965707,77.2565157750343]],[5,[718.2222222222222,97.09739368998628]],[7,[718.3100137174213,77.2565157750343]],[1,[694.3429355281208,73.8326474622771]],[4,[725.5967078189301,90.3374485596708]],[8,[697.5034293552812,77.4320987654321]],[6,[724.6310013717421,85.86008230452676]],[2,[702.244170096022,76.11522633744856]]]},"segments":{"add":[1,2,3,4,5,6,7,8],"remove":[],"start_point":[[3,3],[4,4],[8,8],[1,1],[5,5],[7,7],[2,2],[6,6]],"end_point":[[4,5],[1,2],[5,6],[6,7],[3,4],[7,8],[8,1],[2,3]],"handle_primary":[[6,[-0.7023319615914261,-5.091906721536347]],[5,[0.0,0.0]],[1,[0.0,0.0]],[8,[-3.5116598079559935,-1.6680384087791396]],[7,[-6.236870142765838,-1.74052190030676]],[4,[-1.9392278971834005,5.143169640356035]],[2,[5.267489711934218,-0.7023319615912129]],[3,[3.456189131014753,3.3025807251918877]]],"handle_end":[[3,[2.0192043895747247,-5.355281207133089]],[6,[3.7750342935527215,1.0534979423868265]],[4,[0.0,0.0]],[2,[-3.950617283950578,-3.775034293552821]],[1,[-5.267489711934218,0.7023319615912129]],[8,[0.08779149519887142,0.08779149519891405]],[5,[0.6823799889585871,4.947254919948108]],[7,[3.5116598079559935,1.6680384087791396]]],"stroke":[[3,0],[1,0],[5,0],[6,0],[2,0],[4,0],[7,0],[8,0]]},"regions":{"add":[0],"remove":[],"segment_range":[[0,{"start":1,"end":8}]],"fill":[[0,0]]},"add_g1_continuous":[],"remove_g1_continuous":[]}},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::vector_data::modification::VectorModification","alias":null}},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::vector_data::modification::PathModifyNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[9684857454501250999,{"inputs":[{"Node":{"node_id":8699675339613677057,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"Fill":{"Solid":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}}},"exposed":false}},{"Value":{"tagged_value":{"OptionalColor":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}},"exposed":false}},{"Value":{"tagged_value":{"Gradient":{"stops":[[0.0,{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}],[1.0,{"red":1.0,"green":1.0,"blue":1.0,"alpha":1.0}]],"gradient_type":"Linear","start":[0.0,0.5],"end":[1.0,0.5],"transform":[1.0,0.0,0.0,1.0,0.0,0.0]}},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::FillNode"}},"visible":true,"skip_deduplication":false}],[13444661581815146533,{"inputs":[{"Node":{"node_id":16450742929146919960,"output_index":0,"lambda":false}},{"Node":{"node_id":10792166025753022402,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[14993053984267866751,{"inputs":[{"Node":{"node_id":13907578809542898348,"output_index":0,"lambda":false}},{"Node":{"node_id":9863310024364795214,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[16195626650123806176,{"inputs":[{"Node":{"node_id":14057307926677215422,"output_index":0,"lambda":false}},{"Node":{"node_id":1869448627329502330,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[18279507457571359732,{"inputs":[{"Node":{"node_id":8697043784435445845,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"Fill":{"Solid":{"red":0.8980392,"green":0.8,"blue":0.6117647,"alpha":1.0}}},"exposed":false}},{"Value":{"tagged_value":{"OptionalColor":{"red":0.8980392,"green":0.8,"blue":0.6117647,"alpha":1.0}},"exposed":false}},{"Value":{"tagged_value":{"Gradient":{"stops":[[0.0,{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}],[1.0,{"red":1.0,"green":1.0,"blue":1.0,"alpha":1.0}]],"gradient_type":"Linear","start":[0.0,0.5],"end":[1.0,0.5],"transform":[1.0,0.0,0.0,1.0,0.0,0.0]}},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::FillNode"}},"visible":true,"skip_deduplication":false}],[3121275823460307102,{"inputs":[{"Value":{"tagged_value":{"VectorData":{"instance":[{"style":{"stroke":{"color":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0},"weight":0.0,"dash_lengths":[],"dash_offset":0.0,"cap":"Butt","join":"Miter","join_miter_limit":4.0,"align":"Center","transform":[1.0,0.0,0.0,1.0,0.0,0.0],"non_scaling":false,"paint_order":"StrokeAbove"},"fill":"None"},"colinear_manipulators":[],"point_domain":{"id":[],"position":[]},"segment_domain":{"id":[],"start_point":[],"end_point":[],"handles":[],"stroke":[]},"region_domain":{"id":[],"segment_range":[],"fill":[]},"upstream_graphic_group":null}],"transform":[[1.0,0.0,0.0,1.0,0.0,0.0]],"alpha_blending":[{"blend_mode":"Normal","opacity":1.0,"fill":1.0,"clip":false}],"source_node_id":[null]}},"exposed":true}},{"Value":{"tagged_value":{"VectorModification":{"points":{"add":[1,2,3,4,5],"remove":[],"delta":[[2,[612.0,780.0]],[5,[595.5555555555555,791.1111111111111]],[4,[449.77777777777777,1025.7777777777778]],[3,[452.88888888888886,1025.3333333333333]],[1,[705.7777777777778,698.6666666666666]]]},"segments":{"add":[1,2,3,4,5],"remove":[],"start_point":[[5,5],[1,1],[3,3],[2,2],[4,4]],"end_point":[[4,5],[3,4],[1,2],[2,3],[5,1]],"handle_primary":[[1,[0.0,0.0]],[2,[-35.111111111111086,34.66666666666663]],[3,[0.0,0.0]],[5,[54.93054949731868,-52.22097082256312]],[4,[0.0,0.0]]],"handle_end":[[1,[35.111111111111086,-34.66666666666663]],[5,[-1.1368683772161605e-13,-0.5925925925926094]],[3,[0.0,0.0]],[2,[59.111111111111086,-144.8888888888889]],[4,[-99.11111111111104,94.22222222222229]]],"stroke":[[3,0],[2,0],[4,0],[1,0],[5,0]]},"regions":{"add":[0],"remove":[],"segment_range":[[0,{"start":1,"end":5}]],"fill":[[0,0]]},"add_g1_continuous":[],"remove_g1_continuous":[]}},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::vector_data::modification::VectorModification","alias":null}},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::vector_data::modification::PathModifyNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[13269760558336088742,{"inputs":[{"Value":{"tagged_value":{"VectorData":{"instance":[{"style":{"stroke":{"color":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0},"weight":0.0,"dash_lengths":[],"dash_offset":0.0,"cap":"Butt","join":"Miter","join_miter_limit":4.0,"align":"Center","transform":[1.0,0.0,0.0,1.0,0.0,0.0],"non_scaling":false,"paint_order":"StrokeAbove"},"fill":"None"},"colinear_manipulators":[],"point_domain":{"id":[],"position":[]},"segment_domain":{"id":[],"start_point":[],"end_point":[],"handles":[],"stroke":[]},"region_domain":{"id":[],"segment_range":[],"fill":[]},"upstream_graphic_group":null}],"transform":[[1.0,0.0,0.0,1.0,0.0,0.0]],"alpha_blending":[{"blend_mode":"Normal","opacity":1.0,"fill":1.0,"clip":false}],"source_node_id":[null]}},"exposed":true}},{"Value":{"tagged_value":{"VectorModification":{"points":{"add":[1,2,3,4,5],"remove":[],"delta":[[5,[756.4444444444443,438.22222222222223]],[3,[595.1111111111111,439.55555555555554]],[1,[265.3333333333333,312.0]],[2,[447.1111111111111,332.44444444444446]],[4,[698.2222222222222,483.1111111111111]]]},"segments":{"add":[1,2,3,4],"remove":[],"start_point":[[3,3],[2,2],[4,4],[1,1]],"end_point":[[3,4],[4,5],[1,2],[2,3]],"handle_primary":[[1,[0.0,0.0]],[3,[20.8888888888888,20.444444444444457]],[2,[83.95959630801838,35.04735442215451]],[4,[22.46059594926794,-9.800987323316916]]],"handle_end":[[2,[-20.8888888888888,-20.444444444444457]],[1,[-96.88888888888886,-40.44444444444446]],[3,[-48.888888888888914,21.33333333333331]],[4,[-22.222222222222285,23.111111111111143]]],"stroke":[[2,0],[4,0],[3,0],[1,0]]},"regions":{"add":[],"remove":[],"segment_range":[],"fill":[]},"add_g1_continuous":[],"remove_g1_continuous":[]}},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::vector_data::modification::VectorModification","alias":null}},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::vector_data::modification::PathModifyNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[11590691579869262546,{"inputs":[{"Node":{"node_id":11553850607251055696,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"Fill":{"Solid":{"red":0.8980392,"green":0.8,"blue":0.6117647,"alpha":1.0}}},"exposed":false}},{"Value":{"tagged_value":{"OptionalColor":{"red":0.8980392,"green":0.8,"blue":0.6117647,"alpha":1.0}},"exposed":false}},{"Value":{"tagged_value":{"Gradient":{"stops":[[0.0,{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}],[1.0,{"red":1.0,"green":1.0,"blue":1.0,"alpha":1.0}]],"gradient_type":"Linear","start":[0.0,0.5],"end":[1.0,0.5],"transform":[1.0,0.0,0.0,1.0,0.0,0.0]}},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::FillNode"}},"visible":true,"skip_deduplication":false}],[13481022631108980683,{"inputs":[{"Node":{"node_id":9182448229950585507,"output_index":0,"lambda":false}},{"Node":{"node_id":12224498203743157414,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[14797986717815207528,{"inputs":[{"Value":{"tagged_value":{"VectorData":{"instance":[{"style":{"stroke":{"color":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0},"weight":0.0,"dash_lengths":[],"dash_offset":0.0,"cap":"Butt","join":"Miter","join_miter_limit":4.0,"align":"Center","transform":[1.0,0.0,0.0,1.0,0.0,0.0],"non_scaling":false,"paint_order":"StrokeAbove"},"fill":"None"},"colinear_manipulators":[],"point_domain":{"id":[],"position":[]},"segment_domain":{"id":[],"start_point":[],"end_point":[],"handles":[],"stroke":[]},"region_domain":{"id":[],"segment_range":[],"fill":[]},"upstream_graphic_group":null}],"transform":[[1.0,0.0,0.0,1.0,0.0,0.0]],"alpha_blending":[{"blend_mode":"Normal","opacity":1.0,"fill":1.0,"clip":false}],"source_node_id":[null]}},"exposed":true}},{"Value":{"tagged_value":{"VectorModification":{"points":{"add":[1,2,3,4,5],"remove":[],"delta":[[5,[868.0,380.44444444444446]],[4,[826.6666666666665,552.4444444444443]],[3,[665.7777777777778,658.6666666666667]],[1,[80.0,557.0]],[2,[425.0,650.0]]]},"segments":{"add":[1,2,3,4],"remove":[],"start_point":[[2,2],[3,3],[1,1],[4,4]],"end_point":[[4,5],[3,4],[2,3],[1,2]],"handle_primary":[[4,[59.11111111111131,-70.66666666666652]],[3,[0.0,0.0]],[1,[134.0,-75.0]],[2,[105.59298295237464,48.735222901095995]]],"handle_end":[[4,[0.0,0.0]],[2,[0.0,0.0]],[1,[-104.0,-48.0]],[3,[-59.11111111111131,70.66666666666652]]],"stroke":[[3,0],[1,0],[2,0],[4,0]]},"regions":{"add":[],"remove":[],"segment_range":[],"fill":[]},"add_g1_continuous":[],"remove_g1_continuous":[]}},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::vector_data::modification::VectorModification","alias":null}},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::vector_data::modification::PathModifyNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[5861306074868809692,{"inputs":[{"Node":{"node_id":10190227675276560561,"output_index":0,"lambda":false}},{"Node":{"node_id":3636653585682494814,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[13907578809542898348,{"inputs":[{"Node":{"node_id":12313564802550122052,"output_index":0,"lambda":false}},{"Node":{"node_id":15827578515555598997,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[581013017684525986,{"inputs":[{"Value":{"tagged_value":{"VectorData":{"instance":[{"style":{"stroke":{"color":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0},"weight":0.0,"dash_lengths":[],"dash_offset":0.0,"cap":"Butt","join":"Miter","join_miter_limit":4.0,"align":"Center","transform":[1.0,0.0,0.0,1.0,0.0,0.0],"non_scaling":false,"paint_order":"StrokeAbove"},"fill":"None"},"colinear_manipulators":[],"point_domain":{"id":[],"position":[]},"segment_domain":{"id":[],"start_point":[],"end_point":[],"handles":[],"stroke":[]},"region_domain":{"id":[],"segment_range":[],"fill":[]},"upstream_graphic_group":null}],"transform":[[1.0,0.0,0.0,1.0,0.0,0.0]],"alpha_blending":[{"blend_mode":"Normal","opacity":1.0,"fill":1.0,"clip":false}],"source_node_id":[null]}},"exposed":true}},{"Value":{"tagged_value":{"VectorModification":{"points":{"add":[1,2],"remove":[],"delta":[[1,[803.5555555555554,878.6666666666665]],[2,[852.0,631.1111111111111]]]},"segments":{"add":[1,2],"remove":[],"start_point":[[1,1],[2,2]],"end_point":[[1,2],[2,1]],"handle_primary":[[2,[-41.77777777777783,81.77777777777771]],[1,[0.0,0.0]]],"handle_end":[[1,[-37.77777777777783,80.88888888888903]],[2,[0.0,-0.4444444444443434]]],"stroke":[[2,0],[1,0]]},"regions":{"add":[0],"remove":[],"segment_range":[[0,{"start":1,"end":2}]],"fill":[[0,0]]},"add_g1_continuous":[],"remove_g1_continuous":[]}},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::vector_data::modification::VectorModification","alias":null}},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::vector_data::modification::PathModifyNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[3670529450440935325,{"inputs":[{"Node":{"node_id":1384427686127078856,"output_index":0,"lambda":false}},{"Node":{"node_id":8543051864256131356,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[12030171742672119253,{"inputs":[{"Node":{"node_id":12801133692316734622,"output_index":0,"lambda":false}},{"Node":{"node_id":17078740291337047697,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"F64":1.2},"exposed":false}},{"Value":{"tagged_value":{"F64":2.0},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"U32":0},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"U32":0},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::CopyToPointsNode"}},"visible":true,"skip_deduplication":false}],[7450965328305122110,{"inputs":[{"Node":{"node_id":2659768650911099730,"output_index":0,"lambda":false}},{"Node":{"node_id":17078740291337047697,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"F64":1.4},"exposed":false}},{"Value":{"tagged_value":{"F64":2.5},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"U32":0},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"U32":0},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::CopyToPointsNode"}},"visible":true,"skip_deduplication":false}],[1806828617441445250,{"inputs":[{"Value":{"tagged_value":{"VectorData":{"instance":[{"style":{"stroke":{"color":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0},"weight":0.0,"dash_lengths":[],"dash_offset":0.0,"cap":"Butt","join":"Miter","join_miter_limit":4.0,"align":"Center","transform":[1.0,0.0,0.0,1.0,0.0,0.0],"non_scaling":false,"paint_order":"StrokeAbove"},"fill":"None"},"colinear_manipulators":[],"point_domain":{"id":[],"position":[]},"segment_domain":{"id":[],"start_point":[],"end_point":[],"handles":[],"stroke":[]},"region_domain":{"id":[],"segment_range":[],"fill":[]},"upstream_graphic_group":null}],"transform":[[1.0,0.0,0.0,1.0,0.0,0.0]],"alpha_blending":[{"blend_mode":"Normal","opacity":1.0,"fill":1.0,"clip":false}],"source_node_id":[null]}},"exposed":true}},{"Value":{"tagged_value":{"VectorModification":{"points":{"add":[1,2,3,4],"remove":[],"delta":[[1,[395.3333333333333,758.0]],[4,[32.0,1025.3333333333333]],[3,[147.33333333333334,814.0000000000001]],[2,[304.6666666666667,765.3333333333333]]]},"segments":{"add":[1,2,3],"remove":[],"start_point":[[3,3],[2,2],[1,1]],"end_point":[[1,2],[2,3],[3,4]],"handle_primary":[[2,[-32.666666666666686,0.6666666666667425]],[1,[0.0,0.0]],[3,[-50.13723402627032,36.301698579412914]]],"handle_end":[[2,[50.137234026270335,-36.301698579412914]],[3,[-0.6666666666666892,-122.66666666666686]],[1,[32.666666666666686,-0.6666666666667425]]],"stroke":[[2,0],[1,0],[3,0]]},"regions":{"add":[],"remove":[],"segment_range":[],"fill":[]},"add_g1_continuous":[],"remove_g1_continuous":[]}},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::vector_data::modification::VectorModification","alias":null}},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::vector_data::modification::PathModifyNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[13475705179546695973,{"inputs":[{"Node":{"node_id":11451028343967836482,"output_index":0,"lambda":false}},{"Node":{"node_id":501401493219507773,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[2594533001540454577,{"inputs":[{"Node":{"node_id":15518174914032911052,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"PointSpacingType":"Separation"},"exposed":false}},{"Value":{"tagged_value":{"F64":8.0},"exposed":false}},{"Value":{"tagged_value":{"U32":100},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"Bool":false},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":4,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::SubpathSegmentLengthsNode"}},"visible":true,"skip_deduplication":false}],[4,{"inputs":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::BoundlessFootprintNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":2,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::FreezeRealTimeNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MemoNode"}},"visible":true,"skip_deduplication":false}],[1,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::misc::PointSpacingType","alias":null}},"import_index":1}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":2}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":3}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":4}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":5}},{"Network":{"import_type":{"Concrete":{"name":"bool","alias":null}},"import_index":6}},{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::SamplePolylineNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[9276497172451351253,{"inputs":[{"Value":{"tagged_value":{"VectorData":{"instance":[{"style":{"stroke":{"color":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0},"weight":0.0,"dash_lengths":[],"dash_offset":0.0,"cap":"Butt","join":"Miter","join_miter_limit":4.0,"align":"Center","transform":[1.0,0.0,0.0,1.0,0.0,0.0],"non_scaling":false,"paint_order":"StrokeAbove"},"fill":"None"},"colinear_manipulators":[],"point_domain":{"id":[],"position":[]},"segment_domain":{"id":[],"start_point":[],"end_point":[],"handles":[],"stroke":[]},"region_domain":{"id":[],"segment_range":[],"fill":[]},"upstream_graphic_group":null}],"transform":[[1.0,0.0,0.0,1.0,0.0,0.0]],"alpha_blending":[{"blend_mode":"Normal","opacity":1.0,"fill":1.0,"clip":false}],"source_node_id":[null]}},"exposed":true}},{"Value":{"tagged_value":{"VectorModification":{"points":{"add":[1,2,3,4],"remove":[],"delta":[[2,[607.1269623532997,114.75323883554336]],[3,[605.1760402377686,111.78783721993597]],[4,[605.9173906416706,103.71101966163694]],[1,[606.8928516994359,102.3453741807651]]]},"segments":{"add":[1,2,3,4],"remove":[],"start_point":[[4,4],[2,2],[3,3],[1,1]],"end_point":[[1,2],[3,4],[4,1],[2,3]],"handle_primary":[[3,[-0.585276634659408,-2.419143423258646]],[2,[0.0,0.0]],[4,[0.27360881696279193,-0.7182231445274425]],[1,[0.0,0.0]]],"handle_end":[[3,[-0.6242950769699291,1.6387745770462772]],[1,[-1.3656454808717626,-5.306508154244753]],[2,[0.585276634659408,2.4191434232586317]],[4,[0.0,0.03901844231063478]]],"stroke":[[3,0],[1,0],[2,0],[4,0]]},"regions":{"add":[0],"remove":[],"segment_range":[[0,{"start":1,"end":4}]],"fill":[[0,0]]},"add_g1_continuous":[],"remove_g1_continuous":[]}},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::vector_data::modification::VectorModification","alias":null}},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::vector_data::modification::PathModifyNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[7821977654068146599,{"inputs":[{"Value":{"tagged_value":{"VectorData":{"instance":[{"style":{"stroke":{"color":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0},"weight":0.0,"dash_lengths":[],"dash_offset":0.0,"cap":"Butt","join":"Miter","join_miter_limit":4.0,"align":"Center","transform":[1.0,0.0,0.0,1.0,0.0,0.0],"non_scaling":false,"paint_order":"StrokeAbove"},"fill":"None"},"colinear_manipulators":[],"point_domain":{"id":[],"position":[]},"segment_domain":{"id":[],"start_point":[],"end_point":[],"handles":[],"stroke":[]},"region_domain":{"id":[],"segment_range":[],"fill":[]},"upstream_graphic_group":null}],"transform":[[1.0,0.0,0.0,1.0,0.0,0.0]],"alpha_blending":[{"blend_mode":"Normal","opacity":1.0,"fill":1.0,"clip":false}],"source_node_id":[null]}},"exposed":true}},{"Value":{"tagged_value":{"VectorModification":{"points":{"add":[1,2,3],"remove":[],"delta":[[3,[825.9524005971,863.6469292802573]],[1,[917.0,471.6]],[2,[826.5068586621596,856.9308484975209]]]},"segments":{"add":[1,2,3],"remove":[],"start_point":[[1,1],[2,2],[3,3]],"end_point":[[1,2],[3,1],[2,3]],"handle_primary":[[1,[0.0,0.0]],[2,[0.0,0.0]],[3,[0.0,0.0]]],"handle_end":[[3,[-0.39999999999997726,191.19999999999985]],[2,[0.0,0.0]],[1,[94.89314133784036,-231.73084849752092]]],"stroke":[[2,0],[3,0],[1,0]]},"regions":{"add":[0],"remove":[],"segment_range":[[0,{"start":1,"end":3}]],"fill":[[0,0]]},"add_g1_continuous":[],"remove_g1_continuous":[]}},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::vector_data::modification::VectorModification","alias":null}},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::vector_data::modification::PathModifyNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[15126865253122550765,{"inputs":[{"Node":{"node_id":13014628586360765651,"output_index":0,"lambda":false}},{"Node":{"node_id":4307303572241320716,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[2682920349304670808,{"inputs":[{"Node":{"node_id":10928540355449103287,"output_index":0,"lambda":false}},{"Node":{"node_id":16324258033206362312,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[13368990606109678244,{"inputs":[{"Node":{"node_id":421715625023770179,"output_index":0,"lambda":false}},{"Node":{"node_id":15961046538654083626,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[16290933138334939444,{"inputs":[{"Node":{"node_id":17426609415699324395,"output_index":0,"lambda":false}},{"Node":{"node_id":14888395629683671889,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[12496143061817048445,{"inputs":[{"Node":{"node_id":7525593029671097583,"output_index":0,"lambda":false}},{"Node":{"node_id":7654665057468818389,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[12880230498984021417,{"inputs":[{"Node":{"node_id":15949658764632267703,"output_index":0,"lambda":false}},{"Node":{"node_id":17078740291337047697,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"F64":1.2},"exposed":false}},{"Value":{"tagged_value":{"F64":2.0},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"U32":0},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"U32":0},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::CopyToPointsNode"}},"visible":true,"skip_deduplication":false}],[14883504161508594099,{"inputs":[{"Node":{"node_id":13368990606109678244,"output_index":0,"lambda":false}},{"Node":{"node_id":11025165626998987360,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[7262199696924786895,{"inputs":[{"Node":{"node_id":14029368390543839187,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"PointSpacingType":"Separation"},"exposed":false}},{"Value":{"tagged_value":{"F64":5.0},"exposed":false}},{"Value":{"tagged_value":{"U32":100},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"Bool":false},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":4,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::SubpathSegmentLengthsNode"}},"visible":true,"skip_deduplication":false}],[4,{"inputs":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::BoundlessFootprintNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":2,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::FreezeRealTimeNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MemoNode"}},"visible":true,"skip_deduplication":false}],[1,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::misc::PointSpacingType","alias":null}},"import_index":1}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":2}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":3}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":4}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":5}},{"Network":{"import_type":{"Concrete":{"name":"bool","alias":null}},"import_index":6}},{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::SamplePolylineNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[952330505278607301,{"inputs":[{"Node":{"node_id":15038739378867834454,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"Fill":{"Solid":{"red":0.8980392,"green":0.8,"blue":0.6117647,"alpha":1.0}}},"exposed":false}},{"Value":{"tagged_value":{"OptionalColor":{"red":0.8980392,"green":0.8,"blue":0.6117647,"alpha":1.0}},"exposed":false}},{"Value":{"tagged_value":{"Gradient":{"stops":[[0.0,{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}],[1.0,{"red":1.0,"green":1.0,"blue":1.0,"alpha":1.0}]],"gradient_type":"Linear","start":[0.0,0.5],"end":[1.0,0.5],"transform":[1.0,0.0,0.0,1.0,0.0,0.0]}},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::FillNode"}},"visible":true,"skip_deduplication":false}],[5302437193964714993,{"inputs":[{"Node":{"node_id":1235106489581249820,"output_index":0,"lambda":false}},{"Node":{"node_id":17078740291337047697,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"F64":1.2},"exposed":false}},{"Value":{"tagged_value":{"F64":2.0},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"U32":0},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"U32":0},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::CopyToPointsNode"}},"visible":true,"skip_deduplication":false}],[10792166025753022402,{"inputs":[{"Node":{"node_id":2780251074492832077,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"Fill":{"Solid":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}}},"exposed":false}},{"Value":{"tagged_value":{"OptionalColor":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}},"exposed":false}},{"Value":{"tagged_value":{"Gradient":{"stops":[[0.0,{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}],[1.0,{"red":1.0,"green":1.0,"blue":1.0,"alpha":1.0}]],"gradient_type":"Linear","start":[0.0,0.5],"end":[1.0,0.5],"transform":[1.0,0.0,0.0,1.0,0.0,0.0]}},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::FillNode"}},"visible":true,"skip_deduplication":false}],[16649851742084147477,{"inputs":[{"Value":{"tagged_value":{"VectorData":{"instance":[{"style":{"stroke":{"color":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0},"weight":0.0,"dash_lengths":[],"dash_offset":0.0,"cap":"Butt","join":"Miter","join_miter_limit":4.0,"align":"Center","transform":[1.0,0.0,0.0,1.0,0.0,0.0],"non_scaling":false,"paint_order":"StrokeAbove"},"fill":"None"},"colinear_manipulators":[],"point_domain":{"id":[],"position":[]},"segment_domain":{"id":[],"start_point":[],"end_point":[],"handles":[],"stroke":[]},"region_domain":{"id":[],"segment_range":[],"fill":[]},"upstream_graphic_group":null}],"transform":[[1.0,0.0,0.0,1.0,0.0,0.0]],"alpha_blending":[{"blend_mode":"Normal","opacity":1.0,"fill":1.0,"clip":false}],"source_node_id":[null]}},"exposed":true}},{"Value":{"tagged_value":{"VectorModification":{"points":{"add":[1,2],"remove":[],"delta":[[2,[838.6666666666666,564.0]],[1,[870.6666666666665,383.55555555555554]]]},"segments":{"add":[1],"remove":[],"start_point":[[1,1]],"end_point":[[1,2]],"handle_primary":[[1,[16.000000000000227,37.33333333333337]]],"handle_end":[[1,[48.44444444444446,-91.11111111111109]]],"stroke":[[1,0]]},"regions":{"add":[],"remove":[],"segment_range":[],"fill":[]},"add_g1_continuous":[],"remove_g1_continuous":[]}},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::vector_data::modification::VectorModification","alias":null}},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::vector_data::modification::PathModifyNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[1272070255512697108,{"inputs":[{"Node":{"node_id":14012648643507848353,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"Fill":{"Solid":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}}},"exposed":false}},{"Value":{"tagged_value":{"OptionalColor":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}},"exposed":false}},{"Value":{"tagged_value":{"Gradient":{"stops":[[0.0,{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}],[1.0,{"red":1.0,"green":1.0,"blue":1.0,"alpha":1.0}]],"gradient_type":"Linear","start":[0.0,0.5],"end":[1.0,0.5],"transform":[1.0,0.0,0.0,1.0,0.0,0.0]}},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::FillNode"}},"visible":true,"skip_deduplication":false}],[17147975601187022720,{"inputs":[{"Node":{"node_id":18015048324114736039,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"Fill":{"Solid":{"red":0.8980392,"green":0.8,"blue":0.6117647,"alpha":1.0}}},"exposed":false}},{"Value":{"tagged_value":{"OptionalColor":{"red":0.8980392,"green":0.8,"blue":0.6117647,"alpha":1.0}},"exposed":false}},{"Value":{"tagged_value":{"Gradient":{"stops":[[0.0,{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}],[1.0,{"red":1.0,"green":1.0,"blue":1.0,"alpha":1.0}]],"gradient_type":"Linear","start":[0.0,0.5],"end":[1.0,0.5],"transform":[1.0,0.0,0.0,1.0,0.0,0.0]}},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::FillNode"}},"visible":true,"skip_deduplication":false}],[15518174914032911052,{"inputs":[{"Value":{"tagged_value":{"VectorData":{"instance":[{"style":{"stroke":{"color":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0},"weight":0.0,"dash_lengths":[],"dash_offset":0.0,"cap":"Butt","join":"Miter","join_miter_limit":4.0,"align":"Center","transform":[1.0,0.0,0.0,1.0,0.0,0.0],"non_scaling":false,"paint_order":"StrokeAbove"},"fill":"None"},"colinear_manipulators":[],"point_domain":{"id":[],"position":[]},"segment_domain":{"id":[],"start_point":[],"end_point":[],"handles":[],"stroke":[]},"region_domain":{"id":[],"segment_range":[],"fill":[]},"upstream_graphic_group":null}],"transform":[[1.0,0.0,0.0,1.0,0.0,0.0]],"alpha_blending":[{"blend_mode":"Normal","opacity":1.0,"fill":1.0,"clip":false}],"source_node_id":[null]}},"exposed":true}},{"Value":{"tagged_value":{"VectorModification":{"points":{"add":[1,2,3,4,5,6],"remove":[],"delta":[[2,[814.2222222222223,498.66666666666663]],[4,[429.7777777777778,551.5555555555555]],[1,[851.5555555555557,370.66666666666663]],[3,[639.1111111111112,614.6666666666666]],[5,[262.6666666666667,423.5555555555556]],[6,[129.77777777777777,406.2222222222222]]]},"segments":{"add":[1,2,3,4,5],"remove":[],"start_point":[[2,2],[5,5],[3,3],[1,1],[4,4]],"end_point":[[3,4],[1,2],[2,3],[4,5],[5,6]],"handle_primary":[[2,[-43.55555555555554,54.66666666666663]],[4,[-74.22222222222217,-57.77777777777783]],[3,[-83.11111111111109,3.111111111111086]],[1,[0.0,0.0]],[5,[-58.2222222222222,-21.77777777777783]]],"handle_end":[[4,[66.87431172777582,25.01405553176352]],[5,[57.333333333333314,-5.777777777777828]],[2,[83.11111111111109,-3.111111111111086]],[3,[74.22222222222217,57.77777777777783]],[1,[43.55555555555554,-54.66666666666663]]],"stroke":[[2,0],[3,0],[5,0],[1,0],[4,0]]},"regions":{"add":[],"remove":[],"segment_range":[],"fill":[]},"add_g1_continuous":[],"remove_g1_continuous":[]}},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::vector_data::modification::VectorModification","alias":null}},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::vector_data::modification::PathModifyNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[17078740291337047697,{"inputs":[{"Node":{"node_id":3406722917122601552,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"Fill":{"Solid":{"red":0.84765625,"green":0.5384252,"blue":0.3874054,"alpha":1.0}}},"exposed":false}},{"Value":{"tagged_value":{"OptionalColor":{"red":0.84765625,"green":0.5384252,"blue":0.3874054,"alpha":1.0}},"exposed":false}},{"Value":{"tagged_value":{"Gradient":{"stops":[[0.0,{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}],[1.0,{"red":1.0,"green":1.0,"blue":1.0,"alpha":1.0}]],"gradient_type":"Linear","start":[0.0,0.5],"end":[1.0,0.5],"transform":[1.0,0.0,0.0,1.0,0.0,0.0]}},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::FillNode"}},"visible":true,"skip_deduplication":false}],[10264089084180279094,{"inputs":[{"Node":{"node_id":5213978458941436169,"output_index":0,"lambda":false}},{"Node":{"node_id":4332145463108161926,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"F64":1.0},"exposed":false}},{"Value":{"tagged_value":{"F64":60.0},"exposed":false}},{"Value":{"tagged_value":{"F64":-100.0},"exposed":false}},{"Value":{"tagged_value":{"U32":0},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"U32":0},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::CopyToPointsNode"}},"visible":true,"skip_deduplication":false}],[4859656512650360562,{"inputs":[{"Value":{"tagged_value":{"VectorData":{"instance":[{"style":{"stroke":{"color":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0},"weight":0.0,"dash_lengths":[],"dash_offset":0.0,"cap":"Butt","join":"Miter","join_miter_limit":4.0,"align":"Center","transform":[1.0,0.0,0.0,1.0,0.0,0.0],"non_scaling":false,"paint_order":"StrokeAbove"},"fill":"None"},"colinear_manipulators":[],"point_domain":{"id":[],"position":[]},"segment_domain":{"id":[],"start_point":[],"end_point":[],"handles":[],"stroke":[]},"region_domain":{"id":[],"segment_range":[],"fill":[]},"upstream_graphic_group":null}],"transform":[[1.0,0.0,0.0,1.0,0.0,0.0]],"alpha_blending":[{"blend_mode":"Normal","opacity":1.0,"fill":1.0,"clip":false}],"source_node_id":[null]}},"exposed":true}},{"Value":{"tagged_value":{"VectorModification":{"points":{"add":[1,2,3],"remove":[],"delta":[[3,[416.66666666666663,803.3333333333333]],[2,[249.3333333333334,898.0]],[1,[163.33333333333343,1025.3333333333333]]]},"segments":{"add":[1,2],"remove":[],"start_point":[[2,2],[1,1]],"end_point":[[1,2],[2,3]],"handle_primary":[[2,[40.66666666666666,-40.666666666666515]],[1,[0.0,0.0]]],"handle_end":[[2,[-77.99999999999994,22.666666666666742]],[1,[-45.09988913511887,45.099889135118815]]],"stroke":[[2,0],[1,0]]},"regions":{"add":[],"remove":[],"segment_range":[],"fill":[]},"add_g1_continuous":[],"remove_g1_continuous":[]}},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::vector_data::modification::VectorModification","alias":null}},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::vector_data::modification::PathModifyNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[13594670583065022897,{"inputs":[{"Node":{"node_id":13302269488061286120,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"PointSpacingType":"Separation"},"exposed":false}},{"Value":{"tagged_value":{"F64":5.0},"exposed":false}},{"Value":{"tagged_value":{"U32":100},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"Bool":false},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":4,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::SubpathSegmentLengthsNode"}},"visible":true,"skip_deduplication":false}],[4,{"inputs":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::BoundlessFootprintNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":2,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::FreezeRealTimeNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MemoNode"}},"visible":true,"skip_deduplication":false}],[1,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::misc::PointSpacingType","alias":null}},"import_index":1}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":2}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":3}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":4}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":5}},{"Network":{"import_type":{"Concrete":{"name":"bool","alias":null}},"import_index":6}},{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::SamplePolylineNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[4265165189651403984,{"inputs":[{"Value":{"tagged_value":{"GraphicGroup":{"instance":[],"transform":[],"alpha_blending":[],"source_node_id":[]}},"exposed":true}},{"Node":{"node_id":10264089084180279094,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[12428327489525325219,{"inputs":[{"Node":{"node_id":14209241002058525241,"output_index":0,"lambda":false}},{"Node":{"node_id":1984475088429379731,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[16767482995096345179,{"inputs":[{"Node":{"node_id":6532401937876437300,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"Fill":{"Solid":{"red":0.7529412,"green":0.15686275,"blue":0.13333334,"alpha":1.0}}},"exposed":false}},{"Value":{"tagged_value":{"OptionalColor":{"red":0.7529412,"green":0.15686275,"blue":0.13333334,"alpha":1.0}},"exposed":false}},{"Value":{"tagged_value":{"Gradient":{"stops":[[0.0,{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}],[1.0,{"red":1.0,"green":1.0,"blue":1.0,"alpha":1.0}]],"gradient_type":"Linear","start":[0.0,0.5],"end":[1.0,0.5],"transform":[1.0,0.0,0.0,1.0,0.0,0.0]}},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::FillNode"}},"visible":true,"skip_deduplication":false}],[5278509881589546420,{"inputs":[{"Value":{"tagged_value":{"VectorData":{"instance":[{"style":{"stroke":{"color":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0},"weight":0.0,"dash_lengths":[],"dash_offset":0.0,"cap":"Butt","join":"Miter","join_miter_limit":4.0,"align":"Center","transform":[1.0,0.0,0.0,1.0,0.0,0.0],"non_scaling":false,"paint_order":"StrokeAbove"},"fill":"None"},"colinear_manipulators":[],"point_domain":{"id":[],"position":[]},"segment_domain":{"id":[],"start_point":[],"end_point":[],"handles":[],"stroke":[]},"region_domain":{"id":[],"segment_range":[],"fill":[]},"upstream_graphic_group":null}],"transform":[[1.0,0.0,0.0,1.0,0.0,0.0]],"alpha_blending":[{"blend_mode":"Normal","opacity":1.0,"fill":1.0,"clip":false}],"source_node_id":[null]}},"exposed":true}},{"Value":{"tagged_value":{"VectorModification":{"points":{"add":[1,2,3],"remove":[],"delta":[[1,[899.1111111111111,600.0000000000001]],[3,[823.7037037037037,861.8666666666667]],[2,[824.4444444444445,850.2222222222223]]]},"segments":{"add":[1,2,3],"remove":[],"start_point":[[3,3],[2,2],[1,1]],"end_point":[[1,2],[2,3],[3,1]],"handle_primary":[[3,[0.0,0.0]],[2,[0.0,0.0]],[1,[0.0,0.0]]],"handle_end":[[2,[0.0,0.0]],[3,[-26.31111111111113,120.79999999999984]],[1,[39.55555555555554,-105.8222222222222]]],"stroke":[[3,0],[1,0],[2,0]]},"regions":{"add":[0],"remove":[],"segment_range":[[0,{"start":1,"end":3}]],"fill":[[0,0]]},"add_g1_continuous":[],"remove_g1_continuous":[]}},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::vector_data::modification::VectorModification","alias":null}},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::vector_data::modification::PathModifyNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[7659717355245331967,{"inputs":[{"Node":{"node_id":18422317423856403288,"output_index":0,"lambda":false}},{"Node":{"node_id":4479074488343511985,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[8697043784435445845,{"inputs":[{"Value":{"tagged_value":{"VectorData":{"instance":[{"style":{"stroke":{"color":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0},"weight":0.0,"dash_lengths":[],"dash_offset":0.0,"cap":"Butt","join":"Miter","join_miter_limit":4.0,"align":"Center","transform":[1.0,0.0,0.0,1.0,0.0,0.0],"non_scaling":false,"paint_order":"StrokeAbove"},"fill":"None"},"colinear_manipulators":[],"point_domain":{"id":[],"position":[]},"segment_domain":{"id":[],"start_point":[],"end_point":[],"handles":[],"stroke":[]},"region_domain":{"id":[],"segment_range":[],"fill":[]},"upstream_graphic_group":null}],"transform":[[1.0,0.0,0.0,1.0,0.0,0.0]],"alpha_blending":[{"blend_mode":"Normal","opacity":1.0,"fill":1.0,"clip":false}],"source_node_id":[null]}},"exposed":true}},{"Value":{"tagged_value":{"VectorModification":{"points":{"add":[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35],"remove":[],"delta":[[9,[326.22222222222223,208.0]],[16,[172.44444444444446,239.40740740740745]],[4,[647.5555555555554,171.55555555555557]],[27,[251.06172839506175,233.283950617284]],[5,[616.4444444444443,170.22222222222223]],[33,[602.2716049382716,229.5308641975309]],[2,[701.7777777777777,252.0]],[24,[188.90085842299663,268.4351595864769]],[3,[679.9012345679013,198.716049382716]],[14,[155.06172839506175,249.08641975308643]],[23,[185.37661941777165,263.56957780826093]],[8,[413.77777777777777,199.55555555555551]],[35,[680.888888888889,281.48148148148147]],[12,[199.11111111111111,214.51851851851853]],[1,[699.5555555555554,303.55555555555554]],[34,[647.5061728395062,240.79012345679013]],[10,[271.1111111111111,207.55555555555551]],[22,[195.95061728395063,253.8271604938272]],[17,[183.50617283950615,231.70370370370372]],[28,[278.9135802469136,223.80246913580248]],[11,[208.44444444444443,212.0]],[25,[201.87654320987656,262.12345679012344]],[31,[463.01234567901247,246.71604938271605]],[29,[369.3827160493828,240.19753086419755]],[18,[195.1604938271605,228.54320987654324]],[19,[205.23456790123456,227.55555555555557]],[26,[227.55555555555557,246.51851851851853]],[30,[425.4814814814815,246.71604938271605]],[6,[553.7777777777777,195.11111111111111]],[7,[452.0,206.22222222222223]],[13,[173.03703703703707,226.962962962963]],[32,[526.0246913580247,240.79012345679013]],[20,[217.87654320987656,231.90123456790127]],[15,[155.85185185185185,253.03703703703707]],[21,[216.8888888888889,238.22222222222223]]]},"segments":{"add":[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35],"remove":[],"start_point":[[34,34],[9,9],[2,2],[17,17],[11,11],[29,29],[19,19],[14,14],[27,27],[30,30],[24,24],[5,5],[4,4],[31,31],[23,23],[1,1],[15,15],[6,6],[28,28],[7,7],[16,16],[22,22],[35,35],[18,18],[13,13],[12,12],[26,26],[8,8],[20,20],[25,25],[21,21],[10,10],[33,33],[3,3],[32,32]],"end_point":[[4,5],[27,28],[24,25],[33,34],[2,3],[9,10],[3,4],[1,2],[25,26],[18,19],[13,14],[23,24],[26,27],[21,22],[28,29],[8,9],[35,1],[12,13],[15,16],[19,20],[10,11],[17,18],[16,17],[11,12],[14,15],[32,33],[30,31],[7,8],[22,23],[20,21],[6,7],[5,6],[34,35],[29,30],[31,32]],"handle_primary":[[12,[-5.53086419753086,3.3580246913580254]],[13,[-9.28395061728395,7.703703703703695]],[24,[3.3430068414448044,-0.5735531240474074]],[4,[-10.222222222222172,-3.5555555555555713]],[18,[4.148148148148124,-1.3827160493827364]],[30,[11.061728395061778,0.7901234567900985]],[21,[-3.753086419753061,3.5555555555555713]],[7,[-8.444444444444457,-2.2222222222222285]],[27,[6.518518518518505,-6.518518518518562]],[3,[-17.576025737442137,-14.306067460708704]],[32,[23.90123456790127,-2.765432098765416]],[33,[24.098765432098844,-2.5679012345678984]],[23,[-0.9364426154549506,2.4191434232586175]],[9,[-30.22222222222223,1.3333333333333712]],[11,[0.0,0.0]],[22,[-8.16460905349794,4.4115226337448235]],[6,[-23.11111111111109,9.777777777777771]],[29,[29.4320987654321,3.358024691358054]],[25,[4.938271604938279,-3.160493827160451]],[10,[-12.888888888888856,1.7777777777778567]],[20,[2.3703703703704093,1.185185185185162]],[28,[14.81481481481478,1.9753086419753176]],[35,[10.469135802469168,11.851851851851848]],[1,[0.0,0.0]],[16,[5.530864197530889,-7.111111111111143]],[14,[-1.61975308641982,1.935802469135723]],[17,[2.7654320987654444,-0.790123456790127]],[34,[10.074074074074131,11.85185185185182]],[31,[19.753086419753004,-4.543209876543159]],[8,[-25.33333333333331,1.7777777777778567]],[15,[3.7530864197531177,-1.580246913580254]],[5,[-12.0,3.555555555555543]],[26,[8.493827160493822,-2.765432098765416]],[19,[4.74074074074079,0.9876543209876728]],[2,[-2.913580246913398,-22.66666666666669]]],"handle_end":[[26,[-6.518518518518505,6.518518518518505]],[27,[-14.81481481481478,-1.9753086419753176]],[34,[-10.469135802469168,-11.851851851851848]],[6,[8.444444444444457,2.222222222222257]],[31,[-23.90123456790127,2.7654320987653875]],[35,[0.0,5.684341886080804e-14]],[25,[-8.493827160493822,2.765432098765416]],[22,[0.752878950104872,-1.9449372877709263]],[19,[-2.3703703703704093,-1.185185185185162]],[20,[3.753086419753089,-3.5555555555556]],[14,[-3.7530864197531177,1.580246913580254]],[13,[1.4782632300064904,-1.7667048358613044]],[29,[-11.061728395061778,-0.790123456790127]],[1,[2.822923929132685,21.961391245287817]],[8,[30.22222222222223,-1.3333333333333712]],[11,[5.530864197530917,-3.3580246913580254]],[28,[-29.4320987654321,-3.358024691357997]],[9,[12.888888888888856,-1.777777777777743]],[2,[8.493827160493879,6.913580246913597]],[15,[-5.530864197530889,7.111111111111086]],[5,[23.11111111111109,-9.777777777777745]],[18,[-4.740740740740705,-0.9876543209876728]],[30,[-19.753086419753004,4.543209876543187]],[24,[-4.938271604938279,3.160493827160451]],[12,[9.283950617283978,-7.703703703703695]],[10,[20.88888888888889,-1.4814814814814952]],[4,[12.0,-3.555555555555543]],[17,[-4.148148148148152,1.3827160493827648]],[33,[-10.074074074074131,-11.851851851851848]],[32,[-24.098765432098844,2.5679012345678984]],[23,[-1.24660051630255,0.213876804468498]],[7,[25.33333333333331,-1.777777777777743]],[21,[9.952891875905069,-5.377772223271279]],[16,[-2.765432098765416,0.790123456790127]],[3,[10.222222222222172,3.5555555555555713]]],"stroke":[[13,0],[8,0],[1,0],[31,0],[21,0],[19,0],[2,0],[22,0],[25,0],[11,0],[17,0],[6,0],[28,0],[9,0],[24,0],[12,0],[20,0],[10,0],[4,0],[15,0],[16,0],[29,0],[34,0],[33,0],[3,0],[32,0],[14,0],[26,0],[23,0],[5,0],[30,0],[7,0],[27,0],[35,0],[18,0]]},"regions":{"add":[0],"remove":[],"segment_range":[[0,{"start":1,"end":35}]],"fill":[[0,0]]},"add_g1_continuous":[],"remove_g1_continuous":[]}},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::vector_data::modification::VectorModification","alias":null}},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::vector_data::modification::PathModifyNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[4236845268521674740,{"inputs":[{"Value":{"tagged_value":{"VectorData":{"instance":[{"style":{"stroke":{"color":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0},"weight":0.0,"dash_lengths":[],"dash_offset":0.0,"cap":"Butt","join":"Miter","join_miter_limit":4.0,"align":"Center","transform":[1.0,0.0,0.0,1.0,0.0,0.0],"non_scaling":false,"paint_order":"StrokeAbove"},"fill":"None"},"colinear_manipulators":[],"point_domain":{"id":[],"position":[]},"segment_domain":{"id":[],"start_point":[],"end_point":[],"handles":[],"stroke":[]},"region_domain":{"id":[],"segment_range":[],"fill":[]},"upstream_graphic_group":null}],"transform":[[1.0,0.0,0.0,1.0,0.0,0.0]],"alpha_blending":[{"blend_mode":"Normal","opacity":1.0,"fill":1.0,"clip":false}],"source_node_id":[null]}},"exposed":true}},{"Value":{"tagged_value":{"VectorModification":{"points":{"add":[1,2,3],"remove":[],"delta":[[2,[568.8888888888889,785.4814814814813]],[1,[397.6296296296296,1025.185185185185]],[3,[393.1851851851852,1025.4814814814813]]]},"segments":{"add":[1,2,3],"remove":[],"start_point":[[2,2],[1,1],[3,3]],"end_point":[[3,1],[1,2],[2,3]],"handle_primary":[[2,[0.0,0.0]],[3,[0.0,0.0]],[1,[0.0,0.0]]],"handle_end":[[3,null],[1,[-153.1851851851851,112.88888888888891]],[2,[33.777777777777885,-150.22222222222194]]],"stroke":[[1,0],[2,0],[3,0]]},"regions":{"add":[0],"remove":[],"segment_range":[[0,{"start":1,"end":3}]],"fill":[[0,0]]},"add_g1_continuous":[],"remove_g1_continuous":[]}},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::vector_data::modification::VectorModification","alias":null}},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::vector_data::modification::PathModifyNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[1984475088429379731,{"inputs":[{"Node":{"node_id":1621196991038859321,"output_index":0,"lambda":false}},{"Node":{"node_id":17078740291337047697,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"F64":1.2},"exposed":false}},{"Value":{"tagged_value":{"F64":2.0},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"U32":0},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"U32":0},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::CopyToPointsNode"}},"visible":true,"skip_deduplication":false}],[9271343782272072828,{"inputs":[{"Node":{"node_id":4078100635676202528,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"Fill":{"Solid":{"red":0.8980392,"green":0.8,"blue":0.6117647,"alpha":1.0}}},"exposed":false}},{"Value":{"tagged_value":{"OptionalColor":{"red":0.8980392,"green":0.8,"blue":0.6117647,"alpha":1.0}},"exposed":false}},{"Value":{"tagged_value":{"Gradient":{"stops":[[0.0,{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}],[1.0,{"red":1.0,"green":1.0,"blue":1.0,"alpha":1.0}]],"gradient_type":"Linear","start":[0.0,0.5],"end":[1.0,0.5],"transform":[1.0,0.0,0.0,1.0,0.0,0.0]}},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::FillNode"}},"visible":true,"skip_deduplication":false}],[514796034658094296,{"inputs":[{"Node":{"node_id":13352561089252322209,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"Fill":{"Solid":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}}},"exposed":false}},{"Value":{"tagged_value":{"OptionalColor":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}},"exposed":false}},{"Value":{"tagged_value":{"Gradient":{"stops":[[0.0,{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}],[1.0,{"red":1.0,"green":1.0,"blue":1.0,"alpha":1.0}]],"gradient_type":"Linear","start":[0.0,0.5],"end":[1.0,0.5],"transform":[1.0,0.0,0.0,1.0,0.0,0.0]}},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::FillNode"}},"visible":true,"skip_deduplication":false}],[8698602280607307123,{"inputs":[{"Node":{"node_id":14098374807212007572,"output_index":0,"lambda":false}},{"Node":{"node_id":14285767317419627814,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[10770443343193024138,{"inputs":[{"Value":{"tagged_value":{"VectorData":{"instance":[{"style":{"stroke":{"color":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0},"weight":0.0,"dash_lengths":[],"dash_offset":0.0,"cap":"Butt","join":"Miter","join_miter_limit":4.0,"align":"Center","transform":[1.0,0.0,0.0,1.0,0.0,0.0],"non_scaling":false,"paint_order":"StrokeAbove"},"fill":"None"},"colinear_manipulators":[],"point_domain":{"id":[],"position":[]},"segment_domain":{"id":[],"start_point":[],"end_point":[],"handles":[],"stroke":[]},"region_domain":{"id":[],"segment_range":[],"fill":[]},"upstream_graphic_group":null}],"transform":[[1.0,0.0,0.0,1.0,0.0,0.0]],"alpha_blending":[{"blend_mode":"Normal","opacity":1.0,"fill":1.0,"clip":false}],"source_node_id":[null]}},"exposed":true}},{"Value":{"tagged_value":{"VectorModification":{"points":{"add":[1,2,3,4,5,6,7],"remove":[],"delta":[[1,[616.0987654320988,23.01234567901235]],[2,[621.0370370370372,23.01234567901235]],[4,[656.6913580246915,28.049382716049383]],[5,[671.3086419753088,28.641975308641975]],[6,[656.4609053497943,30.375857338820303]],[3,[634.172839506173,30.814814814814817]],[7,[634.1618655692731,33.7997256515775]]]},"segments":{"add":[1,2,3,4,5,6,7],"remove":[],"start_point":[[6,6],[4,4],[3,3],[5,5],[7,7],[2,2],[1,1]],"end_point":[[7,1],[2,3],[4,5],[1,2],[6,7],[3,4],[5,6]],"handle_primary":[[4,[4.345679012345727,-0.39506172839505993]],[1,[0.0,0.0]],[6,[-10.31550068587103,2.4142661179698237]],[5,[0.0,0.0]],[2,[1.1851851851851052,1.5802469135802468]],[3,[6.024691358024711,0.4938271604938329]],[7,[-6.408779149519887,-0.8340192043895769]]],"handle_end":[[6,[6.408779149519887,0.8340192043895769]],[5,[10.31550068587103,-2.4142661179698237]],[2,[-6.024691358024711,-0.49382716049382935]],[1,[-1.1851851851851052,-1.5802469135802468]],[3,[-4.345679012345727,0.39506172839506704]],[7,[4.455418381344316,5.4759945130315515]],[4,[-0.39506172839503506,-0.5925925925925917]]],"stroke":[[3,0],[2,0],[1,0],[5,0],[7,0],[4,0],[6,0]]},"regions":{"add":[0],"remove":[],"segment_range":[[0,{"start":1,"end":7}]],"fill":[[0,0]]},"add_g1_continuous":[],"remove_g1_continuous":[]}},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::vector_data::modification::VectorModification","alias":null}},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::vector_data::modification::PathModifyNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[1019037285881657884,{"inputs":[{"Node":{"node_id":11481949351661484921,"output_index":0,"lambda":false}},{"Node":{"node_id":17078740291337047697,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"F64":1.2},"exposed":false}},{"Value":{"tagged_value":{"F64":2.0},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"U32":0},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"U32":0},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::CopyToPointsNode"}},"visible":true,"skip_deduplication":false}],[8410534738018320047,{"inputs":[{"Value":{"tagged_value":{"VectorData":{"instance":[{"style":{"stroke":{"color":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0},"weight":0.0,"dash_lengths":[],"dash_offset":0.0,"cap":"Butt","join":"Miter","join_miter_limit":4.0,"align":"Center","transform":[1.0,0.0,0.0,1.0,0.0,0.0],"non_scaling":false,"paint_order":"StrokeAbove"},"fill":"None"},"colinear_manipulators":[],"point_domain":{"id":[],"position":[]},"segment_domain":{"id":[],"start_point":[],"end_point":[],"handles":[],"stroke":[]},"region_domain":{"id":[],"segment_range":[],"fill":[]},"upstream_graphic_group":null}],"transform":[[1.0,0.0,0.0,1.0,0.0,0.0]],"alpha_blending":[{"blend_mode":"Normal","opacity":1.0,"fill":1.0,"clip":false}],"source_node_id":[null]}},"exposed":true}},{"Value":{"tagged_value":{"VectorModification":{"points":{"add":[1,2],"remove":[],"delta":[[1,[834.6666666666665,551.8024691358028]],[2,[762.5185185185184,667.5061728395063]]]},"segments":{"add":[1,2],"remove":[],"start_point":[[2,2],[1,1]],"end_point":[[1,2],[2,1]],"handle_primary":[[2,[44.88888888888857,-64.49382716049388]],[1,[0.0,0.0]]],"handle_end":[[2,null],[1,[47.85185185185162,-63.160493827160394]]],"stroke":[[2,0],[1,0]]},"regions":{"add":[0],"remove":[],"segment_range":[[0,{"start":1,"end":2}]],"fill":[[0,0]]},"add_g1_continuous":[],"remove_g1_continuous":[]}},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::vector_data::modification::VectorModification","alias":null}},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::vector_data::modification::PathModifyNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[2397243911096708995,{"inputs":[{"Node":{"node_id":10587073897090054035,"output_index":0,"lambda":false}},{"Node":{"node_id":7505360855062237520,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[541002100261582638,{"inputs":[{"Value":{"tagged_value":{"VectorData":{"instance":[{"style":{"stroke":{"color":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0},"weight":0.0,"dash_lengths":[],"dash_offset":0.0,"cap":"Butt","join":"Miter","join_miter_limit":4.0,"align":"Center","transform":[1.0,0.0,0.0,1.0,0.0,0.0],"non_scaling":false,"paint_order":"StrokeAbove"},"fill":"None"},"colinear_manipulators":[],"point_domain":{"id":[],"position":[]},"segment_domain":{"id":[],"start_point":[],"end_point":[],"handles":[],"stroke":[]},"region_domain":{"id":[],"segment_range":[],"fill":[]},"upstream_graphic_group":null}],"transform":[[1.0,0.0,0.0,1.0,0.0,0.0]],"alpha_blending":[{"blend_mode":"Normal","opacity":1.0,"fill":1.0,"clip":false}],"source_node_id":[null]}},"exposed":true}},{"Value":{"tagged_value":{"VectorModification":{"points":{"add":[1,2,3,4],"remove":[],"delta":[[4,[648.4444444444443,543.5555555555555]],[2,[536.8888888888889,544.4444444444445]],[1,[456.88888888888886,483.55555555555554]],[3,[609.7777777777777,559.5555555555555]]]},"segments":{"add":[1,2,3],"remove":[],"start_point":[[2,2],[1,1],[3,3]],"end_point":[[2,3],[1,2],[3,4]],"handle_primary":[[1,[0.0,0.0]],[3,[20.0,-7.555555555555543]],[2,[25.777777777777715,11.555555555555545]]],"handle_end":[[3,[0.0,0.0]],[1,[-25.777777777777715,-11.555555555555545]],[2,[-20.0,7.555555555555543]]],"stroke":[[1,0],[2,0],[3,0]]},"regions":{"add":[],"remove":[],"segment_range":[],"fill":[]},"add_g1_continuous":[],"remove_g1_continuous":[]}},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::vector_data::modification::VectorModification","alias":null}},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::vector_data::modification::PathModifyNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[5009664118231399060,{"inputs":[{"Node":{"node_id":3226457726231232839,"output_index":0,"lambda":false}},{"Node":{"node_id":17207895962122263432,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[1378578509112405,{"inputs":[{"Value":{"tagged_value":{"VectorData":{"instance":[{"style":{"stroke":{"color":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0},"weight":0.0,"dash_lengths":[],"dash_offset":0.0,"cap":"Butt","join":"Miter","join_miter_limit":4.0,"align":"Center","transform":[1.0,0.0,0.0,1.0,0.0,0.0],"non_scaling":false,"paint_order":"StrokeAbove"},"fill":"None"},"colinear_manipulators":[],"point_domain":{"id":[],"position":[]},"segment_domain":{"id":[],"start_point":[],"end_point":[],"handles":[],"stroke":[]},"region_domain":{"id":[],"segment_range":[],"fill":[]},"upstream_graphic_group":null}],"transform":[[1.0,0.0,0.0,1.0,0.0,0.0]],"alpha_blending":[{"blend_mode":"Normal","opacity":1.0,"fill":1.0,"clip":false}],"source_node_id":[null]}},"exposed":true}},{"Value":{"tagged_value":{"VectorModification":{"points":{"add":[1,2,3,4,5],"remove":[],"delta":[[3,[590.4855967078191,66.80932784636488]],[5,[593.3924706599604,60.59564090839812]],[2,[599.5281207133061,50.3923182441701]],[4,[594.6410608139003,75.57872275567746]],[1,[602.6886145404666,50.91906721536352]]]},"segments":{"add":[1,2,3,4,5],"remove":[],"start_point":[[3,3],[4,4],[2,2],[5,5],[1,1]],"end_point":[[3,4],[2,3],[5,1],[4,5],[1,2]],"handle_primary":[[1,[0.0,0.0]],[3,[1.9314128943758533,7.3257125438195345]],[2,[-1.843621399176982,0.5267489711934203]],[5,[1.248590153939972,-3.9798811156835896]],[4,[0.0,0.0]]],"handle_end":[[4,[-1.704168058538812,5.432035686592322]],[5,[-4.379820149367788,0.9754610577655498]],[1,[1.843621399176982,-0.5267489711934203]],[3,[0.0,0.0]],[2,[-2.7532629181224593,-10.4429315732828]]],"stroke":[[2,0],[4,0],[5,0],[1,0],[3,0]]},"regions":{"add":[0],"remove":[],"segment_range":[[0,{"start":1,"end":5}]],"fill":[[0,0]]},"add_g1_continuous":[],"remove_g1_continuous":[]}},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::vector_data::modification::VectorModification","alias":null}},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::vector_data::modification::PathModifyNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[501401493219507773,{"inputs":[{"Node":{"node_id":9425359632144678256,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"Fill":{"Solid":{"red":0.7529412,"green":0.15686275,"blue":0.13333334,"alpha":1.0}}},"exposed":false}},{"Value":{"tagged_value":{"OptionalColor":{"red":0.7529412,"green":0.15686275,"blue":0.13333334,"alpha":1.0}},"exposed":false}},{"Value":{"tagged_value":{"Gradient":{"stops":[[0.0,{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}],[1.0,{"red":1.0,"green":1.0,"blue":1.0,"alpha":1.0}]],"gradient_type":"Linear","start":[0.0,0.5],"end":[1.0,0.5],"transform":[1.0,0.0,0.0,1.0,0.0,0.0]}},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::FillNode"}},"visible":true,"skip_deduplication":false}],[1235106489581249820,{"inputs":[{"Node":{"node_id":3970516859959908758,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"PointSpacingType":"Separation"},"exposed":false}},{"Value":{"tagged_value":{"F64":5.0},"exposed":false}},{"Value":{"tagged_value":{"U32":100},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"Bool":false},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":4,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::SubpathSegmentLengthsNode"}},"visible":true,"skip_deduplication":false}],[4,{"inputs":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::BoundlessFootprintNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":2,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::FreezeRealTimeNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MemoNode"}},"visible":true,"skip_deduplication":false}],[1,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::misc::PointSpacingType","alias":null}},"import_index":1}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":2}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":3}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":4}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":5}},{"Network":{"import_type":{"Concrete":{"name":"bool","alias":null}},"import_index":6}},{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::SamplePolylineNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[2394762731964337494,{"inputs":[{"Value":{"tagged_value":{"ArtboardGroup":{"instance":[],"transform":[],"alpha_blending":[],"source_node_id":[]}},"exposed":true}},{"Node":{"node_id":4422453582814483232,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"IVec2":[0,0]},"exposed":false}},{"Value":{"tagged_value":{"IVec2":[1024,1024]},"exposed":false}},{"Value":{"tagged_value":{"Color":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}},"exposed":false}},{"Value":{"tagged_value":{"Bool":true},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":2,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graph_craft::document::value::TaggedValue","alias":null}},"import_index":1}},{"Value":{"tagged_value":{"String":"Artboard"},"exposed":false}},{"Network":{"import_type":{"Concrete":{"name":"graph_craft::document::value::TaggedValue","alias":null}},"import_index":2}},{"Network":{"import_type":{"Concrete":{"name":"graph_craft::document::value::TaggedValue","alias":null}},"import_index":3}},{"Network":{"import_type":{"Concrete":{"name":"graph_craft::document::value::TaggedValue","alias":null}},"import_index":4}},{"Network":{"import_type":{"Concrete":{"name":"graph_craft::document::value::TaggedValue","alias":null}},"import_index":5}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToArtboardNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Network":{"import_type":{"Fn":[{"Concrete":{"name":"core::option::Option>","alias":null}},{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}}]},"import_index":0}},{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::AppendArtboardNode"}},"visible":true,"skip_deduplication":false}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[4341772758799935306,{"inputs":[{"Node":{"node_id":1785173043494067496,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"PointSpacingType":"Separation"},"exposed":false}},{"Value":{"tagged_value":{"F64":5.0},"exposed":false}},{"Value":{"tagged_value":{"U32":100},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"Bool":false},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":4,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::SubpathSegmentLengthsNode"}},"visible":true,"skip_deduplication":false}],[4,{"inputs":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::BoundlessFootprintNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":2,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::FreezeRealTimeNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MemoNode"}},"visible":true,"skip_deduplication":false}],[1,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::misc::PointSpacingType","alias":null}},"import_index":1}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":2}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":3}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":4}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":5}},{"Network":{"import_type":{"Concrete":{"name":"bool","alias":null}},"import_index":6}},{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::SamplePolylineNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[3226457726231232839,{"inputs":[{"Node":{"node_id":4493274523708782092,"output_index":0,"lambda":false}},{"Node":{"node_id":7922156219537051964,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[6645255982686652881,{"inputs":[{"Value":{"tagged_value":{"VectorData":{"instance":[{"style":{"stroke":{"color":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0},"weight":0.0,"dash_lengths":[],"dash_offset":0.0,"cap":"Butt","join":"Miter","join_miter_limit":4.0,"align":"Center","transform":[1.0,0.0,0.0,1.0,0.0,0.0],"non_scaling":false,"paint_order":"StrokeAbove"},"fill":"None"},"colinear_manipulators":[],"point_domain":{"id":[],"position":[]},"segment_domain":{"id":[],"start_point":[],"end_point":[],"handles":[],"stroke":[]},"region_domain":{"id":[],"segment_range":[],"fill":[]},"upstream_graphic_group":null}],"transform":[[1.0,0.0,0.0,1.0,0.0,0.0]],"alpha_blending":[{"blend_mode":"Normal","opacity":1.0,"fill":1.0,"clip":false}],"source_node_id":[null]}},"exposed":true}},{"Value":{"tagged_value":{"VectorModification":{"points":{"add":[1,2,3,4],"remove":[],"delta":[[1,[0.5,0.0]],[3,[0.5,1.0]],[2,[1.0,0.5]],[4,[0.0,0.5]]]},"segments":{"add":[1,2,3,4],"remove":[],"start_point":[[2,2],[3,3],[1,1],[4,4]],"end_point":[[1,2],[4,1],[3,4],[2,3]],"handle_primary":[[3,[-0.275892388889507,0.0]],[2,[0.0,0.27589238888950707]],[1,[0.27589238888950707,0.0]],[4,[0.0,-0.275892388889507]]],"handle_end":[[2,[0.27589238888950707,0.0]],[3,[0.0,0.27589238888950707]],[4,[-0.275892388889507,0.0]],[1,[0.0,-0.275892388889507]]],"stroke":[[1,0],[2,0],[3,0],[4,0]]},"regions":{"add":[0],"remove":[],"segment_range":[[0,{"start":1,"end":4}]],"fill":[[0,0]]},"add_g1_continuous":[],"remove_g1_continuous":[]}},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::vector_data::modification::VectorModification","alias":null}},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::vector_data::modification::PathModifyNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[1162381870526064378,{"inputs":[{"Value":{"tagged_value":{"GraphicGroup":{"instance":[],"transform":[],"alpha_blending":[],"source_node_id":[]}},"exposed":true}},{"Node":{"node_id":9271343782272072828,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[7447657690776686262,{"inputs":[{"Node":{"node_id":3649809135741361946,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"PointSpacingType":"Separation"},"exposed":false}},{"Value":{"tagged_value":{"F64":5.0},"exposed":false}},{"Value":{"tagged_value":{"U32":100},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"Bool":false},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":4,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::SubpathSegmentLengthsNode"}},"visible":true,"skip_deduplication":false}],[4,{"inputs":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::BoundlessFootprintNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":2,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::FreezeRealTimeNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MemoNode"}},"visible":true,"skip_deduplication":false}],[1,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::misc::PointSpacingType","alias":null}},"import_index":1}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":2}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":3}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":4}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":5}},{"Network":{"import_type":{"Concrete":{"name":"bool","alias":null}},"import_index":6}},{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::SamplePolylineNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[9698363115186534174,{"inputs":[{"Node":{"node_id":1661691009086487874,"output_index":0,"lambda":false}},{"Node":{"node_id":17078740291337047697,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"F64":1.2},"exposed":false}},{"Value":{"tagged_value":{"F64":2.0},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"U32":0},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"U32":0},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::CopyToPointsNode"}},"visible":true,"skip_deduplication":false}],[5471152581000334146,{"inputs":[{"Node":{"node_id":12761901161949743155,"output_index":0,"lambda":false}},{"Node":{"node_id":952330505278607301,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[15827578515555598997,{"inputs":[{"Node":{"node_id":15656854169166220905,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"Fill":{"Solid":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}}},"exposed":false}},{"Value":{"tagged_value":{"OptionalColor":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}},"exposed":false}},{"Value":{"tagged_value":{"Gradient":{"stops":[[0.0,{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}],[1.0,{"red":1.0,"green":1.0,"blue":1.0,"alpha":1.0}]],"gradient_type":"Linear","start":[0.0,0.5],"end":[1.0,0.5],"transform":[1.0,0.0,0.0,1.0,0.0,0.0]}},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::FillNode"}},"visible":true,"skip_deduplication":false}],[14539627480594383748,{"inputs":[{"Node":{"node_id":581013017684525986,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"Fill":{"Solid":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}}},"exposed":false}},{"Value":{"tagged_value":{"OptionalColor":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}},"exposed":false}},{"Value":{"tagged_value":{"Gradient":{"stops":[[0.0,{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}],[1.0,{"red":1.0,"green":1.0,"blue":1.0,"alpha":1.0}]],"gradient_type":"Linear","start":[0.0,0.5],"end":[1.0,0.5],"transform":[1.0,0.0,0.0,1.0,0.0,0.0]}},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::FillNode"}},"visible":true,"skip_deduplication":false}],[2282726379014798660,{"inputs":[{"Node":{"node_id":454416440369338250,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"PointSpacingType":"Separation"},"exposed":false}},{"Value":{"tagged_value":{"F64":5.0},"exposed":false}},{"Value":{"tagged_value":{"U32":100},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"Bool":false},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":4,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::SubpathSegmentLengthsNode"}},"visible":true,"skip_deduplication":false}],[4,{"inputs":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::BoundlessFootprintNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":2,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::FreezeRealTimeNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MemoNode"}},"visible":true,"skip_deduplication":false}],[1,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::misc::PointSpacingType","alias":null}},"import_index":1}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":2}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":3}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":4}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":5}},{"Network":{"import_type":{"Concrete":{"name":"bool","alias":null}},"import_index":6}},{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::SamplePolylineNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[11417901103965737900,{"inputs":[{"Node":{"node_id":13269760558336088742,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"PointSpacingType":"Separation"},"exposed":false}},{"Value":{"tagged_value":{"F64":5.0},"exposed":false}},{"Value":{"tagged_value":{"U32":100},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"Bool":false},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":4,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::SubpathSegmentLengthsNode"}},"visible":true,"skip_deduplication":false}],[4,{"inputs":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::BoundlessFootprintNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":2,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::FreezeRealTimeNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MemoNode"}},"visible":true,"skip_deduplication":false}],[1,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::misc::PointSpacingType","alias":null}},"import_index":1}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":2}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":3}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":4}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":5}},{"Network":{"import_type":{"Concrete":{"name":"bool","alias":null}},"import_index":6}},{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::SamplePolylineNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[15637103575662751567,{"inputs":[{"Node":{"node_id":314278016428495768,"output_index":0,"lambda":false}},{"Node":{"node_id":4350324834849900949,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[10375238420217738812,{"inputs":[{"Node":{"node_id":2282726379014798660,"output_index":0,"lambda":false}},{"Node":{"node_id":17078740291337047697,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"F64":1.2},"exposed":false}},{"Value":{"tagged_value":{"F64":2.0},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"U32":0},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"U32":0},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::CopyToPointsNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]},"network_metadata":{"persistent_metadata":{"node_metadata":[[11025165626998987360,{"persistent_metadata":{"reference":"Copy to Points","display_name":"","input_properties":[{"input_data":{"input_name":"Points"},"widget_override":null},{"input_data":{"input_name":"Instance","tooltip":"Artwork to be copied and placed at each point"},"widget_override":null},{"input_data":{"input_name":"Random Scale Min","is_integer":false,"mode":"Range","range_min":0.0,"min":0.0,"tooltip":"Minimum range of randomized sizes given to each instance","blank_assist":true,"unit":"x","range_max":2.0},"widget_override":"number"},{"input_data":{"is_integer":false,"unit":"x","mode":"Range","min":0.0,"tooltip":"Minimum range of randomized sizes given to each instance","range_min":0.0,"blank_assist":true,"input_name":"Random Scale Max","range_max":2.0},"widget_override":"number"},{"input_data":{"range_min":-50.0,"input_name":"Random Scale Bias","blank_assist":true,"is_integer":false,"range_max":50.0,"mode":"Range","tooltip":"Bias for the probability distribution of randomized sizes (0 is uniform, negatives favor more of small sizes, positives favor more of large sizes)"},"widget_override":"number"},{"input_data":{"blank_assist":true,"mode":"Increment","is_integer":true,"min":0.0,"input_name":"Random Scale Seed","tooltip":"Seed to determine unique variations on all the randomized instance sizes"},"widget_override":"number"},{"input_data":{"blank_assist":true,"min":0.0,"is_integer":false,"input_name":"Random Rotation","max":360.0,"mode":"Range","tooltip":"Range of randomized angles given to each instance, in degrees ranging from furthest clockwise to counterclockwise","unit":"°"},"widget_override":"number"},{"input_data":{"blank_assist":true,"min":0.0,"input_name":"Random Rotation Seed","tooltip":"Seed to determine unique variations on all the randomized instance angles","is_integer":true,"mode":"Increment"},"widget_override":"number"}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[7654665057468818389,{"persistent_metadata":{"reference":"Fill","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Fill"},"widget_override":null},{"input_data":{"input_name":"Backup Color"},"widget_override":null},{"input_data":{"input_name":"Backup Gradient"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[1204243038352113866,{"persistent_metadata":{"reference":"Path","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Modification"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"Path Modify","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[431994205232245356,{"persistent_metadata":{"reference":"Merge","display_name":"","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Absolute":[-17,7]}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[13035777574951374461,{"persistent_metadata":{"reference":"Path","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Modification"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"Path Modify","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[7821977654068146599,{"persistent_metadata":{"reference":"Path","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Modification"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"Path Modify","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[9182448229950585507,{"persistent_metadata":{"reference":"Merge","display_name":"","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":0}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[1806828617441445250,{"persistent_metadata":{"reference":"Path","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Modification"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"Path Modify","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[16051539163551573193,{"persistent_metadata":{"reference":"Path","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Modification"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"Path Modify","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[14345191642063772510,{"persistent_metadata":{"reference":"Path","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Modification"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"Path Modify","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[2397243911096708995,{"persistent_metadata":{"reference":"Merge","display_name":"","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":0}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[17494926338451345058,{"persistent_metadata":{"reference":"Merge","display_name":"","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":0}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[5174744389209053970,{"persistent_metadata":{"reference":"Merge","display_name":"","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":0}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[11464423670065789907,{"persistent_metadata":{"reference":"Copy to Points","display_name":"","input_properties":[{"input_data":{"input_name":"Points"},"widget_override":null},{"input_data":{"input_name":"Instance","tooltip":"Artwork to be copied and placed at each point"},"widget_override":null},{"input_data":{"range_max":2.0,"input_name":"Random Scale Min","tooltip":"Minimum range of randomized sizes given to each instance","blank_assist":true,"unit":"x","is_integer":false,"min":0.0,"mode":"Range","range_min":0.0},"widget_override":"number"},{"input_data":{"range_min":0.0,"is_integer":false,"min":0.0,"tooltip":"Minimum range of randomized sizes given to each instance","input_name":"Random Scale Max","unit":"x","range_max":2.0,"blank_assist":true,"mode":"Range"},"widget_override":"number"},{"input_data":{"blank_assist":true,"input_name":"Random Scale Bias","range_min":-50.0,"is_integer":false,"mode":"Range","range_max":50.0,"tooltip":"Bias for the probability distribution of randomized sizes (0 is uniform, negatives favor more of small sizes, positives favor more of large sizes)"},"widget_override":"number"},{"input_data":{"mode":"Increment","is_integer":true,"min":0.0,"blank_assist":true,"input_name":"Random Scale Seed","tooltip":"Seed to determine unique variations on all the randomized instance sizes"},"widget_override":"number"},{"input_data":{"input_name":"Random Rotation","mode":"Range","min":0.0,"tooltip":"Range of randomized angles given to each instance, in degrees ranging from furthest clockwise to counterclockwise","max":360.0,"unit":"°","blank_assist":true,"is_integer":false},"widget_override":"number"},{"input_data":{"mode":"Increment","tooltip":"Seed to determine unique variations on all the randomized instance angles","min":0.0,"is_integer":true,"blank_assist":true,"input_name":"Random Rotation Seed"},"widget_override":"number"}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[10375238420217738812,{"persistent_metadata":{"reference":"Copy to Points","display_name":"","input_properties":[{"input_data":{"input_name":"Points"},"widget_override":null},{"input_data":{"tooltip":"Artwork to be copied and placed at each point","input_name":"Instance"},"widget_override":null},{"input_data":{"min":0.0,"range_max":2.0,"range_min":0.0,"unit":"x","mode":"Range","input_name":"Random Scale Min","is_integer":false,"tooltip":"Minimum range of randomized sizes given to each instance","blank_assist":true},"widget_override":"number"},{"input_data":{"tooltip":"Minimum range of randomized sizes given to each instance","input_name":"Random Scale Max","mode":"Range","range_min":0.0,"min":0.0,"is_integer":false,"blank_assist":true,"range_max":2.0,"unit":"x"},"widget_override":"number"},{"input_data":{"is_integer":false,"range_max":50.0,"range_min":-50.0,"tooltip":"Bias for the probability distribution of randomized sizes (0 is uniform, negatives favor more of small sizes, positives favor more of large sizes)","mode":"Range","blank_assist":true,"input_name":"Random Scale Bias"},"widget_override":"number"},{"input_data":{"mode":"Increment","tooltip":"Seed to determine unique variations on all the randomized instance sizes","blank_assist":true,"input_name":"Random Scale Seed","is_integer":true,"min":0.0},"widget_override":"number"},{"input_data":{"input_name":"Random Rotation","min":0.0,"mode":"Range","unit":"°","blank_assist":true,"max":360.0,"is_integer":false,"tooltip":"Range of randomized angles given to each instance, in degrees ranging from furthest clockwise to counterclockwise"},"widget_override":"number"},{"input_data":{"is_integer":true,"blank_assist":true,"min":0.0,"tooltip":"Seed to determine unique variations on all the randomized instance angles","input_name":"Random Rotation Seed","mode":"Increment"},"widget_override":"number"}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[18279507457571359732,{"persistent_metadata":{"reference":"Fill","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Fill"},"widget_override":null},{"input_data":{"input_name":"Backup Color"},"widget_override":null},{"input_data":{"input_name":"Backup Gradient"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[10432831427187785843,{"persistent_metadata":{"reference":"Fill","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Fill"},"widget_override":null},{"input_data":{"input_name":"Backup Color"},"widget_override":null},{"input_data":{"input_name":"Backup Gradient"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[13045580349734858212,{"persistent_metadata":{"reference":"Scatter Points","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"min":0.01,"range_min":1.0,"input_name":"Separation Disk Diameter","is_integer":false,"blank_assist":true,"range_max":100.0,"mode":"Range"},"widget_override":"number"},{"input_data":{"blank_assist":true,"min":0.0,"mode":"Increment","input_name":"Seed","is_integer":true},"widget_override":"number"}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[2,{"persistent_metadata":{"reference":null,"display_name":"Freeze Real Time","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[14,0]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Boundless Footprint","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[21,0]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"Poisson-Disk Points","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"Memoize","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[8413863870096329943,{"persistent_metadata":{"reference":"Merge","display_name":"","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":0}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[15177845878727456758,{"persistent_metadata":{"reference":"Fill","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Fill"},"widget_override":null},{"input_data":{"input_name":"Backup Color"},"widget_override":null},{"input_data":{"input_name":"Backup Gradient"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[2878992817082507910,{"persistent_metadata":{"reference":"Path","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Modification"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"Path Modify","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[4784708315242877950,{"persistent_metadata":{"reference":"Path","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Modification"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"Path Modify","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[9740500978584792725,{"persistent_metadata":{"reference":"Merge","display_name":"","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":0}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[12473080738469616517,{"persistent_metadata":{"reference":"Fill","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Fill"},"widget_override":null},{"input_data":{"input_name":"Backup Color"},"widget_override":null},{"input_data":{"input_name":"Backup Gradient"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[15286091228862934481,{"persistent_metadata":{"reference":"Path","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Modification"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"Path Modify","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[2959546142916532439,{"persistent_metadata":{"reference":"Path","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Modification"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"Path Modify","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[14946189826912398678,{"persistent_metadata":{"reference":"Merge","display_name":"","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":0}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[4663768795652429571,{"persistent_metadata":{"reference":"Path","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Modification"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"Path Modify","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[1162381870526064378,{"persistent_metadata":{"reference":"Merge","display_name":"","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":0}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[14887821801874852671,{"persistent_metadata":{"reference":"Merge","display_name":"","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":0}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[6292009934909381201,{"persistent_metadata":{"reference":"Merge","display_name":"","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Absolute":[-17,88]}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[2087303479944421366,{"persistent_metadata":{"reference":"Path","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Modification"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"Path Modify","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[11630078441485655672,{"persistent_metadata":{"reference":"Path","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Modification"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"Path Modify","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[542361600097372754,{"persistent_metadata":{"reference":"Merge","display_name":"","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":0}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[14982414026754548178,{"persistent_metadata":{"reference":"Copy to Points","display_name":"","input_properties":[{"input_data":{"input_name":"Points"},"widget_override":null},{"input_data":{"tooltip":"Artwork to be copied and placed at each point","input_name":"Instance"},"widget_override":null},{"input_data":{"mode":"Range","unit":"x","range_min":0.0,"blank_assist":true,"is_integer":false,"min":0.0,"tooltip":"Minimum range of randomized sizes given to each instance","range_max":2.0,"input_name":"Random Scale Min"},"widget_override":"number"},{"input_data":{"range_max":2.0,"is_integer":false,"tooltip":"Minimum range of randomized sizes given to each instance","blank_assist":true,"input_name":"Random Scale Max","min":0.0,"range_min":0.0,"unit":"x","mode":"Range"},"widget_override":"number"},{"input_data":{"tooltip":"Bias for the probability distribution of randomized sizes (0 is uniform, negatives favor more of small sizes, positives favor more of large sizes)","range_max":50.0,"range_min":-50.0,"is_integer":false,"input_name":"Random Scale Bias","mode":"Range","blank_assist":true},"widget_override":"number"},{"input_data":{"blank_assist":true,"input_name":"Random Scale Seed","is_integer":true,"min":0.0,"tooltip":"Seed to determine unique variations on all the randomized instance sizes","mode":"Increment"},"widget_override":"number"},{"input_data":{"is_integer":false,"input_name":"Random Rotation","mode":"Range","blank_assist":true,"unit":"°","max":360.0,"min":0.0,"tooltip":"Range of randomized angles given to each instance, in degrees ranging from furthest clockwise to counterclockwise"},"widget_override":"number"},{"input_data":{"min":0.0,"blank_assist":true,"mode":"Increment","is_integer":true,"tooltip":"Seed to determine unique variations on all the randomized instance angles","input_name":"Random Rotation Seed"},"widget_override":"number"}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[13557369662261607646,{"persistent_metadata":{"reference":"Merge","display_name":"","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":0}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[16175421708184657649,{"persistent_metadata":{"reference":"Merge","display_name":"","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":0}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[10918055532782314571,{"persistent_metadata":{"reference":"Copy to Points","display_name":"","input_properties":[{"input_data":{"input_name":"Points"},"widget_override":null},{"input_data":{"input_name":"Instance","tooltip":"Artwork to be copied and placed at each point"},"widget_override":null},{"input_data":{"input_name":"Random Scale Min","blank_assist":true,"min":0.0,"range_min":0.0,"tooltip":"Minimum range of randomized sizes given to each instance","is_integer":false,"range_max":2.0,"mode":"Range","unit":"x"},"widget_override":"number"},{"input_data":{"tooltip":"Minimum range of randomized sizes given to each instance","range_min":0.0,"mode":"Range","range_max":2.0,"unit":"x","input_name":"Random Scale Max","blank_assist":true,"is_integer":false,"min":0.0},"widget_override":"number"},{"input_data":{"blank_assist":true,"range_max":50.0,"input_name":"Random Scale Bias","is_integer":false,"range_min":-50.0,"tooltip":"Bias for the probability distribution of randomized sizes (0 is uniform, negatives favor more of small sizes, positives favor more of large sizes)","mode":"Range"},"widget_override":"number"},{"input_data":{"is_integer":true,"mode":"Increment","min":0.0,"blank_assist":true,"input_name":"Random Scale Seed","tooltip":"Seed to determine unique variations on all the randomized instance sizes"},"widget_override":"number"},{"input_data":{"max":360.0,"tooltip":"Range of randomized angles given to each instance, in degrees ranging from furthest clockwise to counterclockwise","mode":"Range","blank_assist":true,"input_name":"Random Rotation","min":0.0,"is_integer":false,"unit":"°"},"widget_override":"number"},{"input_data":{"mode":"Increment","tooltip":"Seed to determine unique variations on all the randomized instance angles","is_integer":true,"input_name":"Random Rotation Seed","blank_assist":true,"min":0.0},"widget_override":"number"}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[15982852655074258238,{"persistent_metadata":{"reference":"Path","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Modification"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"Path Modify","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[13261814586176172586,{"persistent_metadata":{"reference":"Path","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Modification"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"Path Modify","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[4572557574846980832,{"persistent_metadata":{"reference":"Copy to Points","display_name":"","input_properties":[{"input_data":{"input_name":"Points"},"widget_override":null},{"input_data":{"tooltip":"Artwork to be copied and placed at each point","input_name":"Instance"},"widget_override":null},{"input_data":{"blank_assist":true,"tooltip":"Minimum range of randomized sizes given to each instance","input_name":"Random Scale Min","is_integer":false,"range_min":0.0,"min":0.0,"mode":"Range","range_max":2.0,"unit":"x"},"widget_override":"number"},{"input_data":{"is_integer":false,"blank_assist":true,"range_min":0.0,"min":0.0,"tooltip":"Minimum range of randomized sizes given to each instance","range_max":2.0,"input_name":"Random Scale Max","mode":"Range","unit":"x"},"widget_override":"number"},{"input_data":{"range_min":-50.0,"tooltip":"Bias for the probability distribution of randomized sizes (0 is uniform, negatives favor more of small sizes, positives favor more of large sizes)","input_name":"Random Scale Bias","is_integer":false,"blank_assist":true,"mode":"Range","range_max":50.0},"widget_override":"number"},{"input_data":{"is_integer":true,"min":0.0,"tooltip":"Seed to determine unique variations on all the randomized instance sizes","mode":"Increment","blank_assist":true,"input_name":"Random Scale Seed"},"widget_override":"number"},{"input_data":{"mode":"Range","is_integer":false,"tooltip":"Range of randomized angles given to each instance, in degrees ranging from furthest clockwise to counterclockwise","unit":"°","max":360.0,"blank_assist":true,"input_name":"Random Rotation","min":0.0},"widget_override":"number"},{"input_data":{"input_name":"Random Rotation Seed","min":0.0,"mode":"Increment","tooltip":"Seed to determine unique variations on all the randomized instance angles","blank_assist":true,"is_integer":true},"widget_override":"number"}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[9529195152569434392,{"persistent_metadata":{"reference":"Fill","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Fill"},"widget_override":null},{"input_data":{"input_name":"Backup Color"},"widget_override":null},{"input_data":{"input_name":"Backup Gradient"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[14057307926677215422,{"persistent_metadata":{"reference":"Merge","display_name":"","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":0}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[16767482995096345179,{"persistent_metadata":{"reference":"Fill","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Fill"},"widget_override":null},{"input_data":{"input_name":"Backup Color"},"widget_override":null},{"input_data":{"input_name":"Backup Gradient"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[1272070255512697108,{"persistent_metadata":{"reference":"Fill","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Fill"},"widget_override":null},{"input_data":{"input_name":"Backup Color"},"widget_override":null},{"input_data":{"input_name":"Backup Gradient"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[15827578515555598997,{"persistent_metadata":{"reference":"Fill","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Fill"},"widget_override":null},{"input_data":{"input_name":"Backup Color"},"widget_override":null},{"input_data":{"input_name":"Backup Gradient"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[4222034829755771252,{"persistent_metadata":{"reference":"Path","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Modification"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"Path Modify","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[6672826052605647592,{"persistent_metadata":{"reference":"Path","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Modification"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"Path Modify","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[12531351117929704587,{"persistent_metadata":{"reference":"Fill","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Fill"},"widget_override":null},{"input_data":{"input_name":"Backup Color"},"widget_override":null},{"input_data":{"input_name":"Backup Gradient"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[9276497172451351253,{"persistent_metadata":{"reference":"Path","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Modification"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"Path Modify","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[14598755603287563819,{"persistent_metadata":{"reference":"Fill","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Fill"},"widget_override":null},{"input_data":{"input_name":"Backup Color"},"widget_override":null},{"input_data":{"input_name":"Backup Gradient"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[6124821161363551058,{"persistent_metadata":{"reference":"Sample Polyline","display_name":"","input_properties":[{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{"mode":"Increment","blank_assist":true,"unit":" px","is_integer":false,"min":0.0},"widget_override":"number"},{"input_data":{"is_integer":true,"mode":"Increment","min":2.0,"blank_assist":true},"widget_override":"number"},{"input_data":{"unit":" px","min":0.0,"blank_assist":true,"is_integer":false,"mode":"Increment"},"widget_override":"number"},{"input_data":{"is_integer":false,"unit":" px","min":0.0,"blank_assist":true,"mode":"Increment"},"widget_override":"number"},{"input_data":{},"widget_override":null}],"output_names":["Vector"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"Subpath Segment Lengths","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,7]}}},"network_metadata":null}}],[4,{"persistent_metadata":{"reference":null,"display_name":"Boundless Footprint","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[28,0]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Memoize","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[14,0]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"Sample Polyline","input_properties":[{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Freeze Real Time","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[21,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[17971411534648521628,{"persistent_metadata":{"reference":"Merge","display_name":"","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":0}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[8595304668947966919,{"persistent_metadata":{"reference":"Path","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Modification"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"Path Modify","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[1157261387411722141,{"persistent_metadata":{"reference":"Fill","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Fill"},"widget_override":null},{"input_data":{"input_name":"Backup Color"},"widget_override":null},{"input_data":{"input_name":"Backup Gradient"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[15239301303367148581,{"persistent_metadata":{"reference":"Merge","display_name":"","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":0}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[12496143061817048445,{"persistent_metadata":{"reference":"Merge","display_name":"","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":0}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[15798070933198867970,{"persistent_metadata":{"reference":"Path","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Modification"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"Path Modify","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[6645255982686652881,{"persistent_metadata":{"reference":"Path","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Modification"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"Path Modify","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[16446146761452576438,{"persistent_metadata":{"reference":"Transform","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"x":"X","input_name":"Translation","unit":" px","y":"Y"},"widget_override":"vec2"},{"input_data":{"input_name":"Rotation"},"widget_override":"transform_rotation"},{"input_data":{"y":"H","input_name":"Scale","unit":"x","x":"W"},"widget_override":"vec2"},{"input_data":{"input_name":"Skew"},"widget_override":"hidden"},{"input_data":{"input_name":"Pivot"},"widget_override":"hidden"}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"Transform","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[11481949351661484921,{"persistent_metadata":{"reference":"Sample Polyline","display_name":"","input_properties":[{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{"min":0.0,"mode":"Increment","is_integer":false,"blank_assist":true,"unit":" px"},"widget_override":"number"},{"input_data":{"is_integer":true,"mode":"Increment","min":2.0,"blank_assist":true},"widget_override":"number"},{"input_data":{"unit":" px","blank_assist":true,"is_integer":false,"min":0.0,"mode":"Increment"},"widget_override":"number"},{"input_data":{"blank_assist":true,"is_integer":false,"mode":"Increment","min":0.0,"unit":" px"},"widget_override":"number"},{"input_data":{},"widget_override":null}],"output_names":["Vector"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[2,{"persistent_metadata":{"reference":null,"display_name":"Memoize","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[14,0]}}},"network_metadata":null}}],[4,{"persistent_metadata":{"reference":null,"display_name":"Boundless Footprint","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[28,0]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Freeze Real Time","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[21,0]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"Sample Polyline","input_properties":[{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"Subpath Segment Lengths","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,7]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[15303587427289959766,{"persistent_metadata":{"reference":"Path","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Modification"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"Path Modify","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[14991324592500870173,{"persistent_metadata":{"reference":"Merge","display_name":"","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":0}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[8375495949882478840,{"persistent_metadata":{"reference":"Path","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Modification"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"Path Modify","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[4350324834849900949,{"persistent_metadata":{"reference":"Fill","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Fill"},"widget_override":null},{"input_data":{"input_name":"Backup Color"},"widget_override":null},{"input_data":{"input_name":"Backup Gradient"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[4479074488343511985,{"persistent_metadata":{"reference":"Fill","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Fill"},"widget_override":null},{"input_data":{"input_name":"Backup Color"},"widget_override":null},{"input_data":{"input_name":"Backup Gradient"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[9425359632144678256,{"persistent_metadata":{"reference":"Path","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Modification"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"Path Modify","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[13302269488061286120,{"persistent_metadata":{"reference":"Path","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Modification"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"Path Modify","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[12387541320114693418,{"persistent_metadata":{"reference":"Merge","display_name":"","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":0}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[9778375740427894463,{"persistent_metadata":{"reference":"Fill","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Fill"},"widget_override":null},{"input_data":{"input_name":"Backup Color"},"widget_override":null},{"input_data":{"input_name":"Backup Gradient"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[3992858139802231032,{"persistent_metadata":{"reference":"Path","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Modification"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"Path Modify","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[11479098559726891734,{"persistent_metadata":{"reference":"Path","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Modification"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"Path Modify","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[2641530639940889619,{"persistent_metadata":{"reference":"Merge","display_name":"","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":0}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[3150436463719911922,{"persistent_metadata":{"reference":"Transform","display_name":"","input_properties":[{"input_data":{},"widget_override":null},{"input_data":{"y":"Y","unit":" px","x":"X"},"widget_override":"vec2"},{"input_data":{},"widget_override":"transform_rotation"},{"input_data":{"unit":"x","x":"W","y":"H"},"widget_override":"vec2"},{"input_data":{},"widget_override":"transform_skew"},{"input_data":{},"widget_override":"hidden"}],"output_names":["Data"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"Transform","input_properties":[{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[13352561089252322209,{"persistent_metadata":{"reference":"Path","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Modification"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"Path Modify","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[7747398671834040298,{"persistent_metadata":{"reference":"Scatter Points","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Separation Disk Diameter","blank_assist":true,"range_max":100.0,"is_integer":false,"min":0.01,"range_min":1.0,"mode":"Range"},"widget_override":"number"},{"input_data":{"is_integer":true,"min":0.0,"mode":"Increment","input_name":"Seed","blank_assist":true},"widget_override":"number"}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[3,{"persistent_metadata":{"reference":null,"display_name":"Boundless Footprint","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[21,0]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Freeze Real Time","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[14,0]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"Memoize","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"Poisson-Disk Points","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[11677503666435782605,{"persistent_metadata":{"reference":"Fill","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Fill"},"widget_override":null},{"input_data":{"input_name":"Backup Color"},"widget_override":null},{"input_data":{"input_name":"Backup Gradient"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[18190631752493248867,{"persistent_metadata":{"reference":"Merge","display_name":"","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":0}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[3170924135668664007,{"persistent_metadata":{"reference":"Merge","display_name":"Pointing Arm","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":6}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[10928540355449103287,{"persistent_metadata":{"reference":"Merge","display_name":"","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":0}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[10792166025753022402,{"persistent_metadata":{"reference":"Fill","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Fill"},"widget_override":null},{"input_data":{"input_name":"Backup Color"},"widget_override":null},{"input_data":{"input_name":"Backup Gradient"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[4332145463108161926,{"persistent_metadata":{"reference":"Fill","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Fill"},"widget_override":null},{"input_data":{"input_name":"Backup Color"},"widget_override":null},{"input_data":{"input_name":"Backup Gradient"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-31,292]}}},"network_metadata":null}}],[7893851488963635918,{"persistent_metadata":{"reference":"Path","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Modification"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"Path Modify","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[11356586238302409958,{"persistent_metadata":{"reference":"Path","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Modification"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"Path Modify","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[9271343782272072828,{"persistent_metadata":{"reference":"Fill","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Fill"},"widget_override":null},{"input_data":{"input_name":"Backup Color"},"widget_override":null},{"input_data":{"input_name":"Backup Gradient"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[9847383247226990698,{"persistent_metadata":{"reference":"Fill","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Fill"},"widget_override":null},{"input_data":{"input_name":"Backup Color"},"widget_override":null},{"input_data":{"input_name":"Backup Gradient"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[16290933138334939444,{"persistent_metadata":{"reference":"Merge","display_name":"","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":0}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[4265165189651403984,{"persistent_metadata":{"reference":"Merge","display_name":"","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":0}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[9470742171134780193,{"persistent_metadata":{"reference":"Merge","display_name":"Dotted Skirt","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":81}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[6416452251137958677,{"persistent_metadata":{"reference":"Copy to Points","display_name":"","input_properties":[{"input_data":{"input_name":"Points"},"widget_override":null},{"input_data":{"tooltip":"Artwork to be copied and placed at each point","input_name":"Instance"},"widget_override":null},{"input_data":{"range_min":0.0,"min":0.0,"unit":"x","range_max":2.0,"input_name":"Random Scale Min","is_integer":false,"tooltip":"Minimum range of randomized sizes given to each instance","blank_assist":true,"mode":"Range"},"widget_override":"number"},{"input_data":{"range_max":2.0,"tooltip":"Minimum range of randomized sizes given to each instance","mode":"Range","range_min":0.0,"blank_assist":true,"is_integer":false,"unit":"x","input_name":"Random Scale Max","min":0.0},"widget_override":"number"},{"input_data":{"mode":"Range","range_min":-50.0,"range_max":50.0,"tooltip":"Bias for the probability distribution of randomized sizes (0 is uniform, negatives favor more of small sizes, positives favor more of large sizes)","blank_assist":true,"input_name":"Random Scale Bias","is_integer":false},"widget_override":"number"},{"input_data":{"blank_assist":true,"input_name":"Random Scale Seed","min":0.0,"tooltip":"Seed to determine unique variations on all the randomized instance sizes","is_integer":true,"mode":"Increment"},"widget_override":"number"},{"input_data":{"min":0.0,"tooltip":"Range of randomized angles given to each instance, in degrees ranging from furthest clockwise to counterclockwise","mode":"Range","unit":"°","input_name":"Random Rotation","max":360.0,"is_integer":false,"blank_assist":true},"widget_override":"number"},{"input_data":{"min":0.0,"blank_assist":true,"tooltip":"Seed to determine unique variations on all the randomized instance angles","input_name":"Random Rotation Seed","is_integer":true,"mode":"Increment"},"widget_override":"number"}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[7320676248579211727,{"persistent_metadata":{"reference":"Fill","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Fill"},"widget_override":null},{"input_data":{"input_name":"Backup Color"},"widget_override":null},{"input_data":{"input_name":"Backup Gradient"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[5213978458941436169,{"persistent_metadata":{"reference":"Scatter Points","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"range_min":1.0,"min":0.01,"mode":"Range","input_name":"Separation Disk Diameter","is_integer":false,"range_max":100.0,"blank_assist":true},"widget_override":"number"},{"input_data":{"input_name":"Seed","blank_assist":true,"is_integer":true,"min":0.0,"mode":"Increment"},"widget_override":"number"}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[2,{"persistent_metadata":{"reference":null,"display_name":"Freeze Real Time","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[14,0]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"Poisson-Disk Points","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"Memoize","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Boundless Footprint","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[21,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[12219771677493189964,{"persistent_metadata":{"reference":"Merge","display_name":"","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":0}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[8699675339613677057,{"persistent_metadata":{"reference":"Transform","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"x":"X","unit":" px","y":"Y","input_name":"Translation"},"widget_override":"vec2"},{"input_data":{"input_name":"Rotation"},"widget_override":"transform_rotation"},{"input_data":{"input_name":"Scale","y":"H","unit":"x","x":"W"},"widget_override":"vec2"},{"input_data":{"input_name":"Skew"},"widget_override":"hidden"},{"input_data":{"input_name":"Pivot"},"widget_override":"hidden"}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"Transform","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[2440895173483452224,{"persistent_metadata":{"reference":"Path","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Modification"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"Path Modify","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[3802858053991775169,{"persistent_metadata":{"reference":"Scatter Points","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"range_max":100.0,"min":0.01,"range_min":1.0,"blank_assist":true,"input_name":"Separation Disk Diameter","is_integer":false,"mode":"Range"},"widget_override":"number"},{"input_data":{"min":0.0,"mode":"Increment","blank_assist":true,"is_integer":true,"input_name":"Seed"},"widget_override":"number"}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[2,{"persistent_metadata":{"reference":null,"display_name":"Freeze Real Time","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[14,0]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Boundless Footprint","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[21,0]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"Memoize","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"Poisson-Disk Points","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[5555007473125503522,{"persistent_metadata":{"reference":"Path","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Modification"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"Path Modify","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[11656581020969095354,{"persistent_metadata":{"reference":"Merge","display_name":"","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":0}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[541002100261582638,{"persistent_metadata":{"reference":"Path","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Modification"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"Path Modify","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[10587073897090054035,{"persistent_metadata":{"reference":"Merge","display_name":"","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":0}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[12876462860151722087,{"persistent_metadata":{"reference":"Merge","display_name":"","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":0}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[12554368619682347699,{"persistent_metadata":{"reference":"Copy to Points","display_name":"","input_properties":[{"input_data":{"input_name":"Points"},"widget_override":null},{"input_data":{"tooltip":"Artwork to be copied and placed at each point","input_name":"Instance"},"widget_override":null},{"input_data":{"unit":"x","mode":"Range","range_min":0.0,"blank_assist":true,"input_name":"Random Scale Min","is_integer":false,"min":0.0,"range_max":2.0,"tooltip":"Minimum range of randomized sizes given to each instance"},"widget_override":"number"},{"input_data":{"input_name":"Random Scale Max","unit":"x","is_integer":false,"min":0.0,"tooltip":"Minimum range of randomized sizes given to each instance","range_max":2.0,"mode":"Range","range_min":0.0,"blank_assist":true},"widget_override":"number"},{"input_data":{"range_min":-50.0,"input_name":"Random Scale Bias","mode":"Range","is_integer":false,"tooltip":"Bias for the probability distribution of randomized sizes (0 is uniform, negatives favor more of small sizes, positives favor more of large sizes)","range_max":50.0,"blank_assist":true},"widget_override":"number"},{"input_data":{"mode":"Increment","tooltip":"Seed to determine unique variations on all the randomized instance sizes","is_integer":true,"blank_assist":true,"input_name":"Random Scale Seed","min":0.0},"widget_override":"number"},{"input_data":{"input_name":"Random Rotation","mode":"Range","blank_assist":true,"is_integer":false,"tooltip":"Range of randomized angles given to each instance, in degrees ranging from furthest clockwise to counterclockwise","min":0.0,"max":360.0,"unit":"°"},"widget_override":"number"},{"input_data":{"mode":"Increment","tooltip":"Seed to determine unique variations on all the randomized instance angles","is_integer":true,"blank_assist":true,"input_name":"Random Rotation Seed","min":0.0},"widget_override":"number"}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[10264089084180279094,{"persistent_metadata":{"reference":"Copy to Points","display_name":"","input_properties":[{"input_data":{"input_name":"Points"},"widget_override":null},{"input_data":{"input_name":"Instance","tooltip":"Artwork to be copied and placed at each point"},"widget_override":null},{"input_data":{"tooltip":"Minimum range of randomized sizes given to each instance","is_integer":false,"range_max":2.0,"min":0.0,"blank_assist":true,"range_min":0.0,"mode":"Range","unit":"x","input_name":"Random Scale Min"},"widget_override":"number"},{"input_data":{"range_max":2.0,"unit":"x","range_min":0.0,"tooltip":"Minimum range of randomized sizes given to each instance","input_name":"Random Scale Max","is_integer":false,"blank_assist":true,"mode":"Range","min":0.0},"widget_override":"number"},{"input_data":{"blank_assist":true,"input_name":"Random Scale Bias","is_integer":false,"mode":"Range","range_max":50.0,"tooltip":"Bias for the probability distribution of randomized sizes (0 is uniform, negatives favor more of small sizes, positives favor more of large sizes)","range_min":-50.0},"widget_override":"number"},{"input_data":{"min":0.0,"blank_assist":true,"mode":"Increment","input_name":"Random Scale Seed","tooltip":"Seed to determine unique variations on all the randomized instance sizes","is_integer":true},"widget_override":"number"},{"input_data":{"input_name":"Random Rotation","mode":"Range","tooltip":"Range of randomized angles given to each instance, in degrees ranging from furthest clockwise to counterclockwise","unit":"°","is_integer":false,"min":0.0,"blank_assist":true,"max":360.0},"widget_override":"number"},{"input_data":{"tooltip":"Seed to determine unique variations on all the randomized instance angles","min":0.0,"mode":"Increment","blank_assist":true,"input_name":"Random Rotation Seed","is_integer":true},"widget_override":"number"}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[1621196991038859321,{"persistent_metadata":{"reference":"Sample Polyline","display_name":"","input_properties":[{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{"min":0.0,"mode":"Increment","unit":" px","is_integer":false,"blank_assist":true},"widget_override":"number"},{"input_data":{"is_integer":true,"mode":"Increment","blank_assist":true,"min":2.0},"widget_override":"number"},{"input_data":{"unit":" px","is_integer":false,"min":0.0,"blank_assist":true,"mode":"Increment"},"widget_override":"number"},{"input_data":{"unit":" px","blank_assist":true,"mode":"Increment","is_integer":false,"min":0.0},"widget_override":"number"},{"input_data":{},"widget_override":null}],"output_names":["Vector"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[4,{"persistent_metadata":{"reference":null,"display_name":"Boundless Footprint","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[28,0]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"Subpath Segment Lengths","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,7]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"Sample Polyline","input_properties":[{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Memoize","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[14,0]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Freeze Real Time","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[21,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[17378885078543074499,{"persistent_metadata":{"reference":"Path","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Modification"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"Path Modify","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[12761901161949743155,{"persistent_metadata":{"reference":"Merge","display_name":"","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":0}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[14993053984267866751,{"persistent_metadata":{"reference":"Merge","display_name":"","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":0}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[1384427686127078856,{"persistent_metadata":{"reference":"Merge","display_name":"","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":0}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[16649851742084147477,{"persistent_metadata":{"reference":"Path","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Modification"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"Path Modify","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[17133591775058457007,{"persistent_metadata":{"reference":"Copy to Points","display_name":"","input_properties":[{"input_data":{"input_name":"Points"},"widget_override":null},{"input_data":{"tooltip":"Artwork to be copied and placed at each point","input_name":"Instance"},"widget_override":null},{"input_data":{"tooltip":"Minimum range of randomized sizes given to each instance","range_min":0.0,"range_max":2.0,"input_name":"Random Scale Min","is_integer":false,"mode":"Range","unit":"x","blank_assist":true,"min":0.0},"widget_override":"number"},{"input_data":{"mode":"Range","tooltip":"Minimum range of randomized sizes given to each instance","range_min":0.0,"range_max":2.0,"unit":"x","input_name":"Random Scale Max","min":0.0,"is_integer":false,"blank_assist":true},"widget_override":"number"},{"input_data":{"is_integer":false,"mode":"Range","range_max":50.0,"range_min":-50.0,"tooltip":"Bias for the probability distribution of randomized sizes (0 is uniform, negatives favor more of small sizes, positives favor more of large sizes)","blank_assist":true,"input_name":"Random Scale Bias"},"widget_override":"number"},{"input_data":{"blank_assist":true,"min":0.0,"mode":"Increment","input_name":"Random Scale Seed","is_integer":true,"tooltip":"Seed to determine unique variations on all the randomized instance sizes"},"widget_override":"number"},{"input_data":{"max":360.0,"unit":"°","min":0.0,"tooltip":"Range of randomized angles given to each instance, in degrees ranging from furthest clockwise to counterclockwise","is_integer":false,"blank_assist":true,"input_name":"Random Rotation","mode":"Range"},"widget_override":"number"},{"input_data":{"is_integer":true,"input_name":"Random Rotation Seed","min":0.0,"mode":"Increment","blank_assist":true,"tooltip":"Seed to determine unique variations on all the randomized instance angles"},"widget_override":"number"}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[12313564802550122052,{"persistent_metadata":{"reference":"Merge","display_name":"","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":0}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[12385950900718181935,{"persistent_metadata":{"reference":"Merge","display_name":"","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":0}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[10086073308516686449,{"persistent_metadata":{"reference":"Merge","display_name":"","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":0}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[8091904580702893317,{"persistent_metadata":{"reference":"Fill","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Fill"},"widget_override":null},{"input_data":{"input_name":"Backup Color"},"widget_override":null},{"input_data":{"input_name":"Backup Gradient"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[11021243031011826737,{"persistent_metadata":{"reference":"Fill","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Fill"},"widget_override":null},{"input_data":{"input_name":"Backup Color"},"widget_override":null},{"input_data":{"input_name":"Backup Gradient"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[2126710823743005151,{"persistent_metadata":{"reference":"Fill","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Fill"},"widget_override":null},{"input_data":{"input_name":"Backup Color"},"widget_override":null},{"input_data":{"input_name":"Backup Gradient"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[17364155187784942740,{"persistent_metadata":{"reference":"Fill","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Fill"},"widget_override":null},{"input_data":{"input_name":"Backup Color"},"widget_override":null},{"input_data":{"input_name":"Backup Gradient"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[421715625023770179,{"persistent_metadata":{"reference":"Merge","display_name":"","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":0}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[15038739378867834454,{"persistent_metadata":{"reference":"Path","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Modification"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"Path Modify","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[4307303572241320716,{"persistent_metadata":{"reference":"Merge","display_name":"","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Absolute":[-17,319]}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[8543051864256131356,{"persistent_metadata":{"reference":"Copy to Points","display_name":"","input_properties":[{"input_data":{"input_name":"Points"},"widget_override":null},{"input_data":{"input_name":"Instance","tooltip":"Artwork to be copied and placed at each point"},"widget_override":null},{"input_data":{"blank_assist":true,"is_integer":false,"tooltip":"Minimum range of randomized sizes given to each instance","mode":"Range","range_max":2.0,"range_min":0.0,"input_name":"Random Scale Min","unit":"x","min":0.0},"widget_override":"number"},{"input_data":{"input_name":"Random Scale Max","min":0.0,"range_min":0.0,"unit":"x","blank_assist":true,"tooltip":"Minimum range of randomized sizes given to each instance","mode":"Range","is_integer":false,"range_max":2.0},"widget_override":"number"},{"input_data":{"input_name":"Random Scale Bias","is_integer":false,"blank_assist":true,"mode":"Range","range_max":50.0,"range_min":-50.0,"tooltip":"Bias for the probability distribution of randomized sizes (0 is uniform, negatives favor more of small sizes, positives favor more of large sizes)"},"widget_override":"number"},{"input_data":{"min":0.0,"tooltip":"Seed to determine unique variations on all the randomized instance sizes","input_name":"Random Scale Seed","is_integer":true,"mode":"Increment","blank_assist":true},"widget_override":"number"},{"input_data":{"unit":"°","blank_assist":true,"input_name":"Random Rotation","tooltip":"Range of randomized angles given to each instance, in degrees ranging from furthest clockwise to counterclockwise","mode":"Range","max":360.0,"min":0.0,"is_integer":false},"widget_override":"number"},{"input_data":{"input_name":"Random Rotation Seed","min":0.0,"is_integer":true,"mode":"Increment","tooltip":"Seed to determine unique variations on all the randomized instance angles","blank_assist":true},"widget_override":"number"}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[615144098061106242,{"persistent_metadata":{"reference":"Fill","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Fill"},"widget_override":null},{"input_data":{"input_name":"Backup Color"},"widget_override":null},{"input_data":{"input_name":"Backup Gradient"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[9698363115186534174,{"persistent_metadata":{"reference":"Copy to Points","display_name":"","input_properties":[{"input_data":{"input_name":"Points"},"widget_override":null},{"input_data":{"tooltip":"Artwork to be copied and placed at each point","input_name":"Instance"},"widget_override":null},{"input_data":{"tooltip":"Minimum range of randomized sizes given to each instance","unit":"x","range_max":2.0,"is_integer":false,"min":0.0,"mode":"Range","blank_assist":true,"input_name":"Random Scale Min","range_min":0.0},"widget_override":"number"},{"input_data":{"mode":"Range","range_min":0.0,"blank_assist":true,"is_integer":false,"tooltip":"Minimum range of randomized sizes given to each instance","unit":"x","input_name":"Random Scale Max","range_max":2.0,"min":0.0},"widget_override":"number"},{"input_data":{"blank_assist":true,"range_max":50.0,"range_min":-50.0,"tooltip":"Bias for the probability distribution of randomized sizes (0 is uniform, negatives favor more of small sizes, positives favor more of large sizes)","mode":"Range","input_name":"Random Scale Bias","is_integer":false},"widget_override":"number"},{"input_data":{"is_integer":true,"tooltip":"Seed to determine unique variations on all the randomized instance sizes","blank_assist":true,"mode":"Increment","input_name":"Random Scale Seed","min":0.0},"widget_override":"number"},{"input_data":{"unit":"°","blank_assist":true,"input_name":"Random Rotation","min":0.0,"mode":"Range","tooltip":"Range of randomized angles given to each instance, in degrees ranging from furthest clockwise to counterclockwise","max":360.0,"is_integer":false},"widget_override":"number"},{"input_data":{"tooltip":"Seed to determine unique variations on all the randomized instance angles","min":0.0,"is_integer":true,"blank_assist":true,"mode":"Increment","input_name":"Random Rotation Seed"},"widget_override":"number"}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[18214377096178867498,{"persistent_metadata":{"reference":"Copy to Points","display_name":"","input_properties":[{"input_data":{"input_name":"Points"},"widget_override":null},{"input_data":{"tooltip":"Artwork to be copied and placed at each point","input_name":"Instance"},"widget_override":null},{"input_data":{"min":0.0,"input_name":"Random Scale Min","blank_assist":true,"is_integer":false,"mode":"Range","range_max":2.0,"range_min":0.0,"unit":"x","tooltip":"Minimum range of randomized sizes given to each instance"},"widget_override":"number"},{"input_data":{"range_max":2.0,"input_name":"Random Scale Max","blank_assist":true,"min":0.0,"unit":"x","is_integer":false,"range_min":0.0,"mode":"Range","tooltip":"Minimum range of randomized sizes given to each instance"},"widget_override":"number"},{"input_data":{"mode":"Range","input_name":"Random Scale Bias","tooltip":"Bias for the probability distribution of randomized sizes (0 is uniform, negatives favor more of small sizes, positives favor more of large sizes)","is_integer":false,"range_max":50.0,"blank_assist":true,"range_min":-50.0},"widget_override":"number"},{"input_data":{"min":0.0,"tooltip":"Seed to determine unique variations on all the randomized instance sizes","blank_assist":true,"is_integer":true,"input_name":"Random Scale Seed","mode":"Increment"},"widget_override":"number"},{"input_data":{"max":360.0,"mode":"Range","tooltip":"Range of randomized angles given to each instance, in degrees ranging from furthest clockwise to counterclockwise","input_name":"Random Rotation","blank_assist":true,"is_integer":false,"min":0.0,"unit":"°"},"widget_override":"number"},{"input_data":{"mode":"Increment","input_name":"Random Rotation Seed","is_integer":true,"blank_assist":true,"tooltip":"Seed to determine unique variations on all the randomized instance angles","min":0.0},"widget_override":"number"}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[4105711298139980122,{"persistent_metadata":{"reference":"Merge","display_name":"","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":0}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[13368990606109678244,{"persistent_metadata":{"reference":"Merge","display_name":"","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":0}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[10253927692147706615,{"persistent_metadata":{"reference":"Copy to Points","display_name":"","input_properties":[{"input_data":{"input_name":"Points"},"widget_override":null},{"input_data":{"tooltip":"Artwork to be copied and placed at each point","input_name":"Instance"},"widget_override":null},{"input_data":{"blank_assist":true,"min":0.0,"input_name":"Random Scale Min","range_max":2.0,"is_integer":false,"tooltip":"Minimum range of randomized sizes given to each instance","range_min":0.0,"mode":"Range","unit":"x"},"widget_override":"number"},{"input_data":{"mode":"Range","range_min":0.0,"unit":"x","input_name":"Random Scale Max","min":0.0,"range_max":2.0,"tooltip":"Minimum range of randomized sizes given to each instance","blank_assist":true,"is_integer":false},"widget_override":"number"},{"input_data":{"is_integer":false,"blank_assist":true,"mode":"Range","input_name":"Random Scale Bias","range_max":50.0,"range_min":-50.0,"tooltip":"Bias for the probability distribution of randomized sizes (0 is uniform, negatives favor more of small sizes, positives favor more of large sizes)"},"widget_override":"number"},{"input_data":{"min":0.0,"is_integer":true,"mode":"Increment","input_name":"Random Scale Seed","blank_assist":true,"tooltip":"Seed to determine unique variations on all the randomized instance sizes"},"widget_override":"number"},{"input_data":{"max":360.0,"tooltip":"Range of randomized angles given to each instance, in degrees ranging from furthest clockwise to counterclockwise","unit":"°","input_name":"Random Rotation","blank_assist":true,"mode":"Range","is_integer":false,"min":0.0},"widget_override":"number"},{"input_data":{"min":0.0,"blank_assist":true,"input_name":"Random Rotation Seed","tooltip":"Seed to determine unique variations on all the randomized instance angles","is_integer":true,"mode":"Increment"},"widget_override":"number"}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[1659518581611333812,{"persistent_metadata":{"reference":"Path","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Modification"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"Path Modify","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[8934999452649011837,{"persistent_metadata":{"reference":"Merge","display_name":"","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Absolute":[-17,130]}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[13163272246010991228,{"persistent_metadata":{"reference":"Merge","display_name":"","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":0}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[11804065810513502701,{"persistent_metadata":{"reference":"Merge","display_name":"","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":0}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[5140869461760168364,{"persistent_metadata":{"reference":"Fill","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Fill"},"widget_override":null},{"input_data":{"input_name":"Backup Color"},"widget_override":null},{"input_data":{"input_name":"Backup Gradient"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[14285767317419627814,{"persistent_metadata":{"reference":"Fill","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Fill"},"widget_override":null},{"input_data":{"input_name":"Backup Color"},"widget_override":null},{"input_data":{"input_name":"Backup Gradient"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[8814059393325469059,{"persistent_metadata":{"reference":"Merge","display_name":"","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":0}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[12131058586835568367,{"persistent_metadata":{"reference":"Path","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Modification"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"Path Modify","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[10514847656270897393,{"persistent_metadata":{"reference":"Merge","display_name":"","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":0}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[15637103575662751567,{"persistent_metadata":{"reference":"Merge","display_name":"","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":0}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[6867142265138950838,{"persistent_metadata":{"reference":"Fill","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Fill"},"widget_override":null},{"input_data":{"input_name":"Backup Color"},"widget_override":null},{"input_data":{"input_name":"Backup Gradient"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[1713644030979611623,{"persistent_metadata":{"reference":"Path","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Modification"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"Path Modify","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[3406722917122601552,{"persistent_metadata":{"reference":"Circle","display_name":"","input_properties":[{"input_data":{"input_name":"Primary"},"widget_override":null},{"input_data":{"input_name":"Radius"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-38,208]}}},"network_metadata":null}}],[13444661581815146533,{"persistent_metadata":{"reference":"Merge","display_name":"","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Absolute":[-17,97]}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[4078100635676202528,{"persistent_metadata":{"reference":"Path","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Modification"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"Path Modify","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[4787732047489141819,{"persistent_metadata":{"reference":"Merge","display_name":"Tucked Arm","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":24}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[4909350123806022131,{"persistent_metadata":{"reference":"Merge","display_name":"","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":0}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[3971837674569123876,{"persistent_metadata":{"reference":"Copy to Points","display_name":"","input_properties":[{"input_data":{"input_name":"Points"},"widget_override":null},{"input_data":{"input_name":"Instance","tooltip":"Artwork to be copied and placed at each point"},"widget_override":null},{"input_data":{"range_max":2.0,"blank_assist":true,"tooltip":"Minimum range of randomized sizes given to each instance","mode":"Range","range_min":0.0,"min":0.0,"unit":"x","is_integer":false,"input_name":"Random Scale Min"},"widget_override":"number"},{"input_data":{"range_max":2.0,"is_integer":false,"min":0.0,"tooltip":"Minimum range of randomized sizes given to each instance","unit":"x","input_name":"Random Scale Max","mode":"Range","range_min":0.0,"blank_assist":true},"widget_override":"number"},{"input_data":{"tooltip":"Bias for the probability distribution of randomized sizes (0 is uniform, negatives favor more of small sizes, positives favor more of large sizes)","is_integer":false,"input_name":"Random Scale Bias","mode":"Range","range_max":50.0,"range_min":-50.0,"blank_assist":true},"widget_override":"number"},{"input_data":{"mode":"Increment","input_name":"Random Scale Seed","min":0.0,"tooltip":"Seed to determine unique variations on all the randomized instance sizes","blank_assist":true,"is_integer":true},"widget_override":"number"},{"input_data":{"min":0.0,"mode":"Range","tooltip":"Range of randomized angles given to each instance, in degrees ranging from furthest clockwise to counterclockwise","blank_assist":true,"input_name":"Random Rotation","is_integer":false,"unit":"°","max":360.0},"widget_override":"number"},{"input_data":{"input_name":"Random Rotation Seed","min":0.0,"mode":"Increment","is_integer":true,"blank_assist":true,"tooltip":"Seed to determine unique variations on all the randomized instance angles"},"widget_override":"number"}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[1167210731467447244,{"persistent_metadata":{"reference":"Merge","display_name":"","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":0}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[5185036609290210853,{"persistent_metadata":{"reference":"Path","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Modification"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"Path Modify","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[3535178979443201645,{"persistent_metadata":{"reference":"Merge","display_name":"","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":0}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[1661691009086487874,{"persistent_metadata":{"reference":"Sample Polyline","display_name":"","input_properties":[{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{"is_integer":false,"unit":" px","min":0.0,"blank_assist":true,"mode":"Increment"},"widget_override":"number"},{"input_data":{"mode":"Increment","is_integer":true,"blank_assist":true,"min":2.0},"widget_override":"number"},{"input_data":{"mode":"Increment","is_integer":false,"min":0.0,"blank_assist":true,"unit":" px"},"widget_override":"number"},{"input_data":{"blank_assist":true,"unit":" px","mode":"Increment","is_integer":false,"min":0.0},"widget_override":"number"},{"input_data":{},"widget_override":null}],"output_names":["Vector"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[2,{"persistent_metadata":{"reference":null,"display_name":"Memoize","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[14,0]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Freeze Real Time","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[21,0]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"Sample Polyline","input_properties":[{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"Subpath Segment Lengths","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,7]}}},"network_metadata":null}}],[4,{"persistent_metadata":{"reference":null,"display_name":"Boundless Footprint","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[28,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[5278509881589546420,{"persistent_metadata":{"reference":"Path","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Modification"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"Path Modify","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[2594533001540454577,{"persistent_metadata":{"reference":"Sample Polyline","display_name":"","input_properties":[{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{"min":0.0,"blank_assist":true,"is_integer":false,"mode":"Increment","unit":" px"},"widget_override":"number"},{"input_data":{"is_integer":true,"blank_assist":true,"mode":"Increment","min":2.0},"widget_override":"number"},{"input_data":{"min":0.0,"unit":" px","blank_assist":true,"mode":"Increment","is_integer":false},"widget_override":"number"},{"input_data":{"blank_assist":true,"min":0.0,"is_integer":false,"mode":"Increment","unit":" px"},"widget_override":"number"},{"input_data":{},"widget_override":null}],"output_names":["Vector"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[4,{"persistent_metadata":{"reference":null,"display_name":"Boundless Footprint","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[28,0]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"Sample Polyline","input_properties":[{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"Subpath Segment Lengths","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,7]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Freeze Real Time","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[21,0]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Memoize","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[14,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[17699121037850769131,{"persistent_metadata":{"reference":"Path","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Modification"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"Path Modify","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[1889157037801767612,{"persistent_metadata":{"reference":"Scatter Points","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Separation Disk Diameter","blank_assist":true,"min":0.01,"is_integer":false,"mode":"Range","range_max":100.0,"range_min":1.0},"widget_override":"number"},{"input_data":{"is_integer":true,"min":0.0,"blank_assist":true,"mode":"Increment","input_name":"Seed"},"widget_override":"number"}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"Memoize","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Freeze Real Time","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[14,0]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Boundless Footprint","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[21,0]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"Poisson-Disk Points","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[13045087323693407920,{"persistent_metadata":{"reference":"Path","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Modification"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"Path Modify","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[17529660518597229229,{"persistent_metadata":{"reference":"Copy to Points","display_name":"","input_properties":[{"input_data":{"input_name":"Points"},"widget_override":null},{"input_data":{"tooltip":"Artwork to be copied and placed at each point","input_name":"Instance"},"widget_override":null},{"input_data":{"input_name":"Random Scale Min","blank_assist":true,"min":0.0,"mode":"Range","unit":"x","tooltip":"Minimum range of randomized sizes given to each instance","range_max":2.0,"is_integer":false,"range_min":0.0},"widget_override":"number"},{"input_data":{"min":0.0,"range_max":2.0,"input_name":"Random Scale Max","tooltip":"Minimum range of randomized sizes given to each instance","range_min":0.0,"mode":"Range","is_integer":false,"unit":"x","blank_assist":true},"widget_override":"number"},{"input_data":{"is_integer":false,"mode":"Range","range_max":50.0,"range_min":-50.0,"tooltip":"Bias for the probability distribution of randomized sizes (0 is uniform, negatives favor more of small sizes, positives favor more of large sizes)","input_name":"Random Scale Bias","blank_assist":true},"widget_override":"number"},{"input_data":{"tooltip":"Seed to determine unique variations on all the randomized instance sizes","blank_assist":true,"mode":"Increment","is_integer":true,"min":0.0,"input_name":"Random Scale Seed"},"widget_override":"number"},{"input_data":{"max":360.0,"tooltip":"Range of randomized angles given to each instance, in degrees ranging from furthest clockwise to counterclockwise","min":0.0,"unit":"°","input_name":"Random Rotation","blank_assist":true,"is_integer":false,"mode":"Range"},"widget_override":"number"},{"input_data":{"blank_assist":true,"tooltip":"Seed to determine unique variations on all the randomized instance angles","min":0.0,"mode":"Increment","is_integer":true,"input_name":"Random Rotation Seed"},"widget_override":"number"}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[5020096817747898028,{"persistent_metadata":{"reference":"Fill","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Fill"},"widget_override":null},{"input_data":{"input_name":"Backup Color"},"widget_override":null},{"input_data":{"input_name":"Backup Gradient"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[12801133692316734622,{"persistent_metadata":{"reference":"Sample Polyline","display_name":"","input_properties":[{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{"min":0.0,"blank_assist":true,"unit":" px","mode":"Increment","is_integer":false},"widget_override":"number"},{"input_data":{"mode":"Increment","min":2.0,"is_integer":true,"blank_assist":true},"widget_override":"number"},{"input_data":{"mode":"Increment","unit":" px","blank_assist":true,"is_integer":false,"min":0.0},"widget_override":"number"},{"input_data":{"mode":"Increment","unit":" px","is_integer":false,"blank_assist":true,"min":0.0},"widget_override":"number"},{"input_data":{},"widget_override":null}],"output_names":["Vector"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[4,{"persistent_metadata":{"reference":null,"display_name":"Boundless Footprint","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[28,0]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Freeze Real Time","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[21,0]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"Subpath Segment Lengths","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,7]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"Sample Polyline","input_properties":[{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Memoize","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[14,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[5040278174920511484,{"persistent_metadata":{"reference":"Fill","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Fill"},"widget_override":null},{"input_data":{"input_name":"Backup Color"},"widget_override":null},{"input_data":{"input_name":"Backup Gradient"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[14012583111791538162,{"persistent_metadata":{"reference":"Path","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Modification"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"Path Modify","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[9782123335421401489,{"persistent_metadata":{"reference":"Merge","display_name":"","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":0}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[15896921950407486754,{"persistent_metadata":{"reference":"Merge","display_name":"","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":0}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[17118107476414252025,{"persistent_metadata":{"reference":"Transform","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Translation","y":"Y","unit":" px","x":"X"},"widget_override":"vec2"},{"input_data":{"input_name":"Rotation"},"widget_override":"transform_rotation"},{"input_data":{"input_name":"Scale","y":"H","x":"W","unit":"x"},"widget_override":"vec2"},{"input_data":{"input_name":"Skew"},"widget_override":"hidden"},{"input_data":{"input_name":"Pivot"},"widget_override":"hidden"}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"Transform","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[10424806499648491677,{"persistent_metadata":{"reference":"Merge","display_name":"","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":0}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[14079496619264986678,{"persistent_metadata":{"reference":"Path","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Modification"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"Path Modify","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[3686761601672683183,{"persistent_metadata":{"reference":"Sample Polyline","display_name":"","input_properties":[{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{"blank_assist":true,"mode":"Increment","min":0.0,"unit":" px","is_integer":false},"widget_override":"number"},{"input_data":{"min":2.0,"blank_assist":true,"mode":"Increment","is_integer":true},"widget_override":"number"},{"input_data":{"min":0.0,"mode":"Increment","blank_assist":true,"unit":" px","is_integer":false},"widget_override":"number"},{"input_data":{"unit":" px","min":0.0,"mode":"Increment","blank_assist":true,"is_integer":false},"widget_override":"number"},{"input_data":{},"widget_override":null}],"output_names":["Vector"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"Subpath Segment Lengths","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,7]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Freeze Real Time","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[21,0]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"Sample Polyline","input_properties":[{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Memoize","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[14,0]}}},"network_metadata":null}}],[4,{"persistent_metadata":{"reference":null,"display_name":"Boundless Footprint","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[28,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[4248321400839848160,{"persistent_metadata":{"reference":"Merge","display_name":"","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Absolute":[-17,124]}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[6988349135757634271,{"persistent_metadata":{"reference":"Path","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Modification"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"Path Modify","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[6973438081601736688,{"persistent_metadata":{"reference":"Fill","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Fill"},"widget_override":null},{"input_data":{"input_name":"Backup Color"},"widget_override":null},{"input_data":{"input_name":"Backup Gradient"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[17945736750161448391,{"persistent_metadata":{"reference":"Path","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Modification"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"Path Modify","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[4493274523708782092,{"persistent_metadata":{"reference":"Merge","display_name":"","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":0}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[11565160497886435388,{"persistent_metadata":{"reference":"Sample Polyline","display_name":"","input_properties":[{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{"min":0.0,"unit":" px","is_integer":false,"mode":"Increment","blank_assist":true},"widget_override":"number"},{"input_data":{"blank_assist":true,"is_integer":true,"mode":"Increment","min":2.0},"widget_override":"number"},{"input_data":{"mode":"Increment","unit":" px","is_integer":false,"blank_assist":true,"min":0.0},"widget_override":"number"},{"input_data":{"blank_assist":true,"is_integer":false,"mode":"Increment","min":0.0,"unit":" px"},"widget_override":"number"},{"input_data":{},"widget_override":null}],"output_names":["Vector"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"Subpath Segment Lengths","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,7]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"Sample Polyline","input_properties":[{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}],[4,{"persistent_metadata":{"reference":null,"display_name":"Boundless Footprint","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[28,0]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Memoize","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[14,0]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Freeze Real Time","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[21,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[3670529450440935325,{"persistent_metadata":{"reference":"Merge","display_name":"","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":0}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[3827449344952693766,{"persistent_metadata":{"reference":"Sample Polyline","display_name":"","input_properties":[{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{"unit":" px","blank_assist":true,"is_integer":false,"mode":"Increment","min":0.0},"widget_override":"number"},{"input_data":{"is_integer":true,"blank_assist":true,"min":2.0,"mode":"Increment"},"widget_override":"number"},{"input_data":{"mode":"Increment","blank_assist":true,"unit":" px","min":0.0,"is_integer":false},"widget_override":"number"},{"input_data":{"is_integer":false,"blank_assist":true,"mode":"Increment","unit":" px","min":0.0},"widget_override":"number"},{"input_data":{},"widget_override":null}],"output_names":["Vector"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[4,{"persistent_metadata":{"reference":null,"display_name":"Boundless Footprint","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[28,0]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Freeze Real Time","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[21,0]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Memoize","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[14,0]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"Subpath Segment Lengths","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,7]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"Sample Polyline","input_properties":[{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[7525593029671097583,{"persistent_metadata":{"reference":"Merge","display_name":"","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":0}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[7447657690776686262,{"persistent_metadata":{"reference":"Sample Polyline","display_name":"","input_properties":[{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{"is_integer":false,"unit":" px","mode":"Increment","blank_assist":true,"min":0.0},"widget_override":"number"},{"input_data":{"mode":"Increment","blank_assist":true,"is_integer":true,"min":2.0},"widget_override":"number"},{"input_data":{"is_integer":false,"mode":"Increment","unit":" px","blank_assist":true,"min":0.0},"widget_override":"number"},{"input_data":{"mode":"Increment","is_integer":false,"blank_assist":true,"min":0.0,"unit":" px"},"widget_override":"number"},{"input_data":{},"widget_override":null}],"output_names":["Vector"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[4,{"persistent_metadata":{"reference":null,"display_name":"Boundless Footprint","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[28,0]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Freeze Real Time","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[21,0]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Memoize","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[14,0]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"Sample Polyline","input_properties":[{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"Subpath Segment Lengths","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,7]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[10190227675276560561,{"persistent_metadata":{"reference":"Merge","display_name":"","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":0}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[3414873131936208778,{"persistent_metadata":{"reference":"Path","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Modification"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"Path Modify","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[10795820039540504703,{"persistent_metadata":{"reference":"Path","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Modification"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"Path Modify","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[13644138583806412631,{"persistent_metadata":{"reference":"Merge","display_name":"","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":0}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[16796171662855500935,{"persistent_metadata":{"reference":"Merge","display_name":"","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":0}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[13014628586360765651,{"persistent_metadata":{"reference":"Merge","display_name":"Dotted Aura","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":6}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[7922156219537051964,{"persistent_metadata":{"reference":"Copy to Points","display_name":"","input_properties":[{"input_data":{"input_name":"Points"},"widget_override":null},{"input_data":{"input_name":"Instance","tooltip":"Artwork to be copied and placed at each point"},"widget_override":null},{"input_data":{"is_integer":false,"blank_assist":true,"min":0.0,"mode":"Range","unit":"x","input_name":"Random Scale Min","range_min":0.0,"range_max":2.0,"tooltip":"Minimum range of randomized sizes given to each instance"},"widget_override":"number"},{"input_data":{"min":0.0,"range_max":2.0,"unit":"x","input_name":"Random Scale Max","range_min":0.0,"is_integer":false,"blank_assist":true,"tooltip":"Minimum range of randomized sizes given to each instance","mode":"Range"},"widget_override":"number"},{"input_data":{"blank_assist":true,"range_min":-50.0,"range_max":50.0,"is_integer":false,"mode":"Range","input_name":"Random Scale Bias","tooltip":"Bias for the probability distribution of randomized sizes (0 is uniform, negatives favor more of small sizes, positives favor more of large sizes)"},"widget_override":"number"},{"input_data":{"input_name":"Random Scale Seed","tooltip":"Seed to determine unique variations on all the randomized instance sizes","is_integer":true,"blank_assist":true,"min":0.0,"mode":"Increment"},"widget_override":"number"},{"input_data":{"unit":"°","input_name":"Random Rotation","tooltip":"Range of randomized angles given to each instance, in degrees ranging from furthest clockwise to counterclockwise","blank_assist":true,"max":360.0,"min":0.0,"is_integer":false,"mode":"Range"},"widget_override":"number"},{"input_data":{"input_name":"Random Rotation Seed","blank_assist":true,"min":0.0,"is_integer":true,"tooltip":"Seed to determine unique variations on all the randomized instance angles","mode":"Increment"},"widget_override":"number"}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[16324258033206362312,{"persistent_metadata":{"reference":"Copy to Points","display_name":"","input_properties":[{"input_data":{"input_name":"Points"},"widget_override":null},{"input_data":{"tooltip":"Artwork to be copied and placed at each point","input_name":"Instance"},"widget_override":null},{"input_data":{"input_name":"Random Scale Min","range_min":0.0,"is_integer":false,"tooltip":"Minimum range of randomized sizes given to each instance","min":0.0,"unit":"x","range_max":2.0,"mode":"Range","blank_assist":true},"widget_override":"number"},{"input_data":{"tooltip":"Minimum range of randomized sizes given to each instance","input_name":"Random Scale Max","min":0.0,"range_min":0.0,"is_integer":false,"mode":"Range","range_max":2.0,"unit":"x","blank_assist":true},"widget_override":"number"},{"input_data":{"mode":"Range","range_max":50.0,"tooltip":"Bias for the probability distribution of randomized sizes (0 is uniform, negatives favor more of small sizes, positives favor more of large sizes)","range_min":-50.0,"input_name":"Random Scale Bias","blank_assist":true,"is_integer":false},"widget_override":"number"},{"input_data":{"tooltip":"Seed to determine unique variations on all the randomized instance sizes","input_name":"Random Scale Seed","is_integer":true,"min":0.0,"blank_assist":true,"mode":"Increment"},"widget_override":"number"},{"input_data":{"mode":"Range","blank_assist":true,"tooltip":"Range of randomized angles given to each instance, in degrees ranging from furthest clockwise to counterclockwise","is_integer":false,"max":360.0,"unit":"°","min":0.0,"input_name":"Random Rotation"},"widget_override":"number"},{"input_data":{"mode":"Increment","blank_assist":true,"is_integer":true,"input_name":"Random Rotation Seed","min":0.0,"tooltip":"Seed to determine unique variations on all the randomized instance angles"},"widget_override":"number"}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[10860592954464951000,{"persistent_metadata":{"reference":"Fill","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Fill"},"widget_override":null},{"input_data":{"input_name":"Backup Color"},"widget_override":null},{"input_data":{"input_name":"Backup Gradient"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[10619788176782820865,{"persistent_metadata":{"reference":"Merge","display_name":"","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":0}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[14012648643507848353,{"persistent_metadata":{"reference":"Path","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Modification"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"Path Modify","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[17078740291337047697,{"persistent_metadata":{"reference":"Fill","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Fill"},"widget_override":null},{"input_data":{"input_name":"Backup Color"},"widget_override":null},{"input_data":{"input_name":"Backup Gradient"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-31,208]}}},"network_metadata":null}}],[8698602280607307123,{"persistent_metadata":{"reference":"Merge","display_name":"","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":0}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[3955326429435439190,{"persistent_metadata":{"reference":"Copy to Points","display_name":"","input_properties":[{"input_data":{"input_name":"Points"},"widget_override":null},{"input_data":{"tooltip":"Artwork to be copied and placed at each point","input_name":"Instance"},"widget_override":null},{"input_data":{"blank_assist":true,"is_integer":false,"min":0.0,"tooltip":"Minimum range of randomized sizes given to each instance","unit":"x","mode":"Range","range_min":0.0,"range_max":2.0,"input_name":"Random Scale Min"},"widget_override":"number"},{"input_data":{"is_integer":false,"mode":"Range","range_min":0.0,"tooltip":"Minimum range of randomized sizes given to each instance","min":0.0,"range_max":2.0,"blank_assist":true,"unit":"x","input_name":"Random Scale Max"},"widget_override":"number"},{"input_data":{"range_max":50.0,"blank_assist":true,"range_min":-50.0,"tooltip":"Bias for the probability distribution of randomized sizes (0 is uniform, negatives favor more of small sizes, positives favor more of large sizes)","mode":"Range","input_name":"Random Scale Bias","is_integer":false},"widget_override":"number"},{"input_data":{"tooltip":"Seed to determine unique variations on all the randomized instance sizes","mode":"Increment","min":0.0,"input_name":"Random Scale Seed","is_integer":true,"blank_assist":true},"widget_override":"number"},{"input_data":{"unit":"°","blank_assist":true,"max":360.0,"min":0.0,"input_name":"Random Rotation","tooltip":"Range of randomized angles given to each instance, in degrees ranging from furthest clockwise to counterclockwise","is_integer":false,"mode":"Range"},"widget_override":"number"},{"input_data":{"input_name":"Random Rotation Seed","min":0.0,"mode":"Increment","tooltip":"Seed to determine unique variations on all the randomized instance angles","is_integer":true,"blank_assist":true},"widget_override":"number"}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[15460109068588328521,{"persistent_metadata":{"reference":"Fill","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Fill"},"widget_override":null},{"input_data":{"input_name":"Backup Color"},"widget_override":null},{"input_data":{"input_name":"Backup Gradient"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[13231685386999438557,{"persistent_metadata":{"reference":"Fill","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Fill"},"widget_override":null},{"input_data":{"input_name":"Backup Color"},"widget_override":null},{"input_data":{"input_name":"Backup Gradient"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[9954843247420111867,{"persistent_metadata":{"reference":"Transform","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Translation","x":"X","unit":" px","y":"Y"},"widget_override":"vec2"},{"input_data":{"input_name":"Rotation"},"widget_override":"transform_rotation"},{"input_data":{"x":"W","unit":"x","y":"H","input_name":"Scale"},"widget_override":"vec2"},{"input_data":{"input_name":"Skew"},"widget_override":"hidden"},{"input_data":{"input_name":"Pivot"},"widget_override":"hidden"}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"Transform","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[11616089678400336955,{"persistent_metadata":{"reference":"Copy to Points","display_name":"","input_properties":[{"input_data":{"input_name":"Points"},"widget_override":null},{"input_data":{"input_name":"Instance","tooltip":"Artwork to be copied and placed at each point"},"widget_override":null},{"input_data":{"range_max":2.0,"blank_assist":true,"mode":"Range","min":0.0,"unit":"x","range_min":0.0,"is_integer":false,"input_name":"Random Scale Min","tooltip":"Minimum range of randomized sizes given to each instance"},"widget_override":"number"},{"input_data":{"range_max":2.0,"blank_assist":true,"input_name":"Random Scale Max","is_integer":false,"mode":"Range","min":0.0,"tooltip":"Minimum range of randomized sizes given to each instance","range_min":0.0,"unit":"x"},"widget_override":"number"},{"input_data":{"range_min":-50.0,"blank_assist":true,"is_integer":false,"range_max":50.0,"tooltip":"Bias for the probability distribution of randomized sizes (0 is uniform, negatives favor more of small sizes, positives favor more of large sizes)","input_name":"Random Scale Bias","mode":"Range"},"widget_override":"number"},{"input_data":{"input_name":"Random Scale Seed","is_integer":true,"blank_assist":true,"mode":"Increment","tooltip":"Seed to determine unique variations on all the randomized instance sizes","min":0.0},"widget_override":"number"},{"input_data":{"tooltip":"Range of randomized angles given to each instance, in degrees ranging from furthest clockwise to counterclockwise","is_integer":false,"min":0.0,"input_name":"Random Rotation","unit":"°","max":360.0,"blank_assist":true,"mode":"Range"},"widget_override":"number"},{"input_data":{"min":0.0,"mode":"Increment","tooltip":"Seed to determine unique variations on all the randomized instance angles","is_integer":true,"input_name":"Random Rotation Seed","blank_assist":true},"widget_override":"number"}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[15446793500614592278,{"persistent_metadata":{"reference":"Path","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Modification"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"Path Modify","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[514796034658094296,{"persistent_metadata":{"reference":"Fill","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Fill"},"widget_override":null},{"input_data":{"input_name":"Backup Color"},"widget_override":null},{"input_data":{"input_name":"Backup Gradient"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[16805628435335819723,{"persistent_metadata":{"reference":"Fill","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Fill"},"widget_override":null},{"input_data":{"input_name":"Backup Color"},"widget_override":null},{"input_data":{"input_name":"Backup Gradient"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[15815816861435910950,{"persistent_metadata":{"reference":"Merge","display_name":"","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":0}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[11058365317860779469,{"persistent_metadata":{"reference":"Path","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Modification"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"Path Modify","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[7141088190930752823,{"persistent_metadata":{"reference":"Sample Polyline","display_name":"","input_properties":[{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{"is_integer":false,"mode":"Increment","blank_assist":true,"unit":" px","min":0.0},"widget_override":"number"},{"input_data":{"min":2.0,"mode":"Increment","blank_assist":true,"is_integer":true},"widget_override":"number"},{"input_data":{"mode":"Increment","unit":" px","blank_assist":true,"is_integer":false,"min":0.0},"widget_override":"number"},{"input_data":{"mode":"Increment","unit":" px","min":0.0,"blank_assist":true,"is_integer":false},"widget_override":"number"},{"input_data":{},"widget_override":null}],"output_names":["Vector"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[4,{"persistent_metadata":{"reference":null,"display_name":"Boundless Footprint","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[28,0]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"Sample Polyline","input_properties":[{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Memoize","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[14,0]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Freeze Real Time","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[21,0]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"Subpath Segment Lengths","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,7]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[13481022631108980683,{"persistent_metadata":{"reference":"Merge","display_name":"","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":0}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[581013017684525986,{"persistent_metadata":{"reference":"Path","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Modification"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"Path Modify","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[11451028343967836482,{"persistent_metadata":{"reference":"Merge","display_name":"","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":0}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[7466034304713056391,{"persistent_metadata":{"reference":"Path","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Modification"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"Path Modify","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[13014916927589286309,{"persistent_metadata":{"reference":"Scatter Points","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"is_integer":false,"input_name":"Separation Disk Diameter","mode":"Range","range_max":100.0,"range_min":1.0,"min":0.01,"blank_assist":true},"widget_override":"number"},{"input_data":{"mode":"Increment","input_name":"Seed","blank_assist":true,"min":0.0,"is_integer":true},"widget_override":"number"}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"Memoize","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"Poisson-Disk Points","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Boundless Footprint","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[21,0]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Freeze Real Time","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[14,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[1235106489581249820,{"persistent_metadata":{"reference":"Sample Polyline","display_name":"","input_properties":[{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{"unit":" px","blank_assist":true,"is_integer":false,"mode":"Increment","min":0.0},"widget_override":"number"},{"input_data":{"min":2.0,"mode":"Increment","is_integer":true,"blank_assist":true},"widget_override":"number"},{"input_data":{"blank_assist":true,"is_integer":false,"unit":" px","min":0.0,"mode":"Increment"},"widget_override":"number"},{"input_data":{"is_integer":false,"blank_assist":true,"unit":" px","min":0.0,"mode":"Increment"},"widget_override":"number"},{"input_data":{},"widget_override":null}],"output_names":["Vector"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[2,{"persistent_metadata":{"reference":null,"display_name":"Memoize","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[14,0]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Freeze Real Time","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[21,0]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"Sample Polyline","input_properties":[{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}],[4,{"persistent_metadata":{"reference":null,"display_name":"Boundless Footprint","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[28,0]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"Subpath Segment Lengths","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,7]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[3649809135741361946,{"persistent_metadata":{"reference":"Path","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Modification"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"Path Modify","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[3226457726231232839,{"persistent_metadata":{"reference":"Merge","display_name":"","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":0}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[17336535036064625290,{"persistent_metadata":{"reference":"Transform","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Translation","x":"X","y":"Y","unit":" px"},"widget_override":"vec2"},{"input_data":{"input_name":"Rotation"},"widget_override":"transform_rotation"},{"input_data":{"input_name":"Scale","unit":"x","y":"H","x":"W"},"widget_override":"vec2"},{"input_data":{"input_name":"Skew"},"widget_override":"hidden"},{"input_data":{"input_name":"Pivot"},"widget_override":"hidden"}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"Transform","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[4832236468224231783,{"persistent_metadata":{"reference":"Path","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Modification"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"Path Modify","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[4372998635946271235,{"persistent_metadata":{"reference":"Merge","display_name":"","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":0}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[5471152581000334146,{"persistent_metadata":{"reference":"Merge","display_name":"","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":0}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[14817659161913199655,{"persistent_metadata":{"reference":"Path","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Modification"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"Path Modify","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[17815494794630739611,{"persistent_metadata":{"reference":"Fill","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Fill"},"widget_override":null},{"input_data":{"input_name":"Backup Color"},"widget_override":null},{"input_data":{"input_name":"Backup Gradient"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[6580280438672662494,{"persistent_metadata":{"reference":"Merge","display_name":"","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":0}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[14894569344576297448,{"persistent_metadata":{"reference":"Fill","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Fill"},"widget_override":null},{"input_data":{"input_name":"Backup Color"},"widget_override":null},{"input_data":{"input_name":"Backup Gradient"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[4422453582814483232,{"persistent_metadata":{"reference":"Merge","display_name":"Hair and Face","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Absolute":[-7,4]}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[14675232891471617236,{"persistent_metadata":{"reference":"Path","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Modification"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"Path Modify","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[14778750092903591172,{"persistent_metadata":{"reference":"Path","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Modification"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"Path Modify","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[14888395629683671889,{"persistent_metadata":{"reference":"Copy to Points","display_name":"","input_properties":[{"input_data":{"input_name":"Points"},"widget_override":null},{"input_data":{"input_name":"Instance","tooltip":"Artwork to be copied and placed at each point"},"widget_override":null},{"input_data":{"min":0.0,"blank_assist":true,"is_integer":false,"mode":"Range","range_max":2.0,"range_min":0.0,"input_name":"Random Scale Min","unit":"x","tooltip":"Minimum range of randomized sizes given to each instance"},"widget_override":"number"},{"input_data":{"blank_assist":true,"unit":"x","is_integer":false,"range_max":2.0,"input_name":"Random Scale Max","min":0.0,"mode":"Range","tooltip":"Minimum range of randomized sizes given to each instance","range_min":0.0},"widget_override":"number"},{"input_data":{"range_min":-50.0,"input_name":"Random Scale Bias","is_integer":false,"blank_assist":true,"mode":"Range","range_max":50.0,"tooltip":"Bias for the probability distribution of randomized sizes (0 is uniform, negatives favor more of small sizes, positives favor more of large sizes)"},"widget_override":"number"},{"input_data":{"blank_assist":true,"tooltip":"Seed to determine unique variations on all the randomized instance sizes","input_name":"Random Scale Seed","is_integer":true,"min":0.0,"mode":"Increment"},"widget_override":"number"},{"input_data":{"is_integer":false,"input_name":"Random Rotation","max":360.0,"mode":"Range","min":0.0,"unit":"°","tooltip":"Range of randomized angles given to each instance, in degrees ranging from furthest clockwise to counterclockwise","blank_assist":true},"widget_override":"number"},{"input_data":{"blank_assist":true,"is_integer":true,"tooltip":"Seed to determine unique variations on all the randomized instance angles","input_name":"Random Rotation Seed","min":0.0,"mode":"Increment"},"widget_override":"number"}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[8240895922641772563,{"persistent_metadata":{"reference":"Fill","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Fill"},"widget_override":null},{"input_data":{"input_name":"Backup Color"},"widget_override":null},{"input_data":{"input_name":"Backup Gradient"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[3627710206997006419,{"persistent_metadata":{"reference":"Path","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Modification"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"Path Modify","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[10336592647221792772,{"persistent_metadata":{"reference":"Fill","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Fill"},"widget_override":null},{"input_data":{"input_name":"Backup Color"},"widget_override":null},{"input_data":{"input_name":"Backup Gradient"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[10420981328998103391,{"persistent_metadata":{"reference":"Path","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Modification"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"Path Modify","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[12428327489525325219,{"persistent_metadata":{"reference":"Merge","display_name":"","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":0}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[11199691961479466803,{"persistent_metadata":{"reference":"Copy to Points","display_name":"","input_properties":[{"input_data":{"input_name":"Points"},"widget_override":null},{"input_data":{"tooltip":"Artwork to be copied and placed at each point","input_name":"Instance"},"widget_override":null},{"input_data":{"tooltip":"Minimum range of randomized sizes given to each instance","input_name":"Random Scale Min","range_max":2.0,"min":0.0,"is_integer":false,"blank_assist":true,"range_min":0.0,"unit":"x","mode":"Range"},"widget_override":"number"},{"input_data":{"is_integer":false,"mode":"Range","unit":"x","blank_assist":true,"min":0.0,"tooltip":"Minimum range of randomized sizes given to each instance","range_min":0.0,"input_name":"Random Scale Max","range_max":2.0},"widget_override":"number"},{"input_data":{"blank_assist":true,"range_max":50.0,"range_min":-50.0,"mode":"Range","tooltip":"Bias for the probability distribution of randomized sizes (0 is uniform, negatives favor more of small sizes, positives favor more of large sizes)","is_integer":false,"input_name":"Random Scale Bias"},"widget_override":"number"},{"input_data":{"is_integer":true,"mode":"Increment","tooltip":"Seed to determine unique variations on all the randomized instance sizes","blank_assist":true,"input_name":"Random Scale Seed","min":0.0},"widget_override":"number"},{"input_data":{"blank_assist":true,"max":360.0,"mode":"Range","min":0.0,"unit":"°","input_name":"Random Rotation","tooltip":"Range of randomized angles given to each instance, in degrees ranging from furthest clockwise to counterclockwise","is_integer":false},"widget_override":"number"},{"input_data":{"mode":"Increment","tooltip":"Seed to determine unique variations on all the randomized instance angles","blank_assist":true,"input_name":"Random Rotation Seed","is_integer":true,"min":0.0},"widget_override":"number"}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[12049041947382267086,{"persistent_metadata":{"reference":"Transform","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"unit":" px","x":"X","y":"Y","input_name":"Translation"},"widget_override":"vec2"},{"input_data":{"input_name":"Rotation"},"widget_override":"transform_rotation"},{"input_data":{"input_name":"Scale","unit":"x","x":"W","y":"H"},"widget_override":"vec2"},{"input_data":{"input_name":"Skew"},"widget_override":"hidden"},{"input_data":{"input_name":"Pivot"},"widget_override":"hidden"}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"Transform","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[5269304445610080925,{"persistent_metadata":{"reference":"Copy to Points","display_name":"","input_properties":[{"input_data":{"input_name":"Points"},"widget_override":null},{"input_data":{"input_name":"Instance","tooltip":"Artwork to be copied and placed at each point"},"widget_override":null},{"input_data":{"min":0.0,"blank_assist":true,"input_name":"Random Scale Min","is_integer":false,"range_max":2.0,"range_min":0.0,"mode":"Range","unit":"x","tooltip":"Minimum range of randomized sizes given to each instance"},"widget_override":"number"},{"input_data":{"is_integer":false,"tooltip":"Minimum range of randomized sizes given to each instance","unit":"x","blank_assist":true,"input_name":"Random Scale Max","mode":"Range","min":0.0,"range_max":2.0,"range_min":0.0},"widget_override":"number"},{"input_data":{"range_max":50.0,"is_integer":false,"mode":"Range","input_name":"Random Scale Bias","range_min":-50.0,"blank_assist":true,"tooltip":"Bias for the probability distribution of randomized sizes (0 is uniform, negatives favor more of small sizes, positives favor more of large sizes)"},"widget_override":"number"},{"input_data":{"is_integer":true,"mode":"Increment","tooltip":"Seed to determine unique variations on all the randomized instance sizes","input_name":"Random Scale Seed","min":0.0,"blank_assist":true},"widget_override":"number"},{"input_data":{"mode":"Range","unit":"°","is_integer":false,"max":360.0,"tooltip":"Range of randomized angles given to each instance, in degrees ranging from furthest clockwise to counterclockwise","blank_assist":true,"min":0.0,"input_name":"Random Rotation"},"widget_override":"number"},{"input_data":{"is_integer":true,"tooltip":"Seed to determine unique variations on all the randomized instance angles","blank_assist":true,"mode":"Increment","min":0.0,"input_name":"Random Rotation Seed"},"widget_override":"number"}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[8230694129617719636,{"persistent_metadata":{"reference":"Merge","display_name":"","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":0}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[2394762731964337494,{"persistent_metadata":{"reference":"Artboard","display_name":"","input_properties":[{"input_data":{"input_name":"Artboards"},"widget_override":null},{"input_data":{"input_name":"Contents"},"widget_override":"hidden"},{"input_data":{"unit":" px","input_name":"Location","x":"X","y":"Y"},"widget_override":"vec2"},{"input_data":{"y":"H","unit":" px","input_name":"Dimensions","x":"W"},"widget_override":"vec2"},{"input_data":{"input_name":"Background"},"widget_override":"artboard_background"},{"input_data":{"input_name":"Clip"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Absolute":[-3,1]}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-2,-3]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Append Artboards","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[6,-4]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"To Artboard","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-10,-3]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[2659768650911099730,{"persistent_metadata":{"reference":"Sample Polyline","display_name":"","input_properties":[{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{"blank_assist":true,"unit":" px","min":0.0,"mode":"Increment","is_integer":false},"widget_override":"number"},{"input_data":{"blank_assist":true,"min":2.0,"is_integer":true,"mode":"Increment"},"widget_override":"number"},{"input_data":{"mode":"Increment","unit":" px","blank_assist":true,"is_integer":false,"min":0.0},"widget_override":"number"},{"input_data":{"blank_assist":true,"min":0.0,"mode":"Increment","is_integer":false,"unit":" px"},"widget_override":"number"},{"input_data":{},"widget_override":null}],"output_names":["Vector"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[3,{"persistent_metadata":{"reference":null,"display_name":"Freeze Real Time","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[21,0]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"Subpath Segment Lengths","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,7]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Memoize","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[14,0]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"Sample Polyline","input_properties":[{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}],[4,{"persistent_metadata":{"reference":null,"display_name":"Boundless Footprint","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[28,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[17426609415699324395,{"persistent_metadata":{"reference":"Merge","display_name":"","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":0}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[2282726379014798660,{"persistent_metadata":{"reference":"Sample Polyline","display_name":"","input_properties":[{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{"is_integer":false,"mode":"Increment","blank_assist":true,"unit":" px","min":0.0},"widget_override":"number"},{"input_data":{"is_integer":true,"min":2.0,"mode":"Increment","blank_assist":true},"widget_override":"number"},{"input_data":{"blank_assist":true,"min":0.0,"mode":"Increment","unit":" px","is_integer":false},"widget_override":"number"},{"input_data":{"blank_assist":true,"unit":" px","min":0.0,"is_integer":false,"mode":"Increment"},"widget_override":"number"},{"input_data":{},"widget_override":null}],"output_names":["Vector"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"Sample Polyline","input_properties":[{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}],[4,{"persistent_metadata":{"reference":null,"display_name":"Boundless Footprint","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[28,0]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Freeze Real Time","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[21,0]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Memoize","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[14,0]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"Subpath Segment Lengths","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,7]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[14225285635863713990,{"persistent_metadata":{"reference":"Transform","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"unit":" px","input_name":"Translation","x":"X","y":"Y"},"widget_override":"vec2"},{"input_data":{"input_name":"Rotation"},"widget_override":"transform_rotation"},{"input_data":{"y":"H","unit":"x","input_name":"Scale","x":"W"},"widget_override":"vec2"},{"input_data":{"input_name":"Skew"},"widget_override":"hidden"},{"input_data":{"input_name":"Pivot"},"widget_override":"hidden"}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"Transform","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[4859656512650360562,{"persistent_metadata":{"reference":"Path","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Modification"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"Path Modify","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[14883504161508594099,{"persistent_metadata":{"reference":"Merge","display_name":"","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Absolute":[-17,295]}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[12838133055063962839,{"persistent_metadata":{"reference":"Merge","display_name":"","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":0}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[2780251074492832077,{"persistent_metadata":{"reference":"Path","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Modification"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"Path Modify","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[3970516859959908758,{"persistent_metadata":{"reference":"Path","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Modification"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"Path Modify","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[5302437193964714993,{"persistent_metadata":{"reference":"Copy to Points","display_name":"","input_properties":[{"input_data":{"input_name":"Points"},"widget_override":null},{"input_data":{"input_name":"Instance","tooltip":"Artwork to be copied and placed at each point"},"widget_override":null},{"input_data":{"input_name":"Random Scale Min","range_min":0.0,"blank_assist":true,"is_integer":false,"min":0.0,"range_max":2.0,"mode":"Range","tooltip":"Minimum range of randomized sizes given to each instance","unit":"x"},"widget_override":"number"},{"input_data":{"is_integer":false,"blank_assist":true,"input_name":"Random Scale Max","range_min":0.0,"mode":"Range","min":0.0,"range_max":2.0,"unit":"x","tooltip":"Minimum range of randomized sizes given to each instance"},"widget_override":"number"},{"input_data":{"input_name":"Random Scale Bias","tooltip":"Bias for the probability distribution of randomized sizes (0 is uniform, negatives favor more of small sizes, positives favor more of large sizes)","range_max":50.0,"is_integer":false,"mode":"Range","range_min":-50.0,"blank_assist":true},"widget_override":"number"},{"input_data":{"blank_assist":true,"mode":"Increment","tooltip":"Seed to determine unique variations on all the randomized instance sizes","min":0.0,"is_integer":true,"input_name":"Random Scale Seed"},"widget_override":"number"},{"input_data":{"min":0.0,"unit":"°","mode":"Range","blank_assist":true,"is_integer":false,"max":360.0,"input_name":"Random Rotation","tooltip":"Range of randomized angles given to each instance, in degrees ranging from furthest clockwise to counterclockwise"},"widget_override":"number"},{"input_data":{"is_integer":true,"min":0.0,"input_name":"Random Rotation Seed","blank_assist":true,"mode":"Increment","tooltip":"Seed to determine unique variations on all the randomized instance angles"},"widget_override":"number"}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[17207349373429328029,{"persistent_metadata":{"reference":"Fill","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Fill"},"widget_override":null},{"input_data":{"input_name":"Backup Color"},"widget_override":null},{"input_data":{"input_name":"Backup Gradient"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[18207065424980079673,{"persistent_metadata":{"reference":"Sample Polyline","display_name":"","input_properties":[{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{"unit":" px","blank_assist":true,"is_integer":false,"mode":"Increment","min":0.0},"widget_override":"number"},{"input_data":{"blank_assist":true,"min":2.0,"mode":"Increment","is_integer":true},"widget_override":"number"},{"input_data":{"is_integer":false,"blank_assist":true,"min":0.0,"unit":" px","mode":"Increment"},"widget_override":"number"},{"input_data":{"min":0.0,"is_integer":false,"mode":"Increment","unit":" px","blank_assist":true},"widget_override":"number"},{"input_data":{},"widget_override":null}],"output_names":["Vector"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[4,{"persistent_metadata":{"reference":null,"display_name":"Boundless Footprint","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[28,0]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"Sample Polyline","input_properties":[{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Freeze Real Time","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[21,0]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Memoize","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[14,0]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"Subpath Segment Lengths","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,7]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[8697043784435445845,{"persistent_metadata":{"reference":"Path","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Modification"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"Path Modify","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[10270446074640675342,{"persistent_metadata":{"reference":"Transform","display_name":"","input_properties":[{"input_data":{},"widget_override":null},{"input_data":{"y":"Y","unit":" px","x":"X"},"widget_override":"vec2"},{"input_data":{},"widget_override":"transform_rotation"},{"input_data":{"unit":"x","y":"H","x":"W"},"widget_override":"vec2"},{"input_data":{},"widget_override":"transform_skew"},{"input_data":{},"widget_override":"hidden"}],"output_names":["Data"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"Transform","input_properties":[{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[5861306074868809692,{"persistent_metadata":{"reference":"Merge","display_name":"","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":0}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[15518174914032911052,{"persistent_metadata":{"reference":"Path","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Modification"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"Path Modify","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[2698266912167150713,{"persistent_metadata":{"reference":"Fill","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Fill"},"widget_override":null},{"input_data":{"input_name":"Backup Color"},"widget_override":null},{"input_data":{"input_name":"Backup Gradient"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[15126865253122550765,{"persistent_metadata":{"reference":"Merge","display_name":"Dotted Bodice","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":21}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[5455777299776842371,{"persistent_metadata":{"reference":"Merge","display_name":"Beaded Skirt","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":78}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[907841922684377912,{"persistent_metadata":{"reference":"Fill","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Fill"},"widget_override":null},{"input_data":{"input_name":"Backup Color"},"widget_override":null},{"input_data":{"input_name":"Backup Gradient"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[15498700602024283966,{"persistent_metadata":{"reference":"Merge","display_name":"","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":0}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[4453139144069993994,{"persistent_metadata":{"reference":"Merge","display_name":"","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":0}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[12224498203743157414,{"persistent_metadata":{"reference":"Fill","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Fill"},"widget_override":null},{"input_data":{"input_name":"Backup Color"},"widget_override":null},{"input_data":{"input_name":"Backup Gradient"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[17967471489196302183,{"persistent_metadata":{"reference":"Path","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Modification"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"Path Modify","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[14539627480594383748,{"persistent_metadata":{"reference":"Fill","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Fill"},"widget_override":null},{"input_data":{"input_name":"Backup Color"},"widget_override":null},{"input_data":{"input_name":"Backup Gradient"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[16530658574540156160,{"persistent_metadata":{"reference":"Transform","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Translation","y":"Y","x":"X","unit":" px"},"widget_override":"vec2"},{"input_data":{"input_name":"Rotation"},"widget_override":"transform_rotation"},{"input_data":{"input_name":"Scale","unit":"x","x":"W","y":"H"},"widget_override":"vec2"},{"input_data":{"input_name":"Skew"},"widget_override":"hidden"},{"input_data":{"input_name":"Pivot"},"widget_override":"hidden"}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"Transform","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[17324767436949538365,{"persistent_metadata":{"reference":"Path","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Modification"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"Path Modify","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[9371909264427723282,{"persistent_metadata":{"reference":"Fill","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Fill"},"widget_override":null},{"input_data":{"input_name":"Backup Color"},"widget_override":null},{"input_data":{"input_name":"Backup Gradient"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[8410534738018320047,{"persistent_metadata":{"reference":"Path","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Modification"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"Path Modify","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[5326536612985524219,{"persistent_metadata":{"reference":"Scatter Points","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"range_min":1.0,"range_max":100.0,"is_integer":false,"input_name":"Separation Disk Diameter","min":0.01,"mode":"Range","blank_assist":true},"widget_override":"number"},{"input_data":{"min":0.0,"input_name":"Seed","is_integer":true,"blank_assist":true,"mode":"Increment"},"widget_override":"number"}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"Memoize","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Boundless Footprint","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[21,0]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Freeze Real Time","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[14,0]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"Poisson-Disk Points","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[16450742929146919960,{"persistent_metadata":{"reference":"Merge","display_name":"","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":0}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[9684857454501250999,{"persistent_metadata":{"reference":"Fill","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Fill"},"widget_override":null},{"input_data":{"input_name":"Backup Color"},"widget_override":null},{"input_data":{"input_name":"Backup Gradient"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[15395954548128560685,{"persistent_metadata":{"reference":"Merge","display_name":"","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":0}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[10770443343193024138,{"persistent_metadata":{"reference":"Path","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Modification"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"Path Modify","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[10421722418968896452,{"persistent_metadata":{"reference":"Path","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Modification"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"Path Modify","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[11268046366284173800,{"persistent_metadata":{"reference":"Merge","display_name":"","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":0}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[1378578509112405,{"persistent_metadata":{"reference":"Path","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Modification"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"Path Modify","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[13975451746581400000,{"persistent_metadata":{"reference":"Path","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Modification"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"Path Modify","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[8644924780109919177,{"persistent_metadata":{"reference":"Sample Polyline","display_name":"","input_properties":[{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{"unit":" px","is_integer":false,"min":0.0,"mode":"Increment","blank_assist":true},"widget_override":"number"},{"input_data":{"blank_assist":true,"mode":"Increment","is_integer":true,"min":2.0},"widget_override":"number"},{"input_data":{"min":0.0,"mode":"Increment","unit":" px","blank_assist":true,"is_integer":false},"widget_override":"number"},{"input_data":{"mode":"Increment","min":0.0,"unit":" px","blank_assist":true,"is_integer":false},"widget_override":"number"},{"input_data":{},"widget_override":null}],"output_names":["Vector"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"Subpath Segment Lengths","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,7]}}},"network_metadata":null}}],[4,{"persistent_metadata":{"reference":null,"display_name":"Boundless Footprint","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[28,0]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Memoize","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[14,0]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Freeze Real Time","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[21,0]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"Sample Polyline","input_properties":[{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[16536768589601337644,{"persistent_metadata":{"reference":"Fill","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Fill"},"widget_override":null},{"input_data":{"input_name":"Backup Color"},"widget_override":null},{"input_data":{"input_name":"Backup Gradient"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[18015048324114736039,{"persistent_metadata":{"reference":"Path","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Modification"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"Path Modify","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[13594670583065022897,{"persistent_metadata":{"reference":"Sample Polyline","display_name":"","input_properties":[{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{"unit":" px","min":0.0,"is_integer":false,"blank_assist":true,"mode":"Increment"},"widget_override":"number"},{"input_data":{"min":2.0,"is_integer":true,"mode":"Increment","blank_assist":true},"widget_override":"number"},{"input_data":{"unit":" px","mode":"Increment","blank_assist":true,"is_integer":false,"min":0.0},"widget_override":"number"},{"input_data":{"unit":" px","min":0.0,"is_integer":false,"mode":"Increment","blank_assist":true},"widget_override":"number"},{"input_data":{},"widget_override":null}],"output_names":["Vector"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"Sample Polyline","input_properties":[{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"Subpath Segment Lengths","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,7]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Freeze Real Time","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[21,0]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Memoize","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[14,0]}}},"network_metadata":null}}],[4,{"persistent_metadata":{"reference":null,"display_name":"Boundless Footprint","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[28,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[10133176481349663495,{"persistent_metadata":{"reference":"Merge","display_name":"","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":0}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[172538270105470471,{"persistent_metadata":{"reference":"Fill","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Fill"},"widget_override":null},{"input_data":{"input_name":"Backup Color"},"widget_override":null},{"input_data":{"input_name":"Backup Gradient"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[11573595155909211511,{"persistent_metadata":{"reference":"Sample Polyline","display_name":"","input_properties":[{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{"mode":"Increment","is_integer":false,"unit":" px","blank_assist":true,"min":0.0},"widget_override":"number"},{"input_data":{"is_integer":true,"mode":"Increment","min":2.0,"blank_assist":true},"widget_override":"number"},{"input_data":{"min":0.0,"is_integer":false,"blank_assist":true,"mode":"Increment","unit":" px"},"widget_override":"number"},{"input_data":{"is_integer":false,"blank_assist":true,"min":0.0,"mode":"Increment","unit":" px"},"widget_override":"number"},{"input_data":{},"widget_override":null}],"output_names":["Vector"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[4,{"persistent_metadata":{"reference":null,"display_name":"Boundless Footprint","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[28,0]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Freeze Real Time","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[21,0]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Memoize","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[14,0]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"Subpath Segment Lengths","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,7]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"Sample Polyline","input_properties":[{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[7450965328305122110,{"persistent_metadata":{"reference":"Copy to Points","display_name":"","input_properties":[{"input_data":{"input_name":"Points"},"widget_override":null},{"input_data":{"tooltip":"Artwork to be copied and placed at each point","input_name":"Instance"},"widget_override":null},{"input_data":{"unit":"x","blank_assist":true,"mode":"Range","range_min":0.0,"is_integer":false,"range_max":2.0,"tooltip":"Minimum range of randomized sizes given to each instance","input_name":"Random Scale Min","min":0.0},"widget_override":"number"},{"input_data":{"range_min":0.0,"mode":"Range","is_integer":false,"tooltip":"Minimum range of randomized sizes given to each instance","range_max":2.0,"min":0.0,"unit":"x","blank_assist":true,"input_name":"Random Scale Max"},"widget_override":"number"},{"input_data":{"range_min":-50.0,"is_integer":false,"input_name":"Random Scale Bias","range_max":50.0,"mode":"Range","tooltip":"Bias for the probability distribution of randomized sizes (0 is uniform, negatives favor more of small sizes, positives favor more of large sizes)","blank_assist":true},"widget_override":"number"},{"input_data":{"is_integer":true,"min":0.0,"input_name":"Random Scale Seed","mode":"Increment","tooltip":"Seed to determine unique variations on all the randomized instance sizes","blank_assist":true},"widget_override":"number"},{"input_data":{"min":0.0,"mode":"Range","unit":"°","input_name":"Random Rotation","max":360.0,"blank_assist":true,"is_integer":false,"tooltip":"Range of randomized angles given to each instance, in degrees ranging from furthest clockwise to counterclockwise"},"widget_override":"number"},{"input_data":{"blank_assist":true,"input_name":"Random Rotation Seed","mode":"Increment","min":0.0,"is_integer":true,"tooltip":"Seed to determine unique variations on all the randomized instance angles"},"widget_override":"number"}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[14831840560430171946,{"persistent_metadata":{"reference":"Path","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Modification"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"Path Modify","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[7505360855062237520,{"persistent_metadata":{"reference":"Fill","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Fill"},"widget_override":null},{"input_data":{"input_name":"Backup Color"},"widget_override":null},{"input_data":{"input_name":"Backup Gradient"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[16195626650123806176,{"persistent_metadata":{"reference":"Merge","display_name":"","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":0}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[11632506522064533635,{"persistent_metadata":{"reference":"Path","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Modification"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"Path Modify","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[15492651270767932214,{"persistent_metadata":{"reference":"Merge","display_name":"","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":0}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[18319784717194273926,{"persistent_metadata":{"reference":"Path","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Modification"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"Path Modify","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[13475705179546695973,{"persistent_metadata":{"reference":"Merge","display_name":"","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":0}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[3121275823460307102,{"persistent_metadata":{"reference":"Path","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Modification"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"Path Modify","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[18067513817508158001,{"persistent_metadata":{"reference":"Sample Polyline","display_name":"","input_properties":[{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{"min":0.0,"is_integer":false,"mode":"Increment","unit":" px","blank_assist":true},"widget_override":"number"},{"input_data":{"min":2.0,"is_integer":true,"mode":"Increment","blank_assist":true},"widget_override":"number"},{"input_data":{"blank_assist":true,"is_integer":false,"min":0.0,"mode":"Increment","unit":" px"},"widget_override":"number"},{"input_data":{"blank_assist":true,"mode":"Increment","unit":" px","is_integer":false,"min":0.0},"widget_override":"number"},{"input_data":{},"widget_override":null}],"output_names":["Vector"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[4,{"persistent_metadata":{"reference":null,"display_name":"Boundless Footprint","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[28,0]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Memoize","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[14,0]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"Sample Polyline","input_properties":[{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"Subpath Segment Lengths","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,7]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Freeze Real Time","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[21,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[11417901103965737900,{"persistent_metadata":{"reference":"Sample Polyline","display_name":"","input_properties":[{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{"min":0.0,"is_integer":false,"mode":"Increment","unit":" px","blank_assist":true},"widget_override":"number"},{"input_data":{"min":2.0,"mode":"Increment","is_integer":true,"blank_assist":true},"widget_override":"number"},{"input_data":{"unit":" px","is_integer":false,"min":0.0,"mode":"Increment","blank_assist":true},"widget_override":"number"},{"input_data":{"min":0.0,"blank_assist":true,"unit":" px","is_integer":false,"mode":"Increment"},"widget_override":"number"},{"input_data":{},"widget_override":null}],"output_names":["Vector"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"Sample Polyline","input_properties":[{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Freeze Real Time","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[21,0]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Memoize","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[14,0]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"Subpath Segment Lengths","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,7]}}},"network_metadata":null}}],[4,{"persistent_metadata":{"reference":null,"display_name":"Boundless Footprint","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[28,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[16732130236852371275,{"persistent_metadata":{"reference":"Sample Polyline","display_name":"","input_properties":[{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{"unit":" px","is_integer":false,"mode":"Increment","min":0.0,"blank_assist":true},"widget_override":"number"},{"input_data":{"blank_assist":true,"is_integer":true,"mode":"Increment","min":2.0},"widget_override":"number"},{"input_data":{"is_integer":false,"mode":"Increment","unit":" px","min":0.0,"blank_assist":true},"widget_override":"number"},{"input_data":{"min":0.0,"is_integer":false,"blank_assist":true,"mode":"Increment","unit":" px"},"widget_override":"number"},{"input_data":{},"widget_override":null}],"output_names":["Vector"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[4,{"persistent_metadata":{"reference":null,"display_name":"Boundless Footprint","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[28,0]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Memoize","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[14,0]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"Subpath Segment Lengths","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,7]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Freeze Real Time","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[21,0]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"Sample Polyline","input_properties":[{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[1984475088429379731,{"persistent_metadata":{"reference":"Copy to Points","display_name":"","input_properties":[{"input_data":{"input_name":"Points"},"widget_override":null},{"input_data":{"tooltip":"Artwork to be copied and placed at each point","input_name":"Instance"},"widget_override":null},{"input_data":{"input_name":"Random Scale Min","blank_assist":true,"mode":"Range","tooltip":"Minimum range of randomized sizes given to each instance","is_integer":false,"range_min":0.0,"range_max":2.0,"unit":"x","min":0.0},"widget_override":"number"},{"input_data":{"input_name":"Random Scale Max","range_max":2.0,"min":0.0,"range_min":0.0,"mode":"Range","is_integer":false,"tooltip":"Minimum range of randomized sizes given to each instance","unit":"x","blank_assist":true},"widget_override":"number"},{"input_data":{"range_min":-50.0,"is_integer":false,"input_name":"Random Scale Bias","blank_assist":true,"range_max":50.0,"tooltip":"Bias for the probability distribution of randomized sizes (0 is uniform, negatives favor more of small sizes, positives favor more of large sizes)","mode":"Range"},"widget_override":"number"},{"input_data":{"input_name":"Random Scale Seed","min":0.0,"is_integer":true,"mode":"Increment","tooltip":"Seed to determine unique variations on all the randomized instance sizes","blank_assist":true},"widget_override":"number"},{"input_data":{"mode":"Range","tooltip":"Range of randomized angles given to each instance, in degrees ranging from furthest clockwise to counterclockwise","unit":"°","blank_assist":true,"min":0.0,"is_integer":false,"input_name":"Random Rotation","max":360.0},"widget_override":"number"},{"input_data":{"input_name":"Random Rotation Seed","blank_assist":true,"min":0.0,"tooltip":"Seed to determine unique variations on all the randomized instance angles","is_integer":true,"mode":"Increment"},"widget_override":"number"}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[14035980686649077716,{"persistent_metadata":{"reference":"Fill","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Fill"},"widget_override":null},{"input_data":{"input_name":"Backup Color"},"widget_override":null},{"input_data":{"input_name":"Backup Gradient"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[17891208858820401648,{"persistent_metadata":{"reference":"Transform","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"y":"Y","unit":" px","input_name":"Translation","x":"X"},"widget_override":"vec2"},{"input_data":{"input_name":"Rotation"},"widget_override":"transform_rotation"},{"input_data":{"input_name":"Scale","y":"H","unit":"x","x":"W"},"widget_override":"vec2"},{"input_data":{"input_name":"Skew"},"widget_override":"hidden"},{"input_data":{"input_name":"Pivot"},"widget_override":"hidden"}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"Transform","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[15735375935164094402,{"persistent_metadata":{"reference":"Fill","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Fill"},"widget_override":null},{"input_data":{"input_name":"Backup Color"},"widget_override":null},{"input_data":{"input_name":"Backup Gradient"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[314278016428495768,{"persistent_metadata":{"reference":"Merge","display_name":"","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":0}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[9863310024364795214,{"persistent_metadata":{"reference":"Fill","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Fill"},"widget_override":null},{"input_data":{"input_name":"Backup Color"},"widget_override":null},{"input_data":{"input_name":"Backup Gradient"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[3636653585682494814,{"persistent_metadata":{"reference":"Copy to Points","display_name":"","input_properties":[{"input_data":{"input_name":"Points"},"widget_override":null},{"input_data":{"input_name":"Instance","tooltip":"Artwork to be copied and placed at each point"},"widget_override":null},{"input_data":{"tooltip":"Minimum range of randomized sizes given to each instance","unit":"x","range_max":2.0,"blank_assist":true,"input_name":"Random Scale Min","mode":"Range","range_min":0.0,"min":0.0,"is_integer":false},"widget_override":"number"},{"input_data":{"range_min":0.0,"input_name":"Random Scale Max","mode":"Range","is_integer":false,"tooltip":"Minimum range of randomized sizes given to each instance","unit":"x","min":0.0,"blank_assist":true,"range_max":2.0},"widget_override":"number"},{"input_data":{"mode":"Range","input_name":"Random Scale Bias","range_max":50.0,"tooltip":"Bias for the probability distribution of randomized sizes (0 is uniform, negatives favor more of small sizes, positives favor more of large sizes)","is_integer":false,"blank_assist":true,"range_min":-50.0},"widget_override":"number"},{"input_data":{"blank_assist":true,"min":0.0,"input_name":"Random Scale Seed","is_integer":true,"mode":"Increment","tooltip":"Seed to determine unique variations on all the randomized instance sizes"},"widget_override":"number"},{"input_data":{"tooltip":"Range of randomized angles given to each instance, in degrees ranging from furthest clockwise to counterclockwise","max":360.0,"is_integer":false,"mode":"Range","input_name":"Random Rotation","blank_assist":true,"min":0.0,"unit":"°"},"widget_override":"number"},{"input_data":{"is_integer":true,"min":0.0,"mode":"Increment","blank_assist":true,"tooltip":"Seed to determine unique variations on all the randomized instance angles","input_name":"Random Rotation Seed"},"widget_override":"number"}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[16434255153991868080,{"persistent_metadata":{"reference":"Copy to Points","display_name":"","input_properties":[{"input_data":{"input_name":"Points"},"widget_override":null},{"input_data":{"input_name":"Instance","tooltip":"Artwork to be copied and placed at each point"},"widget_override":null},{"input_data":{"range_min":0.0,"tooltip":"Minimum range of randomized sizes given to each instance","input_name":"Random Scale Min","unit":"x","mode":"Range","blank_assist":true,"range_max":2.0,"min":0.0,"is_integer":false},"widget_override":"number"},{"input_data":{"input_name":"Random Scale Max","min":0.0,"range_max":2.0,"mode":"Range","unit":"x","range_min":0.0,"tooltip":"Minimum range of randomized sizes given to each instance","is_integer":false,"blank_assist":true},"widget_override":"number"},{"input_data":{"tooltip":"Bias for the probability distribution of randomized sizes (0 is uniform, negatives favor more of small sizes, positives favor more of large sizes)","blank_assist":true,"is_integer":false,"mode":"Range","range_max":50.0,"input_name":"Random Scale Bias","range_min":-50.0},"widget_override":"number"},{"input_data":{"input_name":"Random Scale Seed","blank_assist":true,"mode":"Increment","is_integer":true,"min":0.0,"tooltip":"Seed to determine unique variations on all the randomized instance sizes"},"widget_override":"number"},{"input_data":{"input_name":"Random Rotation","unit":"°","max":360.0,"mode":"Range","is_integer":false,"min":0.0,"tooltip":"Range of randomized angles given to each instance, in degrees ranging from furthest clockwise to counterclockwise","blank_assist":true},"widget_override":"number"},{"input_data":{"mode":"Increment","blank_assist":true,"min":0.0,"is_integer":true,"input_name":"Random Rotation Seed","tooltip":"Seed to determine unique variations on all the randomized instance angles"},"widget_override":"number"}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[501401493219507773,{"persistent_metadata":{"reference":"Fill","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Fill"},"widget_override":null},{"input_data":{"input_name":"Backup Color"},"widget_override":null},{"input_data":{"input_name":"Backup Gradient"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[14537754528543289381,{"persistent_metadata":{"reference":"Merge","display_name":"","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":0}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[952330505278607301,{"persistent_metadata":{"reference":"Fill","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Fill"},"widget_override":null},{"input_data":{"input_name":"Backup Color"},"widget_override":null},{"input_data":{"input_name":"Backup Gradient"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[4577638792388493935,{"persistent_metadata":{"reference":"Merge","display_name":"Head and Neck","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":78}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[17064046832210629373,{"persistent_metadata":{"reference":"Merge","display_name":"","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":0}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[11899713172487274471,{"persistent_metadata":{"reference":"Fill","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Fill"},"widget_override":null},{"input_data":{"input_name":"Backup Color"},"widget_override":null},{"input_data":{"input_name":"Backup Gradient"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[15466714490303763249,{"persistent_metadata":{"reference":"Merge","display_name":"","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":0}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[10689298484366290551,{"persistent_metadata":{"reference":"Path","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Modification"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"Path Modify","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[1785173043494067496,{"persistent_metadata":{"reference":"Path","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Modification"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"Path Modify","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[454416440369338250,{"persistent_metadata":{"reference":"Path","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Modification"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"Path Modify","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[14209241002058525241,{"persistent_metadata":{"reference":"Merge","display_name":"","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":0}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[7385465194555106679,{"persistent_metadata":{"reference":"Merge","display_name":"","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Absolute":[-17,211]}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[17147975601187022720,{"persistent_metadata":{"reference":"Fill","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Fill"},"widget_override":null},{"input_data":{"input_name":"Backup Color"},"widget_override":null},{"input_data":{"input_name":"Backup Gradient"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[4341772758799935306,{"persistent_metadata":{"reference":"Sample Polyline","display_name":"","input_properties":[{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{"is_integer":false,"min":0.0,"mode":"Increment","unit":" px","blank_assist":true},"widget_override":"number"},{"input_data":{"mode":"Increment","is_integer":true,"min":2.0,"blank_assist":true},"widget_override":"number"},{"input_data":{"is_integer":false,"blank_assist":true,"min":0.0,"mode":"Increment","unit":" px"},"widget_override":"number"},{"input_data":{"unit":" px","blank_assist":true,"mode":"Increment","is_integer":false,"min":0.0},"widget_override":"number"},{"input_data":{},"widget_override":null}],"output_names":["Vector"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"Sample Polyline","input_properties":[{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Memoize","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[14,0]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Freeze Real Time","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[21,0]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"Subpath Segment Lengths","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,7]}}},"network_metadata":null}}],[4,{"persistent_metadata":{"reference":null,"display_name":"Boundless Footprint","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[28,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[14098374807212007572,{"persistent_metadata":{"reference":"Merge","display_name":"","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":0}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[2175432926627256613,{"persistent_metadata":{"reference":"Merge","display_name":"","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Absolute":[-17,328]}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[11666664915283969027,{"persistent_metadata":{"reference":"Path","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Modification"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"Path Modify","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[13907578809542898348,{"persistent_metadata":{"reference":"Merge","display_name":"","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":0}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[15857077552290328068,{"persistent_metadata":{"reference":"Path","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Modification"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"Path Modify","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[7659717355245331967,{"persistent_metadata":{"reference":"Merge","display_name":"","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":0}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[12062649793560663566,{"persistent_metadata":{"reference":"Merge","display_name":"Solid Red Skirt","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":3}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[2660652185019504730,{"persistent_metadata":{"reference":"Sample Polyline","display_name":"","input_properties":[{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{"blank_assist":true,"is_integer":false,"min":0.0,"unit":" px","mode":"Increment"},"widget_override":"number"},{"input_data":{"mode":"Increment","is_integer":true,"blank_assist":true,"min":2.0},"widget_override":"number"},{"input_data":{"blank_assist":true,"mode":"Increment","min":0.0,"is_integer":false,"unit":" px"},"widget_override":"number"},{"input_data":{"blank_assist":true,"min":0.0,"is_integer":false,"mode":"Increment","unit":" px"},"widget_override":"number"},{"input_data":{},"widget_override":null}],"output_names":["Vector"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[3,{"persistent_metadata":{"reference":null,"display_name":"Freeze Real Time","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[21,0]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Memoize","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[14,0]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"Sample Polyline","input_properties":[{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"Subpath Segment Lengths","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,7]}}},"network_metadata":null}}],[4,{"persistent_metadata":{"reference":null,"display_name":"Boundless Footprint","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[28,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[5002654561220917457,{"persistent_metadata":{"reference":"Scatter Points","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"range_max":100.0,"input_name":"Separation Disk Diameter","mode":"Range","min":0.01,"range_min":1.0,"blank_assist":true,"is_integer":false},"widget_override":"number"},{"input_data":{"mode":"Increment","blank_assist":true,"input_name":"Seed","min":0.0,"is_integer":true},"widget_override":"number"}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"Memoize","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Freeze Real Time","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[14,0]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"Poisson-Disk Points","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Boundless Footprint","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[21,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[15578929303912288394,{"persistent_metadata":{"reference":"Fill","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Fill"},"widget_override":null},{"input_data":{"input_name":"Backup Color"},"widget_override":null},{"input_data":{"input_name":"Backup Gradient"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[16756940771483104467,{"persistent_metadata":{"reference":"Fill","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Fill"},"widget_override":null},{"input_data":{"input_name":"Backup Color"},"widget_override":null},{"input_data":{"input_name":"Backup Gradient"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[1869448627329502330,{"persistent_metadata":{"reference":"Copy to Points","display_name":"","input_properties":[{"input_data":{"input_name":"Points"},"widget_override":null},{"input_data":{"input_name":"Instance","tooltip":"Artwork to be copied and placed at each point"},"widget_override":null},{"input_data":{"input_name":"Random Scale Min","min":0.0,"blank_assist":true,"mode":"Range","range_max":2.0,"tooltip":"Minimum range of randomized sizes given to each instance","is_integer":false,"unit":"x","range_min":0.0},"widget_override":"number"},{"input_data":{"range_max":2.0,"tooltip":"Minimum range of randomized sizes given to each instance","is_integer":false,"blank_assist":true,"min":0.0,"range_min":0.0,"unit":"x","mode":"Range","input_name":"Random Scale Max"},"widget_override":"number"},{"input_data":{"mode":"Range","tooltip":"Bias for the probability distribution of randomized sizes (0 is uniform, negatives favor more of small sizes, positives favor more of large sizes)","blank_assist":true,"is_integer":false,"range_min":-50.0,"input_name":"Random Scale Bias","range_max":50.0},"widget_override":"number"},{"input_data":{"input_name":"Random Scale Seed","blank_assist":true,"tooltip":"Seed to determine unique variations on all the randomized instance sizes","is_integer":true,"mode":"Increment","min":0.0},"widget_override":"number"},{"input_data":{"mode":"Range","tooltip":"Range of randomized angles given to each instance, in degrees ranging from furthest clockwise to counterclockwise","unit":"°","max":360.0,"is_integer":false,"min":0.0,"blank_assist":true,"input_name":"Random Rotation"},"widget_override":"number"},{"input_data":{"tooltip":"Seed to determine unique variations on all the randomized instance angles","blank_assist":true,"is_integer":true,"min":0.0,"input_name":"Random Rotation Seed","mode":"Increment"},"widget_override":"number"}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[11553850607251055696,{"persistent_metadata":{"reference":"Path","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Modification"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"Path Modify","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[18422317423856403288,{"persistent_metadata":{"reference":"Merge","display_name":"","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":0}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[15961046538654083626,{"persistent_metadata":{"reference":"Copy to Points","display_name":"","input_properties":[{"input_data":{"input_name":"Points"},"widget_override":null},{"input_data":{"tooltip":"Artwork to be copied and placed at each point","input_name":"Instance"},"widget_override":null},{"input_data":{"is_integer":false,"min":0.0,"range_max":2.0,"tooltip":"Minimum range of randomized sizes given to each instance","mode":"Range","input_name":"Random Scale Min","blank_assist":true,"range_min":0.0,"unit":"x"},"widget_override":"number"},{"input_data":{"range_max":2.0,"mode":"Range","blank_assist":true,"range_min":0.0,"tooltip":"Minimum range of randomized sizes given to each instance","min":0.0,"is_integer":false,"input_name":"Random Scale Max","unit":"x"},"widget_override":"number"},{"input_data":{"blank_assist":true,"tooltip":"Bias for the probability distribution of randomized sizes (0 is uniform, negatives favor more of small sizes, positives favor more of large sizes)","input_name":"Random Scale Bias","is_integer":false,"range_max":50.0,"mode":"Range","range_min":-50.0},"widget_override":"number"},{"input_data":{"tooltip":"Seed to determine unique variations on all the randomized instance sizes","blank_assist":true,"input_name":"Random Scale Seed","is_integer":true,"mode":"Increment","min":0.0},"widget_override":"number"},{"input_data":{"mode":"Range","input_name":"Random Rotation","tooltip":"Range of randomized angles given to each instance, in degrees ranging from furthest clockwise to counterclockwise","unit":"°","blank_assist":true,"is_integer":false,"min":0.0,"max":360.0},"widget_override":"number"},{"input_data":{"is_integer":true,"min":0.0,"mode":"Increment","tooltip":"Seed to determine unique variations on all the randomized instance angles","input_name":"Random Rotation Seed","blank_assist":true},"widget_override":"number"}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[6282972142629473139,{"persistent_metadata":{"reference":"Merge","display_name":"","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":0}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[12594527670567285670,{"persistent_metadata":{"reference":"Fill","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Fill"},"widget_override":null},{"input_data":{"input_name":"Backup Color"},"widget_override":null},{"input_data":{"input_name":"Backup Gradient"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[12880230498984021417,{"persistent_metadata":{"reference":"Copy to Points","display_name":"","input_properties":[{"input_data":{"input_name":"Points"},"widget_override":null},{"input_data":{"tooltip":"Artwork to be copied and placed at each point","input_name":"Instance"},"widget_override":null},{"input_data":{"is_integer":false,"input_name":"Random Scale Min","min":0.0,"tooltip":"Minimum range of randomized sizes given to each instance","mode":"Range","unit":"x","range_min":0.0,"blank_assist":true,"range_max":2.0},"widget_override":"number"},{"input_data":{"range_max":2.0,"mode":"Range","range_min":0.0,"input_name":"Random Scale Max","tooltip":"Minimum range of randomized sizes given to each instance","is_integer":false,"min":0.0,"unit":"x","blank_assist":true},"widget_override":"number"},{"input_data":{"range_max":50.0,"range_min":-50.0,"tooltip":"Bias for the probability distribution of randomized sizes (0 is uniform, negatives favor more of small sizes, positives favor more of large sizes)","is_integer":false,"input_name":"Random Scale Bias","mode":"Range","blank_assist":true},"widget_override":"number"},{"input_data":{"tooltip":"Seed to determine unique variations on all the randomized instance sizes","min":0.0,"mode":"Increment","blank_assist":true,"input_name":"Random Scale Seed","is_integer":true},"widget_override":"number"},{"input_data":{"unit":"°","blank_assist":true,"max":360.0,"tooltip":"Range of randomized angles given to each instance, in degrees ranging from furthest clockwise to counterclockwise","min":0.0,"input_name":"Random Rotation","mode":"Range","is_integer":false},"widget_override":"number"},{"input_data":{"is_integer":true,"blank_assist":true,"tooltip":"Seed to determine unique variations on all the randomized instance angles","input_name":"Random Rotation Seed","min":0.0,"mode":"Increment"},"widget_override":"number"}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[13269760558336088742,{"persistent_metadata":{"reference":"Path","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Modification"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"Path Modify","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[16551385471328831128,{"persistent_metadata":{"reference":"Merge","display_name":"","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":0}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[15656854169166220905,{"persistent_metadata":{"reference":"Transform","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"y":"Y","input_name":"Translation","unit":" px","x":"X"},"widget_override":"vec2"},{"input_data":{"input_name":"Rotation"},"widget_override":"transform_rotation"},{"input_data":{"input_name":"Scale","unit":"x","x":"W","y":"H"},"widget_override":"vec2"},{"input_data":{"input_name":"Skew"},"widget_override":"hidden"},{"input_data":{"input_name":"Pivot"},"widget_override":"hidden"}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"Transform","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[2682920349304670808,{"persistent_metadata":{"reference":"Merge","display_name":"","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":0}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[12030171742672119253,{"persistent_metadata":{"reference":"Copy to Points","display_name":"","input_properties":[{"input_data":{"input_name":"Points"},"widget_override":null},{"input_data":{"input_name":"Instance","tooltip":"Artwork to be copied and placed at each point"},"widget_override":null},{"input_data":{"is_integer":false,"mode":"Range","blank_assist":true,"min":0.0,"range_max":2.0,"tooltip":"Minimum range of randomized sizes given to each instance","input_name":"Random Scale Min","unit":"x","range_min":0.0},"widget_override":"number"},{"input_data":{"input_name":"Random Scale Max","tooltip":"Minimum range of randomized sizes given to each instance","mode":"Range","range_max":2.0,"range_min":0.0,"unit":"x","is_integer":false,"blank_assist":true,"min":0.0},"widget_override":"number"},{"input_data":{"tooltip":"Bias for the probability distribution of randomized sizes (0 is uniform, negatives favor more of small sizes, positives favor more of large sizes)","range_max":50.0,"range_min":-50.0,"input_name":"Random Scale Bias","is_integer":false,"blank_assist":true,"mode":"Range"},"widget_override":"number"},{"input_data":{"blank_assist":true,"input_name":"Random Scale Seed","min":0.0,"is_integer":true,"tooltip":"Seed to determine unique variations on all the randomized instance sizes","mode":"Increment"},"widget_override":"number"},{"input_data":{"input_name":"Random Rotation","blank_assist":true,"min":0.0,"unit":"°","tooltip":"Range of randomized angles given to each instance, in degrees ranging from furthest clockwise to counterclockwise","is_integer":false,"mode":"Range","max":360.0},"widget_override":"number"},{"input_data":{"tooltip":"Seed to determine unique variations on all the randomized instance angles","input_name":"Random Rotation Seed","is_integer":true,"mode":"Increment","blank_assist":true,"min":0.0},"widget_override":"number"}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[10599660455959346550,{"persistent_metadata":{"reference":"Path","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Modification"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"Path Modify","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[7262199696924786895,{"persistent_metadata":{"reference":"Sample Polyline","display_name":"","input_properties":[{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{"unit":" px","min":0.0,"mode":"Increment","blank_assist":true,"is_integer":false},"widget_override":"number"},{"input_data":{"is_integer":true,"blank_assist":true,"min":2.0,"mode":"Increment"},"widget_override":"number"},{"input_data":{"blank_assist":true,"min":0.0,"is_integer":false,"unit":" px","mode":"Increment"},"widget_override":"number"},{"input_data":{"min":0.0,"is_integer":false,"blank_assist":true,"unit":" px","mode":"Increment"},"widget_override":"number"},{"input_data":{},"widget_override":null}],"output_names":["Vector"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"Sample Polyline","input_properties":[{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}],[4,{"persistent_metadata":{"reference":null,"display_name":"Boundless Footprint","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[28,0]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Freeze Real Time","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[21,0]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"Subpath Segment Lengths","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,7]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Memoize","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[14,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[5009664118231399060,{"persistent_metadata":{"reference":"Merge","display_name":"","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":0}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[16137033772363318157,{"persistent_metadata":{"reference":"Path","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Modification"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"Path Modify","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[10586744777717861556,{"persistent_metadata":{"reference":"Copy to Points","display_name":"","input_properties":[{"input_data":{"input_name":"Points"},"widget_override":null},{"input_data":{"tooltip":"Artwork to be copied and placed at each point","input_name":"Instance"},"widget_override":null},{"input_data":{"mode":"Range","range_max":2.0,"blank_assist":true,"range_min":0.0,"tooltip":"Minimum range of randomized sizes given to each instance","min":0.0,"input_name":"Random Scale Min","is_integer":false,"unit":"x"},"widget_override":"number"},{"input_data":{"input_name":"Random Scale Max","tooltip":"Minimum range of randomized sizes given to each instance","mode":"Range","range_max":2.0,"unit":"x","is_integer":false,"blank_assist":true,"min":0.0,"range_min":0.0},"widget_override":"number"},{"input_data":{"blank_assist":true,"range_min":-50.0,"tooltip":"Bias for the probability distribution of randomized sizes (0 is uniform, negatives favor more of small sizes, positives favor more of large sizes)","mode":"Range","input_name":"Random Scale Bias","range_max":50.0,"is_integer":false},"widget_override":"number"},{"input_data":{"mode":"Increment","blank_assist":true,"tooltip":"Seed to determine unique variations on all the randomized instance sizes","is_integer":true,"input_name":"Random Scale Seed","min":0.0},"widget_override":"number"},{"input_data":{"is_integer":false,"mode":"Range","max":360.0,"min":0.0,"unit":"°","blank_assist":true,"input_name":"Random Rotation","tooltip":"Range of randomized angles given to each instance, in degrees ranging from furthest clockwise to counterclockwise"},"widget_override":"number"},{"input_data":{"input_name":"Random Rotation Seed","tooltip":"Seed to determine unique variations on all the randomized instance angles","is_integer":true,"mode":"Increment","min":0.0,"blank_assist":true},"widget_override":"number"}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[11659756061767599421,{"persistent_metadata":{"reference":"Fill","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Fill"},"widget_override":null},{"input_data":{"input_name":"Backup Color"},"widget_override":null},{"input_data":{"input_name":"Backup Gradient"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[6532401937876437300,{"persistent_metadata":{"reference":"Transform","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Translation","x":"X","unit":" px","y":"Y"},"widget_override":"vec2"},{"input_data":{"input_name":"Rotation"},"widget_override":"transform_rotation"},{"input_data":{"x":"W","input_name":"Scale","unit":"x","y":"H"},"widget_override":"vec2"},{"input_data":{"input_name":"Skew"},"widget_override":"hidden"},{"input_data":{"input_name":"Pivot"},"widget_override":"hidden"}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"Transform","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[14862049226133442027,{"persistent_metadata":{"reference":"Fill","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Fill"},"widget_override":null},{"input_data":{"input_name":"Backup Color"},"widget_override":null},{"input_data":{"input_name":"Backup Gradient"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[16339345235172368839,{"persistent_metadata":{"reference":"Fill","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Fill"},"widget_override":null},{"input_data":{"input_name":"Backup Color"},"widget_override":null},{"input_data":{"input_name":"Backup Gradient"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[14797986717815207528,{"persistent_metadata":{"reference":"Path","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Modification"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"Path Modify","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[4236845268521674740,{"persistent_metadata":{"reference":"Path","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Modification"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"Path Modify","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[4131094614457622424,{"persistent_metadata":{"reference":"Sample Polyline","display_name":"","input_properties":[{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{"unit":" px","blank_assist":true,"is_integer":false,"mode":"Increment","min":0.0},"widget_override":"number"},{"input_data":{"blank_assist":true,"is_integer":true,"min":2.0,"mode":"Increment"},"widget_override":"number"},{"input_data":{"blank_assist":true,"mode":"Increment","min":0.0,"is_integer":false,"unit":" px"},"widget_override":"number"},{"input_data":{"mode":"Increment","blank_assist":true,"min":0.0,"unit":" px","is_integer":false},"widget_override":"number"},{"input_data":{},"widget_override":null}],"output_names":["Vector"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"Subpath Segment Lengths","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,7]}}},"network_metadata":null}}],[4,{"persistent_metadata":{"reference":null,"display_name":"Boundless Footprint","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[28,0]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Freeze Real Time","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[21,0]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Memoize","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[14,0]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"Sample Polyline","input_properties":[{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[11194653561109699287,{"persistent_metadata":{"reference":"Path","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Modification"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"Path Modify","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[11590691579869262546,{"persistent_metadata":{"reference":"Fill","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Fill"},"widget_override":null},{"input_data":{"input_name":"Backup Color"},"widget_override":null},{"input_data":{"input_name":"Backup Gradient"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[15949658764632267703,{"persistent_metadata":{"reference":"Sample Polyline","display_name":"","input_properties":[{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{"unit":" px","blank_assist":true,"is_integer":false,"min":0.0,"mode":"Increment"},"widget_override":"number"},{"input_data":{"blank_assist":true,"min":2.0,"mode":"Increment","is_integer":true},"widget_override":"number"},{"input_data":{"min":0.0,"blank_assist":true,"unit":" px","mode":"Increment","is_integer":false},"widget_override":"number"},{"input_data":{"blank_assist":true,"mode":"Increment","is_integer":false,"min":0.0,"unit":" px"},"widget_override":"number"},{"input_data":{},"widget_override":null}],"output_names":["Vector"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"Subpath Segment Lengths","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,7]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"Sample Polyline","input_properties":[{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Freeze Real Time","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[21,0]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Memoize","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[14,0]}}},"network_metadata":null}}],[4,{"persistent_metadata":{"reference":null,"display_name":"Boundless Footprint","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[28,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[2044103368441997753,{"persistent_metadata":{"reference":"Path","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Modification"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"Path Modify","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[1019037285881657884,{"persistent_metadata":{"reference":"Copy to Points","display_name":"","input_properties":[{"input_data":{"input_name":"Points"},"widget_override":null},{"input_data":{"input_name":"Instance","tooltip":"Artwork to be copied and placed at each point"},"widget_override":null},{"input_data":{"input_name":"Random Scale Min","is_integer":false,"unit":"x","tooltip":"Minimum range of randomized sizes given to each instance","range_min":0.0,"range_max":2.0,"mode":"Range","blank_assist":true,"min":0.0},"widget_override":"number"},{"input_data":{"blank_assist":true,"mode":"Range","input_name":"Random Scale Max","min":0.0,"range_max":2.0,"tooltip":"Minimum range of randomized sizes given to each instance","range_min":0.0,"is_integer":false,"unit":"x"},"widget_override":"number"},{"input_data":{"blank_assist":true,"is_integer":false,"mode":"Range","range_min":-50.0,"input_name":"Random Scale Bias","range_max":50.0,"tooltip":"Bias for the probability distribution of randomized sizes (0 is uniform, negatives favor more of small sizes, positives favor more of large sizes)"},"widget_override":"number"},{"input_data":{"tooltip":"Seed to determine unique variations on all the randomized instance sizes","input_name":"Random Scale Seed","is_integer":true,"min":0.0,"mode":"Increment","blank_assist":true},"widget_override":"number"},{"input_data":{"max":360.0,"is_integer":false,"blank_assist":true,"mode":"Range","unit":"°","tooltip":"Range of randomized angles given to each instance, in degrees ranging from furthest clockwise to counterclockwise","min":0.0,"input_name":"Random Rotation"},"widget_override":"number"},{"input_data":{"tooltip":"Seed to determine unique variations on all the randomized instance angles","mode":"Increment","input_name":"Random Rotation Seed","is_integer":true,"blank_assist":true,"min":0.0},"widget_override":"number"}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[4577174813962563383,{"persistent_metadata":{"reference":"Path","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Modification"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"Path Modify","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[17207895962122263432,{"persistent_metadata":{"reference":"Copy to Points","display_name":"","input_properties":[{"input_data":{"input_name":"Points"},"widget_override":null},{"input_data":{"input_name":"Instance","tooltip":"Artwork to be copied and placed at each point"},"widget_override":null},{"input_data":{"is_integer":false,"mode":"Range","range_min":0.0,"tooltip":"Minimum range of randomized sizes given to each instance","blank_assist":true,"input_name":"Random Scale Min","min":0.0,"unit":"x","range_max":2.0},"widget_override":"number"},{"input_data":{"min":0.0,"input_name":"Random Scale Max","tooltip":"Minimum range of randomized sizes given to each instance","blank_assist":true,"mode":"Range","is_integer":false,"range_min":0.0,"unit":"x","range_max":2.0},"widget_override":"number"},{"input_data":{"is_integer":false,"range_min":-50.0,"input_name":"Random Scale Bias","tooltip":"Bias for the probability distribution of randomized sizes (0 is uniform, negatives favor more of small sizes, positives favor more of large sizes)","range_max":50.0,"blank_assist":true,"mode":"Range"},"widget_override":"number"},{"input_data":{"tooltip":"Seed to determine unique variations on all the randomized instance sizes","blank_assist":true,"input_name":"Random Scale Seed","mode":"Increment","is_integer":true,"min":0.0},"widget_override":"number"},{"input_data":{"blank_assist":true,"input_name":"Random Rotation","min":0.0,"max":360.0,"is_integer":false,"mode":"Range","tooltip":"Range of randomized angles given to each instance, in degrees ranging from furthest clockwise to counterclockwise","unit":"°"},"widget_override":"number"},{"input_data":{"mode":"Increment","min":0.0,"tooltip":"Seed to determine unique variations on all the randomized instance angles","blank_assist":true,"input_name":"Random Rotation Seed","is_integer":true},"widget_override":"number"}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[10415872992231003638,{"persistent_metadata":{"reference":"Fill","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Fill"},"widget_override":null},{"input_data":{"input_name":"Backup Color"},"widget_override":null},{"input_data":{"input_name":"Backup Gradient"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[6666260895482068061,{"persistent_metadata":{"reference":"Path","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Modification"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"Path Modify","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[3165571685352930240,{"persistent_metadata":{"reference":"Path","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Modification"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"Path Modify","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[1689789805659535712,{"persistent_metadata":{"reference":"Merge","display_name":"","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":0}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[6749771744300551215,{"persistent_metadata":{"reference":"Path","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Modification"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"Path Modify","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[16614450796751955858,{"persistent_metadata":{"reference":"Path","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Modification"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"Path Modify","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[14029368390543839187,{"persistent_metadata":{"reference":"Path","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Modification"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"Path Modify","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[10127467043900015225,{"persistent_metadata":{"reference":"Path","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Modification"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"Path Modify","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[2422139482859833437,{"persistent_metadata":{"reference":"Merge","display_name":"","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":0}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[9374264173303233490,{"persistent_metadata":{"reference":"Sample Polyline","display_name":"","input_properties":[{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{"is_integer":false,"mode":"Increment","blank_assist":true,"unit":" px","min":0.0},"widget_override":"number"},{"input_data":{"mode":"Increment","blank_assist":true,"is_integer":true,"min":2.0},"widget_override":"number"},{"input_data":{"min":0.0,"unit":" px","is_integer":false,"mode":"Increment","blank_assist":true},"widget_override":"number"},{"input_data":{"blank_assist":true,"is_integer":false,"min":0.0,"unit":" px","mode":"Increment"},"widget_override":"number"},{"input_data":{},"widget_override":null}],"output_names":["Vector"],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[4,{"persistent_metadata":{"reference":null,"display_name":"Boundless Footprint","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[28,0]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Freeze Real Time","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[21,0]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Memoize","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[14,0]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"Subpath Segment Lengths","input_properties":[{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,7]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"Sample Polyline","input_properties":[{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[8766106989344197438,{"persistent_metadata":{"reference":"Path","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Modification"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"Path Modify","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[737.4067596403,-6318.358748666366],"tilt":0.0,"zoom":0.6328125,"flip":false},"node_graph_to_viewport":[0.6328125,0.0,0.0,0.6328125,1457.0,-3418.0],"node_graph_top_right":[1980.796875,0.0]},"selection_undo_history":[[3457800614598085282],[17426704671299246894],[2699408592782313690],[4493274523708782092],[14031411536409518176],[13263961817794116841],[835795066714655983],[11477846841203274509],[727544715487174952],[6480666310383891203],[15086626938904467381],[12994398686940961368],[15086626938904467381],[],[12994398686940961368],[],[5140869461760168364],[11677503666435782605],[776454851019809551],[],[10662978266497754900],[],[13201515093260842314],[],[3932608775253338292],[],[8090442493082590595],[],[17545135276965178247],[4332145463108161926],[],[4332145463108161926],[],[4332145463108161926],[],[11356586238302409958,10086073308516686449],[],[4332145463108161926],[],[3406722917122601552],[4332145463108161926],[],[4332145463108161926],[],[10086073308516686449],[17545135276965178247],[],[17078740291337047697],[3457800614598085282],[3457800614598085282,17426704671299246894],[3457800614598085282,17426704671299246894,2699408592782313690],[3457800614598085282,17426704671299246894,2699408592782313690,14031411536409518176],[3457800614598085282,17426704671299246894,2699408592782313690,14031411536409518176,15239301303367148581],[3457800614598085282,17426704671299246894,2699408592782313690,14031411536409518176,15239301303367148581,13263961817794116841],[3457800614598085282,17426704671299246894,2699408592782313690,14031411536409518176,15239301303367148581,13263961817794116841],[3457800614598085282,17426704671299246894,2699408592782313690,14031411536409518176,13263961817794116841],[3457800614598085282,17426704671299246894,2699408592782313690,14031411536409518176,13263961817794116841,835795066714655983],[3457800614598085282,17426704671299246894,2699408592782313690,14031411536409518176,13263961817794116841,835795066714655983,11477846841203274509],[3457800614598085282,17426704671299246894,2699408592782313690,14031411536409518176,13263961817794116841,835795066714655983,11477846841203274509,727544715487174952],[3457800614598085282,17426704671299246894,2699408592782313690,14031411536409518176,13263961817794116841,835795066714655983,11477846841203274509,727544715487174952,6480666310383891203],[3457800614598085282,17426704671299246894,2699408592782313690,14031411536409518176,13263961817794116841,835795066714655983,11477846841203274509,727544715487174952,6480666310383891203,10550662778443296023],[3457800614598085282,17426704671299246894,2699408592782313690,14031411536409518176,13263961817794116841,835795066714655983,11477846841203274509,727544715487174952,6480666310383891203,10550662778443296023,13185163654003144011],[3457800614598085282,17426704671299246894,2699408592782313690,14031411536409518176,13263961817794116841,835795066714655983,11477846841203274509,727544715487174952,6480666310383891203,10550662778443296023,13185163654003144011,3559656994078944914],[3457800614598085282,17426704671299246894,2699408592782313690,14031411536409518176,13263961817794116841,835795066714655983,11477846841203274509,727544715487174952,6480666310383891203,10550662778443296023,13185163654003144011,3559656994078944914,12747708470463124971],[3457800614598085282,17426704671299246894,2699408592782313690,14031411536409518176,13263961817794116841,835795066714655983,11477846841203274509,727544715487174952,6480666310383891203,10550662778443296023,13185163654003144011,3559656994078944914,12747708470463124971,898580338082782932],[3457800614598085282,17426704671299246894,2699408592782313690,14031411536409518176,13263961817794116841,835795066714655983,11477846841203274509,727544715487174952,6480666310383891203,10550662778443296023,13185163654003144011,3559656994078944914,12747708470463124971,898580338082782932,17099718003896986529],[3457800614598085282,17426704671299246894,2699408592782313690,14031411536409518176,13263961817794116841,835795066714655983,11477846841203274509,727544715487174952,6480666310383891203,10550662778443296023,13185163654003144011,3559656994078944914,12747708470463124971,898580338082782932,17099718003896986529,1510915657479425828],[3457800614598085282,17426704671299246894,2699408592782313690,14031411536409518176,13263961817794116841,835795066714655983,11477846841203274509,727544715487174952,6480666310383891203,10550662778443296023,13185163654003144011,3559656994078944914,12747708470463124971,898580338082782932,17099718003896986529,1510915657479425828,770786980744949903],[3457800614598085282,17426704671299246894,2699408592782313690,14031411536409518176,13263961817794116841,835795066714655983,11477846841203274509,727544715487174952,6480666310383891203,10550662778443296023,13185163654003144011,3559656994078944914,12747708470463124971,898580338082782932,17099718003896986529,1510915657479425828,770786980744949903,5742628441455317378],[3457800614598085282,17426704671299246894,2699408592782313690,14031411536409518176,13263961817794116841,835795066714655983,11477846841203274509,727544715487174952,6480666310383891203,10550662778443296023,13185163654003144011,3559656994078944914,12747708470463124971,898580338082782932,17099718003896986529,1510915657479425828,770786980744949903,5742628441455317378,12579808169500774530],[3457800614598085282,17426704671299246894,2699408592782313690,14031411536409518176,13263961817794116841,835795066714655983,11477846841203274509,727544715487174952,6480666310383891203,10550662778443296023,13185163654003144011,3559656994078944914,12747708470463124971,898580338082782932,17099718003896986529,1510915657479425828,770786980744949903,5742628441455317378,12579808169500774530,862014397356527450],[3457800614598085282,17426704671299246894,2699408592782313690,14031411536409518176,13263961817794116841,835795066714655983,11477846841203274509,727544715487174952,6480666310383891203,10550662778443296023,13185163654003144011,3559656994078944914,12747708470463124971,898580338082782932,17099718003896986529,1510915657479425828,770786980744949903,5742628441455317378,12579808169500774530,862014397356527450,13790235862723082076],[3457800614598085282,17426704671299246894,2699408592782313690,14031411536409518176,13263961817794116841,835795066714655983,11477846841203274509,727544715487174952,6480666310383891203,10550662778443296023,13185163654003144011,3559656994078944914,12747708470463124971,898580338082782932,17099718003896986529,1510915657479425828,770786980744949903,5742628441455317378,12579808169500774530,862014397356527450,13790235862723082076,9531720291230511752],[3457800614598085282,17426704671299246894,2699408592782313690,14031411536409518176,13263961817794116841,835795066714655983,11477846841203274509,727544715487174952,6480666310383891203,10550662778443296023,13185163654003144011,3559656994078944914,12747708470463124971,898580338082782932,17099718003896986529,1510915657479425828,770786980744949903,5742628441455317378,12579808169500774530,862014397356527450,13790235862723082076,9531720291230511752,12792838691218304039],[3457800614598085282,17426704671299246894,2699408592782313690,14031411536409518176,13263961817794116841,835795066714655983,11477846841203274509,727544715487174952,6480666310383891203,10550662778443296023,13185163654003144011,3559656994078944914,12747708470463124971,898580338082782932,17099718003896986529,1510915657479425828,770786980744949903,5742628441455317378,12579808169500774530,862014397356527450,13790235862723082076,9531720291230511752,12792838691218304039,5102308641931177440],[3457800614598085282,17426704671299246894,2699408592782313690,14031411536409518176,13263961817794116841,835795066714655983,11477846841203274509,727544715487174952,6480666310383891203,10550662778443296023,13185163654003144011,3559656994078944914,12747708470463124971,898580338082782932,17099718003896986529,1510915657479425828,770786980744949903,5742628441455317378,12579808169500774530,862014397356527450,13790235862723082076,9531720291230511752,12792838691218304039,5102308641931177440,14480644719732559657],[3457800614598085282,17426704671299246894,2699408592782313690,14031411536409518176,13263961817794116841,835795066714655983,11477846841203274509,727544715487174952,6480666310383891203,10550662778443296023,13185163654003144011,3559656994078944914,12747708470463124971,898580338082782932,17099718003896986529,1510915657479425828,770786980744949903,5742628441455317378,12579808169500774530,862014397356527450,13790235862723082076,9531720291230511752,12792838691218304039,5102308641931177440,14480644719732559657,3601587624047636241],[],[17078740291337047697],[3406722917122601552],[],[9470742171134780193],[14883504161508594099],[],[13163272246010991228],[],[4332145463108161926],[17078740291337047697],[],[],[17078740291337047697,3406722917122601552],[],[9470742171134780193],[13368990606109678244],[9470742171134780193],[14883504161508594099],[421715625023770179],[3670529450440935325],[4265165189651403984],[]],"selection_redo_history":[]}}},"collapsed":[4422453582814483233,4577638792388493936,3170924135668664008,4787732047489141820,12062649793560663567,5455777299776842372,9470742171134780194,15126865253122550766,13014628586360765652],"name":"red-dress.graphite","commit_hash":"8fa46ba63a69bb5fa18a49194cf112d963a2d43b","document_ptz":{"pan":[-512.5,-515.648496025349],"tilt":0.0,"zoom":1.0,"flip":false},"document_mode":"DesignMode","view_mode":"Normal","overlays_visibility_settings":{"all":true,"artboard_name":true,"compass_rose":true,"quick_measurement":true,"transform_measurement":true,"transform_cage":true,"hover_outline":true,"selection_outline":true,"pivot":true,"path":true,"anchors":true,"handles":true},"rulers_visible":true,"snapping_state":{"snapping_enabled":false,"grid_snapping":false,"artboards":true,"tolerance":8.0,"bounding_box":{"center_point":true,"corner_point":true,"edge_midpoint":true,"align_with_edges":true,"distribute_evenly":true},"path":{"anchor_point":true,"line_midpoint":true,"along_path":true,"normal_to_path":true,"tangent_to_path":true,"path_intersection_point":true,"align_with_anchor_point":true,"perpendicular_from_endpoint":true},"grid":{"origin":[0.0,0.0],"grid_type":{"Rectangular":{"spacing":[1.0,1.0]}},"rectangular_spacing":[1.0,1.0],"isometric_y_spacing":1.0,"isometric_angle_a":30.0,"isometric_angle_b":30.0,"grid_color":{"red":0.6038274,"green":0.6038274,"blue":0.6038274,"alpha":1.0},"dot_display":false}},"graph_view_overlay_open":false,"graph_fade_artwork_percentage":80.0} \ No newline at end of file diff --git a/demo-artwork/valley-of-spires.graphite b/demo-artwork/valley-of-spires.graphite new file mode 100644 index 0000000000000000000000000000000000000000..f973db4d76693520ebce584bdbee218ce54071fd --- /dev/null +++ b/demo-artwork/valley-of-spires.graphite @@ -0,0 +1 @@ +{"network_interface":{"network":{"exports":[{"Node":{"node_id":16815500381887058038,"output_index":0,"lambda":false}}],"nodes":[[202,{"inputs":[{"Node":{"node_id":206,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"Fill":{"Solid":{"red":0.5058824,"green":0.26666668,"blue":0.20392157,"alpha":1.0}}},"exposed":false}},{"Value":{"tagged_value":{"OptionalColor":{"red":0.5058824,"green":0.26666668,"blue":0.20392157,"alpha":1.0}},"exposed":false}},{"Value":{"tagged_value":{"Gradient":{"stops":[[0.0,{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}],[1.0,{"red":1.0,"green":1.0,"blue":1.0,"alpha":1.0}]],"gradient_type":"Linear","start":[0.0,0.5],"end":[1.0,0.5],"transform":[1.0,0.0,0.0,1.0,0.0,0.0]}},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::FillNode"}},"visible":true,"skip_deduplication":false}],[404,{"inputs":[{"Node":{"node_id":402,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"OptionalColor":{"red":0.24313726,"green":0.18431373,"blue":0.19215687,"alpha":1.0}},"exposed":false}},{"Value":{"tagged_value":{"F64":2.0},"exposed":false}},{"Value":{"tagged_value":{"StrokeAlign":"Center"},"exposed":false}},{"Value":{"tagged_value":{"StrokeCap":"Butt"},"exposed":false}},{"Value":{"tagged_value":{"StrokeJoin":"Miter"},"exposed":false}},{"Value":{"tagged_value":{"F64":4.0},"exposed":false}},{"Value":{"tagged_value":{"PaintOrder":"StrokeAbove"},"exposed":false}},{"Value":{"tagged_value":{"VecF64":[]},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::StrokeNode"}},"visible":true,"skip_deduplication":false}],[93,{"inputs":[{"Node":{"node_id":94,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"DVec2":[851.1666666666667,668.5377104806669]},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[39.677869315599935,39.67786931560005]},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[0.0,0.0]},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[0.5,0.5]},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":1}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":2}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":3}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":4}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":5}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::TransformNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[155,{"inputs":[{"Node":{"node_id":159,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"Fill":{"Gradient":{"stops":[[0.0,{"red":0.7529412,"green":0.34117648,"blue":0.2,"alpha":1.0}],[1.0,{"red":0.6431373,"green":0.31764707,"blue":0.21176471,"alpha":1.0}]],"gradient_type":"Linear","start":[0.9001916129448388,0.7881778212017586],"end":[0.8902470335613286,0.6662432828529555],"transform":[603.3437683597715,0.0,0.0,426.45833333333366,450.87499999999994,340.8749999999998]}}},"exposed":false}},{"Value":{"tagged_value":{"OptionalColor":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}},"exposed":false}},{"Value":{"tagged_value":{"Gradient":{"stops":[[0.0,{"red":0.7529412,"green":0.34117648,"blue":0.2,"alpha":1.0}],[1.0,{"red":0.6431373,"green":0.31764707,"blue":0.21176471,"alpha":1.0}]],"gradient_type":"Linear","start":[0.9001916129448388,0.7881778212017586],"end":[0.8902470335613286,0.6662432828529555],"transform":[603.3437683597715,0.0,0.0,426.45833333333366,450.87499999999994,340.8749999999998]}},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::FillNode"}},"visible":true,"skip_deduplication":false}],[497,{"inputs":[{"Value":{"tagged_value":{"VectorData":{"instance":[{"style":{"stroke":{"color":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0},"weight":0.0,"dash_lengths":[],"dash_offset":0.0,"cap":"Butt","join":"Miter","join_miter_limit":4.0,"align":"Center","transform":[1.0,0.0,0.0,1.0,0.0,0.0],"non_scaling":false,"paint_order":"StrokeAbove"},"fill":"None"},"colinear_manipulators":[],"point_domain":{"id":[],"position":[]},"segment_domain":{"id":[],"start_point":[],"end_point":[],"handles":[],"stroke":[]},"region_domain":{"id":[],"segment_range":[],"fill":[]},"upstream_graphic_group":null}],"transform":[[1.0,0.0,0.0,1.0,0.0,0.0]],"alpha_blending":[{"blend_mode":"Normal","opacity":1.0,"fill":1.0,"clip":false}],"source_node_id":[null]}},"exposed":true}},{"Value":{"tagged_value":{"VectorModification":{"points":{"add":[1,2,3,4],"remove":[],"delta":[[1,[0.0,0.0]],[2,[1.0,0.0]],[4,[0.0,1.0]],[3,[1.0,1.0]]]},"segments":{"add":[1,2,3,4],"remove":[],"start_point":[[2,2],[3,3],[4,4],[1,1]],"end_point":[[1,2],[3,4],[4,1],[2,3]],"handle_primary":[[2,[0.0,0.0]],[3,[0.0,0.0]],[1,[0.0,0.0]],[4,[0.0,0.0]]],"handle_end":[[3,[0.0,0.0]],[2,[0.0,0.0]],[1,[0.0,0.0]],[4,[0.0,0.0]]],"stroke":[[2,0],[4,0],[1,0],[3,0]]},"regions":{"add":[0],"remove":[],"segment_range":[[0,{"start":1,"end":4}]],"fill":[[0,0]]},"add_g1_continuous":[],"remove_g1_continuous":[]}},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::vector_data::modification::VectorModification","alias":null}},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::vector_data::modification::PathModifyNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[8861964493222160710,{"inputs":[{"Node":{"node_id":16894739051789815098,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"Fill":{"Gradient":{"stops":[[0.0,{"red":0.5058824,"green":0.26666668,"blue":0.20392157,"alpha":1.0}],[1.0,{"red":0.5058824,"green":0.26666668,"blue":0.20392157,"alpha":0.0390625}]],"gradient_type":"Radial","start":[0.49999999999999994,0.5000000000000009],"end":[0.9003149237651733,0.5000000000000009],"transform":[1153.5000000000016,0.0,0.0,116.99999999999352,390.5000000000018,782.9999999999995]}}},"exposed":false}},{"Value":{"tagged_value":{"OptionalColor":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}},"exposed":false}},{"Value":{"tagged_value":{"Gradient":{"stops":[[0.0,{"red":0.5058824,"green":0.26666668,"blue":0.20392157,"alpha":1.0}],[1.0,{"red":0.5058824,"green":0.26666668,"blue":0.20392157,"alpha":0.0390625}]],"gradient_type":"Radial","start":[0.49999999999999994,0.5000000000000009],"end":[0.9003149237651733,0.5000000000000009],"transform":[1153.5000000000016,0.0,0.0,116.99999999999352,390.5000000000018,782.9999999999995]}},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::FillNode"}},"visible":true,"skip_deduplication":false}],[248,{"inputs":[{"Value":{"tagged_value":{"VectorData":{"instance":[{"style":{"stroke":{"color":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0},"weight":0.0,"dash_lengths":[],"dash_offset":0.0,"cap":"Butt","join":"Miter","join_miter_limit":4.0,"align":"Center","transform":[1.0,0.0,0.0,1.0,0.0,0.0],"non_scaling":false,"paint_order":"StrokeAbove"},"fill":"None"},"colinear_manipulators":[],"point_domain":{"id":[],"position":[]},"segment_domain":{"id":[],"start_point":[],"end_point":[],"handles":[],"stroke":[]},"region_domain":{"id":[],"segment_range":[],"fill":[]},"upstream_graphic_group":null}],"transform":[[1.0,0.0,0.0,1.0,0.0,0.0]],"alpha_blending":[{"blend_mode":"Normal","opacity":1.0,"fill":1.0,"clip":false}],"source_node_id":[null]}},"exposed":true}},{"Value":{"tagged_value":{"VectorModification":{"points":{"add":[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20],"remove":[],"delta":[[20,[850.4753086419754,600.0720164609053]],[9,[1026.277777777778,628.0555555555557]],[18,[884.845679012346,621.141975308642]],[5,[923.956790123457,545.6851851851852]],[1,[866.5679012345681,572.641975308642]],[4,[898.8703703703707,571.5617283950618]],[2,[890.3765432098768,558.3271604938273]],[3,[884.6481481481485,571.7592592592594]],[19,[867.9970278920896,620.4835390946502]],[17,[915.067901234568,618.7716049382716]],[11,[991.9074074074076,607.667262767384]],[13,[955.9567901234568,612.4506172839507]],[16,[922.574074074074,606.9197530864199]],[10,[999.8086419753088,626.6728395061729]],[6,[944.141561350963,527.7098765432099]],[7,[986.8703703703704,552.6481481481483]],[14,[944.3024691358024,613.8333333333334]],[8,[1025.882716049383,576.7015952852717]],[12,[965.0432098765434,605.3395061728396]],[15,[935.0185185185186,608.3024691358025]]]},"segments":{"add":[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20],"remove":[],"start_point":[[14,14],[17,17],[16,16],[9,9],[20,20],[19,19],[11,11],[18,18],[4,4],[13,13],[5,5],[10,10],[12,12],[3,3],[1,1],[7,7],[15,15],[2,2],[8,8],[6,6]],"end_point":[[4,5],[1,2],[20,1],[17,18],[15,16],[18,19],[5,6],[8,9],[12,13],[11,12],[3,4],[19,20],[14,15],[13,14],[2,3],[10,11],[7,8],[6,7],[16,17],[9,10]],"handle_primary":[[18,[0.0,0.0]],[9,[0.0,0.0]],[2,[0.0,0.0]],[17,[0.0,0.0]],[3,[0.0,0.0]],[15,[0.0,0.0]],[16,[0.0,0.0]],[14,[0.0,0.0]],[12,[0.0,0.0]],[19,[-11.881115683584769,-0.11705532693190436]],[4,[0.0,0.0]],[11,[0.0,0.0]],[1,[0.0,0.0]],[6,[0.0,0.0]],[10,[-2.96296296296282,-1.1851851851851052]],[20,[0.0,0.0]],[13,[0.0,0.0]],[5,[0.0,0.5925925925926094]],[7,[22.254029366644772,13.337995427526266]],[8,[0.0,0.0]]],"handle_end":[[7,[0.0,0.0]],[20,[0.0,0.0]],[15,[5.135802469136024,0.9876543209877582]],[6,[-11.851851851851848,-16.036008230452808]],[9,[2.962962962963047,1.1851851851851052]],[3,[-8.69135802469134,0.39506172839503506]],[16,[2.3703703703704377,-1.7777777777778283]],[4,[-7.703703703703809,15.604938271604851]],[13,[2.1728395061727497,0.39506172839503506]],[2,[0.5925925925926094,-3.555555555555543]],[12,[2.7654320987655865,-2.7624450928566375]],[14,[4.740740740740762,0.7901234567901838]],[10,[0.3950617283951487,3.117880051334623]],[11,[18.567901234567785,4.543209876543301]],[5,[0.0,0.0]],[17,[20.5432098765433,0.1975308641974607]],[19,[0.0,0.0]],[1,[-10.271604938271707,4.543209876543187]],[18,[11.881115683584769,0.11705532693190436]],[8,[0.0,0.0]]],"stroke":[[11,0],[15,0],[5,0],[13,0],[12,0],[16,0],[6,0],[9,0],[19,0],[14,0],[20,0],[7,0],[1,0],[3,0],[17,0],[18,0],[2,0],[10,0],[4,0],[8,0]]},"regions":{"add":[0],"remove":[],"segment_range":[[0,{"start":1,"end":20}]],"fill":[[0,0]]},"add_g1_continuous":[],"remove_g1_continuous":[]}},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::vector_data::modification::VectorModification","alias":null}},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::vector_data::modification::PathModifyNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[419,{"inputs":[{"Value":{"tagged_value":{"VectorData":{"instance":[{"style":{"stroke":{"color":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0},"weight":0.0,"dash_lengths":[],"dash_offset":0.0,"cap":"Butt","join":"Miter","join_miter_limit":4.0,"align":"Center","transform":[1.0,0.0,0.0,1.0,0.0,0.0],"non_scaling":false,"paint_order":"StrokeAbove"},"fill":"None"},"colinear_manipulators":[],"point_domain":{"id":[],"position":[]},"segment_domain":{"id":[],"start_point":[],"end_point":[],"handles":[],"stroke":[]},"region_domain":{"id":[],"segment_range":[],"fill":[]},"upstream_graphic_group":null}],"transform":[[1.0,0.0,0.0,1.0,0.0,0.0]],"alpha_blending":[{"blend_mode":"Normal","opacity":1.0,"fill":1.0,"clip":false}],"source_node_id":[null]}},"exposed":true}},{"Value":{"tagged_value":{"VectorModification":{"points":{"add":[1,2,3,4],"remove":[],"delta":[[1,[0.0,0.0]],[3,[1.0,1.0]],[2,[1.0,0.0]],[4,[0.0,1.0]]]},"segments":{"add":[1,2,3,4],"remove":[],"start_point":[[1,1],[3,3],[2,2],[4,4]],"end_point":[[2,3],[3,4],[4,1],[1,2]],"handle_primary":[[4,[0.0,0.0]],[1,[0.0,0.0]],[2,[0.0,0.0]],[3,[0.0,0.0]]],"handle_end":[[4,[0.0,0.0]],[3,[0.0,0.0]],[1,[0.0,0.0]],[2,[0.0,0.0]]],"stroke":[[3,0],[2,0],[1,0],[4,0]]},"regions":{"add":[0],"remove":[],"segment_range":[[0,{"start":1,"end":4}]],"fill":[[0,0]]},"add_g1_continuous":[],"remove_g1_continuous":[]}},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::vector_data::modification::VectorModification","alias":null}},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::vector_data::modification::PathModifyNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[77,{"inputs":[{"Node":{"node_id":78,"output_index":0,"lambda":false}},{"Node":{"node_id":448,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[108,{"inputs":[{"Node":{"node_id":109,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"DVec2":[858.7905598373798,601.6041802310946]},"exposed":false}},{"Value":{"tagged_value":{"F64":1.2246469000000002e-16},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[0.1014123874504275,0.11427520552998474]},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[1.3799770244301692e-16,0.0]},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[0.5,0.5]},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":1}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":2}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":3}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":4}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":5}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::TransformNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[450,{"inputs":[{"Node":{"node_id":451,"output_index":0,"lambda":false}},{"Node":{"node_id":467,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[310,{"inputs":[{"Value":{"tagged_value":{"VectorData":{"instance":[{"style":{"stroke":{"color":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0},"weight":0.0,"dash_lengths":[],"dash_offset":0.0,"cap":"Butt","join":"Miter","join_miter_limit":4.0,"align":"Center","transform":[1.0,0.0,0.0,1.0,0.0,0.0],"non_scaling":false,"paint_order":"StrokeAbove"},"fill":"None"},"colinear_manipulators":[],"point_domain":{"id":[],"position":[]},"segment_domain":{"id":[],"start_point":[],"end_point":[],"handles":[],"stroke":[]},"region_domain":{"id":[],"segment_range":[],"fill":[]},"upstream_graphic_group":null}],"transform":[[1.0,0.0,0.0,1.0,0.0,0.0]],"alpha_blending":[{"blend_mode":"Normal","opacity":1.0,"fill":1.0,"clip":false}],"source_node_id":[null]}},"exposed":true}},{"Value":{"tagged_value":{"VectorModification":{"points":{"add":[1,2,3,4,5,6,7],"remove":[],"delta":[[5,[710.9477975918305,613.6358024691357]],[1,[744.3996087994717,586.9732002235432]],[7,[779.7592592592597,612.6204267490609]],[3,[698.0912208504803,600.3792866941013]],[4,[706.1680384087791,607.8415637860082]],[2,[734.9571457603006,587.5194584158918]],[6,[729.3449931412895,610.3875171467763]]]},"segments":{"add":[1,2,3,4,5,6,7],"remove":[],"start_point":[[7,7],[2,2],[6,6],[1,1],[4,4],[3,3],[5,5]],"end_point":[[6,7],[5,6],[3,4],[7,1],[2,3],[4,5],[1,2]],"handle_primary":[[7,[0.0,0.0]],[1,[0.0,0.0]],[6,[15.119646395366544,2.853223593964344]],[5,[7.452522481329197,2.721536351166037]],[4,[2.1947873799731497,4.691071467853249]],[2,[0.0,0.0]],[3,[0.0,0.0]]],"handle_end":[[2,[6.496570644718986,-11.149519890260422]],[4,null],[6,[0.0,0.0]],[5,null],[7,[9.28638926992835,13.56378600823075]],[3,[-2.494608558449272,-5.331900091455282]],[1,[0.0,0.0]]],"stroke":[[6,0],[7,0],[4,0],[1,0],[5,0],[3,0],[2,0]]},"regions":{"add":[0],"remove":[],"segment_range":[[0,{"start":1,"end":7}]],"fill":[[0,0]]},"add_g1_continuous":[],"remove_g1_continuous":[]}},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::vector_data::modification::VectorModification","alias":null}},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::vector_data::modification::PathModifyNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[481,{"inputs":[{"Node":{"node_id":485,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"Fill":{"Gradient":{"stops":[[0.0,{"red":0.8980392,"green":0.67058825,"blue":0.28235295,"alpha":1.0}],[1.0,{"red":0.73333335,"green":0.3764706,"blue":0.2,"alpha":1.0}]],"gradient_type":"Linear","start":[0.5563229660866629,0.005130077289715984],"end":[0.5563229660866629,0.9884201225302],"transform":[105.93178001350952,0.0,0.0,640.7349028554129,1148.0677179400443,125.71298042613309]}}},"exposed":false}},{"Value":{"tagged_value":{"OptionalColor":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}},"exposed":false}},{"Value":{"tagged_value":{"Gradient":{"stops":[[0.0,{"red":0.8980392,"green":0.67058825,"blue":0.28235295,"alpha":1.0}],[1.0,{"red":0.73333335,"green":0.3764706,"blue":0.2,"alpha":1.0}]],"gradient_type":"Linear","start":[0.5563229660866629,0.005130077289715984],"end":[0.5563229660866629,0.9884201225302],"transform":[105.93178001350952,0.0,0.0,640.7349028554129,1148.0677179400443,125.71298042613309]}},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::FillNode"}},"visible":true,"skip_deduplication":false}],[170,{"inputs":[{"Node":{"node_id":171,"output_index":0,"lambda":false}},{"Node":{"node_id":196,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[4913361824430066698,{"inputs":[{"Node":{"node_id":11807598261442997948,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"Fill":{"Solid":{"red":0.5058824,"green":0.26666668,"blue":0.20392157,"alpha":1.0}}},"exposed":false}},{"Value":{"tagged_value":{"OptionalColor":{"red":0.5058824,"green":0.26666668,"blue":0.20392157,"alpha":1.0}},"exposed":false}},{"Value":{"tagged_value":{"Gradient":{"stops":[[0.0,{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}],[1.0,{"red":1.0,"green":1.0,"blue":1.0,"alpha":1.0}]],"gradient_type":"Linear","start":[0.0,0.5],"end":[1.0,0.5],"transform":[1.0,0.0,0.0,1.0,0.0,0.0]}},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::FillNode"}},"visible":true,"skip_deduplication":false}],[14080831508667499826,{"inputs":[{"Node":{"node_id":11377169273880889832,"output_index":0,"lambda":false}},{"Node":{"node_id":14113040319560793790,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[232,{"inputs":[{"Node":{"node_id":236,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"Fill":{"Solid":{"red":0.3764706,"green":0.23529412,"blue":0.20784314,"alpha":1.0}}},"exposed":false}},{"Value":{"tagged_value":{"OptionalColor":{"red":0.3764706,"green":0.23529412,"blue":0.20784314,"alpha":1.0}},"exposed":false}},{"Value":{"tagged_value":{"Gradient":{"stops":[[0.0,{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}],[1.0,{"red":1.0,"green":1.0,"blue":1.0,"alpha":1.0}]],"gradient_type":"Linear","start":[0.0,0.5],"end":[1.0,0.5],"transform":[1.0,0.0,0.0,1.0,0.0,0.0]}},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::FillNode"}},"visible":true,"skip_deduplication":false}],[434,{"inputs":[{"Value":{"tagged_value":{"VectorData":{"instance":[{"style":{"stroke":{"color":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0},"weight":0.0,"dash_lengths":[],"dash_offset":0.0,"cap":"Butt","join":"Miter","join_miter_limit":4.0,"align":"Center","transform":[1.0,0.0,0.0,1.0,0.0,0.0],"non_scaling":false,"paint_order":"StrokeAbove"},"fill":"None"},"colinear_manipulators":[],"point_domain":{"id":[],"position":[]},"segment_domain":{"id":[],"start_point":[],"end_point":[],"handles":[],"stroke":[]},"region_domain":{"id":[],"segment_range":[],"fill":[]},"upstream_graphic_group":null}],"transform":[[1.0,0.0,0.0,1.0,0.0,0.0]],"alpha_blending":[{"blend_mode":"Normal","opacity":1.0,"fill":1.0,"clip":false}],"source_node_id":[null]}},"exposed":true}},{"Value":{"tagged_value":{"VectorModification":{"points":{"add":[1,2,3,4],"remove":[],"delta":[[4,[0.4436233919998075,1.0]],[1,[0.5926327057682128,-0.43396226415094336]],[3,[1.0069833844920426,0.9999999999999988]],[2,[0.8076864692090735,-0.4339622641509434]]]},"segments":{"add":[1,2,3,4],"remove":[],"start_point":[[1,1],[3,3],[2,2],[4,4]],"end_point":[[1,2],[3,4],[4,1],[2,3]],"handle_primary":[[3,[0.0,0.0]],[1,[0.0,0.0]],[4,[0.0,0.0]],[2,[0.0,0.0]]],"handle_end":[[2,[0.0,0.0]],[3,[0.0,0.0]],[4,[0.0,0.0]],[1,[0.0,0.0]]],"stroke":[[3,0],[2,0],[1,0],[4,0]]},"regions":{"add":[0],"remove":[],"segment_range":[[0,{"start":1,"end":4}]],"fill":[[0,0]]},"add_g1_continuous":[],"remove_g1_continuous":[]}},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::vector_data::modification::VectorModification","alias":null}},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::vector_data::modification::PathModifyNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[465,{"inputs":[{"Node":{"node_id":469,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"Fill":{"Gradient":{"stops":[[0.0,{"red":0.8784314,"green":0.63529414,"blue":0.24313726,"alpha":1.0}],[1.0,{"red":0.827451,"green":0.36862746,"blue":0.20784314,"alpha":1.0}]],"gradient_type":"Linear","start":[0.543973941368078,0.19174161896974656],"end":[0.373641330960254,0.5573628465419693],"transform":[302.3829616698968,-53.04285523745623,140.87168719958515,803.0713618290636,568.5525435223506,63.555059935554134]}}},"exposed":false}},{"Value":{"tagged_value":{"OptionalColor":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}},"exposed":false}},{"Value":{"tagged_value":{"Gradient":{"stops":[[0.0,{"red":0.8784314,"green":0.63529414,"blue":0.24313726,"alpha":1.0}],[1.0,{"red":0.827451,"green":0.36862746,"blue":0.20784314,"alpha":1.0}]],"gradient_type":"Linear","start":[0.543973941368078,0.19174161896974656],"end":[0.373641330960254,0.5573628465419693],"transform":[302.3829616698968,-53.04285523745623,140.87168719958515,803.0713618290636,568.5525435223506,63.555059935554134]}},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::FillNode"}},"visible":true,"skip_deduplication":false}],[7148230379224894975,{"inputs":[{"Value":{"tagged_value":{"VectorData":{"instance":[{"style":{"stroke":{"color":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0},"weight":0.0,"dash_lengths":[],"dash_offset":0.0,"cap":"Butt","join":"Miter","join_miter_limit":4.0,"align":"Center","transform":[1.0,0.0,0.0,1.0,0.0,0.0],"non_scaling":false,"paint_order":"StrokeAbove"},"fill":"None"},"colinear_manipulators":[],"point_domain":{"id":[],"position":[]},"segment_domain":{"id":[],"start_point":[],"end_point":[],"handles":[],"stroke":[]},"region_domain":{"id":[],"segment_range":[],"fill":[]},"upstream_graphic_group":null}],"transform":[[1.0,0.0,0.0,1.0,0.0,0.0]],"alpha_blending":[{"blend_mode":"Normal","opacity":1.0,"fill":1.0,"clip":false}],"source_node_id":[null]}},"exposed":true}},{"Value":{"tagged_value":{"VectorModification":{"points":{"add":[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20],"remove":[],"delta":[[15,[496.30246913580254,612.3006782502672]],[8,[502.6234567901235,563.1154930650816]],[16,[478.9197530864198,618.6875095259874]],[7,[495.90740740740733,567.882982777016]],[9,[510.261316872428,573.2078189300412]],[14,[496.49999999999994,603.4117893613783]],[20,[480.89506172839504,532.4323654930657]],[6,[490.17901234567904,556.0043819539711]],[18,[438.2283950617284,585.5544307531777]],[1,[506.7057613168725,531.9348803536052]],[5,[500.4506172839507,547.5105547934772]],[19,[468.05555555555594,550.6710486206383]],[3,[488.5329218106997,551.6587029416252]],[4,[500.77983539094663,544.0208428593207]],[2,[497.8388203017833,534.5393613778391]],[13,[516.8017832647463,593.4437585733884]],[10,[496.50000000000006,582.6234567901236]],[11,[504.00617283950623,588.9444444444446]],[17,[448.3683127572017,617.6340115836006]],[12,[513.3888888888889,585.5544307531777]]]},"segments":{"add":[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20],"remove":[],"start_point":[[20,20],[3,3],[12,12],[5,5],[13,13],[16,16],[18,18],[11,11],[19,19],[15,15],[6,6],[7,7],[14,14],[17,17],[8,8],[9,9],[4,4],[1,1],[10,10],[2,2]],"end_point":[[4,5],[10,11],[11,12],[16,17],[6,7],[9,10],[7,8],[3,4],[13,14],[17,18],[1,2],[5,6],[15,16],[18,19],[2,3],[20,1],[12,13],[19,20],[8,9],[14,15]],"handle_primary":[[8,[0.0,0.0]],[14,[0.0,0.0]],[10,[0.0,0.0]],[1,[0.0,0.0]],[12,[0.0,0.0]],[16,[0.0,0.0]],[20,[7.46503467504715,-4.02781143068205]],[15,[0.0,0.0]],[7,[0.0,0.0]],[5,[-6.737997256515712,3.1824417009599983]],[19,[0.0,0.0]],[4,null],[9,[0.0,0.0]],[6,[0.0,0.0]],[11,[0.0,0.0]],[17,[0.0,0.0]],[2,[-7.188100137174104,2.6138545953361927]],[3,[4.565157750342848,-4.301783264746064]],[13,[0.0,0.0]],[18,[0.0,0.0]]],"handle_end":[[1,[3.4386245260820374,-1.250408918575317]],[2,[0.27087722942241044,-5.120145445603839]],[4,null],[20,[0.0,0.0]],[7,[-3.6872427983540206,1.4485596707820605]],[3,null],[10,[-2.765432098765416,-3.555555555555543]],[5,[0.0,0.0]],[13,[0.0,0.0]],[12,[-0.39506172839503506,-1.975308641975289]],[8,[-1.7777777777777717,-5.728395061728406]],[6,[-2.508333333333439,-2.0902777777778283]],[18,[0.0,0.0]],[17,[0.0,0.0]],[9,[6.716049382716108,-8.49382716049422]],[19,[-3.394604481024089,3.2873037646699004]],[11,[-3.851851851851848,0.7581344568814075]],[16,[0.0,0.0]],[15,[0.0,0.0]],[14,[-0.7901234567900701,-4.938271604938336]]],"stroke":[[11,0],[19,0],[1,0],[13,0],[4,0],[7,0],[17,0],[8,0],[5,0],[9,0],[14,0],[12,0],[20,0],[16,0],[15,0],[18,0],[10,0],[6,0],[3,0],[2,0]]},"regions":{"add":[0],"remove":[],"segment_range":[[0,{"start":1,"end":20}]],"fill":[[0,0]]},"add_g1_continuous":[],"remove_g1_continuous":[]}},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::vector_data::modification::VectorModification","alias":null}},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::vector_data::modification::PathModifyNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[325,{"inputs":[{"Value":{"tagged_value":{"VectorData":{"instance":[{"style":{"stroke":{"color":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0},"weight":0.0,"dash_lengths":[],"dash_offset":0.0,"cap":"Butt","join":"Miter","join_miter_limit":4.0,"align":"Center","transform":[1.0,0.0,0.0,1.0,0.0,0.0],"non_scaling":false,"paint_order":"StrokeAbove"},"fill":"None"},"colinear_manipulators":[],"point_domain":{"id":[],"position":[]},"segment_domain":{"id":[],"start_point":[],"end_point":[],"handles":[],"stroke":[]},"region_domain":{"id":[],"segment_range":[],"fill":[]},"upstream_graphic_group":null}],"transform":[[1.0,0.0,0.0,1.0,0.0,0.0]],"alpha_blending":[{"blend_mode":"Normal","opacity":1.0,"fill":1.0,"clip":false}],"source_node_id":[null]}},"exposed":true}},{"Value":{"tagged_value":{"VectorModification":{"points":{"add":[1,2,3,4,5,6,7,8,9],"remove":[],"delta":[[1,[744.0,592.0]],[8,[631.8333333333333,608.5]],[7,[619.8333333333333,577.1666666666666]],[9,[677.1666666666666,609.1666666666666]],[3,[708.5,335.16666666666663]],[2,[733.1666666666666,489.16666666666663]],[4,[695.8333333333333,239.16666666666663]],[5,[660.5,187.83333333333331]],[6,[619.8333333333333,207.83333333333331]]]},"segments":{"add":[1,2,3,4,5,6,7,8,9],"remove":[],"start_point":[[9,9],[8,8],[7,7],[4,4],[5,5],[3,3],[6,6],[1,1],[2,2]],"end_point":[[5,6],[6,7],[9,1],[8,9],[3,4],[7,8],[1,2],[2,3],[4,5]],"handle_primary":[[1,[0.0,0.0]],[8,[12.666666666666742,4.666666666666629]],[5,[-36.0,-6.666666666666686]],[9,[18.66666666666663,-5.3333333333332575]],[7,[0.0,12.666666666666742]],[3,[-6.6666666666667425,-57.333333333333314]],[6,[0.0,16.666666666666686]],[2,[-4.666666666666629,-50.666666666666686]],[4,[-3.3333333333332575,-21.33333333333331]]],"handle_end":[[2,[6.6666666666667425,57.333333333333314]],[9,[0.0,0.0]],[1,[4.666666666666629,50.66666666666663]],[7,[-12.666666666666742,-4.666666666666629]],[8,[-18.66666666666663,5.3333333333332575]],[4,[36.0,6.666666666666657]],[6,[0.0,-12.666666666666742]],[5,[0.0,-16.666666666666686]],[3,[3.3333333333332575,21.33333333333331]]],"stroke":[[9,0],[7,0],[4,0],[3,0],[1,0],[8,0],[5,0],[2,0],[6,0]]},"regions":{"add":[0],"remove":[],"segment_range":[[0,{"start":1,"end":9}]],"fill":[[0,0]]},"add_g1_continuous":[],"remove_g1_continuous":[]}},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::vector_data::modification::VectorModification","alias":null}},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::vector_data::modification::PathModifyNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[496,{"inputs":[{"Node":{"node_id":497,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"DVec2":[0.0,0.0]},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[1024.0,600.0]},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[0.0,0.0]},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[0.0,0.0]},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":1}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":2}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":3}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":4}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":5}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::TransformNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[11377169273880889832,{"inputs":[{"Value":{"tagged_value":{"GraphicGroup":{"instance":[],"transform":[],"alpha_blending":[],"source_node_id":[]}},"exposed":true}},{"Node":{"node_id":14433811491576609500,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[11891167879168294182,{"inputs":[{"Value":{"tagged_value":{"VectorData":{"instance":[{"style":{"stroke":{"color":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0},"weight":0.0,"dash_lengths":[],"dash_offset":0.0,"cap":"Butt","join":"Miter","join_miter_limit":4.0,"align":"Center","transform":[1.0,0.0,0.0,1.0,0.0,0.0],"non_scaling":false,"paint_order":"StrokeAbove"},"fill":"None"},"colinear_manipulators":[],"point_domain":{"id":[],"position":[]},"segment_domain":{"id":[],"start_point":[],"end_point":[],"handles":[],"stroke":[]},"region_domain":{"id":[],"segment_range":[],"fill":[]},"upstream_graphic_group":null}],"transform":[[1.0,0.0,0.0,1.0,0.0,0.0]],"alpha_blending":[{"blend_mode":"Normal","opacity":1.0,"fill":1.0,"clip":false}],"source_node_id":[null]}},"exposed":true}},{"Value":{"tagged_value":{"VectorModification":{"points":{"add":[1,2,3,4,5,6],"remove":[],"delta":[[4,[126.900438957476,611.0020576131687]],[3,[148.91152263374485,614.1625514403293]],[6,[119.98422496570645,609.4218106995885]],[5,[118.93072702331962,598.7990397805213]],[2,[104.00617283950618,624.6097393689986]],[1,[112.52194787379976,598.7990397805213]]]},"segments":{"add":[1,2,3,4,5,6],"remove":[],"start_point":[[6,6],[3,3],[2,2],[1,1],[5,5],[4,4]],"end_point":[[2,3],[4,5],[3,4],[1,2],[5,6],[6,1]],"handle_primary":[[3,null],[2,[0.0,0.0]],[5,[0.0,0.0]],[6,[-4.477366255144005,-1.843621399176868]],[1,[-2.370370370370395,22.25514403292175]],[4,[-2.058260034882977,-0.6051267923739942]]],"handle_end":[[6,[0.0,0.0]],[5,[0.7023319615912413,-1.9314128943758533]],[3,null],[4,[0.0,0.0]],[1,[0.0,0.0]],[2,[-21.11385459533605,1.053497942386798]]],"stroke":[[4,0],[1,0],[6,0],[5,0],[3,0],[2,0]]},"regions":{"add":[0],"remove":[],"segment_range":[[0,{"start":1,"end":6}]],"fill":[[0,0]]},"add_g1_continuous":[],"remove_g1_continuous":[]}},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::vector_data::modification::VectorModification","alias":null}},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::vector_data::modification::PathModifyNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[418,{"inputs":[{"Node":{"node_id":419,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"DVec2":[83.16666666666677,614.179527199694]},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[294.3945373546583,138.32047280030588]},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[0.0,0.0]},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[0.5,0.5]},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":1}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":2}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":3}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":4}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":5}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::TransformNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[76,{"inputs":[{"Node":{"node_id":77,"output_index":0,"lambda":false}},{"Node":{"node_id":16164610528699022118,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[449,{"inputs":[{"Node":{"node_id":450,"output_index":0,"lambda":false}},{"Node":{"node_id":6015109908395573189,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[14113040319560793790,{"inputs":[{"Node":{"node_id":9603838021022368374,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"Fill":{"Solid":{"red":0.3764706,"green":0.23529412,"blue":0.20784314,"alpha":1.0}}},"exposed":false}},{"Value":{"tagged_value":{"OptionalColor":{"red":0.3764706,"green":0.23529412,"blue":0.20784314,"alpha":1.0}},"exposed":false}},{"Value":{"tagged_value":{"Gradient":{"stops":[[0.0,{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}],[1.0,{"red":1.0,"green":1.0,"blue":1.0,"alpha":1.0}]],"gradient_type":"Linear","start":[0.0,0.5],"end":[1.0,0.5],"transform":[1.0,0.0,0.0,1.0,0.0,0.0]}},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::FillNode"}},"visible":true,"skip_deduplication":false}],[138,{"inputs":[{"Value":{"tagged_value":{"VectorData":{"instance":[{"style":{"stroke":{"color":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0},"weight":0.0,"dash_lengths":[],"dash_offset":0.0,"cap":"Butt","join":"Miter","join_miter_limit":4.0,"align":"Center","transform":[1.0,0.0,0.0,1.0,0.0,0.0],"non_scaling":false,"paint_order":"StrokeAbove"},"fill":"None"},"colinear_manipulators":[],"point_domain":{"id":[],"position":[]},"segment_domain":{"id":[],"start_point":[],"end_point":[],"handles":[],"stroke":[]},"region_domain":{"id":[],"segment_range":[],"fill":[]},"upstream_graphic_group":null}],"transform":[[1.0,0.0,0.0,1.0,0.0,0.0]],"alpha_blending":[{"blend_mode":"Normal","opacity":1.0,"fill":1.0,"clip":false}],"source_node_id":[null]}},"exposed":true}},{"Value":{"tagged_value":{"VectorModification":{"points":{"add":[1,2,3,4],"remove":[],"delta":[[1,[126.55144032921808,714.7983539094649]],[2,[105.84979423868312,685.0102880658435]],[3,[90.17901234567904,708.7139917695472]],[4,[116.38477366255144,723.5946502057614]]]},"segments":{"add":[1,2,3,4],"remove":[],"start_point":[[3,3],[2,2],[4,4],[1,1]],"end_point":[[1,2],[3,4],[2,3],[4,1]],"handle_primary":[[1,[0.0,0.0]],[3,[-2.4237705319430347,10.543401813951732]],[2,[0.0,0.0]],[4,[0.0,0.0]]],"handle_end":[[3,[0.0,0.0]],[2,[2.6337448559670804,-11.456790123456472]],[4,[3.6604938271605647,11.166666666666742]],[1,[16.460905349794245,13.695473251028716]]],"stroke":[[1,0],[4,0],[3,0],[2,0]]},"regions":{"add":[0],"remove":[],"segment_range":[[0,{"start":1,"end":4}]],"fill":[[0,0]]},"add_g1_continuous":[],"remove_g1_continuous":[]}},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::vector_data::modification::VectorModification","alias":null}},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::vector_data::modification::PathModifyNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[169,{"inputs":[{"Node":{"node_id":170,"output_index":0,"lambda":false}},{"Node":{"node_id":190,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[200,{"inputs":[{"Value":{"tagged_value":{"VectorData":{"instance":[{"style":{"stroke":{"color":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0},"weight":0.0,"dash_lengths":[],"dash_offset":0.0,"cap":"Butt","join":"Miter","join_miter_limit":4.0,"align":"Center","transform":[1.0,0.0,0.0,1.0,0.0,0.0],"non_scaling":false,"paint_order":"StrokeAbove"},"fill":"None"},"colinear_manipulators":[],"point_domain":{"id":[],"position":[]},"segment_domain":{"id":[],"start_point":[],"end_point":[],"handles":[],"stroke":[]},"region_domain":{"id":[],"segment_range":[],"fill":[]},"upstream_graphic_group":null}],"transform":[[1.0,0.0,0.0,1.0,0.0,0.0]],"alpha_blending":[{"blend_mode":"Normal","opacity":1.0,"fill":1.0,"clip":false}],"source_node_id":[null]}},"exposed":true}},{"Value":{"tagged_value":{"VectorModification":{"points":{"add":[1,2,3,4,5,6,7,8,9,10],"remove":[],"delta":[[9,[1001.2407407407406,568.2037037037037]],[2,[993.9814814814814,530.7222222222222]],[4,[972.0555555555557,547.0185185185185]],[1,[1004.392496062592,536.8475080018289]],[8,[994.0802469135804,561.8388203017832]],[5,[990.3271604938273,558.7222222222222]],[10,[1010.492379210486,553.0791800030486]],[3,[974.574074074074,539.3148148148148]],[6,[988.3518518518518,565.8333333333333]],[7,[988.9444444444443,571.9567901234568]]]},"segments":{"add":[1,2,3,4,5,6,7,8,9,10],"remove":[],"start_point":[[1,1],[9,9],[5,5],[2,2],[10,10],[6,6],[4,4],[7,7],[8,8],[3,3]],"end_point":[[6,7],[8,9],[1,2],[7,8],[2,3],[3,4],[5,6],[10,1],[9,10],[4,5]],"handle_primary":[[8,[0.0,0.0]],[10,[0.0,0.0]],[6,[0.0,0.0]],[4,[5.818749999999909,2.0456767733078323]],[5,[1.1368683772161605e-13,0.0]],[9,[0.0,0.0]],[7,[0.0,0.0]],[2,[0.0,0.0]],[1,[0.0,0.0]],[3,[0.0,0.0]]],"handle_end":[[3,[5.171433893884796,-5.185320665887616]],[9,[0.0,0.0]],[6,[0.0,0.0]],[4,[0.0,0.0]],[8,[1.1368683772161605e-13,0.0]],[5,[0.0,0.0]],[1,[0.0,0.0]],[7,[0.0,0.0]],[10,[2.600823045267589,7.538372631948732]],[2,[0.0,0.0]]],"stroke":[[6,0],[8,0],[1,0],[9,0],[5,0],[7,0],[3,0],[2,0],[10,0],[4,0]]},"regions":{"add":[0],"remove":[],"segment_range":[[0,{"start":1,"end":10}]],"fill":[[0,0]]},"add_g1_continuous":[],"remove_g1_continuous":[]}},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::vector_data::modification::VectorModification","alias":null}},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::vector_data::modification::PathModifyNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[6015109908395573189,{"inputs":[{"Node":{"node_id":459,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"DVec2":[-8.0,2.6666666666000083]},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[1.0,1.0]},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[0.0,0.0]},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[0.5,0.5]},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":1}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":2}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":3}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":4}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":5}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::TransformNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[402,{"inputs":[{"Node":{"node_id":406,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"Fill":{"Solid":{"red":0.24313726,"green":0.18431373,"blue":0.19215687,"alpha":1.0}}},"exposed":false}},{"Value":{"tagged_value":{"OptionalColor":{"red":0.24313726,"green":0.18431373,"blue":0.19215687,"alpha":1.0}},"exposed":false}},{"Value":{"tagged_value":{"Gradient":{"stops":[[0.0,{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}],[1.0,{"red":1.0,"green":1.0,"blue":1.0,"alpha":1.0}]],"gradient_type":"Linear","start":[0.0,0.5],"end":[1.0,0.5],"transform":[1.0,0.0,0.0,1.0,0.0,0.0]}},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::FillNode"}},"visible":true,"skip_deduplication":false}],[15552693212536925398,{"inputs":[{"Node":{"node_id":1598976462838094167,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"Fill":{"Gradient":{"stops":[[0.0,{"red":0.3764706,"green":0.23529412,"blue":0.20784314,"alpha":1.0}],[1.0,{"red":0.328125,"green":0.19633627,"blue":0.17047119,"alpha":1.0}]],"gradient_type":"Linear","start":[0.3458831403130609,0.8154173283216788],"end":[0.29832402234636923,0.9999999999999992],"transform":[596.6666666666671,0.0,0.0,669.6474899687091,706.9999999999995,7.352510031290876]}}},"exposed":false}},{"Value":{"tagged_value":{"OptionalColor":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}},"exposed":false}},{"Value":{"tagged_value":{"Gradient":{"stops":[[0.0,{"red":0.3764706,"green":0.23529412,"blue":0.20784314,"alpha":1.0}],[1.0,{"red":0.328125,"green":0.19633627,"blue":0.17047119,"alpha":1.0}]],"gradient_type":"Linear","start":[0.3458831403130609,0.8154173283216788],"end":[0.29832402234636923,0.9999999999999992],"transform":[596.6666666666671,0.0,0.0,669.6474899687091,706.9999999999995,7.352510031290876]}},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::FillNode"}},"visible":true,"skip_deduplication":false}],[262,{"inputs":[{"Node":{"node_id":266,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"Fill":{"Solid":{"red":0.3764706,"green":0.23529412,"blue":0.20784314,"alpha":1.0}}},"exposed":false}},{"Value":{"tagged_value":{"OptionalColor":{"red":0.3764706,"green":0.23529412,"blue":0.20784314,"alpha":1.0}},"exposed":false}},{"Value":{"tagged_value":{"Gradient":{"stops":[[0.0,{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}],[1.0,{"red":1.0,"green":1.0,"blue":1.0,"alpha":1.0}]],"gradient_type":"Linear","start":[0.0,0.5],"end":[1.0,0.5],"transform":[1.0,0.0,0.0,1.0,0.0,0.0]}},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::FillNode"}},"visible":true,"skip_deduplication":false}],[433,{"inputs":[{"Node":{"node_id":434,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"DVec2":[628.6154039265571,697.6163522012579]},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[206.6666666666667,70.66666666666666]},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[0.0,0.0]},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[0.5,0.5]},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":1}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":2}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":3}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":4}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":5}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::TransformNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[122,{"inputs":[{"Node":{"node_id":126,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"Fill":{"Gradient":{"stops":[[0.0,{"red":0.24313726,"green":0.18431373,"blue":0.19215687,"alpha":1.0}],[0.5,{"red":0.24313726,"green":0.18431373,"blue":0.19215687,"alpha":1.0}],[1.0,{"red":0.3764706,"green":0.23529412,"blue":0.20784314,"alpha":1.0}]],"gradient_type":"Linear","start":[0.8261898755429384,0.6803505808618764],"end":[0.9730393010117852,0.6150128281109604],"transform":[674.1599409321643,0.0,0.0,374.9746351607879,311.0158823052205,208.88578915988776]}}},"exposed":false}},{"Value":{"tagged_value":{"OptionalColor":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}},"exposed":false}},{"Value":{"tagged_value":{"Gradient":{"stops":[[0.0,{"red":0.24313726,"green":0.18431373,"blue":0.19215687,"alpha":1.0}],[0.5,{"red":0.24313726,"green":0.18431373,"blue":0.19215687,"alpha":1.0}],[1.0,{"red":0.3764706,"green":0.23529412,"blue":0.20784314,"alpha":1.0}]],"gradient_type":"Linear","start":[0.8261898755429384,0.6803505808618764],"end":[0.9730393010117852,0.6150128281109604],"transform":[674.1599409321643,0.0,0.0,374.9746351607879,311.0158823052205,208.88578915988776]}},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::FillNode"}},"visible":true,"skip_deduplication":false}],[7135480377162524224,{"inputs":[{"Node":{"node_id":487,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"DVec2":[28.82327697714288,-49.808276940773226]},"exposed":false}},{"Value":{"tagged_value":{"F64":0.057504143999955744},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[1.0,1.0]},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[0.0,0.0]},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[0.5,0.5]},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":1}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":2}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":3}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":4}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":5}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::TransformNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[184,{"inputs":[{"Node":{"node_id":188,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"Fill":{"Solid":{"red":0.24313726,"green":0.18431373,"blue":0.19215687,"alpha":1.0}}},"exposed":false}},{"Value":{"tagged_value":{"OptionalColor":{"red":0.24313726,"green":0.18431373,"blue":0.19215687,"alpha":1.0}},"exposed":false}},{"Value":{"tagged_value":{"Gradient":{"stops":[[0.0,{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}],[1.0,{"red":1.0,"green":1.0,"blue":1.0,"alpha":1.0}]],"gradient_type":"Linear","start":[0.0,0.5],"end":[1.0,0.5],"transform":[1.0,0.0,0.0,1.0,0.0,0.0]}},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::FillNode"}},"visible":true,"skip_deduplication":false}],[75,{"inputs":[{"Node":{"node_id":76,"output_index":0,"lambda":false}},{"Node":{"node_id":161,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[277,{"inputs":[{"Node":{"node_id":1453710883947581217,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"Fill":{"Gradient":{"stops":[[0.0,{"red":0.92156863,"green":0.7294118,"blue":0.2784314,"alpha":1.0}],[1.0,{"red":0.7176471,"green":0.28627452,"blue":0.16862746,"alpha":1.0}]],"gradient_type":"Linear","start":[1.0246769250512615,0.027819435424882025],"end":[0.2667933279762451,0.9665428076110212],"transform":[152.18301372607758,-26.46547846507388,122.86581252135512,706.5086564778592,1104.6435199127652,59.354620942005326]}}},"exposed":false}},{"Value":{"tagged_value":{"OptionalColor":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}},"exposed":false}},{"Value":{"tagged_value":{"Gradient":{"stops":[[0.0,{"red":0.92156863,"green":0.7294118,"blue":0.2784314,"alpha":1.0}],[1.0,{"red":0.7176471,"green":0.28627452,"blue":0.16862746,"alpha":1.0}]],"gradient_type":"Linear","start":[1.0246769250512615,0.027819435424882025],"end":[0.2667933279762451,0.9665428076110212],"transform":[152.18301372607758,-26.46547846507388,122.86581252135512,706.5086564778592,1104.6435199127652,59.354620942005326]}},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::FillNode"}},"visible":true,"skip_deduplication":false}],[448,{"inputs":[{"Node":{"node_id":449,"output_index":0,"lambda":false}},{"Node":{"node_id":455,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[11155094820673141470,{"inputs":[{"Node":{"node_id":97478832511923699,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"Fill":{"Gradient":{"stops":[[0.0,{"red":0.3764706,"green":0.23529412,"blue":0.20784314,"alpha":1.0}],[1.0,{"red":0.5058824,"green":0.26666668,"blue":0.20392157,"alpha":1.0}]],"gradient_type":"Linear","start":[0.08732233199581252,0.5212000945774993],"end":[0.9287098983518448,0.5070261975055625],"transform":[139.824941251317,-21.014379437271643,45.64496496886203,416.4689172758892,1005.0,432.99999999999955]}}},"exposed":false}},{"Value":{"tagged_value":{"OptionalColor":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}},"exposed":false}},{"Value":{"tagged_value":{"Gradient":{"stops":[[0.0,{"red":0.3764706,"green":0.23529412,"blue":0.20784314,"alpha":1.0}],[1.0,{"red":0.5058824,"green":0.26666668,"blue":0.20392157,"alpha":1.0}]],"gradient_type":"Linear","start":[0.08732233199581252,0.5212000945774993],"end":[0.9287098983518448,0.5070261975055625],"transform":[139.824941251317,-21.014379437271643,45.64496496886203,416.4689172758892,1005.0,432.99999999999955]}},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::FillNode"}},"visible":true,"skip_deduplication":false}],[17257434333682934071,{"inputs":[{"Node":{"node_id":13606781735926093266,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"Fill":{"Solid":{"red":0.24313726,"green":0.18431373,"blue":0.19215687,"alpha":1.0}}},"exposed":false}},{"Value":{"tagged_value":{"OptionalColor":{"red":0.24313726,"green":0.18431373,"blue":0.19215687,"alpha":1.0}},"exposed":false}},{"Value":{"tagged_value":{"Gradient":{"stops":[[0.0,{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}],[1.0,{"red":1.0,"green":1.0,"blue":1.0,"alpha":1.0}]],"gradient_type":"Linear","start":[0.0,0.5],"end":[1.0,0.5],"transform":[1.0,0.0,0.0,1.0,0.0,0.0]}},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::FillNode"}},"visible":true,"skip_deduplication":false}],[168,{"inputs":[{"Node":{"node_id":169,"output_index":0,"lambda":false}},{"Node":{"node_id":184,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[230,{"inputs":[{"Value":{"tagged_value":{"VectorData":{"instance":[{"style":{"stroke":{"color":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0},"weight":0.0,"dash_lengths":[],"dash_offset":0.0,"cap":"Butt","join":"Miter","join_miter_limit":4.0,"align":"Center","transform":[1.0,0.0,0.0,1.0,0.0,0.0],"non_scaling":false,"paint_order":"StrokeAbove"},"fill":"None"},"colinear_manipulators":[],"point_domain":{"id":[],"position":[]},"segment_domain":{"id":[],"start_point":[],"end_point":[],"handles":[],"stroke":[]},"region_domain":{"id":[],"segment_range":[],"fill":[]},"upstream_graphic_group":null}],"transform":[[1.0,0.0,0.0,1.0,0.0,0.0]],"alpha_blending":[{"blend_mode":"Normal","opacity":1.0,"fill":1.0,"clip":false}],"source_node_id":[null]}},"exposed":true}},{"Value":{"tagged_value":{"VectorModification":{"points":{"add":[1,2,3,4],"remove":[],"delta":[[2,[0.935534758874228,0.06746859421299994]],[4,[0.2700473236113544,1.0652669412541609]],[3,[1.134036317002156,1.0722882682186752]],[1,[-0.03624142718978522,-0.003682959682299257]]]},"segments":{"add":[1,2,3,4],"remove":[],"start_point":[[1,1],[2,2],[3,3],[4,4]],"end_point":[[2,3],[4,1],[1,2],[3,4]],"handle_primary":[[1,[0.0,0.0]],[3,[0.0,0.0]],[2,[0.0,0.0]],[4,[0.0,0.0]]],"handle_end":[[4,[0.0,0.0]],[3,[0.0,0.0]],[2,[0.0,0.0]],[1,[0.0,0.0]]],"stroke":[[1,0],[2,0],[4,0],[3,0]]},"regions":{"add":[0],"remove":[],"segment_range":[[0,{"start":1,"end":4}]],"fill":[[0,0]]},"add_g1_continuous":[],"remove_g1_continuous":[]}},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::vector_data::modification::VectorModification","alias":null}},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::vector_data::modification::PathModifyNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[90,{"inputs":[{"Node":{"node_id":93,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"Fill":{"Gradient":{"stops":[[0.0,{"red":0.24313726,"green":0.18431373,"blue":0.19215687,"alpha":1.0}],[0.5999119243817099,{"red":0.24313726,"green":0.18431373,"blue":0.19215687,"alpha":1.0}],[1.0,{"red":0.3764706,"green":0.23529412,"blue":0.20784314,"alpha":1.0}]],"gradient_type":"Radial","start":[0.3201759714645238,0.5902044022091868],"end":[1.025282605251574,0.18308301136073535],"transform":[138.98607005532313,0.0,0.0,138.98607005532352,1193.5000000000005,570.5540117570772]}}},"exposed":false}},{"Value":{"tagged_value":{"OptionalColor":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}},"exposed":false}},{"Value":{"tagged_value":{"Gradient":{"stops":[[0.0,{"red":0.24313726,"green":0.18431373,"blue":0.19215687,"alpha":1.0}],[0.5999119243817099,{"red":0.24313726,"green":0.18431373,"blue":0.19215687,"alpha":1.0}],[1.0,{"red":0.3764706,"green":0.23529412,"blue":0.20784314,"alpha":1.0}]],"gradient_type":"Radial","start":[0.3201759714645238,0.5902044022091868],"end":[1.025282605251574,0.18308301136073535],"transform":[138.98607005532313,0.0,0.0,138.98607005532352,1193.5000000000005,570.5540117570772]}},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::FillNode"}},"visible":true,"skip_deduplication":false}],[463,{"inputs":[{"Value":{"tagged_value":{"VectorData":{"instance":[{"style":{"stroke":{"color":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0},"weight":0.0,"dash_lengths":[],"dash_offset":0.0,"cap":"Butt","join":"Miter","join_miter_limit":4.0,"align":"Center","transform":[1.0,0.0,0.0,1.0,0.0,0.0],"non_scaling":false,"paint_order":"StrokeAbove"},"fill":"None"},"colinear_manipulators":[],"point_domain":{"id":[],"position":[]},"segment_domain":{"id":[],"start_point":[],"end_point":[],"handles":[],"stroke":[]},"region_domain":{"id":[],"segment_range":[],"fill":[]},"upstream_graphic_group":null}],"transform":[[1.0,0.0,0.0,1.0,0.0,0.0]],"alpha_blending":[{"blend_mode":"Normal","opacity":1.0,"fill":1.0,"clip":false}],"source_node_id":[null]}},"exposed":true}},{"Value":{"tagged_value":{"VectorModification":{"points":{"add":[1,2,3,4],"remove":[],"delta":[[1,[-4.833333333333348,600.0555555555555]],[2,[-4.833333333333332,345.83333333333326]],[4,[129.38888888888889,628.0555555555557]],[3,[80.05555555555559,484.94444444444446]]]},"segments":{"add":[1,2,3,4],"remove":[],"start_point":[[2,2],[4,4],[3,3],[1,1]],"end_point":[[3,4],[1,2],[2,3],[4,1]],"handle_primary":[[2,[0.0,0.0]],[4,[0.0,0.0]],[3,[32.038317168599576,69.73045501401077]],[1,[0.0,0.0]]],"handle_end":[[3,[0.0,0.0]],[2,[-45.33333333333338,-98.66666666666669]],[4,[0.0,0.0]],[1,[0.0,0.0]]],"stroke":[[2,0],[1,0],[3,0],[4,0]]},"regions":{"add":[0],"remove":[],"segment_range":[[0,{"start":1,"end":4}]],"fill":[[0,0]]},"add_g1_continuous":[],"remove_g1_continuous":[]}},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::vector_data::modification::VectorModification","alias":null}},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::vector_data::modification::PathModifyNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[292,{"inputs":[{"Value":{"tagged_value":{"GraphicGroup":{"instance":[],"transform":[],"alpha_blending":[],"source_node_id":[]}},"exposed":true}},{"Node":{"node_id":312,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[17414691604179185270,{"inputs":[{"Value":{"tagged_value":{"VectorData":{"instance":[{"style":{"stroke":{"color":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0},"weight":0.0,"dash_lengths":[],"dash_offset":0.0,"cap":"Butt","join":"Miter","join_miter_limit":4.0,"align":"Center","transform":[1.0,0.0,0.0,1.0,0.0,0.0],"non_scaling":false,"paint_order":"StrokeAbove"},"fill":"None"},"colinear_manipulators":[],"point_domain":{"id":[],"position":[]},"segment_domain":{"id":[],"start_point":[],"end_point":[],"handles":[],"stroke":[]},"region_domain":{"id":[],"segment_range":[],"fill":[]},"upstream_graphic_group":null}],"transform":[[1.0,0.0,0.0,1.0,0.0,0.0]],"alpha_blending":[{"blend_mode":"Normal","opacity":1.0,"fill":1.0,"clip":false}],"source_node_id":[null]}},"exposed":true}},{"Value":{"tagged_value":{"VectorModification":{"points":{"add":[1,2,3,4],"remove":[],"delta":[[1,[546.1069958847736,566.7818930041152]],[4,[547.6604938271604,606.7880658436213]],[3,[539.3641975308641,608.7633744855966]],[2,[530.2777777777771,564.9115226337452]]]},"segments":{"add":[1,2,3,4],"remove":[],"start_point":[[4,4],[1,1],[2,2],[3,3]],"end_point":[[1,2],[2,3],[3,4],[4,1]],"handle_primary":[[1,[0.0,0.0]],[2,[0.0,0.0]],[3,[0.0,0.0]],[4,[0.0,0.0]]],"handle_end":[[3,[0.0,0.0]],[2,[0.0,0.0]],[4,[0.0,0.0]],[1,[0.0,0.0]]],"stroke":[[3,0],[4,0],[2,0],[1,0]]},"regions":{"add":[0],"remove":[],"segment_range":[[0,{"start":1,"end":4}]],"fill":[[0,0]]},"add_g1_continuous":[],"remove_g1_continuous":[]}},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::vector_data::modification::VectorModification","alias":null}},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::vector_data::modification::PathModifyNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[323,{"inputs":[{"Node":{"node_id":321,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"OptionalColor":{"red":0.24313726,"green":0.18431373,"blue":0.19215687,"alpha":1.0}},"exposed":false}},{"Value":{"tagged_value":{"F64":2.0},"exposed":false}},{"Value":{"tagged_value":{"StrokeAlign":"Center"},"exposed":false}},{"Value":{"tagged_value":{"StrokeCap":"Butt"},"exposed":false}},{"Value":{"tagged_value":{"StrokeJoin":"Miter"},"exposed":false}},{"Value":{"tagged_value":{"F64":4.0},"exposed":false}},{"Value":{"tagged_value":{"PaintOrder":"StrokeAbove"},"exposed":false}},{"Value":{"tagged_value":{"VecF64":[]},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::StrokeNode"}},"visible":true,"skip_deduplication":false}],[214,{"inputs":[{"Node":{"node_id":218,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"Fill":{"Solid":{"red":0.24313726,"green":0.18431373,"blue":0.19215687,"alpha":1.0}}},"exposed":false}},{"Value":{"tagged_value":{"OptionalColor":{"red":0.24313726,"green":0.18431373,"blue":0.19215687,"alpha":1.0}},"exposed":false}},{"Value":{"tagged_value":{"Gradient":{"stops":[[0.0,{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}],[1.0,{"red":1.0,"green":1.0,"blue":1.0,"alpha":1.0}]],"gradient_type":"Linear","start":[0.0,0.5],"end":[1.0,0.5],"transform":[1.0,0.0,0.0,1.0,0.0,0.0]}},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::FillNode"}},"visible":true,"skip_deduplication":false}],[6272196533192700024,{"inputs":[{"Node":{"node_id":481,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"DVec2":[28.815503095243457,-49.74366671015599]},"exposed":false}},{"Value":{"tagged_value":{"F64":0.057504143999955744},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[1.0,1.0]},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[0.0,0.0]},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[0.5,0.5]},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":1}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":2}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":3}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":4}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":5}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::TransformNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[74,{"inputs":[{"Node":{"node_id":75,"output_index":0,"lambda":false}},{"Node":{"node_id":81,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[105,{"inputs":[{"Node":{"node_id":108,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"Fill":{"Gradient":{"stops":[[0.0,{"red":0.24313726,"green":0.18431373,"blue":0.19215687,"alpha":1.0}],[0.7721675713724807,{"red":0.24313726,"green":0.18431373,"blue":0.19215687,"alpha":1.0}],[1.0,{"red":0.3764706,"green":0.23529412,"blue":0.20784314,"alpha":1.0}]],"gradient_type":"Radial","start":[0.401555786122616,0.773953065673463],"end":[0.898982212168407,0.4370729973098963],"transform":[490.52480371748175,6.007196307749977e-14,0.0,325.3699488483585,982.0269268305848,323.7895812222803]}}},"exposed":false}},{"Value":{"tagged_value":{"OptionalColor":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}},"exposed":false}},{"Value":{"tagged_value":{"Gradient":{"stops":[[0.0,{"red":0.24313726,"green":0.18431373,"blue":0.19215687,"alpha":1.0}],[0.7721675713724807,{"red":0.24313726,"green":0.18431373,"blue":0.19215687,"alpha":1.0}],[1.0,{"red":0.3764706,"green":0.23529412,"blue":0.20784314,"alpha":1.0}]],"gradient_type":"Radial","start":[0.401555786122616,0.773953065673463],"end":[0.898982212168407,0.4370729973098963],"transform":[490.52480371748175,6.007196307749977e-14,0.0,325.3699488483585,982.0269268305848,323.7895812222803]}},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::FillNode"}},"visible":true,"skip_deduplication":false}],[17173383864410319040,{"inputs":[{"Node":{"node_id":15277819403265847073,"output_index":0,"lambda":false}},{"Node":{"node_id":15552693212536925398,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[478,{"inputs":[{"Value":{"tagged_value":{"GraphicGroup":{"instance":[],"transform":[],"alpha_blending":[],"source_node_id":[]}},"exposed":true}},{"Node":{"node_id":7135480377162524224,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[1635416892097245588,{"inputs":[{"Value":{"tagged_value":{"GraphicGroup":{"instance":[],"transform":[],"alpha_blending":[],"source_node_id":[]}},"exposed":true}},{"Node":{"node_id":11472292186872186521,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[6926019345498826421,{"inputs":[{"Node":{"node_id":989999757220954936,"output_index":0,"lambda":false}},{"Node":{"node_id":17020523203516467057,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[17911294938421300842,{"inputs":[{"Node":{"node_id":17414691604179185270,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"Fill":{"Solid":{"red":0.24313726,"green":0.18431373,"blue":0.19215687,"alpha":1.0}}},"exposed":false}},{"Value":{"tagged_value":{"OptionalColor":{"red":0.24313726,"green":0.18431373,"blue":0.19215687,"alpha":1.0}},"exposed":false}},{"Value":{"tagged_value":{"Gradient":{"stops":[[0.0,{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}],[1.0,{"red":1.0,"green":1.0,"blue":1.0,"alpha":1.0}]],"gradient_type":"Linear","start":[0.0,0.5],"end":[1.0,0.5],"transform":[1.0,0.0,0.0,1.0,0.0,0.0]}},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::FillNode"}},"visible":true,"skip_deduplication":false}],[400,{"inputs":[{"Value":{"tagged_value":{"VectorData":{"instance":[{"style":{"stroke":{"color":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0},"weight":0.0,"dash_lengths":[],"dash_offset":0.0,"cap":"Butt","join":"Miter","join_miter_limit":4.0,"align":"Center","transform":[1.0,0.0,0.0,1.0,0.0,0.0],"non_scaling":false,"paint_order":"StrokeAbove"},"fill":"None"},"colinear_manipulators":[],"point_domain":{"id":[],"position":[]},"segment_domain":{"id":[],"start_point":[],"end_point":[],"handles":[],"stroke":[]},"region_domain":{"id":[],"segment_range":[],"fill":[]},"upstream_graphic_group":null}],"transform":[[1.0,0.0,0.0,1.0,0.0,0.0]],"alpha_blending":[{"blend_mode":"Normal","opacity":1.0,"fill":1.0,"clip":false}],"source_node_id":[null]}},"exposed":true}},{"Value":{"tagged_value":{"VectorModification":{"points":{"add":[1,2,3,4,5,6,7,8,9,10,11,12],"remove":[],"delta":[[10,[378.8703703703703,472.7962962962963]],[9,[378.57407407407413,324.0555555555556]],[6,[457.9814814814815,279.4135802469136]],[1,[531.0946502057612,568.230452674897]],[11,[378.8703703703703,545.3888888888889]],[7,[411.7592592592593,261.83333333333337]],[3,[499.1666666666666,380.94444444444446]],[2,[513.0925925925925,455.6111111111111]],[5,[482.47530864197535,316.35185185185185]],[12,[399.3148148148148,564.0555555555555]],[8,[381.7345679012346,268.5493827160494]],[4,[487.3148148148147,333.24074074074076]]]},"segments":{"add":[1,2,3,4,5,6,7,8,9,10,11,12],"remove":[],"start_point":[[5,5],[1,1],[4,4],[6,6],[12,12],[7,7],[9,9],[3,3],[11,11],[10,10],[2,2],[8,8]],"end_point":[[4,5],[6,7],[10,11],[12,1],[5,6],[8,9],[3,4],[9,10],[11,12],[1,2],[2,3],[7,8]],"handle_primary":[[6,[-20.345679012345727,-8.691358024691397]],[12,[22.22222222222223,-1.1851851851852189]],[1,[0.0,0.0]],[5,[-2.1728395061728065,-7.703703703703695]],[10,[-0.8888888888888573,38.81481481481478]],[2,[-6.51851851851859,-35.55555555555554]],[4,[0.0,0.0]],[8,[-6.716049382716051,13.62962962962962]],[11,[0.0,6.518518518518476]],[3,[-1.7777777777777717,-12.444444444444455]],[7,[-5.925925925925924,-0.9876543209876444]],[9,[0.1975308641974607,16.395061728395035]]],"handle_end":[[12,[-37.99794238683137,-21.306584362139915]],[10,[0.0,-6.518518518518476]],[7,[6.716049382716051,-13.62962962962962]],[11,[-22.22222222222223,1.1851851851852189]],[8,[-0.1975308641974607,-16.395061728395035]],[5,[20.345679012345784,8.691358024691397]],[9,[0.8888888888888573,-38.81481481481478]],[3,[8.888888888888971,23.407407407407447]],[1,[6.51851851851859,35.55555555555554]],[4,[2.1728395061728065,7.703703703703695]],[6,[5.925925925925924,0.9876543209876444]],[2,[1.7777777777777717,12.444444444444455]]],"stroke":[[2,0],[11,0],[5,0],[12,0],[3,0],[7,0],[6,0],[1,0],[4,0],[9,0],[10,0],[8,0]]},"regions":{"add":[0],"remove":[],"segment_range":[[0,{"start":1,"end":12}]],"fill":[[0,0]]},"add_g1_continuous":[],"remove_g1_continuous":[]}},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::vector_data::modification::VectorModification","alias":null}},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::vector_data::modification::PathModifyNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[229,{"inputs":[{"Node":{"node_id":227,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"DVec2":[829.8099807176391,565.8945401302792]},"exposed":false}},{"Value":{"tagged_value":{"F64":-1.958532},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[3.920156284886552,12.362329004080864]},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[-0.12623993859136304,0.0]},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[0.5,0.5]},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":1}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":2}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":3}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":4}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":5}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::TransformNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[4454263454059119441,{"inputs":[{"Value":{"tagged_value":{"VectorData":{"instance":[{"style":{"stroke":{"color":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0},"weight":0.0,"dash_lengths":[],"dash_offset":0.0,"cap":"Butt","join":"Miter","join_miter_limit":4.0,"align":"Center","transform":[1.0,0.0,0.0,1.0,0.0,0.0],"non_scaling":false,"paint_order":"StrokeAbove"},"fill":"None"},"colinear_manipulators":[],"point_domain":{"id":[],"position":[]},"segment_domain":{"id":[],"start_point":[],"end_point":[],"handles":[],"stroke":[]},"region_domain":{"id":[],"segment_range":[],"fill":[]},"upstream_graphic_group":null}],"transform":[[1.0,0.0,0.0,1.0,0.0,0.0]],"alpha_blending":[{"blend_mode":"Normal","opacity":1.0,"fill":1.0,"clip":false}],"source_node_id":[null]}},"exposed":true}},{"Value":{"tagged_value":{"VectorModification":{"points":{"add":[1,2,3,4],"remove":[],"delta":[[4,[0.0,0.5]],[2,[1.0,0.5]],[3,[0.5,1.0]],[1,[0.5,0.0]]]},"segments":{"add":[1,2,3,4],"remove":[],"start_point":[[2,2],[4,4],[1,1],[3,3]],"end_point":[[2,3],[4,1],[3,4],[1,2]],"handle_primary":[[3,[-0.275892388889507,0.0]],[4,[0.0,-0.275892388889507]],[1,[0.27589238888950707,0.0]],[2,[0.0,0.27589238888950707]]],"handle_end":[[1,[0.0,-0.275892388889507]],[3,[0.0,0.27589238888950707]],[2,[0.27589238888950707,0.0]],[4,[-0.275892388889507,0.0]]],"stroke":[[3,0],[4,0],[2,0],[1,0]]},"regions":{"add":[0],"remove":[],"segment_range":[[0,{"start":1,"end":4}]],"fill":[[0,0]]},"add_g1_continuous":[],"remove_g1_continuous":[]}},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::vector_data::modification::VectorModification","alias":null}},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::vector_data::modification::PathModifyNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[260,{"inputs":[{"Value":{"tagged_value":{"VectorData":{"instance":[{"style":{"stroke":{"color":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0},"weight":0.0,"dash_lengths":[],"dash_offset":0.0,"cap":"Butt","join":"Miter","join_miter_limit":4.0,"align":"Center","transform":[1.0,0.0,0.0,1.0,0.0,0.0],"non_scaling":false,"paint_order":"StrokeAbove"},"fill":"None"},"colinear_manipulators":[],"point_domain":{"id":[],"position":[]},"segment_domain":{"id":[],"start_point":[],"end_point":[],"handles":[],"stroke":[]},"region_domain":{"id":[],"segment_range":[],"fill":[]},"upstream_graphic_group":null}],"transform":[[1.0,0.0,0.0,1.0,0.0,0.0]],"alpha_blending":[{"blend_mode":"Normal","opacity":1.0,"fill":1.0,"clip":false}],"source_node_id":[null]}},"exposed":true}},{"Value":{"tagged_value":{"VectorModification":{"points":{"add":[1,2,3,4,5],"remove":[],"delta":[[1,[-0.06772020100134477,-0.27125764892979654]],[5,[0.05417500861004592,0.8211321210533473]],[2,[0.8103689541744266,-0.2611110184526325]],[4,[0.4707515606101555,1.0016674771193048]],[3,[1.1461889241405476,1.0977967891967286]]]},"segments":{"add":[1,2,3,4,5],"remove":[],"start_point":[[3,3],[1,1],[2,2],[5,5],[4,4]],"end_point":[[4,5],[5,1],[3,4],[2,3],[1,2]],"handle_primary":[[1,[0.0,0.0]],[2,[0.0,0.0]],[3,[-2.220446049250313e-16,-2.220446049250313e-16]],[5,[0.0,0.0]],[4,[-0.4165765520001096,-0.1805353560659575]]],"handle_end":[[2,[0.0,0.0]],[4,null],[5,[0.0,0.0]],[3,[0.2875939062231115,0.06333186265853907]],[1,[0.0,0.0]]],"stroke":[[1,0],[2,0],[4,0],[3,0],[5,0]]},"regions":{"add":[0],"remove":[],"segment_range":[[0,{"start":1,"end":5}]],"fill":[[0,0]]},"add_g1_continuous":[],"remove_g1_continuous":[]}},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::vector_data::modification::VectorModification","alias":null}},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::vector_data::modification::PathModifyNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[120,{"inputs":[{"Node":{"node_id":1635416892097245588,"output_index":0,"lambda":false}},{"Node":{"node_id":140,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[10486443711686704000,{"inputs":[{"Node":{"node_id":5714505144727602368,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"Fill":{"Gradient":{"stops":[[0.0,{"red":0.3764706,"green":0.23529412,"blue":0.20784314,"alpha":1.0}],[1.0,{"red":0.5058824,"green":0.26666668,"blue":0.20392157,"alpha":1.0}]],"gradient_type":"Linear","start":[0.15803798551484238,0.5113172122965266],"end":[0.8867475285247997,0.49951059174236745],"transform":[86.14721272187913,-121.25388422552253,404.54387368785456,312.49837227690176,602.5352222980036,467.4253353064524]}}},"exposed":false}},{"Value":{"tagged_value":{"OptionalColor":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}},"exposed":false}},{"Value":{"tagged_value":{"Gradient":{"stops":[[0.0,{"red":0.3764706,"green":0.23529412,"blue":0.20784314,"alpha":1.0}],[1.0,{"red":0.5058824,"green":0.26666668,"blue":0.20392157,"alpha":1.0}]],"gradient_type":"Linear","start":[0.15803798551484238,0.5113172122965266],"end":[0.8867475285247997,0.49951059174236745],"transform":[86.14721272187913,-121.25388422552253,404.54387368785456,312.49837227690176,602.5352222980036,467.4253353064524]}},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::FillNode"}},"visible":true,"skip_deduplication":false}],[291,{"inputs":[{"Node":{"node_id":292,"output_index":0,"lambda":false}},{"Node":{"node_id":306,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[493,{"inputs":[{"Node":{"node_id":496,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"Fill":{"Gradient":{"stops":[[0.0,{"red":0.16152954,"green":0.5000886,"blue":0.5234375,"alpha":1.0}],[0.33108336235841895,{"red":0.2509804,"green":0.54509807,"blue":0.5176471,"alpha":1.0}],[0.6158954287284122,{"red":0.48235294,"green":0.5568628,"blue":0.4,"alpha":1.0}],[1.0,{"red":0.73333335,"green":0.49411765,"blue":0.23137255,"alpha":1.0}]],"gradient_type":"Linear","start":[0.5224609375,-0.000170829498767594],"end":[0.5224609375,0.9116247106204544],"transform":[1024.0,0.0,0.0,595.075070611153,559.0,78.92492938884703]}}},"exposed":false}},{"Value":{"tagged_value":{"OptionalColor":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}},"exposed":false}},{"Value":{"tagged_value":{"Gradient":{"stops":[[0.0,{"red":0.16152954,"green":0.5000886,"blue":0.5234375,"alpha":1.0}],[0.33108336235841895,{"red":0.2509804,"green":0.54509807,"blue":0.5176471,"alpha":1.0}],[0.6158954287284122,{"red":0.48235294,"green":0.5568628,"blue":0.4,"alpha":1.0}],[1.0,{"red":0.73333335,"green":0.49411765,"blue":0.23137255,"alpha":1.0}]],"gradient_type":"Linear","start":[0.5224609375,-0.000170829498767594],"end":[0.5224609375,0.9116247106204544],"transform":[1024.0,0.0,0.0,595.075070611153,559.0,78.92492938884703]}},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::FillNode"}},"visible":true,"skip_deduplication":false}],[11807598261442997948,{"inputs":[{"Value":{"tagged_value":{"VectorData":{"instance":[{"style":{"stroke":{"color":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0},"weight":0.0,"dash_lengths":[],"dash_offset":0.0,"cap":"Butt","join":"Miter","join_miter_limit":4.0,"align":"Center","transform":[1.0,0.0,0.0,1.0,0.0,0.0],"non_scaling":false,"paint_order":"StrokeAbove"},"fill":"None"},"colinear_manipulators":[],"point_domain":{"id":[],"position":[]},"segment_domain":{"id":[],"start_point":[],"end_point":[],"handles":[],"stroke":[]},"region_domain":{"id":[],"segment_range":[],"fill":[]},"upstream_graphic_group":null}],"transform":[[1.0,0.0,0.0,1.0,0.0,0.0]],"alpha_blending":[{"blend_mode":"Normal","opacity":1.0,"fill":1.0,"clip":false}],"source_node_id":[null]}},"exposed":true}},{"Value":{"tagged_value":{"VectorModification":{"points":{"add":[1,2,3,4,5,6],"remove":[],"delta":[[1,[527.0733882030179,547.0898491083676]],[5,[541.9979423868313,611.7921810699589]],[3,[481.882716049383,533.8333333333337]],[2,[500.121399176955,531.6385459533608]],[6,[530.2777777777774,564.9115226337451]],[4,[495.38065843621376,614.5137174211251]]]},"segments":{"add":[1,2,3,4,5,6],"remove":[],"start_point":[[4,4],[6,6],[5,5],[1,1],[3,3],[2,2]],"end_point":[[1,2],[4,5],[6,1],[3,4],[5,6],[2,3]],"handle_primary":[[5,[0.0,0.0]],[3,[0.0,0.0]],[4,[0.0,0.0]],[2,[5.684341886080804e-14,0.0]],[6,[0.0,0.0]],[1,[0.0,0.0]]],"handle_end":[[1,[16.644617182340255,-0.4357059391355733]],[3,[0.0,0.0]],[4,[0.0,0.0]],[5,[0.0,0.0]],[2,[0.0,0.0]],[6,[0.0,0.0]]],"stroke":[[4,0],[2,0],[1,0],[3,0],[6,0],[5,0]]},"regions":{"add":[0],"remove":[],"segment_range":[[0,{"start":1,"end":6}]],"fill":[[0,0]]},"add_g1_continuous":[],"remove_g1_continuous":[]}},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::vector_data::modification::VectorModification","alias":null}},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::vector_data::modification::PathModifyNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[182,{"inputs":[{"Node":{"node_id":12768614558324028960,"output_index":0,"lambda":false}},{"Node":{"node_id":268,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[3930114406985796561,{"inputs":[{"Node":{"node_id":4454263454059119441,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"F64":50.0},"exposed":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::blending_nodes::OpacityNode"}},"visible":true,"skip_deduplication":false}],[12875520257830460085,{"inputs":[{"Node":{"node_id":11891167879168294182,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"Fill":{"Solid":{"red":0.24313726,"green":0.18431373,"blue":0.19215687,"alpha":1.0}}},"exposed":false}},{"Value":{"tagged_value":{"OptionalColor":{"red":0.24313726,"green":0.18431373,"blue":0.19215687,"alpha":1.0}},"exposed":false}},{"Value":{"tagged_value":{"Gradient":{"stops":[[0.0,{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}],[1.0,{"red":1.0,"green":1.0,"blue":1.0,"alpha":1.0}]],"gradient_type":"Linear","start":[0.0,0.5],"end":[1.0,0.5],"transform":[1.0,0.0,0.0,1.0,0.0,0.0]}},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::FillNode"}},"visible":true,"skip_deduplication":false}],[9778003574990260202,{"inputs":[{"Node":{"node_id":6926019345498826421,"output_index":0,"lambda":false}},{"Node":{"node_id":5364427239360309137,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[244,{"inputs":[{"Node":{"node_id":248,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"Fill":{"Solid":{"red":0.24313726,"green":0.18431373,"blue":0.19215687,"alpha":1.0}}},"exposed":false}},{"Value":{"tagged_value":{"OptionalColor":{"red":0.24313726,"green":0.18431373,"blue":0.19215687,"alpha":1.0}},"exposed":false}},{"Value":{"tagged_value":{"Gradient":{"stops":[[0.0,{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}],[1.0,{"red":1.0,"green":1.0,"blue":1.0,"alpha":1.0}]],"gradient_type":"Linear","start":[0.0,0.5],"end":[1.0,0.5],"transform":[1.0,0.0,0.0,1.0,0.0,0.0]}},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::FillNode"}},"visible":true,"skip_deduplication":false}],[415,{"inputs":[{"Node":{"node_id":418,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"Fill":{"Gradient":{"stops":[[0.0,{"red":0.827451,"green":0.36862746,"blue":0.20784314,"alpha":1.0}],[0.5,{"red":0.827451,"green":0.36862746,"blue":0.20784314,"alpha":0.80859375}],[1.0,{"red":0.827451,"green":0.36862746,"blue":0.20784314,"alpha":0.0}]],"gradient_type":"Radial","start":[0.30473369160482133,-0.27613184386946],"end":[0.66690549049424,0.16136781742013184],"transform":[294.3945373546583,0.0,0.0,138.32047280030588,578.6666666666667,646.679527199694]}}},"exposed":false}},{"Value":{"tagged_value":{"OptionalColor":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}},"exposed":false}},{"Value":{"tagged_value":{"Gradient":{"stops":[[0.0,{"red":0.827451,"green":0.36862746,"blue":0.20784314,"alpha":1.0}],[0.5,{"red":0.827451,"green":0.36862746,"blue":0.20784314,"alpha":0.80859375}],[1.0,{"red":0.827451,"green":0.36862746,"blue":0.20784314,"alpha":0.0}]],"gradient_type":"Radial","start":[0.30473369160482133,-0.27613184386946],"end":[0.66690549049424,0.16136781742013184],"transform":[294.3945373546583,0.0,0.0,138.32047280030588,578.6666666666667,646.679527199694]}},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::FillNode"}},"visible":true,"skip_deduplication":false}],[275,{"inputs":[{"Node":{"node_id":11427960919145580782,"output_index":0,"lambda":false}},{"Node":{"node_id":283,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[446,{"inputs":[{"Value":{"tagged_value":{"VectorData":{"instance":[{"style":{"stroke":{"color":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0},"weight":0.0,"dash_lengths":[],"dash_offset":0.0,"cap":"Butt","join":"Miter","join_miter_limit":4.0,"align":"Center","transform":[1.0,0.0,0.0,1.0,0.0,0.0],"non_scaling":false,"paint_order":"StrokeAbove"},"fill":"None"},"colinear_manipulators":[],"point_domain":{"id":[],"position":[]},"segment_domain":{"id":[],"start_point":[],"end_point":[],"handles":[],"stroke":[]},"region_domain":{"id":[],"segment_range":[],"fill":[]},"upstream_graphic_group":null}],"transform":[[1.0,0.0,0.0,1.0,0.0,0.0]],"alpha_blending":[{"blend_mode":"Normal","opacity":1.0,"fill":1.0,"clip":false}],"source_node_id":[null]}},"exposed":true}},{"Value":{"tagged_value":{"VectorModification":{"points":{"add":[1,2,3,4],"remove":[],"delta":[[4,[0.0,1.0]],[2,[1.0,0.0]],[3,[1.0,1.0]],[1,[0.0,0.0]]]},"segments":{"add":[1,2,3,4],"remove":[],"start_point":[[1,1],[4,4],[2,2],[3,3]],"end_point":[[3,4],[1,2],[2,3],[4,1]],"handle_primary":[[3,[0.0,0.0]],[4,[0.0,0.0]],[2,[0.0,0.0]],[1,[0.0,0.0]]],"handle_end":[[3,[0.0,0.0]],[2,[0.0,0.0]],[4,[0.0,0.0]],[1,[0.0,0.0]]],"stroke":[[4,0],[2,0],[3,0],[1,0]]},"regions":{"add":[0],"remove":[],"segment_range":[[0,{"start":1,"end":4}]],"fill":[[0,0]]},"add_g1_continuous":[],"remove_g1_continuous":[]}},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::vector_data::modification::VectorModification","alias":null}},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::vector_data::modification::PathModifyNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[477,{"inputs":[{"Node":{"node_id":478,"output_index":0,"lambda":false}},{"Node":{"node_id":6272196533192700024,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[306,{"inputs":[{"Node":{"node_id":310,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"Fill":{"Solid":{"red":0.3764706,"green":0.23529412,"blue":0.20784314,"alpha":1.0}}},"exposed":false}},{"Value":{"tagged_value":{"OptionalColor":{"red":0.3764706,"green":0.23529412,"blue":0.20784314,"alpha":1.0}},"exposed":false}},{"Value":{"tagged_value":{"Gradient":{"stops":[[0.0,{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}],[1.0,{"red":1.0,"green":1.0,"blue":1.0,"alpha":1.0}]],"gradient_type":"Linear","start":[0.0,0.5],"end":[1.0,0.5],"transform":[1.0,0.0,0.0,1.0,0.0,0.0]}},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::FillNode"}},"visible":true,"skip_deduplication":false}],[166,{"inputs":[{"Value":{"tagged_value":{"GraphicGroup":{"instance":[],"transform":[],"alpha_blending":[],"source_node_id":[]}},"exposed":true}},{"Node":{"node_id":393,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[11472292186872186521,{"inputs":[{"Node":{"node_id":4452902364641883403,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"DVec2":[-1367.319046874664,107.29818643577867]},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[4.24444444444444,0.8618453375356869]},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[0.0,0.0]},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[0.0,0.0]},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":1}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":2}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":3}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":4}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":5}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::TransformNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[88,{"inputs":[{"Value":{"tagged_value":{"GraphicGroup":{"instance":[],"transform":[],"alpha_blending":[],"source_node_id":[]}},"exposed":true}},{"Node":{"node_id":96,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[259,{"inputs":[{"Node":{"node_id":257,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"DVec2":[894.1788584769913,562.0196920444174]},"exposed":false}},{"Value":{"tagged_value":{"F64":-2.3255084},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[15.813534861768243,49.86845076365074]},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[-0.12623993859136165,0.0]},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[0.5,0.5]},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":1}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":2}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":3}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":4}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":5}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::TransformNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[430,{"inputs":[{"Node":{"node_id":433,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"Fill":{"Gradient":{"stops":[[0.0,{"red":0.71875,"green":0.37165833,"blue":0.20214844,"alpha":1.0}],[0.09210526315789476,{"red":0.7254902,"green":0.41960785,"blue":0.2,"alpha":1.0}],[1.0,{"red":0.79607844,"green":0.49411765,"blue":0.22745098,"alpha":1.0}]],"gradient_type":"Linear","start":[0.5000000000000004,0.0],"end":[0.5000000000000004,1.0],"transform":[261.96239650888936,0.0,0.0,227.99999999999997,1386.0376034911103,614.0]}}},"exposed":false}},{"Value":{"tagged_value":{"OptionalColor":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}},"exposed":false}},{"Value":{"tagged_value":{"Gradient":{"stops":[[0.0,{"red":0.71875,"green":0.37165833,"blue":0.20214844,"alpha":1.0}],[0.09210526315789476,{"red":0.7254902,"green":0.41960785,"blue":0.2,"alpha":1.0}],[1.0,{"red":0.79607844,"green":0.49411765,"blue":0.22745098,"alpha":1.0}]],"gradient_type":"Linear","start":[0.5000000000000004,0.0],"end":[0.5000000000000004,1.0],"transform":[261.96239650888936,0.0,0.0,227.99999999999997,1386.0376034911103,614.0]}},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::FillNode"}},"visible":true,"skip_deduplication":false}],[119,{"inputs":[{"Node":{"node_id":120,"output_index":0,"lambda":false}},{"Node":{"node_id":134,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[290,{"inputs":[{"Node":{"node_id":291,"output_index":0,"lambda":false}},{"Node":{"node_id":300,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[321,{"inputs":[{"Node":{"node_id":325,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"Fill":{"Gradient":{"stops":[[0.0,{"red":0.9254902,"green":0.7176471,"blue":0.28627452,"alpha":1.0}],[1.0,{"red":0.7176471,"green":0.28627452,"blue":0.16862746,"alpha":1.0}]],"gradient_type":"Linear","start":[0.6317852697063873,0.02415325870852081],"end":[0.05910622380623476,0.9861828395407052],"transform":[279.388605442177,0.0,0.0,960.4694267308416,951.4863945578228,120.80153345454534]}}},"exposed":false}},{"Value":{"tagged_value":{"OptionalColor":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}},"exposed":false}},{"Value":{"tagged_value":{"Gradient":{"stops":[[0.0,{"red":0.9254902,"green":0.7176471,"blue":0.28627452,"alpha":1.0}],[1.0,{"red":0.7176471,"green":0.28627452,"blue":0.16862746,"alpha":1.0}]],"gradient_type":"Linear","start":[0.6317852697063873,0.02415325870852081],"end":[0.05910622380623476,0.9861828395407052],"transform":[279.388605442177,0.0,0.0,960.4694267308416,951.4863945578228,120.80153345454534]}},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::FillNode"}},"visible":true,"skip_deduplication":false}],[5364427239360309137,{"inputs":[{"Node":{"node_id":12325841371509826180,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"F64":75.0},"exposed":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::blending_nodes::OpacityNode"}},"visible":true,"skip_deduplication":false}],[181,{"inputs":[{"Node":{"node_id":182,"output_index":0,"lambda":false}},{"Node":{"node_id":262,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[14335659566300901430,{"inputs":[{"Value":{"tagged_value":{"GraphicGroup":{"instance":[],"transform":[],"alpha_blending":[],"source_node_id":[]}},"exposed":true}},{"Node":{"node_id":14579754335592291854,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[212,{"inputs":[{"Value":{"tagged_value":{"VectorData":{"instance":[{"style":{"stroke":{"color":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0},"weight":0.0,"dash_lengths":[],"dash_offset":0.0,"cap":"Butt","join":"Miter","join_miter_limit":4.0,"align":"Center","transform":[1.0,0.0,0.0,1.0,0.0,0.0],"non_scaling":false,"paint_order":"StrokeAbove"},"fill":"None"},"colinear_manipulators":[],"point_domain":{"id":[],"position":[]},"segment_domain":{"id":[],"start_point":[],"end_point":[],"handles":[],"stroke":[]},"region_domain":{"id":[],"segment_range":[],"fill":[]},"upstream_graphic_group":null}],"transform":[[1.0,0.0,0.0,1.0,0.0,0.0]],"alpha_blending":[{"blend_mode":"Normal","opacity":1.0,"fill":1.0,"clip":false}],"source_node_id":[null]}},"exposed":true}},{"Value":{"tagged_value":{"VectorModification":{"points":{"add":[1,2,3,4,5,6,7,8],"remove":[],"delta":[[1,[957.8271604938273,462.1234567901235]],[2,[948.746913580247,472.10493827160496]],[3,[925.6111111111112,527.7098765432099]],[5,[977.4876543209878,545.4876543209878]],[4,[922.2777777777778,549.4629629629628]],[7,[984.9112747301664,495.90740740740745]],[8,[965.6358024691358,465.1913580246914]],[6,[990.3271604938273,526.5246913580247]]]},"segments":{"add":[1,2,3,4,5,6,7,8],"remove":[],"start_point":[[3,3],[7,7],[6,6],[5,5],[2,2],[4,4],[8,8],[1,1]],"end_point":[[8,1],[7,8],[1,2],[3,4],[5,6],[2,3],[6,7],[4,5]],"handle_primary":[[7,[0.0,0.0]],[2,[-6.123456790123441,10.962962962962932]],[8,[0.0,0.0]],[1,[0.0,0.0]],[4,[0.0,0.0]],[3,[-2.469135802469168,9.975308641975287]],[6,[0.0,0.0]],[5,[0.0,0.0]]],"handle_end":[[1,[6.123456790123441,-10.96296296296299]],[5,[0.0,0.0]],[4,[0.0,0.0]],[6,[0.0,0.0]],[7,[7.407407407407391,6.814814814814838]],[2,[2.469135802468827,-9.975308641975287]],[8,[0.0,0.0]],[3,[0.0,0.0]]],"stroke":[[8,0],[7,0],[2,0],[5,0],[3,0],[1,0],[6,0],[4,0]]},"regions":{"add":[0],"remove":[],"segment_range":[[0,{"start":1,"end":8}]],"fill":[[0,0]]},"add_g1_continuous":[],"remove_g1_continuous":[]}},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::vector_data::modification::VectorModification","alias":null}},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::vector_data::modification::PathModifyNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[14433811491576609500,{"inputs":[{"Node":{"node_id":9570557034533539493,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"Fill":{"Solid":{"red":0.5058824,"green":0.26666668,"blue":0.20392157,"alpha":1.0}}},"exposed":false}},{"Value":{"tagged_value":{"OptionalColor":{"red":0.5058824,"green":0.26666668,"blue":0.20392157,"alpha":1.0}},"exposed":false}},{"Value":{"tagged_value":{"Gradient":{"stops":[[0.0,{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}],[1.0,{"red":1.0,"green":1.0,"blue":1.0,"alpha":1.0}]],"gradient_type":"Linear","start":[0.0,0.5],"end":[1.0,0.5],"transform":[1.0,0.0,0.0,1.0,0.0,0.0]}},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::FillNode"}},"visible":true,"skip_deduplication":false}],[274,{"inputs":[{"Node":{"node_id":275,"output_index":0,"lambda":false}},{"Node":{"node_id":277,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[445,{"inputs":[{"Node":{"node_id":446,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"DVec2":[83.1666666666668,614.1795271996941]},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[941.3333333333331,154.32047280030588]},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[0.0,0.0]},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[0.5,0.5]},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":1}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":2}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":3}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":4}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":5}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::TransformNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[103,{"inputs":[{"Value":{"tagged_value":{"GraphicGroup":{"instance":[],"transform":[],"alpha_blending":[],"source_node_id":[]}},"exposed":true}},{"Node":{"node_id":111,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[134,{"inputs":[{"Node":{"node_id":138,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"Fill":{"Solid":{"red":0.3764706,"green":0.23529412,"blue":0.20784314,"alpha":1.0}}},"exposed":false}},{"Value":{"tagged_value":{"OptionalColor":{"red":0.3764706,"green":0.23529412,"blue":0.20784314,"alpha":1.0}},"exposed":false}},{"Value":{"tagged_value":{"Gradient":{"stops":[[0.0,{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}],[1.0,{"red":1.0,"green":1.0,"blue":1.0,"alpha":1.0}]],"gradient_type":"Linear","start":[0.0,0.5],"end":[1.0,0.5],"transform":[1.0,0.0,0.0,1.0,0.0,0.0]}},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::FillNode"}},"visible":true,"skip_deduplication":false}],[165,{"inputs":[{"Node":{"node_id":166,"output_index":0,"lambda":false}},{"Node":{"node_id":16821952675128396603,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[10278740841813346388,{"inputs":[{"Value":{"tagged_value":{"VectorData":{"instance":[{"style":{"stroke":{"color":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0},"weight":0.0,"dash_lengths":[],"dash_offset":0.0,"cap":"Butt","join":"Miter","join_miter_limit":4.0,"align":"Center","transform":[1.0,0.0,0.0,1.0,0.0,0.0],"non_scaling":false,"paint_order":"StrokeAbove"},"fill":"None"},"colinear_manipulators":[],"point_domain":{"id":[],"position":[]},"segment_domain":{"id":[],"start_point":[],"end_point":[],"handles":[],"stroke":[]},"region_domain":{"id":[],"segment_range":[],"fill":[]},"upstream_graphic_group":null}],"transform":[[1.0,0.0,0.0,1.0,0.0,0.0]],"alpha_blending":[{"blend_mode":"Normal","opacity":1.0,"fill":1.0,"clip":false}],"source_node_id":[null]}},"exposed":true}},{"Value":{"tagged_value":{"VectorModification":{"points":{"add":[1,2,3,4,5,6,7],"remove":[],"delta":[[7,[779.7592592592597,612.6204267490609]],[6,[729.3449931412895,610.3875171467763]],[2,[734.9571457603006,587.5194584158918]],[5,[710.9477975918305,613.6358024691357]],[3,[698.0912208504803,600.3792866941013]],[1,[744.3996087994717,586.9732002235432]],[4,[706.1680384087791,607.8415637860082]]]},"segments":{"add":[1,2,3,4,5,6,7],"remove":[],"start_point":[[5,5],[3,3],[2,2],[1,1],[7,7],[4,4],[6,6]],"end_point":[[6,7],[5,6],[4,5],[7,1],[1,2],[2,3],[3,4]],"handle_primary":[[7,[0.0,0.0]],[4,[2.1947873799731497,4.691071467853249]],[3,[0.0,0.0]],[2,[0.0,0.0]],[5,[7.452522481329197,2.721536351166037]],[1,[0.0,0.0]],[6,[15.119646395366544,2.853223593964344]]],"handle_end":[[4,null],[1,[0.0,0.0]],[5,null],[3,[-2.494608558449272,-5.331900091455282]],[7,[9.28638926992835,13.56378600823075]],[2,[6.496570644718986,-11.149519890260422]],[6,[0.0,0.0]]],"stroke":[[2,0],[6,0],[4,0],[3,0],[5,0],[7,0],[1,0]]},"regions":{"add":[0],"remove":[],"segment_range":[[0,{"start":1,"end":7}]],"fill":[[0,0]]},"add_g1_continuous":[],"remove_g1_continuous":[]}},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::vector_data::modification::VectorModification","alias":null}},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::vector_data::modification::PathModifyNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[196,{"inputs":[{"Node":{"node_id":200,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"Fill":{"Solid":{"red":0.3764706,"green":0.23529412,"blue":0.20784314,"alpha":1.0}}},"exposed":false}},{"Value":{"tagged_value":{"OptionalColor":{"red":0.3764706,"green":0.23529412,"blue":0.20784314,"alpha":1.0}},"exposed":false}},{"Value":{"tagged_value":{"Gradient":{"stops":[[0.0,{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}],[1.0,{"red":1.0,"green":1.0,"blue":1.0,"alpha":1.0}]],"gradient_type":"Linear","start":[0.0,0.5],"end":[1.0,0.5],"transform":[1.0,0.0,0.0,1.0,0.0,0.0]}},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::FillNode"}},"visible":true,"skip_deduplication":false}],[398,{"inputs":[{"Node":{"node_id":396,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"OptionalColor":{"red":0.24313726,"green":0.18431373,"blue":0.19215687,"alpha":1.0}},"exposed":false}},{"Value":{"tagged_value":{"F64":2.0},"exposed":false}},{"Value":{"tagged_value":{"StrokeAlign":"Center"},"exposed":false}},{"Value":{"tagged_value":{"StrokeCap":"Butt"},"exposed":false}},{"Value":{"tagged_value":{"StrokeJoin":"Miter"},"exposed":false}},{"Value":{"tagged_value":{"F64":4.0},"exposed":false}},{"Value":{"tagged_value":{"PaintOrder":"StrokeAbove"},"exposed":false}},{"Value":{"tagged_value":{"VecF64":[]},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::StrokeNode"}},"visible":true,"skip_deduplication":false}],[227,{"inputs":[{"Node":{"node_id":230,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"F64":75.0},"exposed":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::blending_nodes::OpacityNode"}},"visible":true,"skip_deduplication":false}],[87,{"inputs":[{"Node":{"node_id":88,"output_index":0,"lambda":false}},{"Node":{"node_id":90,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[118,{"inputs":[{"Node":{"node_id":119,"output_index":0,"lambda":false}},{"Node":{"node_id":128,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[491,{"inputs":[{"Value":{"tagged_value":{"VectorData":{"instance":[{"style":{"stroke":{"color":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0},"weight":0.0,"dash_lengths":[],"dash_offset":0.0,"cap":"Butt","join":"Miter","join_miter_limit":4.0,"align":"Center","transform":[1.0,0.0,0.0,1.0,0.0,0.0],"non_scaling":false,"paint_order":"StrokeAbove"},"fill":"None"},"colinear_manipulators":[],"point_domain":{"id":[],"position":[]},"segment_domain":{"id":[],"start_point":[],"end_point":[],"handles":[],"stroke":[]},"region_domain":{"id":[],"segment_range":[],"fill":[]},"upstream_graphic_group":null}],"transform":[[1.0,0.0,0.0,1.0,0.0,0.0]],"alpha_blending":[{"blend_mode":"Normal","opacity":1.0,"fill":1.0,"clip":false}],"source_node_id":[null]}},"exposed":true}},{"Value":{"tagged_value":{"VectorModification":{"points":{"add":[1,2,3,4,5,6],"remove":[],"delta":[[2,[867.3888888888889,344.05555555555554]],[4,[851.3888888888889,542.2777777777777]],[5,[876.9444444444443,582.1008216600221]],[1,[903.3333333333331,336.44444444444446]],[3,[858.2777777777777,377.8333333333333]],[6,[908.5000000000005,581.0432098765432]]]},"segments":{"add":[1,2,3,4,5,6],"remove":[],"start_point":[[2,2],[6,6],[3,3],[1,1],[5,5],[4,4]],"end_point":[[1,2],[3,4],[5,6],[6,1],[4,5],[2,3]],"handle_primary":[[3,[-0.4444444444444571,14.444444444444455]],[5,[0.0,0.0]],[2,[-9.555555555555657,12.444444444444455]],[1,[0.0,0.0]],[4,[-2.888888888888914,28.66666666666663]],[6,[0.0,0.0]]],"handle_end":[[5,[0.0,0.0]],[3,[2.888888888888914,-28.66666666666663]],[1,[9.555555555555657,-12.444444444444455]],[6,[0.16666666666685614,-0.2777777777777146]],[4,[0.0,0.0]],[2,[0.4444444444444571,-14.444444444444455]]],"stroke":[[5,0],[1,0],[3,0],[6,0],[2,0],[4,0]]},"regions":{"add":[0],"remove":[],"segment_range":[[0,{"start":1,"end":6}]],"fill":[[0,0]]},"add_g1_continuous":[],"remove_g1_continuous":[]}},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::vector_data::modification::VectorModification","alias":null}},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::vector_data::modification::PathModifyNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[180,{"inputs":[{"Node":{"node_id":181,"output_index":0,"lambda":false}},{"Node":{"node_id":256,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[11345069121502219134,{"inputs":[{"Node":{"node_id":12068777759187203228,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"Fill":{"Solid":{"red":0.24313726,"green":0.18431373,"blue":0.19215687,"alpha":1.0}}},"exposed":false}},{"Value":{"tagged_value":{"OptionalColor":{"red":0.24313726,"green":0.18431373,"blue":0.19215687,"alpha":1.0}},"exposed":false}},{"Value":{"tagged_value":{"Gradient":{"stops":[[0.0,{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}],[1.0,{"red":1.0,"green":1.0,"blue":1.0,"alpha":1.0}]],"gradient_type":"Linear","start":[0.0,0.5],"end":[1.0,0.5],"transform":[1.0,0.0,0.0,1.0,0.0,0.0]}},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::FillNode"}},"visible":true,"skip_deduplication":false}],[413,{"inputs":[{"Value":{"tagged_value":{"GraphicGroup":{"instance":[],"transform":[],"alpha_blending":[],"source_node_id":[]}},"exposed":true}},{"Node":{"node_id":436,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[242,{"inputs":[{"Value":{"tagged_value":{"VectorData":{"instance":[{"style":{"stroke":{"color":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0},"weight":0.0,"dash_lengths":[],"dash_offset":0.0,"cap":"Butt","join":"Miter","join_miter_limit":4.0,"align":"Center","transform":[1.0,0.0,0.0,1.0,0.0,0.0],"non_scaling":false,"paint_order":"StrokeAbove"},"fill":"None"},"colinear_manipulators":[],"point_domain":{"id":[],"position":[]},"segment_domain":{"id":[],"start_point":[],"end_point":[],"handles":[],"stroke":[]},"region_domain":{"id":[],"segment_range":[],"fill":[]},"upstream_graphic_group":null}],"transform":[[1.0,0.0,0.0,1.0,0.0,0.0]],"alpha_blending":[{"blend_mode":"Normal","opacity":1.0,"fill":1.0,"clip":false}],"source_node_id":[null]}},"exposed":true}},{"Value":{"tagged_value":{"VectorModification":{"points":{"add":[1,2,3,4,5],"remove":[],"delta":[[3,[819.0679012345677,520.2695473251028]],[4,[812.5713305898489,549.7821216278006]],[1,[842.2716049382715,561.8070416095107]],[5,[837.913808870599,583.4355281207133]],[2,[821.8187014174667,518.4112940100595]]]},"segments":{"add":[1,2,3,4,5],"remove":[],"start_point":[[4,4],[5,5],[1,1],[2,2],[3,3]],"end_point":[[4,5],[5,1],[2,3],[3,4],[1,2]],"handle_primary":[[1,[0.0,0.0]],[3,[-1.4046639231823974,2.1801554641060648]],[4,[0.0,0.0]],[2,[0.0,0.0]],[5,[0.0,0.0]]],"handle_end":[[2,[1.4046639231823974,-2.1801554641060648]],[1,[10.88614540466392,16.621856424325642]],[3,[0.0,0.0]],[5,[0.0,0.0]],[4,[0.0,0.0]]],"stroke":[[3,0],[2,0],[1,0],[5,0],[4,0]]},"regions":{"add":[0],"remove":[],"segment_range":[[0,{"start":1,"end":5}]],"fill":[[0,0]]},"add_g1_continuous":[],"remove_g1_continuous":[]}},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::vector_data::modification::VectorModification","alias":null}},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::vector_data::modification::PathModifyNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[102,{"inputs":[{"Node":{"node_id":103,"output_index":0,"lambda":false}},{"Node":{"node_id":105,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[475,{"inputs":[{"Value":{"tagged_value":{"VectorData":{"instance":[{"style":{"stroke":{"color":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0},"weight":0.0,"dash_lengths":[],"dash_offset":0.0,"cap":"Butt","join":"Miter","join_miter_limit":4.0,"align":"Center","transform":[1.0,0.0,0.0,1.0,0.0,0.0],"non_scaling":false,"paint_order":"StrokeAbove"},"fill":"None"},"colinear_manipulators":[],"point_domain":{"id":[],"position":[]},"segment_domain":{"id":[],"start_point":[],"end_point":[],"handles":[],"stroke":[]},"region_domain":{"id":[],"segment_range":[],"fill":[]},"upstream_graphic_group":null}],"transform":[[1.0,0.0,0.0,1.0,0.0,0.0]],"alpha_blending":[{"blend_mode":"Normal","opacity":1.0,"fill":1.0,"clip":false}],"source_node_id":[null]}},"exposed":true}},{"Value":{"tagged_value":{"VectorModification":{"points":{"add":[1,2,3,4,5,6],"remove":[],"delta":[[1,[22.827133919383556,312.5]],[6,[102.27777777777776,528.0555555555553]],[2,[46.49999999999994,177.5]],[5,[172.5,512.0555555555555]],[4,[85.15294924554185,45.49314128943759]],[3,[81.20964791952444,29.23708276177412]]]},"segments":{"add":[1,2,3,4,5,6],"remove":[],"start_point":[[1,1],[2,2],[5,5],[3,3],[4,4],[6,6]],"end_point":[[6,1],[5,6],[2,3],[1,2],[3,4],[4,5]],"handle_primary":[[6,[0.0,0.0]],[3,[0.0,0.0]],[1,[0.0,0.0]],[4,[0.0,0.0]],[2,[15.777777777777828,-79.0]],[5,[0.0,0.0]]],"handle_end":[[2,[0.0,0.0]],[5,[0.0,0.0]],[6,[0.0,0.0]],[3,[0.0,0.0]],[1,[-14.820678206547353,74.20776200602205]],[4,[0.0,0.0]]],"stroke":[[4,0],[6,0],[3,0],[5,0],[1,0],[2,0]]},"regions":{"add":[0],"remove":[],"segment_range":[[0,{"start":1,"end":6}]],"fill":[[0,0]]},"add_g1_continuous":[],"remove_g1_continuous":[]}},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::vector_data::modification::VectorModification","alias":null}},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::vector_data::modification::PathModifyNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[304,{"inputs":[{"Value":{"tagged_value":{"VectorData":{"instance":[{"style":{"stroke":{"color":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0},"weight":0.0,"dash_lengths":[],"dash_offset":0.0,"cap":"Butt","join":"Miter","join_miter_limit":4.0,"align":"Center","transform":[1.0,0.0,0.0,1.0,0.0,0.0],"non_scaling":false,"paint_order":"StrokeAbove"},"fill":"None"},"colinear_manipulators":[],"point_domain":{"id":[],"position":[]},"segment_domain":{"id":[],"start_point":[],"end_point":[],"handles":[],"stroke":[]},"region_domain":{"id":[],"segment_range":[],"fill":[]},"upstream_graphic_group":null}],"transform":[[1.0,0.0,0.0,1.0,0.0,0.0]],"alpha_blending":[{"blend_mode":"Normal","opacity":1.0,"fill":1.0,"clip":false}],"source_node_id":[null]}},"exposed":true}},{"Value":{"tagged_value":{"VectorModification":{"points":{"add":[1,2,3,4,5,6,7,8,9,10],"remove":[],"delta":[[10,[712.0500685871053,614.4420508944315]],[1,[645.3333333333333,614.013717421125]],[5,[744.3996087994716,586.9732002235431]],[6,[717.5809327846364,593.2681755829904]],[8,[708.7139917695473,601.783950617284]],[3,[680.2695473251027,600.730452674897]],[9,[713.2108672458469,610.5533455265964]],[7,[702.5246913580245,600.8931773149878]],[2,[658.574074074074,609.6851851851851]],[4,[699.4958847736627,594.497256515775]]]},"segments":{"add":[1,2,3,4,5,6,7,8,9,10],"remove":[],"start_point":[[3,3],[4,4],[8,8],[10,10],[5,5],[9,9],[7,7],[2,2],[6,6],[1,1]],"end_point":[[5,6],[4,5],[10,1],[7,8],[3,4],[9,10],[6,7],[8,9],[1,2],[2,3]],"handle_primary":[[7,[0.0,0.0]],[4,[4.444444444444002,-5.662551440328798]],[1,[0.0,0.0]],[10,[-58.35223289132739,3.851425709744945]],[6,[-10.886145404663694,2.8971193415636662]],[8,[0.0,0.0]],[9,[0.0,0.0]],[3,[7.374485596707928,-0.92181069958815]],[2,[4.740740740740762,-4.148148148148152]],[5,[0.0,0.0]]],"handle_end":[[2,[-6.174173455107166,0.7717716818881399]],[6,[0.0,0.0]],[5,[10.516302710276136,-2.79869346321857]],[10,null],[3,[-1.6866098186769705,2.1488658430550913]],[4,[-5.794238683127446,-2.0192043895747247]],[8,[-2.5361987501905787,-3.706752019509281]],[7,[-2.89711934156378,-1.975308641975289]],[1,[-4.740740740740762,4.148148148148152]],[9,[-0.08779149519853036,-2.2109123484780184]]],"stroke":[[1,0],[3,0],[4,0],[9,0],[6,0],[2,0],[8,0],[10,0],[5,0],[7,0]]},"regions":{"add":[0],"remove":[],"segment_range":[[0,{"start":1,"end":10}]],"fill":[[0,0]]},"add_g1_continuous":[],"remove_g1_continuous":[]}},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::vector_data::modification::VectorModification","alias":null}},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::vector_data::modification::PathModifyNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[164,{"inputs":[{"Node":{"node_id":165,"output_index":0,"lambda":false}},{"Node":{"node_id":318,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[226,{"inputs":[{"Node":{"node_id":229,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"Fill":{"Gradient":{"stops":[[0.0,{"red":0.3764706,"green":0.23529412,"blue":0.20784314,"alpha":1.0}],[1.0,{"red":0.5058824,"green":0.26666668,"blue":0.20392157,"alpha":1.0}]],"gradient_type":"Linear","start":[0.24641848672125644,0.5269240260497682],"end":[0.8641268166855021,0.5169975680471844],"transform":[-100.21499095458871,-245.37810800253257,714.8940033002694,-259.11571915794843,778.0,832.9999999999964]}}},"exposed":false}},{"Value":{"tagged_value":{"OptionalColor":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}},"exposed":false}},{"Value":{"tagged_value":{"Gradient":{"stops":[[0.0,{"red":0.3764706,"green":0.23529412,"blue":0.20784314,"alpha":1.0}],[1.0,{"red":0.5058824,"green":0.26666668,"blue":0.20392157,"alpha":1.0}]],"gradient_type":"Linear","start":[0.24641848672125644,0.5269240260497682],"end":[0.8641268166855021,0.5169975680471844],"transform":[-100.21499095458871,-245.37810800253257,714.8940033002694,-259.11571915794843,778.0,832.9999999999964]}},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::FillNode"}},"visible":true,"skip_deduplication":false}],[428,{"inputs":[{"Value":{"tagged_value":{"VectorData":{"instance":[{"style":{"stroke":{"color":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0},"weight":0.0,"dash_lengths":[],"dash_offset":0.0,"cap":"Butt","join":"Miter","join_miter_limit":4.0,"align":"Center","transform":[1.0,0.0,0.0,1.0,0.0,0.0],"non_scaling":false,"paint_order":"StrokeAbove"},"fill":"None"},"colinear_manipulators":[],"point_domain":{"id":[],"position":[]},"segment_domain":{"id":[],"start_point":[],"end_point":[],"handles":[],"stroke":[]},"region_domain":{"id":[],"segment_range":[],"fill":[]},"upstream_graphic_group":null}],"transform":[[1.0,0.0,0.0,1.0,0.0,0.0]],"alpha_blending":[{"blend_mode":"Normal","opacity":1.0,"fill":1.0,"clip":false}],"source_node_id":[null]}},"exposed":true}},{"Value":{"tagged_value":{"VectorModification":{"points":{"add":[1,2,3,4],"remove":[],"delta":[[1,[0.17362079214327678,-0.41509433962264153]],[3,[0.7349403737393546,1.0000000000000002]],[4,[0.1596715565350542,1.0]],[2,[0.8076864692090735,-0.4339622641509434]]]},"segments":{"add":[1,2,3,4],"remove":[],"start_point":[[2,2],[1,1],[3,3],[4,4]],"end_point":[[4,1],[2,3],[3,4],[1,2]],"handle_primary":[[3,[0.0,0.0]],[2,[0.0,0.0]],[1,[0.0,0.0]],[4,[0.0,0.0]]],"handle_end":[[1,[0.0,0.0]],[3,[0.0,0.0]],[4,[0.0,0.0]],[2,[0.0,0.0]]],"stroke":[[3,0],[2,0],[1,0],[4,0]]},"regions":{"add":[0],"remove":[],"segment_range":[[0,{"start":1,"end":4}]],"fill":[[0,0]]},"add_g1_continuous":[],"remove_g1_continuous":[]}},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::vector_data::modification::VectorModification","alias":null}},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::vector_data::modification::PathModifyNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[257,{"inputs":[{"Node":{"node_id":260,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"F64":75.0},"exposed":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::blending_nodes::OpacityNode"}},"visible":true,"skip_deduplication":false}],[10544930474333783117,{"inputs":[{"Node":{"node_id":17173383864410319040,"output_index":0,"lambda":false}},{"Node":{"node_id":4633399390154487467,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[117,{"inputs":[{"Node":{"node_id":118,"output_index":0,"lambda":false}},{"Node":{"node_id":122,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[459,{"inputs":[{"Node":{"node_id":463,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"Fill":{"Solid":{"red":0.24313726,"green":0.18431373,"blue":0.19215687,"alpha":1.0}}},"exposed":false}},{"Value":{"tagged_value":{"OptionalColor":{"red":0.24313726,"green":0.18431373,"blue":0.19215687,"alpha":1.0}},"exposed":false}},{"Value":{"tagged_value":{"Gradient":{"stops":[[0.0,{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}],[1.0,{"red":1.0,"green":1.0,"blue":1.0,"alpha":1.0}]],"gradient_type":"Linear","start":[0.0,0.5],"end":[1.0,0.5],"transform":[1.0,0.0,0.0,1.0,0.0,0.0]}},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::FillNode"}},"visible":true,"skip_deduplication":false}],[319,{"inputs":[{"Node":{"node_id":290,"output_index":0,"lambda":false}},{"Node":{"node_id":329,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[12068777759187203228,{"inputs":[{"Value":{"tagged_value":{"VectorData":{"instance":[{"style":{"stroke":{"color":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0},"weight":0.0,"dash_lengths":[],"dash_offset":0.0,"cap":"Butt","join":"Miter","join_miter_limit":4.0,"align":"Center","transform":[1.0,0.0,0.0,1.0,0.0,0.0],"non_scaling":false,"paint_order":"StrokeAbove"},"fill":"None"},"colinear_manipulators":[],"point_domain":{"id":[],"position":[]},"segment_domain":{"id":[],"start_point":[],"end_point":[],"handles":[],"stroke":[]},"region_domain":{"id":[],"segment_range":[],"fill":[]},"upstream_graphic_group":null}],"transform":[[1.0,0.0,0.0,1.0,0.0,0.0]],"alpha_blending":[{"blend_mode":"Normal","opacity":1.0,"fill":1.0,"clip":false}],"source_node_id":[null]}},"exposed":true}},{"Value":{"tagged_value":{"VectorModification":{"points":{"add":[1,2,3,4,5,6,7,8,9,10],"remove":[],"delta":[[6,[717.5809327846364,593.2681755829904]],[2,[658.574074074074,609.6851851851851]],[7,[702.5246913580245,600.8931773149878]],[5,[744.3996087994716,586.9732002235431]],[4,[699.4958847736627,594.497256515775]],[1,[645.3333333333333,614.013717421125]],[8,[708.7139917695473,601.783950617284]],[9,[713.2108672458469,610.5533455265964]],[10,[712.0500685871053,614.4420508944315]],[3,[680.2695473251027,600.730452674897]]]},"segments":{"add":[1,2,3,4,5,6,7,8,9,10],"remove":[],"start_point":[[9,9],[8,8],[7,7],[2,2],[3,3],[4,4],[6,6],[1,1],[5,5],[10,10]],"end_point":[[2,3],[10,1],[7,8],[5,6],[3,4],[9,10],[4,5],[8,9],[1,2],[6,7]],"handle_primary":[[1,[0.0,0.0]],[2,[4.740740740740762,-4.148148148148152]],[9,[0.0,0.0]],[3,[7.374485596707928,-0.92181069958815]],[5,[0.0,0.0]],[6,[-10.886145404663694,2.8971193415636662]],[10,[-58.35223289132739,3.851425709744945]],[4,[4.444444444444002,-5.662551440328798]],[7,[0.0,0.0]],[8,[0.0,0.0]]],"handle_end":[[5,[10.516302710276136,-2.79869346321857]],[2,[-6.174173455107166,0.7717716818881399]],[9,[-0.08779149519853036,-2.2109123484780184]],[7,[-2.89711934156378,-1.975308641975289]],[1,[-4.740740740740762,4.148148148148152]],[8,[-2.5361987501905787,-3.706752019509281]],[6,[0.0,0.0]],[3,[-1.6866098186769705,2.1488658430550913]],[4,[-5.794238683127446,-2.0192043895747247]],[10,null]],"stroke":[[4,0],[7,0],[8,0],[5,0],[2,0],[3,0],[9,0],[1,0],[10,0],[6,0]]},"regions":{"add":[0],"remove":[],"segment_range":[[0,{"start":1,"end":10}]],"fill":[[0,0]]},"add_g1_continuous":[],"remove_g1_continuous":[]}},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::vector_data::modification::VectorModification","alias":null}},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::vector_data::modification::PathModifyNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[179,{"inputs":[{"Node":{"node_id":180,"output_index":0,"lambda":false}},{"Node":{"node_id":250,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[16815500381887058038,{"inputs":[{"Value":{"tagged_value":{"ArtboardGroup":{"instance":[],"transform":[],"alpha_blending":[],"source_node_id":[]}},"exposed":true}},{"Node":{"node_id":74,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"IVec2":[0,0]},"exposed":false}},{"Value":{"tagged_value":{"IVec2":[1024,768]},"exposed":false}},{"Value":{"tagged_value":{"Color":{"red":1.0,"green":1.0,"blue":1.0,"alpha":1.0}},"exposed":false}},{"Value":{"tagged_value":{"Bool":true},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":2,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graph_craft::document::value::TaggedValue","alias":null}},"import_index":1}},{"Value":{"tagged_value":{"String":"Artboard"},"exposed":false}},{"Network":{"import_type":{"Concrete":{"name":"graph_craft::document::value::TaggedValue","alias":null}},"import_index":2}},{"Network":{"import_type":{"Concrete":{"name":"graph_craft::document::value::TaggedValue","alias":null}},"import_index":3}},{"Network":{"import_type":{"Concrete":{"name":"graph_craft::document::value::TaggedValue","alias":null}},"import_index":4}},{"Network":{"import_type":{"Concrete":{"name":"graph_craft::document::value::TaggedValue","alias":null}},"import_index":5}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToArtboardNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Network":{"import_type":{"Fn":[{"Concrete":{"name":"core::option::Option>","alias":null}},{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}}]},"import_index":0}},{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::AppendArtboardNode"}},"visible":true,"skip_deduplication":false}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[412,{"inputs":[{"Node":{"node_id":413,"output_index":0,"lambda":false}},{"Node":{"node_id":421,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[272,{"inputs":[{"Value":{"tagged_value":{"VectorData":{"instance":[{"style":{"stroke":{"color":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0},"weight":0.0,"dash_lengths":[],"dash_offset":0.0,"cap":"Butt","join":"Miter","join_miter_limit":4.0,"align":"Center","transform":[1.0,0.0,0.0,1.0,0.0,0.0],"non_scaling":false,"paint_order":"StrokeAbove"},"fill":"None"},"colinear_manipulators":[],"point_domain":{"id":[],"position":[]},"segment_domain":{"id":[],"start_point":[],"end_point":[],"handles":[],"stroke":[]},"region_domain":{"id":[],"segment_range":[],"fill":[]},"upstream_graphic_group":null}],"transform":[[1.0,0.0,0.0,1.0,0.0,0.0]],"alpha_blending":[{"blend_mode":"Normal","opacity":1.0,"fill":1.0,"clip":false}],"source_node_id":[null]}},"exposed":true}},{"Value":{"tagged_value":{"VectorModification":{"points":{"add":[1,2,3,4,5,6],"remove":[],"delta":[[3,[896.2037037037037,507.6111111111111]],[5,[927.7592592592592,537.8333333333333]],[6,[873.7839506172841,571.9567901234568]],[2,[885.701646090535,534.2283950617283]],[1,[872.6913580246915,564.7407407407408]],[4,[919.7592592592592,507.7592592592593]]]},"segments":{"add":[1,2,3,4,5,6],"remove":[],"start_point":[[2,2],[6,6],[5,5],[1,1],[3,3],[4,4]],"end_point":[[4,5],[2,3],[6,1],[3,4],[5,6],[1,2]],"handle_primary":[[1,[8.404909667028619,-14.163252363220296]],[3,[5.629629629629449,-5.185185185185162]],[2,[2.6337448559671657,-9.349794238682987]],[6,[0.0,0.0]],[5,[0.0,0.0]],[4,[9.641681333516315,12.166883587532825]]],"handle_end":[[5,[0.0,0.0]],[4,[0.0,0.0]],[2,[-6.29752559155645,5.8003525185389435]],[6,[0.0,0.0]],[1,null],[3,[-6.222222222222285,-7.851851851851904]]],"stroke":[[1,0],[5,0],[3,0],[6,0],[2,0],[4,0]]},"regions":{"add":[0],"remove":[],"segment_range":[[0,{"start":1,"end":6}]],"fill":[[0,0]]},"add_g1_continuous":[],"remove_g1_continuous":[]}},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::vector_data::modification::VectorModification","alias":null}},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::vector_data::modification::PathModifyNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[132,{"inputs":[{"Value":{"tagged_value":{"VectorData":{"instance":[{"style":{"stroke":{"color":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0},"weight":0.0,"dash_lengths":[],"dash_offset":0.0,"cap":"Butt","join":"Miter","join_miter_limit":4.0,"align":"Center","transform":[1.0,0.0,0.0,1.0,0.0,0.0],"non_scaling":false,"paint_order":"StrokeAbove"},"fill":"None"},"colinear_manipulators":[],"point_domain":{"id":[],"position":[]},"segment_domain":{"id":[],"start_point":[],"end_point":[],"handles":[],"stroke":[]},"region_domain":{"id":[],"segment_range":[],"fill":[]},"upstream_graphic_group":null}],"transform":[[1.0,0.0,0.0,1.0,0.0,0.0]],"alpha_blending":[{"blend_mode":"Normal","opacity":1.0,"fill":1.0,"clip":false}],"source_node_id":[null]}},"exposed":true}},{"Value":{"tagged_value":{"VectorModification":{"points":{"add":[1,2,3,4,5],"remove":[],"delta":[[5,[170.5082304526749,714.508230452675]],[4,[158.12962962962962,718.0637860082305]],[2,[158.95389422344155,655.6901143957208]],[1,[172.61522633744855,706.3436213991771]],[3,[153.6522633744856,666.8374485596709]]]},"segments":{"add":[1,2,3,4,5],"remove":[],"start_point":[[5,5],[2,2],[4,4],[3,3],[1,1]],"end_point":[[5,1],[2,3],[1,2],[3,4],[4,5]],"handle_primary":[[4,[0.0,0.0]],[2,[0.0,0.0]],[5,[3.160493827160508,-3.5555555555554292]],[1,[0.0,0.0]],[3,[-1.8436213991769537,9.744855967078138]]],"handle_end":[[4,[-3.403056460676396,3.828438518260782]],[3,[0.0,0.0]],[2,[1.8436213991768968,-9.744855967078138]],[1,[10.930041152263357,25.448559670781947]],[5,null]],"stroke":[[3,0],[4,0],[5,0],[1,0],[2,0]]},"regions":{"add":[0],"remove":[],"segment_range":[[0,{"start":1,"end":5}]],"fill":[[0,0]]},"add_g1_continuous":[],"remove_g1_continuous":[]}},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::vector_data::modification::VectorModification","alias":null}},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::vector_data::modification::PathModifyNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[18142347460553706128,{"inputs":[{"Node":{"node_id":3719764965605527929,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"F64":75.0},"exposed":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::blending_nodes::OpacityNode"}},"visible":true,"skip_deduplication":false}],[5714505144727602368,{"inputs":[{"Node":{"node_id":18142347460553706128,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"DVec2":[742.4503588311712,593.3522045638366]},"exposed":false}},{"Value":{"tagged_value":{"F64":-0.9530782},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[11.868580002725764,37.42791872115287]},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[-0.12623993859136118,0.0]},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[0.5,0.5]},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":1}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":2}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":3}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":4}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":5}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::TransformNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[3719764965605527929,{"inputs":[{"Value":{"tagged_value":{"VectorData":{"instance":[{"style":{"stroke":{"color":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0},"weight":0.0,"dash_lengths":[],"dash_offset":0.0,"cap":"Butt","join":"Miter","join_miter_limit":4.0,"align":"Center","transform":[1.0,0.0,0.0,1.0,0.0,0.0],"non_scaling":false,"paint_order":"StrokeAbove"},"fill":"None"},"colinear_manipulators":[],"point_domain":{"id":[],"position":[]},"segment_domain":{"id":[],"start_point":[],"end_point":[],"handles":[],"stroke":[]},"region_domain":{"id":[],"segment_range":[],"fill":[]},"upstream_graphic_group":null}],"transform":[[1.0,0.0,0.0,1.0,0.0,0.0]],"alpha_blending":[{"blend_mode":"Normal","opacity":1.0,"fill":1.0,"clip":false}],"source_node_id":[null]}},"exposed":true}},{"Value":{"tagged_value":{"VectorModification":{"points":{"add":[1,2,3,4,5,6],"remove":[],"delta":[[5,[0.5092009949861728,0.9569233045341342]],[4,[1.0925954941660798,1.0006513038165834]],[2,[0.5284291926980893,-0.05749241759918103]],[3,[0.9294778693529006,0.07804966382593222]],[1,[0.024789182815927936,-0.19742232174172225]],[6,[-0.007635827307500006,0.8135210708932508]]]},"segments":{"add":[1,2,3,4,5,6],"remove":[],"start_point":[[3,3],[1,1],[6,6],[5,5],[2,2],[4,4]],"end_point":[[2,3],[4,5],[1,2],[3,4],[6,1],[5,6]],"handle_primary":[[2,[0.21441988872806772,0.05895880273641681]],[6,[0.0,0.0]],[5,[-0.28124758738050376,-0.047835328360902984]],[4,[0.0,0.0]],[1,[0.0,0.0]],[3,[0.0,0.0]]],"handle_end":[[5,[0.0,0.0]],[6,[0.0,0.0]],[3,[0.0,0.0]],[4,[0.26857587477611267,0.04568009019878494]],[1,[-0.16942059711236046,-0.046585396643413435]],[2,[0.0,0.0]]],"stroke":[[2,0],[6,0],[1,0],[3,0],[5,0],[4,0]]},"regions":{"add":[0],"remove":[],"segment_range":[[0,{"start":1,"end":6}]],"fill":[[0,0]]},"add_g1_continuous":[],"remove_g1_continuous":[]}},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::vector_data::modification::VectorModification","alias":null}},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::vector_data::modification::PathModifyNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[194,{"inputs":[{"Value":{"tagged_value":{"VectorData":{"instance":[{"style":{"stroke":{"color":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0},"weight":0.0,"dash_lengths":[],"dash_offset":0.0,"cap":"Butt","join":"Miter","join_miter_limit":4.0,"align":"Center","transform":[1.0,0.0,0.0,1.0,0.0,0.0],"non_scaling":false,"paint_order":"StrokeAbove"},"fill":"None"},"colinear_manipulators":[],"point_domain":{"id":[],"position":[]},"segment_domain":{"id":[],"start_point":[],"end_point":[],"handles":[],"stroke":[]},"region_domain":{"id":[],"segment_range":[],"fill":[]},"upstream_graphic_group":null}],"transform":[[1.0,0.0,0.0,1.0,0.0,0.0]],"alpha_blending":[{"blend_mode":"Normal","opacity":1.0,"fill":1.0,"clip":false}],"source_node_id":[null]}},"exposed":true}},{"Value":{"tagged_value":{"VectorModification":{"points":{"add":[1,2,3,4,5],"remove":[],"delta":[[5,[0.038029134760865314,0.7285470752399478]],[4,[0.9388148027481048,0.674134940686276]],[1,[-0.15531318767467384,0.11366419216517]],[2,[0.2647731761418837,0.17920265855050785]],[3,[0.7287108039915611,0.06963660702488284]]]},"segments":{"add":[1,2,3,4,5],"remove":[],"start_point":[[5,5],[4,4],[1,1],[3,3],[2,2]],"end_point":[[3,4],[4,5],[2,3],[5,1],[1,2]],"handle_primary":[[1,[0.0,0.0]],[3,[-0.06001521816071698,0.06545334966568245]],[2,[0.12249986382303002,-0.04615791866776875]],[4,[0.0,0.0]],[5,[0.0,0.0]]],"handle_end":[[1,[-0.1993257782423989,0.03454533724430142]],[3,[0.0,0.0]],[2,[-0.2265909018579063,0.03511994027079236]],[4,[0.0,0.0]],[5,[0.0,0.0]]],"stroke":[[5,0],[2,0],[4,0],[1,0],[3,0]]},"regions":{"add":[0],"remove":[],"segment_range":[[0,{"start":1,"end":5}]],"fill":[[0,0]]},"add_g1_continuous":[],"remove_g1_continuous":[]}},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::vector_data::modification::VectorModification","alias":null}},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::vector_data::modification::PathModifyNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[17020523203516467057,{"inputs":[{"Node":{"node_id":7148230379224894975,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"Fill":{"Gradient":{"stops":[[0.0,{"red":0.3764706,"green":0.23529412,"blue":0.20784314,"alpha":1.0}],[1.0,{"red":0.328125,"green":0.19633627,"blue":0.17047119,"alpha":1.0}]],"gradient_type":"Linear","start":[0.3458831403130609,0.8154173283216788],"end":[0.29832402234636923,0.9999999999999992],"transform":[596.6666666666671,0.0,0.0,669.6474899687091,706.9999999999995,7.352510031290876]}}},"exposed":false}},{"Value":{"tagged_value":{"OptionalColor":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}},"exposed":false}},{"Value":{"tagged_value":{"Gradient":{"stops":[[0.0,{"red":0.3764706,"green":0.23529412,"blue":0.20784314,"alpha":1.0}],[1.0,{"red":0.328125,"green":0.19633627,"blue":0.17047119,"alpha":1.0}]],"gradient_type":"Linear","start":[0.3458831403130609,0.8154173283216788],"end":[0.29832402234636923,0.9999999999999992],"transform":[596.6666666666671,0.0,0.0,669.6474899687091,706.9999999999995,7.352510031290876]}},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::FillNode"}},"visible":true,"skip_deduplication":false}],[396,{"inputs":[{"Node":{"node_id":400,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"Fill":{"Gradient":{"stops":[[0.0,{"red":0.7176471,"green":0.28627452,"blue":0.16862746,"alpha":1.0}],[1.0,{"red":0.9098039,"green":0.6862745,"blue":0.27058825,"alpha":1.0}]],"gradient_type":"Linear","start":[0.03910157250347135,0.9695090157857073],"end":[0.36170698072938423,0.042039957474503786],"transform":[340.38852944828716,-58.91966522272131,118.39875359080357,684.0089377789295,972.9016141723532,145.55594755688992]}}},"exposed":false}},{"Value":{"tagged_value":{"OptionalColor":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}},"exposed":false}},{"Value":{"tagged_value":{"Gradient":{"stops":[[0.0,{"red":0.7176471,"green":0.28627452,"blue":0.16862746,"alpha":1.0}],[1.0,{"red":0.9098039,"green":0.6862745,"blue":0.27058825,"alpha":1.0}]],"gradient_type":"Linear","start":[0.03910157250347135,0.9695090157857073],"end":[0.36170698072938423,0.042039957474503786],"transform":[340.38852944828716,-58.91966522272131,118.39875359080357,684.0089377789295,972.9016141723532,145.55594755688992]}},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::FillNode"}},"visible":true,"skip_deduplication":false}],[85,{"inputs":[{"Value":{"tagged_value":{"GraphicGroup":{"instance":[],"transform":[],"alpha_blending":[],"source_node_id":[]}},"exposed":true}},{"Node":{"node_id":155,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[427,{"inputs":[{"Node":{"node_id":428,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"DVec2":[583.9293351067386,697.6163522012579]},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[206.6666666666667,70.66666666666666]},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[0.0,0.0]},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[0.5,0.5]},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":1}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":2}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":3}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":4}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":5}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::TransformNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[256,{"inputs":[{"Node":{"node_id":259,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"Fill":{"Gradient":{"stops":[[0.0,{"red":0.3764706,"green":0.23529412,"blue":0.20784314,"alpha":1.0}],[1.0,{"red":0.5058824,"green":0.26666668,"blue":0.20392157,"alpha":1.0}]],"gradient_type":"Linear","start":[0.19879202692409503,0.5201781689919184],"end":[0.8398128222157668,0.5168778892557565],"transform":[-149.7970504069467,-159.28457060198534,587.8340874439789,-510.0857997683857,879.0000000000035,834.0]}}},"exposed":false}},{"Value":{"tagged_value":{"OptionalColor":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}},"exposed":false}},{"Value":{"tagged_value":{"Gradient":{"stops":[[0.0,{"red":0.3764706,"green":0.23529412,"blue":0.20784314,"alpha":1.0}],[1.0,{"red":0.5058824,"green":0.26666668,"blue":0.20392157,"alpha":1.0}]],"gradient_type":"Linear","start":[0.19879202692409503,0.5201781689919184],"end":[0.8398128222157668,0.5168778892557565],"transform":[-149.7970504069467,-159.28457060198534,587.8340874439789,-510.0857997683857,879.0000000000035,834.0]}},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::FillNode"}},"visible":true,"skip_deduplication":false}],[287,{"inputs":[{"Value":{"tagged_value":{"VectorData":{"instance":[{"style":{"stroke":{"color":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0},"weight":0.0,"dash_lengths":[],"dash_offset":0.0,"cap":"Butt","join":"Miter","join_miter_limit":4.0,"align":"Center","transform":[1.0,0.0,0.0,1.0,0.0,0.0],"non_scaling":false,"paint_order":"StrokeAbove"},"fill":"None"},"colinear_manipulators":[],"point_domain":{"id":[],"position":[]},"segment_domain":{"id":[],"start_point":[],"end_point":[],"handles":[],"stroke":[]},"region_domain":{"id":[],"segment_range":[],"fill":[]},"upstream_graphic_group":null}],"transform":[[1.0,0.0,0.0,1.0,0.0,0.0]],"alpha_blending":[{"blend_mode":"Normal","opacity":1.0,"fill":1.0,"clip":false}],"source_node_id":[null]}},"exposed":true}},{"Value":{"tagged_value":{"VectorModification":{"points":{"add":[1,2,3,4,5,6,7],"remove":[],"delta":[[5,[904.5,283.46296296296293]],[3,[913.619341563786,134.1625514403292]],[6,[898.2777777777778,520.5]],[2,[934.9526748971192,114.67283950617282]],[1,[954.864197530864,116.14814814814812]],[4,[910.06378600823,174.98559670781898]],[7,[944.7962962962962,568.2037037037037]]]},"segments":{"add":[1,2,3,4,5,6,7],"remove":[],"start_point":[[4,4],[7,7],[6,6],[5,5],[1,1],[2,2],[3,3]],"end_point":[[7,1],[4,5],[5,6],[1,2],[2,3],[3,4],[6,7]],"handle_primary":[[2,[-9.481481481481635,1.8436213991769392]],[6,[0.0,0.0]],[3,[-2.2386831275719032,10.008230452674894]],[5,[-3.5555555555556566,34.37037037037038]],[4,[-0.7901234567891606,29.102880658436305]],[7,[0.0,0.0]],[1,[0.0,0.0]]],"handle_end":[[1,[9.481481481481635,-1.8436213991769392]],[7,[0.0,0.0]],[2,[2.677546335770103,-11.970207148147836]],[3,[0.370701337431683,-13.654165928739786]],[4,[3.5555555555554292,-34.37037037037038]],[5,[0.0,0.0]],[6,[0.0,0.0]]],"stroke":[[7,0],[6,0],[4,0],[5,0],[3,0],[1,0],[2,0]]},"regions":{"add":[0],"remove":[],"segment_range":[[0,{"start":1,"end":7}]],"fill":[[0,0]]},"add_g1_continuous":[],"remove_g1_continuous":[]}},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::vector_data::modification::VectorModification","alias":null}},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::vector_data::modification::PathModifyNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[318,{"inputs":[{"Node":{"node_id":319,"output_index":0,"lambda":false}},{"Node":{"node_id":323,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[178,{"inputs":[{"Node":{"node_id":179,"output_index":0,"lambda":false}},{"Node":{"node_id":244,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[16821952675128396603,{"inputs":[{"Node":{"node_id":3885641499621884510,"output_index":0,"lambda":false}},{"Node":{"node_id":36935169817407978,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[36935169817407978,{"inputs":[{"Node":{"node_id":15848750910363784662,"output_index":0,"lambda":false}},{"Node":{"node_id":11279424538712841875,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[411,{"inputs":[{"Node":{"node_id":412,"output_index":0,"lambda":false}},{"Node":{"node_id":415,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[442,{"inputs":[{"Node":{"node_id":445,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"Fill":{"Gradient":{"stops":[[0.0,{"red":0.50980395,"green":0.26666668,"blue":0.2,"alpha":1.0}],[0.14354235440709684,{"red":0.5882353,"green":0.30588236,"blue":0.20392157,"alpha":1.0}],[0.5,{"red":0.6784314,"green":0.33333334,"blue":0.20784314,"alpha":1.0}],[1.0,{"red":0.76953125,"green":0.4772935,"blue":0.21943665,"alpha":1.0}]],"gradient_type":"Linear","start":[0.5063739376770537,0.01352247091271197],"end":[0.5049575070821529,1.015819012091678],"transform":[1412.0,0.0,0.0,231.4807092004588,351.0000000000001,588.5192907995412]}}},"exposed":false}},{"Value":{"tagged_value":{"OptionalColor":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}},"exposed":false}},{"Value":{"tagged_value":{"Gradient":{"stops":[[0.0,{"red":0.50980395,"green":0.26666668,"blue":0.2,"alpha":1.0}],[0.14354235440709684,{"red":0.5882353,"green":0.30588236,"blue":0.20392157,"alpha":1.0}],[0.5,{"red":0.6784314,"green":0.33333334,"blue":0.20784314,"alpha":1.0}],[1.0,{"red":0.76953125,"green":0.4772935,"blue":0.21943665,"alpha":1.0}]],"gradient_type":"Linear","start":[0.5063739376770537,0.01352247091271197],"end":[0.5049575070821529,1.015819012091678],"transform":[1412.0,0.0,0.0,231.4807092004588,351.0000000000001,588.5192907995412]}},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::FillNode"}},"visible":true,"skip_deduplication":false}],[14205611254835578455,{"inputs":[{"Node":{"node_id":14335659566300901430,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"DVec2":[-1339.7031164295145,65.50112655997924]},"exposed":false}},{"Value":{"tagged_value":{"F64":-0.042402443},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[4.244995417859058,0.8619572141015625]},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[4.90381723950611e-18,0.0]},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[0.0,0.0]},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":1}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":2}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":3}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":4}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":5}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::TransformNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[100,{"inputs":[{"Value":{"tagged_value":{"VectorData":{"instance":[{"style":{"stroke":{"color":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0},"weight":0.0,"dash_lengths":[],"dash_offset":0.0,"cap":"Butt","join":"Miter","join_miter_limit":4.0,"align":"Center","transform":[1.0,0.0,0.0,1.0,0.0,0.0],"non_scaling":false,"paint_order":"StrokeAbove"},"fill":"None"},"colinear_manipulators":[],"point_domain":{"id":[],"position":[]},"segment_domain":{"id":[],"start_point":[],"end_point":[],"handles":[],"stroke":[]},"region_domain":{"id":[],"segment_range":[],"fill":[]},"upstream_graphic_group":null}],"transform":[[1.0,0.0,0.0,1.0,0.0,0.0]],"alpha_blending":[{"blend_mode":"Normal","opacity":1.0,"fill":1.0,"clip":false}],"source_node_id":[null]}},"exposed":true}},{"Value":{"tagged_value":{"VectorModification":{"points":{"add":[1,2,3,4],"remove":[],"delta":[[3,[1.0,1.0]],[1,[-0.03917736275965821,1.5785983631388945e-15]],[4,[0.0,1.0]],[2,[0.9501947601024644,0.0]]]},"segments":{"add":[1,2,3,4],"remove":[],"start_point":[[4,4],[3,3],[1,1],[2,2]],"end_point":[[4,1],[1,2],[3,4],[2,3]],"handle_primary":[[3,[0.0,0.0]],[4,[0.0,0.0]],[1,[0.0,0.0]],[2,[0.0,0.0]]],"handle_end":[[1,[0.0,0.0]],[2,[0.0,0.0]],[3,[0.0,0.0]],[4,[0.0,0.0]]],"stroke":[[3,0],[4,0],[1,0],[2,0]]},"regions":{"add":[0],"remove":[],"segment_range":[[0,{"start":1,"end":4}]],"fill":[[0,0]]},"add_g1_continuous":[],"remove_g1_continuous":[]}},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::vector_data::modification::VectorModification","alias":null}},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::vector_data::modification::PathModifyNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[162,{"inputs":[{"Node":{"node_id":164,"output_index":0,"lambda":false}},{"Node":{"node_id":274,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[9422094883894860610,{"inputs":[{"Value":{"tagged_value":{"VectorData":{"instance":[{"style":{"stroke":{"color":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0},"weight":0.0,"dash_lengths":[],"dash_offset":0.0,"cap":"Butt","join":"Miter","join_miter_limit":4.0,"align":"Center","transform":[1.0,0.0,0.0,1.0,0.0,0.0],"non_scaling":false,"paint_order":"StrokeAbove"},"fill":"None"},"colinear_manipulators":[],"point_domain":{"id":[],"position":[]},"segment_domain":{"id":[],"start_point":[],"end_point":[],"handles":[],"stroke":[]},"region_domain":{"id":[],"segment_range":[],"fill":[]},"upstream_graphic_group":null}],"transform":[[1.0,0.0,0.0,1.0,0.0,0.0]],"alpha_blending":[{"blend_mode":"Normal","opacity":1.0,"fill":1.0,"clip":false}],"source_node_id":[null]}},"exposed":true}},{"Value":{"tagged_value":{"VectorModification":{"points":{"add":[1,2,3,4,5,6],"remove":[],"delta":[[1,[527.0733882030179,547.0898491083676]],[2,[500.121399176955,531.6385459533608]],[4,[495.38065843621376,614.5137174211251]],[5,[541.9979423868313,611.7921810699589]],[3,[481.882716049383,533.8333333333337]],[6,[530.2777777777774,564.9115226337451]]]},"segments":{"add":[1,2,3,4,5,6],"remove":[],"start_point":[[2,2],[4,4],[1,1],[3,3],[5,5],[6,6]],"end_point":[[5,6],[6,1],[4,5],[1,2],[2,3],[3,4]],"handle_primary":[[6,[0.0,0.0]],[3,[0.0,0.0]],[1,[0.0,0.0]],[4,[0.0,0.0]],[5,[0.0,0.0]],[2,[5.684341886080804e-14,0.0]]],"handle_end":[[2,[0.0,0.0]],[4,[0.0,0.0]],[1,[16.644617182340255,-0.4357059391355733]],[3,[0.0,0.0]],[5,[0.0,0.0]],[6,[0.0,0.0]]],"stroke":[[5,0],[3,0],[1,0],[2,0],[4,0],[6,0]]},"regions":{"add":[0],"remove":[],"segment_range":[[0,{"start":1,"end":6}]],"fill":[[0,0]]},"add_g1_continuous":[],"remove_g1_continuous":[]}},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::vector_data::modification::VectorModification","alias":null}},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::vector_data::modification::PathModifyNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[193,{"inputs":[{"Node":{"node_id":191,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"DVec2":[965.2687196297846,544.9034434174798]},"exposed":false}},{"Value":{"tagged_value":{"F64":-1.7199705},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[17.59013219658168,55.471003102038694]},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[-0.12623993859136257,0.0]},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[0.5,0.5]},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":1}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":2}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":3}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":4}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":5}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::TransformNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[224,{"inputs":[{"Value":{"tagged_value":{"VectorData":{"instance":[{"style":{"stroke":{"color":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0},"weight":0.0,"dash_lengths":[],"dash_offset":0.0,"cap":"Butt","join":"Miter","join_miter_limit":4.0,"align":"Center","transform":[1.0,0.0,0.0,1.0,0.0,0.0],"non_scaling":false,"paint_order":"StrokeAbove"},"fill":"None"},"colinear_manipulators":[],"point_domain":{"id":[],"position":[]},"segment_domain":{"id":[],"start_point":[],"end_point":[],"handles":[],"stroke":[]},"region_domain":{"id":[],"segment_range":[],"fill":[]},"upstream_graphic_group":null}],"transform":[[1.0,0.0,0.0,1.0,0.0,0.0]],"alpha_blending":[{"blend_mode":"Normal","opacity":1.0,"fill":1.0,"clip":false}],"source_node_id":[null]}},"exposed":true}},{"Value":{"tagged_value":{"VectorModification":{"points":{"add":[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19],"remove":[],"delta":[[18,[876.3518518518517,620.2201646090534]],[19,[742.2503429355281,620.0445816186556]],[17,[877.4053497942385,607.1831275720164]],[11,[830.3930041152262,568.5987654320987]],[15,[874.7716049382715,566.491769547325]],[5,[819.0679012345677,520.2695473251028]],[14,[864.6316872427983,543.3148148148147]],[12,[837.1090534979422,574.2613168724279]],[10,[827.364197530864,555.9567901234567]],[7,[817.6193415637858,545.6851851851851]],[3,[779.9567901234567,598.5451457288699]],[8,[825.5205761316871,544.7633744855966]],[4,[790.0967078189299,592.170781893004]],[9,[825.2572016460904,550.6893004115226]],[2,[773.1090534979423,610.0802469135801]],[16,[858.4423868312756,599.2818930041151]],[13,[852.648148148148,535.9403292181069]],[1,[741.4602194787379,611.9677640603566]],[6,[819.3312757201645,537.1255144032921]]]},"segments":{"add":[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19],"remove":[],"start_point":[[6,6],[9,9],[8,8],[3,3],[11,11],[14,14],[17,17],[19,19],[15,15],[18,18],[2,2],[5,5],[12,12],[4,4],[10,10],[16,16],[7,7],[1,1],[13,13]],"end_point":[[9,10],[5,6],[2,3],[11,12],[10,11],[17,18],[3,4],[18,19],[12,13],[1,2],[15,16],[6,7],[13,14],[16,17],[14,15],[7,8],[8,9],[4,5],[19,1]],"handle_primary":[[14,[3.68724279835385,7.90123456790127]],[16,[0.0,0.0]],[5,[0.0,0.0]],[12,[0.0,0.0]],[11,[0.658436213991763,2.1698525002639144]],[7,[1.4485596707819468,2.633744855967052]],[13,[0.0,0.0]],[18,[-1.843621399176982,1.975308641975289]],[3,[5.530864197530832,-1.8969975807218589]],[8,[0.0,0.0]],[10,[1.7119341563786747,1.316872427983526]],[17,[0.0,0.0]],[19,[-21.66213092273972,1.775584501863932]],[2,[4.609053497942341,-0.9218106995883772]],[6,[0.0,0.0]],[4,[1.0534979423869115,-4.345679012345613]],[1,[0.0,0.0]],[9,[0.0,0.0]],[15,[0.0,0.0]]],"handle_end":[[12,[-7.637860082304542,12.641975308641918]],[14,[0.0,0.0]],[8,[1.1851851851852189,-2.502057613168745]],[16,[-5.1358024691359105,-5.00411522633749]],[5,[-0.39506172839503506,-3.160493827160508]],[9,[-1.7119341563786747,-1.316872427983526]],[1,[-4.609053497942341,0.9218106995883772]],[18,[21.421124828532356,-1.7558299039781105]],[7,[-5.135802469135797,4.609053497942341]],[10,[-0.658436213991763,-2.1698525002639144]],[3,[-1.0534979423869115,4.345679012345613]],[19,[0.0,0.0]],[11,[-2.10699588477371,-0.3950617283951487]],[2,[-5.530864197530832,1.8969975807218589]],[6,[-1.4485596707819468,-2.633744855967052]],[13,[-3.68724279835385,-7.90123456790127]],[15,[2.765432098765359,-11.851851851851848]],[4,[-16.987654320987644,28.049382716049426]],[17,[1.843621399176982,-1.975308641975289]]],"stroke":[[15,0],[10,0],[8,0],[18,0],[2,0],[7,0],[17,0],[16,0],[4,0],[19,0],[11,0],[5,0],[9,0],[6,0],[3,0],[12,0],[1,0],[14,0],[13,0]]},"regions":{"add":[0],"remove":[],"segment_range":[[0,{"start":1,"end":19}]],"fill":[[0,0]]},"add_g1_continuous":[],"remove_g1_continuous":[]}},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::vector_data::modification::VectorModification","alias":null}},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::vector_data::modification::PathModifyNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[14579754335592291854,{"inputs":[{"Node":{"node_id":1644624352314732667,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"Fill":{"Gradient":{"stops":[[0.0,{"red":0.24313726,"green":0.18431373,"blue":0.19215687,"alpha":1.0}],[1.0,{"red":0.24313726,"green":0.18431373,"blue":0.19215687,"alpha":0.0}]],"gradient_type":"Radial","start":[0.49999999999999994,0.5000000000000009],"end":[0.9003149237651733,0.5000000000000009],"transform":[1153.5000000000016,0.0,0.0,116.99999999999352,390.5000000000018,782.9999999999995]}}},"exposed":false}},{"Value":{"tagged_value":{"OptionalColor":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}},"exposed":false}},{"Value":{"tagged_value":{"Gradient":{"stops":[[0.0,{"red":0.24313726,"green":0.18431373,"blue":0.19215687,"alpha":1.0}],[1.0,{"red":0.24313726,"green":0.18431373,"blue":0.19215687,"alpha":0.0}]],"gradient_type":"Radial","start":[0.49999999999999994,0.5000000000000009],"end":[0.9003149237651733,0.5000000000000009],"transform":[1153.5000000000016,0.0,0.0,116.99999999999352,390.5000000000018,782.9999999999995]}},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::FillNode"}},"visible":true,"skip_deduplication":false}],[7134154821675013808,{"inputs":[{"Node":{"node_id":408,"output_index":0,"lambda":false}},{"Node":{"node_id":14205611254835578455,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[457,{"inputs":[{"Value":{"tagged_value":{"VectorData":{"instance":[{"style":{"stroke":{"color":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0},"weight":0.0,"dash_lengths":[],"dash_offset":0.0,"cap":"Butt","join":"Miter","join_miter_limit":4.0,"align":"Center","transform":[1.0,0.0,0.0,1.0,0.0,0.0],"non_scaling":false,"paint_order":"StrokeAbove"},"fill":"None"},"colinear_manipulators":[],"point_domain":{"id":[],"position":[]},"segment_domain":{"id":[],"start_point":[],"end_point":[],"handles":[],"stroke":[]},"region_domain":{"id":[],"segment_range":[],"fill":[]},"upstream_graphic_group":null}],"transform":[[1.0,0.0,0.0,1.0,0.0,0.0]],"alpha_blending":[{"blend_mode":"Normal","opacity":1.0,"fill":1.0,"clip":false}],"source_node_id":[null]}},"exposed":true}},{"Value":{"tagged_value":{"VectorModification":{"points":{"add":[1,2,3],"remove":[],"delta":[[3,[129.38888888888889,628.0555555555557]],[2,[80.05555555555559,484.94444444444446]],[1,[-4.833333333333332,345.83333333333326]]]},"segments":{"add":[1,2],"remove":[],"start_point":[[2,2],[1,1]],"end_point":[[1,2],[2,3]],"handle_primary":[[1,[0.0,0.0]],[2,[32.038317168599576,69.73045501401077]]],"handle_end":[[1,[-45.33333333333338,-98.66666666666669]],[2,[0.0,0.0]]],"stroke":[[1,0],[2,0]]},"regions":{"add":[],"remove":[],"segment_range":[],"fill":[]},"add_g1_continuous":[],"remove_g1_continuous":[]}},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::vector_data::modification::VectorModification","alias":null}},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::vector_data::modification::PathModifyNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[115,{"inputs":[{"Value":{"tagged_value":{"VectorData":{"instance":[{"style":{"stroke":{"color":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0},"weight":0.0,"dash_lengths":[],"dash_offset":0.0,"cap":"Butt","join":"Miter","join_miter_limit":4.0,"align":"Center","transform":[1.0,0.0,0.0,1.0,0.0,0.0],"non_scaling":false,"paint_order":"StrokeAbove"},"fill":"None"},"colinear_manipulators":[],"point_domain":{"id":[],"position":[]},"segment_domain":{"id":[],"start_point":[],"end_point":[],"handles":[],"stroke":[]},"region_domain":{"id":[],"segment_range":[],"fill":[]},"upstream_graphic_group":null}],"transform":[[1.0,0.0,0.0,1.0,0.0,0.0]],"alpha_blending":[{"blend_mode":"Normal","opacity":1.0,"fill":1.0,"clip":false}],"source_node_id":[null]}},"exposed":true}},{"Value":{"tagged_value":{"VectorModification":{"points":{"add":[1,2,3,4],"remove":[],"delta":[[2,[1.0,0.0]],[4,[0.0,1.0]],[3,[1.0,1.0]],[1,[-0.04384002017081715,1.8188575645616826e-15]]]},"segments":{"add":[1,2,3,4],"remove":[],"start_point":[[3,3],[1,1],[2,2],[4,4]],"end_point":[[2,3],[3,4],[4,1],[1,2]],"handle_primary":[[2,[0.0,0.0]],[4,[0.0,0.0]],[3,[0.0,0.0]],[1,[0.0,0.0]]],"handle_end":[[1,[0.0,0.0]],[4,[0.0,0.0]],[2,[0.0,0.0]],[3,[0.0,0.0]]],"stroke":[[4,0],[1,0],[3,0],[2,0]]},"regions":{"add":[0],"remove":[],"segment_range":[[0,{"start":1,"end":4}]],"fill":[[0,0]]},"add_g1_continuous":[],"remove_g1_continuous":[]}},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::vector_data::modification::VectorModification","alias":null}},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::vector_data::modification::PathModifyNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[6710503329407068595,{"inputs":[{"Node":{"node_id":16831252454255560063,"output_index":0,"lambda":false}},{"Node":{"node_id":10486443711686704000,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[9570557034533539493,{"inputs":[{"Value":{"tagged_value":{"VectorData":{"instance":[{"style":{"stroke":{"color":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0},"weight":0.0,"dash_lengths":[],"dash_offset":0.0,"cap":"Butt","join":"Miter","join_miter_limit":4.0,"align":"Center","transform":[1.0,0.0,0.0,1.0,0.0,0.0],"non_scaling":false,"paint_order":"StrokeAbove"},"fill":"None"},"colinear_manipulators":[],"point_domain":{"id":[],"position":[]},"segment_domain":{"id":[],"start_point":[],"end_point":[],"handles":[],"stroke":[]},"region_domain":{"id":[],"segment_range":[],"fill":[]},"upstream_graphic_group":null}],"transform":[[1.0,0.0,0.0,1.0,0.0,0.0]],"alpha_blending":[{"blend_mode":"Normal","opacity":1.0,"fill":1.0,"clip":false}],"source_node_id":[null]}},"exposed":true}},{"Value":{"tagged_value":{"VectorModification":{"points":{"add":[1,2,3,4,5,6],"remove":[],"delta":[[1,[740.3456790123458,588.2030178326476]],[4,[789.2187928669412,601.4967933823075]],[5,[767.1831275720166,614.1625514403293]],[6,[751.1172839506169,611.1776406035664]],[3,[794.0473251028808,582.3820301783265]],[2,[755.3312757201647,586.2448559670783]]]},"segments":{"add":[1,2,3,4,5,6],"remove":[],"start_point":[[6,6],[3,3],[5,5],[2,2],[1,1],[4,4]],"end_point":[[5,6],[1,2],[2,3],[4,5],[3,4],[6,1]],"handle_primary":[[4,[-8.427983539094612,8.539557783673331]],[3,[0.0,0.0]],[1,[0.0,0.0]],[2,[9.481481481481524,0.4824094931645959]],[5,[-11.149519890260535,0.2794994541025062]],[6,[0.0,0.0]]],"handle_end":[[2,[-9.305898491083669,-1.1412894375856697]],[5,[0.0,0.0]],[4,[11.149519890260535,-0.2794994541025062]],[1,[-9.481481481481524,-0.4824094931645959]],[6,[0.0,0.0]],[3,[8.427983539094612,-8.539557783673331]]],"stroke":[[4,0],[5,0],[3,0],[6,0],[1,0],[2,0]]},"regions":{"add":[0],"remove":[],"segment_range":[[0,{"start":1,"end":6}]],"fill":[[0,0]]},"add_g1_continuous":[],"remove_g1_continuous":[]}},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::vector_data::modification::VectorModification","alias":null}},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::vector_data::modification::PathModifyNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[5175066652268973319,{"inputs":[{"Value":{"tagged_value":{"VectorData":{"instance":[{"style":{"stroke":{"color":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0},"weight":0.0,"dash_lengths":[],"dash_offset":0.0,"cap":"Butt","join":"Miter","join_miter_limit":4.0,"align":"Center","transform":[1.0,0.0,0.0,1.0,0.0,0.0],"non_scaling":false,"paint_order":"StrokeAbove"},"fill":"None"},"colinear_manipulators":[],"point_domain":{"id":[],"position":[]},"segment_domain":{"id":[],"start_point":[],"end_point":[],"handles":[],"stroke":[]},"region_domain":{"id":[],"segment_range":[],"fill":[]},"upstream_graphic_group":null}],"transform":[[1.0,0.0,0.0,1.0,0.0,0.0]],"alpha_blending":[{"blend_mode":"Normal","opacity":1.0,"fill":1.0,"clip":false}],"source_node_id":[null]}},"exposed":true}},{"Value":{"tagged_value":{"VectorModification":{"points":{"add":[1,2,3,4],"remove":[],"delta":[[1,[-0.09890842105846484,-0.06578040790199424]],[3,[1.0362898771040632,0.9994054840058096]],[2,[0.8379395417513005,-0.05940639119491883]],[4,[0.0,1.0]]]},"segments":{"add":[1,2,3,4],"remove":[],"start_point":[[3,3],[2,2],[1,1],[4,4]],"end_point":[[2,3],[3,4],[4,1],[1,2]],"handle_primary":[[3,[0.0,0.0]],[4,[0.0,0.0]],[1,[0.0,0.0]],[2,[0.0,0.0]]],"handle_end":[[4,[0.0,0.0]],[3,[0.0,0.0]],[1,[0.0,0.0]],[2,[0.0,0.0]]],"stroke":[[3,0],[4,0],[1,0],[2,0]]},"regions":{"add":[0],"remove":[],"segment_range":[[0,{"start":1,"end":4}]],"fill":[[0,0]]},"add_g1_continuous":[],"remove_g1_continuous":[]}},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::vector_data::modification::VectorModification","alias":null}},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::vector_data::modification::PathModifyNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[177,{"inputs":[{"Node":{"node_id":178,"output_index":0,"lambda":false}},{"Node":{"node_id":238,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[208,{"inputs":[{"Node":{"node_id":212,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"Fill":{"Solid":{"red":0.24313726,"green":0.18431373,"blue":0.19215687,"alpha":1.0}}},"exposed":false}},{"Value":{"tagged_value":{"OptionalColor":{"red":0.24313726,"green":0.18431373,"blue":0.19215687,"alpha":1.0}},"exposed":false}},{"Value":{"tagged_value":{"Gradient":{"stops":[[0.0,{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}],[1.0,{"red":1.0,"green":1.0,"blue":1.0,"alpha":1.0}]],"gradient_type":"Linear","start":[0.0,0.5],"end":[1.0,0.5],"transform":[1.0,0.0,0.0,1.0,0.0,0.0]}},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::FillNode"}},"visible":true,"skip_deduplication":false}],[15277819403265847073,{"inputs":[{"Value":{"tagged_value":{"GraphicGroup":{"instance":[],"transform":[],"alpha_blending":[],"source_node_id":[]}},"exposed":true}},{"Node":{"node_id":4913361824430066698,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[99,{"inputs":[{"Node":{"node_id":100,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"DVec2":[827.4018790826805,704.5]},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[74.57030178326477,63.99999999999989]},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[0.0,0.0]},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[0.5,0.5]},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":1}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":2}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":3}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":4}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":5}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::TransformNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[161,{"inputs":[{"Node":{"node_id":162,"output_index":0,"lambda":false}},{"Node":{"node_id":168,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[17245613731534563958,{"inputs":[{"Value":{"tagged_value":{"VectorData":{"instance":[{"style":{"stroke":{"color":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0},"weight":0.0,"dash_lengths":[],"dash_offset":0.0,"cap":"Butt","join":"Miter","join_miter_limit":4.0,"align":"Center","transform":[1.0,0.0,0.0,1.0,0.0,0.0],"non_scaling":false,"paint_order":"StrokeAbove"},"fill":"None"},"colinear_manipulators":[],"point_domain":{"id":[],"position":[]},"segment_domain":{"id":[],"start_point":[],"end_point":[],"handles":[],"stroke":[]},"region_domain":{"id":[],"segment_range":[],"fill":[]},"upstream_graphic_group":null}],"transform":[[1.0,0.0,0.0,1.0,0.0,0.0]],"alpha_blending":[{"blend_mode":"Normal","opacity":1.0,"fill":1.0,"clip":false}],"source_node_id":[null]}},"exposed":true}},{"Value":{"tagged_value":{"VectorModification":{"points":{"add":[1,2,3,4],"remove":[],"delta":[[1,[0.5,0.0]],[2,[1.0,0.5]],[3,[0.5,1.0]],[4,[0.0,0.5]]]},"segments":{"add":[1,2,3,4],"remove":[],"start_point":[[4,4],[2,2],[1,1],[3,3]],"end_point":[[3,4],[2,3],[1,2],[4,1]],"handle_primary":[[2,[0.0,0.27589238888950707]],[1,[0.27589238888950707,0.0]],[3,[-0.275892388889507,0.0]],[4,[0.0,-0.275892388889507]]],"handle_end":[[1,[0.0,-0.275892388889507]],[2,[0.27589238888950707,0.0]],[3,[0.0,0.27589238888950707]],[4,[-0.275892388889507,0.0]]],"stroke":[[1,0],[4,0],[2,0],[3,0]]},"regions":{"add":[0],"remove":[],"segment_range":[[0,{"start":1,"end":4}]],"fill":[[0,0]]},"add_g1_continuous":[],"remove_g1_continuous":[]}},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::vector_data::modification::VectorModification","alias":null}},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::vector_data::modification::PathModifyNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[394,{"inputs":[{"Value":{"tagged_value":{"GraphicGroup":{"instance":[],"transform":[],"alpha_blending":[],"source_node_id":[]}},"exposed":true}},{"Node":{"node_id":404,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[254,{"inputs":[{"Value":{"tagged_value":{"VectorData":{"instance":[{"style":{"stroke":{"color":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0},"weight":0.0,"dash_lengths":[],"dash_offset":0.0,"cap":"Butt","join":"Miter","join_miter_limit":4.0,"align":"Center","transform":[1.0,0.0,0.0,1.0,0.0,0.0],"non_scaling":false,"paint_order":"StrokeAbove"},"fill":"None"},"colinear_manipulators":[],"point_domain":{"id":[],"position":[]},"segment_domain":{"id":[],"start_point":[],"end_point":[],"handles":[],"stroke":[]},"region_domain":{"id":[],"segment_range":[],"fill":[]},"upstream_graphic_group":null}],"transform":[[1.0,0.0,0.0,1.0,0.0,0.0]],"alpha_blending":[{"blend_mode":"Normal","opacity":1.0,"fill":1.0,"clip":false}],"source_node_id":[null]}},"exposed":true}},{"Value":{"tagged_value":{"VectorModification":{"points":{"add":[1,2,3,4,5],"remove":[],"delta":[[1,[887.506172839506,620.2933732713938]],[5,[910.5246913580244,598.202467627757]],[2,[999.8086419753088,626.6728395061729]],[4,[1004.3518518518516,600.7306004720272]],[3,[1012.648148148148,620.7933732713938]]]},"segments":{"add":[1,2,3,4,5],"remove":[],"start_point":[[2,2],[3,3],[5,5],[1,1],[4,4]],"end_point":[[3,4],[5,1],[1,2],[4,5],[2,3]],"handle_primary":[[4,[0.0,0.0]],[3,[0.0,0.0]],[5,[0.0,0.0]],[1,[0.0,0.0]],[2,[0.0,0.0]]],"handle_end":[[4,[0.0,0.0]],[2,[0.0,0.0]],[1,[-43.25925925925878,-1.3827160493827932]],[5,[0.0,0.0]],[3,[0.0,0.0]]],"stroke":[[1,0],[3,0],[2,0],[5,0],[4,0]]},"regions":{"add":[0],"remove":[],"segment_range":[[0,{"start":1,"end":5}]],"fill":[[0,0]]},"add_g1_continuous":[],"remove_g1_continuous":[]}},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::vector_data::modification::VectorModification","alias":null}},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::vector_data::modification::PathModifyNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[83,{"inputs":[{"Node":{"node_id":85,"output_index":0,"lambda":false}},{"Node":{"node_id":117,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[114,{"inputs":[{"Node":{"node_id":115,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"DVec2":[926.5490676442352,657.3888888888888]},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[97.92901234567933,111.111111111111]},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[0.0,0.0]},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[0.5,0.5]},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":1}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":2}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":3}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":4}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":5}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::TransformNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[487,{"inputs":[{"Node":{"node_id":491,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"Fill":{"Gradient":{"stops":[[0.0,{"red":0.5546875,"green":0.30678105,"blue":0.24050903,"alpha":1.0}],[1.0,{"red":0.41015625,"green":0.26908994,"blue":0.22590637,"alpha":1.0}]],"gradient_type":"Linear","start":[0.6510643291021605,0.0026199374677413345],"end":[0.6510643291021605,0.8853991419751945],"transform":[171.95146556847033,0.0,0.0,739.7405389344278,1183.0485344315307,119.06192604563851]}}},"exposed":false}},{"Value":{"tagged_value":{"OptionalColor":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}},"exposed":false}},{"Value":{"tagged_value":{"Gradient":{"stops":[[0.0,{"red":0.5546875,"green":0.30678105,"blue":0.24050903,"alpha":1.0}],[1.0,{"red":0.41015625,"green":0.26908994,"blue":0.22590637,"alpha":1.0}]],"gradient_type":"Linear","start":[0.6510643291021605,0.0026199374677413345],"end":[0.6510643291021605,0.8853991419751945],"transform":[171.95146556847033,0.0,0.0,739.7405389344278,1183.0485344315307,119.06192604563851]}},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::FillNode"}},"visible":true,"skip_deduplication":false}],[316,{"inputs":[{"Value":{"tagged_value":{"VectorData":{"instance":[{"style":{"stroke":{"color":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0},"weight":0.0,"dash_lengths":[],"dash_offset":0.0,"cap":"Butt","join":"Miter","join_miter_limit":4.0,"align":"Center","transform":[1.0,0.0,0.0,1.0,0.0,0.0],"non_scaling":false,"paint_order":"StrokeAbove"},"fill":"None"},"colinear_manipulators":[],"point_domain":{"id":[],"position":[]},"segment_domain":{"id":[],"start_point":[],"end_point":[],"handles":[],"stroke":[]},"region_domain":{"id":[],"segment_range":[],"fill":[]},"upstream_graphic_group":null}],"transform":[[1.0,0.0,0.0,1.0,0.0,0.0]],"alpha_blending":[{"blend_mode":"Normal","opacity":1.0,"fill":1.0,"clip":false}],"source_node_id":[null]}},"exposed":true}},{"Value":{"tagged_value":{"VectorModification":{"points":{"add":[1,2,3,4,5,6],"remove":[],"delta":[[2,[755.3312757201647,586.2448559670783]],[5,[767.1831275720166,614.1625514403293]],[4,[789.2187928669412,601.4967933823075]],[6,[751.1172839506169,611.1776406035664]],[1,[740.3456790123458,588.2030178326476]],[3,[794.0473251028808,582.3820301783265]]]},"segments":{"add":[1,2,3,4,5,6],"remove":[],"start_point":[[4,4],[1,1],[6,6],[3,3],[2,2],[5,5]],"end_point":[[6,1],[4,5],[2,3],[1,2],[5,6],[3,4]],"handle_primary":[[2,[9.481481481481524,0.4824094931645959]],[1,[0.0,0.0]],[5,[-11.149519890260535,0.2794994541025062]],[6,[0.0,0.0]],[3,[0.0,0.0]],[4,[-8.427983539094612,8.539557783673331]]],"handle_end":[[2,[-9.305898491083669,-1.1412894375856697]],[4,[11.149519890260535,-0.2794994541025062]],[6,[0.0,0.0]],[5,[0.0,0.0]],[1,[-9.481481481481524,-0.4824094931645959]],[3,[8.427983539094612,-8.539557783673331]]],"stroke":[[2,0],[6,0],[5,0],[3,0],[4,0],[1,0]]},"regions":{"add":[0],"remove":[],"segment_range":[[0,{"start":1,"end":6}]],"fill":[[0,0]]},"add_g1_continuous":[],"remove_g1_continuous":[]}},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::vector_data::modification::VectorModification","alias":null}},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::vector_data::modification::PathModifyNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[97478832511923699,{"inputs":[{"Node":{"node_id":2999157202967297847,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"DVec2":[486.78967826851385,539.8989473007496]},"exposed":false}},{"Value":{"tagged_value":{"F64":-0.14917418},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[24.603566707484493,77.5880766500041]},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[-0.12623993859136096,0.0]},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[0.5,0.5]},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":1}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":2}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":3}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":4}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":5}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::TransformNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[176,{"inputs":[{"Node":{"node_id":177,"output_index":0,"lambda":false}},{"Node":{"node_id":232,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[12717405604755313921,{"inputs":[{"Value":{"tagged_value":{"GraphicGroup":{"instance":[],"transform":[],"alpha_blending":[],"source_node_id":[]}},"exposed":true}},{"Node":{"node_id":15483449862348058100,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[1644624352314732667,{"inputs":[{"Node":{"node_id":3930114406985796561,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"DVec2":[337.1982047610469,692.7466487935636]},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[50.0,50.0]},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[0.0,0.0]},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[0.5,0.5]},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":1}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":2}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":3}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":4}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":5}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::TransformNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[409,{"inputs":[{"Value":{"tagged_value":{"GraphicGroup":{"instance":[],"transform":[],"alpha_blending":[],"source_node_id":[]}},"exposed":true}},{"Node":{"node_id":442,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[238,{"inputs":[{"Node":{"node_id":242,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"Fill":{"Solid":{"red":0.5058824,"green":0.26666668,"blue":0.20392157,"alpha":1.0}}},"exposed":false}},{"Value":{"tagged_value":{"OptionalColor":{"red":0.5058824,"green":0.26666668,"blue":0.20392157,"alpha":1.0}},"exposed":false}},{"Value":{"tagged_value":{"Gradient":{"stops":[[0.0,{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}],[1.0,{"red":1.0,"green":1.0,"blue":1.0,"alpha":1.0}]],"gradient_type":"Linear","start":[0.0,0.5],"end":[1.0,0.5],"transform":[1.0,0.0,0.0,1.0,0.0,0.0]}},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::FillNode"}},"visible":true,"skip_deduplication":false}],[3707802522175443254,{"inputs":[{"Node":{"node_id":10278740841813346388,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"Fill":{"Solid":{"red":0.3764706,"green":0.23529412,"blue":0.20784314,"alpha":1.0}}},"exposed":false}},{"Value":{"tagged_value":{"OptionalColor":{"red":0.3764706,"green":0.23529412,"blue":0.20784314,"alpha":1.0}},"exposed":false}},{"Value":{"tagged_value":{"Gradient":{"stops":[[0.0,{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}],[1.0,{"red":1.0,"green":1.0,"blue":1.0,"alpha":1.0}]],"gradient_type":"Linear","start":[0.0,0.5],"end":[1.0,0.5],"transform":[1.0,0.0,0.0,1.0,0.0,0.0]}},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::FillNode"}},"visible":true,"skip_deduplication":false}],[440,{"inputs":[{"Value":{"tagged_value":{"VectorData":{"instance":[{"style":{"stroke":{"color":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0},"weight":0.0,"dash_lengths":[],"dash_offset":0.0,"cap":"Butt","join":"Miter","join_miter_limit":4.0,"align":"Center","transform":[1.0,0.0,0.0,1.0,0.0,0.0],"non_scaling":false,"paint_order":"StrokeAbove"},"fill":"None"},"colinear_manipulators":[],"point_domain":{"id":[],"position":[]},"segment_domain":{"id":[],"start_point":[],"end_point":[],"handles":[],"stroke":[]},"region_domain":{"id":[],"segment_range":[],"fill":[]},"upstream_graphic_group":null}],"transform":[[1.0,0.0,0.0,1.0,0.0,0.0]],"alpha_blending":[{"blend_mode":"Normal","opacity":1.0,"fill":1.0,"clip":false}],"source_node_id":[null]}},"exposed":true}},{"Value":{"tagged_value":{"VectorModification":{"points":{"add":[1,2,3,4],"remove":[],"delta":[[2,[1.0,0.0]],[4,[0.0387096774193552,1.0]],[1,[0.0,0.0]],[3,[1.035483870967742,1.0]]]},"segments":{"add":[1,2,3,4],"remove":[],"start_point":[[3,3],[2,2],[1,1],[4,4]],"end_point":[[2,3],[1,2],[4,1],[3,4]],"handle_primary":[[1,[0.0,0.0]],[2,[0.0,0.0]],[3,[0.0,0.0]],[4,[0.0,0.0]]],"handle_end":[[3,[0.0,0.0]],[4,[0.0,0.0]],[1,[0.0,0.0]],[2,[0.0,0.0]]],"stroke":[[2,0],[4,0],[1,0],[3,0]]},"regions":{"add":[0],"remove":[],"segment_range":[[0,{"start":1,"end":4}]],"fill":[[0,0]]},"add_g1_continuous":[],"remove_g1_continuous":[]}},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::vector_data::modification::VectorModification","alias":null}},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::vector_data::modification::PathModifyNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[9603838021022368374,{"inputs":[{"Value":{"tagged_value":{"VectorData":{"instance":[{"style":{"stroke":{"color":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0},"weight":0.0,"dash_lengths":[],"dash_offset":0.0,"cap":"Butt","join":"Miter","join_miter_limit":4.0,"align":"Center","transform":[1.0,0.0,0.0,1.0,0.0,0.0],"non_scaling":false,"paint_order":"StrokeAbove"},"fill":"None"},"colinear_manipulators":[],"point_domain":{"id":[],"position":[]},"segment_domain":{"id":[],"start_point":[],"end_point":[],"handles":[],"stroke":[]},"region_domain":{"id":[],"segment_range":[],"fill":[]},"upstream_graphic_group":null}],"transform":[[1.0,0.0,0.0,1.0,0.0,0.0]],"alpha_blending":[{"blend_mode":"Normal","opacity":1.0,"fill":1.0,"clip":false}],"source_node_id":[null]}},"exposed":true}},{"Value":{"tagged_value":{"VectorModification":{"points":{"add":[1,2,3,4,5,6,7],"remove":[],"delta":[[1,[744.3996087994717,586.9732002235432]],[5,[710.9477975918305,613.6358024691357]],[3,[698.0912208504803,600.3792866941013]],[2,[734.9571457603006,587.5194584158918]],[4,[706.1680384087791,607.8415637860082]],[7,[779.7592592592597,612.6204267490609]],[6,[729.3449931412895,610.3875171467763]]]},"segments":{"add":[1,2,3,4,5,6,7],"remove":[],"start_point":[[1,1],[7,7],[4,4],[2,2],[3,3],[6,6],[5,5]],"end_point":[[7,1],[5,6],[3,4],[2,3],[1,2],[6,7],[4,5]],"handle_primary":[[5,[7.452522481329197,2.721536351166037]],[1,[0.0,0.0]],[7,[0.0,0.0]],[4,[2.1947873799731497,4.691071467853249]],[6,[15.119646395366544,2.853223593964344]],[3,[0.0,0.0]],[2,[0.0,0.0]]],"handle_end":[[7,[9.28638926992835,13.56378600823075]],[2,[6.496570644718986,-11.149519890260422]],[6,[0.0,0.0]],[3,[-2.494608558449272,-5.331900091455282]],[4,null],[5,null],[1,[0.0,0.0]]],"stroke":[[1,0],[7,0],[4,0],[3,0],[2,0],[5,0],[6,0]]},"regions":{"add":[0],"remove":[],"segment_range":[[0,{"start":1,"end":7}]],"fill":[[0,0]]},"add_g1_continuous":[],"remove_g1_continuous":[]}},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::vector_data::modification::VectorModification","alias":null}},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::vector_data::modification::PathModifyNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[471,{"inputs":[{"Node":{"node_id":475,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"Fill":{"Solid":{"red":0.24313726,"green":0.18431373,"blue":0.19215687,"alpha":1.0}}},"exposed":false}},{"Value":{"tagged_value":{"OptionalColor":{"red":0.24313726,"green":0.18431373,"blue":0.19215687,"alpha":1.0}},"exposed":false}},{"Value":{"tagged_value":{"Gradient":{"stops":[[0.0,{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}],[1.0,{"red":1.0,"green":1.0,"blue":1.0,"alpha":1.0}]],"gradient_type":"Linear","start":[0.0,0.5],"end":[1.0,0.5],"transform":[1.0,0.0,0.0,1.0,0.0,0.0]}},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::FillNode"}},"visible":true,"skip_deduplication":false}],[300,{"inputs":[{"Node":{"node_id":304,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"Fill":{"Solid":{"red":0.24313726,"green":0.18431373,"blue":0.19215687,"alpha":1.0}}},"exposed":false}},{"Value":{"tagged_value":{"OptionalColor":{"red":0.24313726,"green":0.18431373,"blue":0.19215687,"alpha":1.0}},"exposed":false}},{"Value":{"tagged_value":{"Gradient":{"stops":[[0.0,{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}],[1.0,{"red":1.0,"green":1.0,"blue":1.0,"alpha":1.0}]],"gradient_type":"Linear","start":[0.0,0.5],"end":[1.0,0.5],"transform":[1.0,0.0,0.0,1.0,0.0,0.0]}},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::FillNode"}},"visible":true,"skip_deduplication":false}],[331,{"inputs":[{"Value":{"tagged_value":{"VectorData":{"instance":[{"style":{"stroke":{"color":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0},"weight":0.0,"dash_lengths":[],"dash_offset":0.0,"cap":"Butt","join":"Miter","join_miter_limit":4.0,"align":"Center","transform":[1.0,0.0,0.0,1.0,0.0,0.0],"non_scaling":false,"paint_order":"StrokeAbove"},"fill":"None"},"colinear_manipulators":[],"point_domain":{"id":[],"position":[]},"segment_domain":{"id":[],"start_point":[],"end_point":[],"handles":[],"stroke":[]},"region_domain":{"id":[],"segment_range":[],"fill":[]},"upstream_graphic_group":null}],"transform":[[1.0,0.0,0.0,1.0,0.0,0.0]],"alpha_blending":[{"blend_mode":"Normal","opacity":1.0,"fill":1.0,"clip":false}],"source_node_id":[null]}},"exposed":true}},{"Value":{"tagged_value":{"VectorModification":{"points":{"add":[1,2,3,4,5,6,7,8,9,10,11],"remove":[],"delta":[[6,[523.3861454046643,611.9385002286241]],[1,[659.4434537418081,187.67146776406028]],[3,[588.0884773662551,227.52880658436212]],[10,[750.8539094650207,617.9375857338821]],[9,[661.5370370370372,619.7592592592594]],[2,[622.9855967078189,184.4670781893004]],[11,[675.4629629629632,591.0185185185186]],[8,[446.6563786008233,618.9032921810701]],[7,[486.7770919067218,613.3724279835391]],[5,[540.9444444444443,605.8710283878144]],[4,[563.1666666666666,433.38888888888886]]]},"segments":{"add":[1,2,3,4,5,6,7,8,9,10,11],"remove":[],"start_point":[[9,9],[4,4],[2,2],[11,11],[3,3],[10,10],[1,1],[8,8],[7,7],[6,6],[5,5]],"end_point":[[11,1],[10,11],[6,7],[4,5],[5,6],[1,2],[3,4],[8,9],[9,10],[7,8],[2,3]],"handle_primary":[[10,[1.1851851851849915,-37.53086419753106]],[11,[0.0,0.0]],[3,[-3.950617283950692,42.13991769547326]],[2,[-6.716049382716051,0.9218106995884908]],[8,[0.0,0.0]],[1,[-3.9798811156837246,-1.1315348270080108]],[7,[-3.511659807956221,0.819387288523103]],[5,[0.0,0.0]],[9,[43.09465020576113,-0.9876543209876444]],[6,[0.0,0.0]],[4,[-10.222222222222172,79.55555555555549]]],"handle_end":[[7,[1.5363511659809888,-3.599451303154865]],[4,[0.0,0.0]],[9,[-22.386831275720624,5.3991769547326385]],[1,[6.716049382716051,-0.9218106995884624]],[3,[10.222222222222172,-79.55555555555549]],[11,null],[8,[-14.51772944216873,0.33272107201298695]],[6,[5.110425979711636,-1.1924327285993286]],[10,[0.0,0.0]],[2,[3.950617283950692,-42.13991769547323]],[5,[5.5601280292639785,-9.422953818016254]]],"stroke":[[4,0],[2,0],[6,0],[8,0],[9,0],[7,0],[3,0],[10,0],[5,0],[1,0],[11,0]]},"regions":{"add":[0],"remove":[],"segment_range":[[0,{"start":1,"end":11}]],"fill":[[0,0]]},"add_g1_continuous":[],"remove_g1_continuous":[]}},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::vector_data::modification::VectorModification","alias":null}},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::vector_data::modification::PathModifyNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[191,{"inputs":[{"Node":{"node_id":194,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"F64":75.0},"exposed":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::blending_nodes::OpacityNode"}},"visible":true,"skip_deduplication":false}],[6980979116665635870,{"inputs":[{"Node":{"node_id":5175066652268973319,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"DVec2":[486.78967826851385,539.8989473007496]},"exposed":false}},{"Value":{"tagged_value":{"F64":-0.14917418},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[24.603566707484493,77.5880766500041]},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[-0.12623993859136096,0.0]},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[0.5,0.5]},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":1}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":2}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":3}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":4}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":5}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::TransformNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[393,{"inputs":[{"Node":{"node_id":394,"output_index":0,"lambda":false}},{"Node":{"node_id":398,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[424,{"inputs":[{"Node":{"node_id":427,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"Fill":{"Gradient":{"stops":[[0.0,{"red":0.72265625,"green":0.3808298,"blue":0.2117157,"alpha":1.0}],[0.07456140350877193,{"red":0.827451,"green":0.42352942,"blue":0.19215687,"alpha":1.0}],[1.0,{"red":0.84705883,"green":0.48235294,"blue":0.20784314,"alpha":1.0}]],"gradient_type":"Linear","start":[0.5000000000000004,0.0],"end":[0.5000000000000004,1.0],"transform":[301.3269343934191,0.0,0.0,227.99999999999997,1490.0,614.0]}}},"exposed":false}},{"Value":{"tagged_value":{"OptionalColor":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}},"exposed":false}},{"Value":{"tagged_value":{"Gradient":{"stops":[[0.0,{"red":0.72265625,"green":0.3808298,"blue":0.2117157,"alpha":1.0}],[0.07456140350877193,{"red":0.827451,"green":0.42352942,"blue":0.19215687,"alpha":1.0}],[1.0,{"red":0.84705883,"green":0.48235294,"blue":0.20784314,"alpha":1.0}]],"gradient_type":"Linear","start":[0.5000000000000004,0.0],"end":[0.5000000000000004,1.0],"transform":[301.3269343934191,0.0,0.0,227.99999999999997,1490.0,614.0]}},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::FillNode"}},"visible":true,"skip_deduplication":false}],[82,{"inputs":[{"Node":{"node_id":83,"output_index":0,"lambda":false}},{"Node":{"node_id":102,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[455,{"inputs":[{"Node":{"node_id":453,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"OptionalColor":{"red":0.24313726,"green":0.18431373,"blue":0.19215687,"alpha":1.0}},"exposed":false}},{"Value":{"tagged_value":{"F64":6.0},"exposed":false}},{"Value":{"tagged_value":{"StrokeAlign":"Center"},"exposed":false}},{"Value":{"tagged_value":{"StrokeCap":"Butt"},"exposed":false}},{"Value":{"tagged_value":{"StrokeJoin":"Miter"},"exposed":false}},{"Value":{"tagged_value":{"F64":4.0},"exposed":false}},{"Value":{"tagged_value":{"PaintOrder":"StrokeAbove"},"exposed":false}},{"Value":{"tagged_value":{"VecF64":[]},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::StrokeNode"}},"visible":true,"skip_deduplication":false}],[144,{"inputs":[{"Value":{"tagged_value":{"VectorData":{"instance":[{"style":{"stroke":{"color":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0},"weight":0.0,"dash_lengths":[],"dash_offset":0.0,"cap":"Butt","join":"Miter","join_miter_limit":4.0,"align":"Center","transform":[1.0,0.0,0.0,1.0,0.0,0.0],"non_scaling":false,"paint_order":"StrokeAbove"},"fill":"None"},"colinear_manipulators":[],"point_domain":{"id":[],"position":[]},"segment_domain":{"id":[],"start_point":[],"end_point":[],"handles":[],"stroke":[]},"region_domain":{"id":[],"segment_range":[],"fill":[]},"upstream_graphic_group":null}],"transform":[[1.0,0.0,0.0,1.0,0.0,0.0]],"alpha_blending":[{"blend_mode":"Normal","opacity":1.0,"fill":1.0,"clip":false}],"source_node_id":[null]}},"exposed":true}},{"Value":{"tagged_value":{"VectorModification":{"points":{"add":[1,2,3,4],"remove":[],"delta":[[3,[0.5,1.0]],[1,[0.5,0.0]],[2,[1.0,0.5]],[4,[0.0,0.5]]]},"segments":{"add":[1,2,3,4],"remove":[],"start_point":[[2,2],[4,4],[3,3],[1,1]],"end_point":[[2,3],[3,4],[1,2],[4,1]],"handle_primary":[[4,[0.0,-0.275892388889507]],[1,[0.27589238888950707,0.0]],[2,[0.0,0.27589238888950707]],[3,[-0.275892388889507,0.0]]],"handle_end":[[3,[0.0,0.27589238888950707]],[1,[0.0,-0.275892388889507]],[2,[0.27589238888950707,0.0]],[4,[-0.275892388889507,0.0]]],"stroke":[[4,0],[3,0],[2,0],[1,0]]},"regions":{"add":[0],"remove":[],"segment_range":[[0,{"start":1,"end":4}]],"fill":[[0,0]]},"add_g1_continuous":[],"remove_g1_continuous":[]}},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::vector_data::modification::VectorModification","alias":null}},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::vector_data::modification::PathModifyNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[175,{"inputs":[{"Node":{"node_id":176,"output_index":0,"lambda":false}},{"Node":{"node_id":226,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[206,{"inputs":[{"Value":{"tagged_value":{"VectorData":{"instance":[{"style":{"stroke":{"color":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0},"weight":0.0,"dash_lengths":[],"dash_offset":0.0,"cap":"Butt","join":"Miter","join_miter_limit":4.0,"align":"Center","transform":[1.0,0.0,0.0,1.0,0.0,0.0],"non_scaling":false,"paint_order":"StrokeAbove"},"fill":"None"},"colinear_manipulators":[],"point_domain":{"id":[],"position":[]},"segment_domain":{"id":[],"start_point":[],"end_point":[],"handles":[],"stroke":[]},"region_domain":{"id":[],"segment_range":[],"fill":[]},"upstream_graphic_group":null}],"transform":[[1.0,0.0,0.0,1.0,0.0,0.0]],"alpha_blending":[{"blend_mode":"Normal","opacity":1.0,"fill":1.0,"clip":false}],"source_node_id":[null]}},"exposed":true}},{"Value":{"tagged_value":{"VectorModification":{"points":{"add":[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15],"remove":[],"delta":[[15,[1001.8333333333334,567.0185185185184]],[5,[963.3148148148148,466.8703703703703]],[12,[981.6851851851852,523.1666666666666]],[9,[973.0925925925924,496.5]],[11,[975.1666666666664,511.3148148148148]],[8,[972.5274348422496,495.6732967535437]],[4,[956.3024691358024,462.55639384240214]],[3,[971.3148148148148,466.5740740740741]],[2,[988.351851851852,494.72222222222223]],[6,[967.9074074074072,482.8703703703703]],[13,[967.3148148148148,531.9074074074074]],[14,[974.574074074074,539.3148148148148]],[7,[965.9814814814814,501.38888888888886]],[1,[1009.6296296296296,552.8888888888889]],[10,[968.2037037037036,504.05555555555554]]]},"segments":{"add":[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15],"remove":[],"start_point":[[7,7],[4,4],[15,15],[5,5],[8,8],[6,6],[10,10],[2,2],[14,14],[13,13],[9,9],[11,11],[3,3],[12,12],[1,1]],"end_point":[[5,6],[2,3],[12,13],[9,10],[15,1],[11,12],[3,4],[6,7],[8,9],[14,15],[7,8],[13,14],[4,5],[1,2],[10,11]],"handle_primary":[[5,[2.814814814814781,3.7037037037036953]],[11,[3.703703703703809,-0.7407407407407618]],[6,[-5.333333333333144,8.296296296296305]],[13,[0.0,0.0]],[12,[-4.888888888889028,8.59259259259261]],[1,[0.0,0.0]],[9,[0.0,0.0]],[14,[0.0,0.0]],[4,[0.0,0.0]],[7,[0.0,0.0]],[3,[-4.395061728394808,-4.740740740740705]],[15,[0.0,0.0]],[8,[0.0,0.0]],[2,[-6.51851851851859,-12.148148148148152]],[10,[0.0,0.0]]],"handle_end":[[4,[-2.814814814814781,-3.7037037037036953]],[6,[-1.7777777777778283,-0.8888888888889142]],[3,[3.265062349348341,-2.124337414689535]],[13,[-4.296296296296418,-2.6666666666666288]],[12,[0.0,0.0]],[2,[3.786081133230596,4.083862795394623]],[8,[-0.009144947416189098,-0.38774577046183367]],[11,[4.8888888888888005,-8.59259259259261]],[5,[5.333333333333485,-8.296296296296305]],[14,[-3.4074074074073906,-0.7407407407407618]],[10,[-3.7037037037035816,0.7407407407407618]],[7,[-2.6666666666667425,0.740740740740705]],[9,[0.7407407407407618,-4.0]],[1,[6.51851851851859,12.148148148148152]],[15,[-3.796296296296191,11.166666666666517]]],"stroke":[[9,0],[14,0],[10,0],[8,0],[4,0],[15,0],[5,0],[3,0],[12,0],[7,0],[1,0],[6,0],[13,0],[11,0],[2,0]]},"regions":{"add":[0],"remove":[],"segment_range":[[0,{"start":1,"end":15}]],"fill":[[0,0]]},"add_g1_continuous":[],"remove_g1_continuous":[]}},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::vector_data::modification::VectorModification","alias":null}},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::vector_data::modification::PathModifyNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[408,{"inputs":[{"Node":{"node_id":409,"output_index":0,"lambda":false}},{"Node":{"node_id":411,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[1453710883947581217,{"inputs":[{"Node":{"node_id":281,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"OptionalColor":{"red":0.24313726,"green":0.18431373,"blue":0.19215687,"alpha":1.0}},"exposed":false}},{"Value":{"tagged_value":{"F64":2.0},"exposed":false}},{"Value":{"tagged_value":{"StrokeAlign":"Center"},"exposed":false}},{"Value":{"tagged_value":{"StrokeCap":"Butt"},"exposed":false}},{"Value":{"tagged_value":{"StrokeJoin":"Miter"},"exposed":false}},{"Value":{"tagged_value":{"F64":4.0},"exposed":false}},{"Value":{"tagged_value":{"PaintOrder":"StrokeAbove"},"exposed":false}},{"Value":{"tagged_value":{"VecF64":[]},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::StrokeNode"}},"visible":true,"skip_deduplication":false}],[268,{"inputs":[{"Node":{"node_id":272,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"Fill":{"Solid":{"red":0.5058824,"green":0.26666668,"blue":0.20392157,"alpha":1.0}}},"exposed":false}},{"Value":{"tagged_value":{"OptionalColor":{"red":0.5058824,"green":0.26666668,"blue":0.20392157,"alpha":1.0}},"exposed":false}},{"Value":{"tagged_value":{"Gradient":{"stops":[[0.0,{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}],[1.0,{"red":1.0,"green":1.0,"blue":1.0,"alpha":1.0}]],"gradient_type":"Linear","start":[0.0,0.5],"end":[1.0,0.5],"transform":[1.0,0.0,0.0,1.0,0.0,0.0]}},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::FillNode"}},"visible":true,"skip_deduplication":false}],[439,{"inputs":[{"Node":{"node_id":440,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"DVec2":[344.5177419354837,697.8333333333333]},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[206.6666666666667,70.66666666666666]},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[0.0,0.0]},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[0.5,0.5]},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":1}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":2}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":3}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":4}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":5}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::TransformNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[12768614558324028960,{"inputs":[{"Value":{"tagged_value":{"GraphicGroup":{"instance":[],"transform":[],"alpha_blending":[],"source_node_id":[]}},"exposed":true}},{"Node":{"node_id":6710503329407068595,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[128,{"inputs":[{"Node":{"node_id":132,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"Fill":{"Solid":{"red":0.3764706,"green":0.23529412,"blue":0.20784314,"alpha":1.0}}},"exposed":false}},{"Value":{"tagged_value":{"OptionalColor":{"red":0.3764706,"green":0.23529412,"blue":0.20784314,"alpha":1.0}},"exposed":false}},{"Value":{"tagged_value":{"Gradient":{"stops":[[0.0,{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}],[1.0,{"red":1.0,"green":1.0,"blue":1.0,"alpha":1.0}]],"gradient_type":"Linear","start":[0.0,0.5],"end":[1.0,0.5],"transform":[1.0,0.0,0.0,1.0,0.0,0.0]}},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::FillNode"}},"visible":true,"skip_deduplication":false}],[159,{"inputs":[{"Value":{"tagged_value":{"VectorData":{"instance":[{"style":{"stroke":{"color":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0},"weight":0.0,"dash_lengths":[],"dash_offset":0.0,"cap":"Butt","join":"Miter","join_miter_limit":4.0,"align":"Center","transform":[1.0,0.0,0.0,1.0,0.0,0.0],"non_scaling":false,"paint_order":"StrokeAbove"},"fill":"None"},"colinear_manipulators":[],"point_domain":{"id":[],"position":[]},"segment_domain":{"id":[],"start_point":[],"end_point":[],"handles":[],"stroke":[]},"region_domain":{"id":[],"segment_range":[],"fill":[]},"upstream_graphic_group":null}],"transform":[[1.0,0.0,0.0,1.0,0.0,0.0]],"alpha_blending":[{"blend_mode":"Normal","opacity":1.0,"fill":1.0,"clip":false}],"source_node_id":[null]}},"exposed":true}},{"Value":{"tagged_value":{"VectorModification":{"points":{"add":[1,2,3,4,5],"remove":[],"delta":[[1,[-2.6666666666667,581.3333333333333]],[5,[-2.6666666666666856,770.8703703703704]],[3,[266.2777777777779,704.4077331232156]],[4,[249.09259259259255,770.8703703703704]],[2,[153.0925925925926,632.7962962962963]]]},"segments":{"add":[1,2,3,4,5],"remove":[],"start_point":[[2,2],[5,5],[1,1],[4,4],[3,3]],"end_point":[[1,2],[4,5],[3,4],[2,3],[5,1]],"handle_primary":[[1,[0.0,0.0]],[3,[8.273042653236644,16.012340619167617]],[4,[0.0,0.0]],[5,[0.0,0.0]],[2,[69.92592592592595,31.40740740740773]]],"handle_end":[[1,[-105.44980253803315,-47.36304690267639]],[4,[0.0,0.0]],[2,[-9.18518518518522,-17.777777777777715]],[3,[19.407407407407447,-32.148148148148266]],[5,[0.0,0.0]]],"stroke":[[5,0],[3,0],[4,0],[2,0],[1,0]]},"regions":{"add":[0],"remove":[],"segment_range":[[0,{"start":1,"end":5}]],"fill":[[0,0]]},"add_g1_continuous":[],"remove_g1_continuous":[]}},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::vector_data::modification::VectorModification","alias":null}},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::vector_data::modification::PathModifyNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[2489761779922717592,{"inputs":[{"Value":{"tagged_value":{"VectorData":{"instance":[{"style":{"stroke":{"color":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0},"weight":0.0,"dash_lengths":[],"dash_offset":0.0,"cap":"Butt","join":"Miter","join_miter_limit":4.0,"align":"Center","transform":[1.0,0.0,0.0,1.0,0.0,0.0],"non_scaling":false,"paint_order":"StrokeAbove"},"fill":"None"},"colinear_manipulators":[],"point_domain":{"id":[],"position":[]},"segment_domain":{"id":[],"start_point":[],"end_point":[],"handles":[],"stroke":[]},"region_domain":{"id":[],"segment_range":[],"fill":[]},"upstream_graphic_group":null}],"transform":[[1.0,0.0,0.0,1.0,0.0,0.0]],"alpha_blending":[{"blend_mode":"Normal","opacity":1.0,"fill":1.0,"clip":false}],"source_node_id":[null]}},"exposed":true}},{"Value":{"tagged_value":{"VectorModification":{"points":{"add":[1,2,3,4,5,6,7,8,9,10],"remove":[],"delta":[[6,[468.0555555555556,551.0185185185187]],[4,[282.37654320987656,585.9814814814815]],[3,[205.93209876543213,600.5987654320988]],[10,[288.6975308641976,620.1543209876544]],[8,[481.88271604938296,600.2037037037037]],[1,[156.18106995884773,623.2098765432096]],[9,[447.46059205066985,619.9047655337092]],[7,[455.2160493827161,586.8374485596709]],[5,[338.4753086419753,574.1296296296297]],[2,[161.81687242798355,618.7716049382714]]]},"segments":{"add":[1,2,3,4,5,6,7,8,9,10],"remove":[],"start_point":[[6,6],[8,8],[5,5],[1,1],[10,10],[3,3],[4,4],[9,9],[2,2],[7,7]],"end_point":[[6,7],[4,5],[10,1],[3,4],[9,10],[5,6],[8,9],[2,3],[7,8],[1,2]],"handle_primary":[[5,[0.0,0.0]],[3,[21.135802469135797,-7.703703703703695]],[1,[0.0,0.0]],[6,[-0.19753086419751753,-0.19753086419757435]],[10,[-70.32098765432102,1.975308641975289]],[8,[0.0,0.0]],[2,[5.925925925925924,-2.370370370370324]],[7,[0.0,0.0]],[4,[22.71604938271605,-4.9382716049382225]],[9,[0.0,0.0]]],"handle_end":[[4,[0.0,0.0]],[8,[11.358024691357969,-11.390946502057773]],[7,[-8.691358024691567,-7.308641975308547]],[2,[-21.135802469135797,7.703703703703695]],[1,[-5.925925925925924,2.370370370370324]],[9,[70.32098765432102,-1.975308641975289]],[3,[-22.71604938271605,4.9382716049382225]],[5,[-40.09876543209879,-8.09876543209873]],[6,[4.345679012345613,-25.481481481481524]],[10,[41.77160493827162,-2.8703703703704377]]],"stroke":[[10,0],[2,0],[5,0],[9,0],[3,0],[1,0],[6,0],[4,0],[7,0],[8,0]]},"regions":{"add":[0],"remove":[],"segment_range":[[0,{"start":1,"end":10}]],"fill":[[0,0]]},"add_g1_continuous":[],"remove_g1_continuous":[]}},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::vector_data::modification::VectorModification","alias":null}},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::vector_data::modification::PathModifyNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[190,{"inputs":[{"Node":{"node_id":193,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"Fill":{"Gradient":{"stops":[[0.0,{"red":0.3764706,"green":0.23529412,"blue":0.20784314,"alpha":1.0}],[1.0,{"red":0.5058824,"green":0.26666668,"blue":0.20392157,"alpha":1.0}]],"gradient_type":"Linear","start":[0.1331892468887066,0.5346273584022614],"end":[0.8687039445257865,0.5091081472114145],"transform":[-218.7504556627755,-14.37593189759248,43.932245743957935,-414.3431050369427,1186.6527692956029,632.7498382754235]}}},"exposed":false}},{"Value":{"tagged_value":{"OptionalColor":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}},"exposed":false}},{"Value":{"tagged_value":{"Gradient":{"stops":[[0.0,{"red":0.3764706,"green":0.23529412,"blue":0.20784314,"alpha":1.0}],[1.0,{"red":0.5058824,"green":0.26666668,"blue":0.20392157,"alpha":1.0}]],"gradient_type":"Linear","start":[0.1331892468887066,0.5346273584022614],"end":[0.8687039445257865,0.5091081472114145],"transform":[-218.7504556627755,-14.37593189759248,43.932245743957935,-414.3431050369427,1186.6527692956029,632.7498382754235]}},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::FillNode"}},"visible":true,"skip_deduplication":false}],[11427960919145580782,{"inputs":[{"Node":{"node_id":6873123446543957690,"output_index":0,"lambda":false}},{"Node":{"node_id":11345069121502219134,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[15848750910363784662,{"inputs":[{"Value":{"tagged_value":{"GraphicGroup":{"instance":[],"transform":[],"alpha_blending":[],"source_node_id":[]}},"exposed":true}},{"Node":{"node_id":17911294938421300842,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[81,{"inputs":[{"Node":{"node_id":82,"output_index":0,"lambda":false}},{"Node":{"node_id":87,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[15483449862348058100,{"inputs":[{"Node":{"node_id":5382879283978921947,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"Fill":{"Solid":{"red":0.5058824,"green":0.26666668,"blue":0.20392157,"alpha":1.0}}},"exposed":false}},{"Value":{"tagged_value":{"OptionalColor":{"red":0.5058824,"green":0.26666668,"blue":0.20392157,"alpha":1.0}},"exposed":false}},{"Value":{"tagged_value":{"Gradient":{"stops":[[0.0,{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}],[1.0,{"red":1.0,"green":1.0,"blue":1.0,"alpha":1.0}]],"gradient_type":"Linear","start":[0.0,0.5],"end":[1.0,0.5],"transform":[1.0,0.0,0.0,1.0,0.0,0.0]}},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::FillNode"}},"visible":true,"skip_deduplication":false}],[283,{"inputs":[{"Node":{"node_id":16360261423333265502,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"Fill":{"Solid":{"red":0.24313726,"green":0.18431373,"blue":0.19215687,"alpha":1.0}}},"exposed":false}},{"Value":{"tagged_value":{"OptionalColor":{"red":0.24313726,"green":0.18431373,"blue":0.19215687,"alpha":1.0}},"exposed":false}},{"Value":{"tagged_value":{"Gradient":{"stops":[[0.0,{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}],[1.0,{"red":1.0,"green":1.0,"blue":1.0,"alpha":1.0}]],"gradient_type":"Linear","start":[0.0,0.5],"end":[1.0,0.5],"transform":[1.0,0.0,0.0,1.0,0.0,0.0]}},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::FillNode"}},"visible":true,"skip_deduplication":false}],[143,{"inputs":[{"Node":{"node_id":144,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"DVec2":[22.81427346112025,718.7256085656885]},"exposed":false}},{"Value":{"tagged_value":{"F64":-0.028919384},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[114.60967448512612,10.883703174332329]},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[-0.002522502109903075,0.0]},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[0.5,0.5]},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":1}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":2}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":3}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":4}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":5}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::TransformNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[6873123446543957690,{"inputs":[{"Node":{"node_id":12717405604755313921,"output_index":0,"lambda":false}},{"Node":{"node_id":3707802522175443254,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[485,{"inputs":[{"Value":{"tagged_value":{"VectorData":{"instance":[{"style":{"stroke":{"color":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0},"weight":0.0,"dash_lengths":[],"dash_offset":0.0,"cap":"Butt","join":"Miter","join_miter_limit":4.0,"align":"Center","transform":[1.0,0.0,0.0,1.0,0.0,0.0],"non_scaling":false,"paint_order":"StrokeAbove"},"fill":"None"},"colinear_manipulators":[],"point_domain":{"id":[],"position":[]},"segment_domain":{"id":[],"start_point":[],"end_point":[],"handles":[],"stroke":[]},"region_domain":{"id":[],"segment_range":[],"fill":[]},"upstream_graphic_group":null}],"transform":[[1.0,0.0,0.0,1.0,0.0,0.0]],"alpha_blending":[{"blend_mode":"Normal","opacity":1.0,"fill":1.0,"clip":false}],"source_node_id":[null]}},"exposed":true}},{"Value":{"tagged_value":{"VectorModification":{"points":{"add":[1,2,3,4,5,6,7],"remove":[],"delta":[[5,[874.2777777777776,540.5]],[4,[873.611111111111,465.6111111111111]],[7,[907.1666666666664,501.16666666666663]],[2,[881.6925011431184,340.0384849870446]],[6,[879.873428946497,552.0307817039356]],[3,[873.1913580246915,359.61111111111114]],[1,[901.7869989330896,337.4632677945435]]]},"segments":{"add":[1,2,3,4,5,6,7],"remove":[],"start_point":[[7,7],[5,5],[1,1],[3,3],[6,6],[2,2],[4,4]],"end_point":[[4,5],[1,2],[6,7],[5,6],[2,3],[7,1],[3,4]],"handle_primary":[[1,[0.0,0.0]],[4,[-0.22222222222228535,37.77777777777777]],[6,[4.0,1.7777777777777146]],[7,[2.888888888889028,-35.111111111111086]],[5,[1.086419753086716,4.000000000000114]],[3,[0.09876543209873034,9.87654320987656]],[2,[-5.885745135394927,5.678500588373993]]],"handle_end":[[6,[-2.8888888888888005,35.111111111111086]],[1,[5.5406188081085475,-5.34552659655543]],[7,[0.0,0.0]],[3,[0.22222222222228535,-37.77777777777777]],[5,[-4.0,-1.7777777777777146]],[4,[-0.9901901223357754,-3.645699995871837]],[2,[-0.09876543209873034,-9.87654320987656]]],"stroke":[[5,0],[1,0],[7,0],[3,0],[6,0],[4,0],[2,0]]},"regions":{"add":[0],"remove":[],"segment_range":[[0,{"start":1,"end":7}]],"fill":[[0,0]]},"add_g1_continuous":[],"remove_g1_continuous":[]}},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::vector_data::modification::VectorModification","alias":null}},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::vector_data::modification::PathModifyNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[174,{"inputs":[{"Node":{"node_id":175,"output_index":0,"lambda":false}},{"Node":{"node_id":220,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[4633399390154487467,{"inputs":[{"Node":{"node_id":11155094820673141470,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"F64":75.0},"exposed":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::blending_nodes::OpacityNode"}},"visible":true,"skip_deduplication":false}],[236,{"inputs":[{"Value":{"tagged_value":{"VectorData":{"instance":[{"style":{"stroke":{"color":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0},"weight":0.0,"dash_lengths":[],"dash_offset":0.0,"cap":"Butt","join":"Miter","join_miter_limit":4.0,"align":"Center","transform":[1.0,0.0,0.0,1.0,0.0,0.0],"non_scaling":false,"paint_order":"StrokeAbove"},"fill":"None"},"colinear_manipulators":[],"point_domain":{"id":[],"position":[]},"segment_domain":{"id":[],"start_point":[],"end_point":[],"handles":[],"stroke":[]},"region_domain":{"id":[],"segment_range":[],"fill":[]},"upstream_graphic_group":null}],"transform":[[1.0,0.0,0.0,1.0,0.0,0.0]],"alpha_blending":[{"blend_mode":"Normal","opacity":1.0,"fill":1.0,"clip":false}],"source_node_id":[null]}},"exposed":true}},{"Value":{"tagged_value":{"VectorModification":{"points":{"add":[1,2,3,4,5,6],"remove":[],"delta":[[1,[842.2716049382717,560.2962962962963]],[6,[838.425925925926,581.0432098765433]],[2,[837.9320987654322,560.7962962962963]],[4,[828.8127572016463,566.4259259259259]],[5,[826.9691358024693,580.1543209876544]],[3,[832.8950617283951,560.829218106996]]]},"segments":{"add":[1,2,3,4,5,6],"remove":[],"start_point":[[6,6],[1,1],[2,2],[3,3],[5,5],[4,4]],"end_point":[[4,5],[1,2],[5,6],[3,4],[6,1],[2,3]],"handle_primary":[[1,[-4.339506172839492,0.5]],[5,[0.0,0.0]],[2,[0.0,0.0]],[6,[0.0,0.0]],[3,[-2.1728395061728634,1.4814814814815236]],[4,[-3.649513397469832,2.8283728830390373]]],"handle_end":[[5,[0.0,0.0]],[6,[0.0,0.0]],[3,[2.633744855967052,-2.0411522633744426]],[1,null],[2,[2.1728395061728634,-1.4814814814815236]],[4,[0.0,0.0]]],"stroke":[[1,0],[4,0],[6,0],[3,0],[5,0],[2,0]]},"regions":{"add":[0],"remove":[],"segment_range":[[0,{"start":1,"end":6}]],"fill":[[0,0]]},"add_g1_continuous":[],"remove_g1_continuous":[]}},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::vector_data::modification::VectorModification","alias":null}},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::vector_data::modification::PathModifyNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[1598976462838094167,{"inputs":[{"Value":{"tagged_value":{"VectorData":{"instance":[{"style":{"stroke":{"color":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0},"weight":0.0,"dash_lengths":[],"dash_offset":0.0,"cap":"Butt","join":"Miter","join_miter_limit":4.0,"align":"Center","transform":[1.0,0.0,0.0,1.0,0.0,0.0],"non_scaling":false,"paint_order":"StrokeAbove"},"fill":"None"},"colinear_manipulators":[],"point_domain":{"id":[],"position":[]},"segment_domain":{"id":[],"start_point":[],"end_point":[],"handles":[],"stroke":[]},"region_domain":{"id":[],"segment_range":[],"fill":[]},"upstream_graphic_group":null}],"transform":[[1.0,0.0,0.0,1.0,0.0,0.0]],"alpha_blending":[{"blend_mode":"Normal","opacity":1.0,"fill":1.0,"clip":false}],"source_node_id":[null]}},"exposed":true}},{"Value":{"tagged_value":{"VectorModification":{"points":{"add":[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20],"remove":[],"delta":[[14,[496.49999999999994,603.4117893613783]],[16,[478.9197530864198,618.6875095259874]],[3,[488.5329218106997,551.6587029416252]],[5,[500.4506172839507,547.5105547934772]],[9,[510.261316872428,573.2078189300412]],[1,[506.7057613168725,531.9348803536052]],[18,[438.2283950617284,585.5544307531777]],[11,[504.00617283950623,588.9444444444446]],[2,[497.8388203017833,534.5393613778391]],[4,[500.77983539094663,544.0208428593207]],[6,[490.17901234567904,556.0043819539711]],[19,[468.05555555555594,550.6710486206383]],[8,[502.6234567901235,563.1154930650816]],[7,[495.90740740740733,567.882982777016]],[12,[513.3888888888889,585.5544307531777]],[17,[448.3683127572017,617.6340115836006]],[20,[480.89506172839504,532.4323654930657]],[13,[516.8017832647463,593.4437585733884]],[10,[496.50000000000006,582.6234567901236]],[15,[496.30246913580254,612.3006782502672]]]},"segments":{"add":[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20],"remove":[],"start_point":[[16,16],[10,10],[3,3],[12,12],[9,9],[20,20],[5,5],[15,15],[13,13],[6,6],[7,7],[18,18],[1,1],[4,4],[17,17],[8,8],[14,14],[11,11],[2,2],[19,19]],"end_point":[[19,20],[12,13],[17,18],[16,17],[13,14],[4,5],[20,1],[11,12],[1,2],[3,4],[6,7],[15,16],[8,9],[9,10],[14,15],[10,11],[18,19],[2,3],[7,8],[5,6]],"handle_primary":[[9,[0.0,0.0]],[20,[7.46503467504715,-4.02781143068205]],[7,[0.0,0.0]],[19,[0.0,0.0]],[3,[4.565157750342848,-4.301783264746064]],[4,null],[16,[0.0,0.0]],[10,[0.0,0.0]],[6,[0.0,0.0]],[13,[0.0,0.0]],[12,[0.0,0.0]],[15,[0.0,0.0]],[1,[0.0,0.0]],[8,[0.0,0.0]],[11,[0.0,0.0]],[17,[0.0,0.0]],[14,[0.0,0.0]],[2,[-7.188100137174104,2.6138545953361927]],[18,[0.0,0.0]],[5,[-6.737997256515712,3.1824417009599983]]],"handle_end":[[8,[-1.7777777777777717,-5.728395061728406]],[17,[0.0,0.0]],[14,[-0.7901234567900701,-4.938271604938336]],[11,[-3.851851851851848,0.7581344568814075]],[3,null],[16,[0.0,0.0]],[5,[0.0,0.0]],[19,[-3.394604481024089,3.2873037646699004]],[18,[0.0,0.0]],[1,[3.4386245260820374,-1.250408918575317]],[2,[0.27087722942241044,-5.120145445603839]],[7,[-3.6872427983540206,1.4485596707820605]],[15,[0.0,0.0]],[12,[-0.39506172839503506,-1.975308641975289]],[6,[-2.508333333333439,-2.0902777777778283]],[20,[0.0,0.0]],[13,[0.0,0.0]],[9,[6.716049382716108,-8.49382716049422]],[10,[-2.765432098765416,-3.555555555555543]],[4,null]],"stroke":[[14,0],[13,0],[20,0],[4,0],[16,0],[17,0],[1,0],[11,0],[7,0],[10,0],[15,0],[3,0],[18,0],[2,0],[8,0],[5,0],[9,0],[6,0],[12,0],[19,0]]},"regions":{"add":[0],"remove":[],"segment_range":[[0,{"start":1,"end":20}]],"fill":[[0,0]]},"add_g1_continuous":[],"remove_g1_continuous":[]}},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::vector_data::modification::VectorModification","alias":null}},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::vector_data::modification::PathModifyNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[12435496696188763850,{"inputs":[{"Node":{"node_id":9286544882258200464,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"Fill":{"Solid":{"red":0.24313726,"green":0.18431373,"blue":0.19215687,"alpha":1.0}}},"exposed":false}},{"Value":{"tagged_value":{"OptionalColor":{"red":0.24313726,"green":0.18431373,"blue":0.19215687,"alpha":1.0}},"exposed":false}},{"Value":{"tagged_value":{"Gradient":{"stops":[[0.0,{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}],[1.0,{"red":1.0,"green":1.0,"blue":1.0,"alpha":1.0}]],"gradient_type":"Linear","start":[0.0,0.5],"end":[1.0,0.5],"transform":[1.0,0.0,0.0,1.0,0.0,0.0]}},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::FillNode"}},"visible":true,"skip_deduplication":false}],[96,{"inputs":[{"Node":{"node_id":99,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"Fill":{"Gradient":{"stops":[[0.0,{"red":0.24313726,"green":0.18431373,"blue":0.19215687,"alpha":1.0}],[0.7594724231651877,{"red":0.24313726,"green":0.18431373,"blue":0.19215687,"alpha":1.0}],[1.0,{"red":0.3764706,"green":0.23529412,"blue":0.20784314,"alpha":1.0}]],"gradient_type":"Radial","start":[0.0,0.5],"end":[1.0,0.0],"transform":[167.78317901234573,0.0,0.0,143.99999999999977,1158.5733024691351,715.0]}}},"exposed":false}},{"Value":{"tagged_value":{"OptionalColor":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}},"exposed":false}},{"Value":{"tagged_value":{"Gradient":{"stops":[[0.0,{"red":0.24313726,"green":0.18431373,"blue":0.19215687,"alpha":1.0}],[0.7594724231651877,{"red":0.24313726,"green":0.18431373,"blue":0.19215687,"alpha":1.0}],[1.0,{"red":0.3764706,"green":0.23529412,"blue":0.20784314,"alpha":1.0}]],"gradient_type":"Radial","start":[0.0,0.5],"end":[1.0,0.0],"transform":[167.78317901234573,0.0,0.0,143.99999999999977,1158.5733024691351,715.0]}},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::FillNode"}},"visible":true,"skip_deduplication":false}],[469,{"inputs":[{"Value":{"tagged_value":{"VectorData":{"instance":[{"style":{"stroke":{"color":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0},"weight":0.0,"dash_lengths":[],"dash_offset":0.0,"cap":"Butt","join":"Miter","join_miter_limit":4.0,"align":"Center","transform":[1.0,0.0,0.0,1.0,0.0,0.0],"non_scaling":false,"paint_order":"StrokeAbove"},"fill":"None"},"colinear_manipulators":[],"point_domain":{"id":[],"position":[]},"segment_domain":{"id":[],"start_point":[],"end_point":[],"handles":[],"stroke":[]},"region_domain":{"id":[],"segment_range":[],"fill":[]},"upstream_graphic_group":null}],"transform":[[1.0,0.0,0.0,1.0,0.0,0.0]],"alpha_blending":[{"blend_mode":"Normal","opacity":1.0,"fill":1.0,"clip":false}],"source_node_id":[null]}},"exposed":true}},{"Value":{"tagged_value":{"VectorModification":{"points":{"add":[1,2,3,4,5,6,7,8,9,10,11,12,13],"remove":[],"delta":[[8,[82.0,29.5]],[1,[137.75,641.0]],[10,[137.68518518518513,236.64814814814815]],[2,[-7.000000000000025,626.675562328647]],[13,[223.25,608.7633744855967]],[5,[81.68518518518522,338.8703703703703]],[7,[129.38888888888886,443.61235349483104]],[4,[50.72222222222222,278.78532235939633]],[6,[110.91975308641976,406.62345679012344]],[3,[-7.030559365950182,200.5]],[9,[111.83431058292848,134.6107990062408]],[12,[199.1666666666667,473.1666666666667]],[11,[177.83333333333343,384.49999999999994]]]},"segments":{"add":[1,2,3,4,5,6,7,8,9,10,11,12,13],"remove":[],"start_point":[[6,6],[10,10],[2,2],[1,1],[8,8],[11,11],[12,12],[3,3],[4,4],[7,7],[5,5],[9,9],[13,13]],"end_point":[[1,2],[8,9],[4,5],[10,11],[13,1],[9,10],[12,13],[11,12],[5,6],[3,4],[2,3],[7,8],[6,7]],"handle_primary":[[8,[0.0,0.0]],[9,[5.9990227504048335,27.666978771536947]],[10,[12.334360893667936,45.715346431469186]],[12,[11.42335240155694,63.4630688975397]],[6,[8.537957281505157,20.688127259031944]],[13,[0.0,0.0]],[2,[0.0,0.0]],[3,[31.078939476013172,37.97283968100555]],[5,[6.73334689148848,12.881185357630102]],[7,[-20.788075479416264,-70.61235349483104]],[11,[6.410520201070284,29.915760938327992]],[1,[0.0,0.0]],[4,[7.654320987654309,14.850480109739408]]],"handle_end":[[4,[-9.08641975308646,-17.382716049382736]],[8,[-13.354098963944438,-61.58795989288773]],[9,[-13.510174692931455,-48.54050114169854]],[7,[14.499999999999943,172.0]],[6,[0.0,0.0]],[12,[0.0,0.0]],[5,[-10.271604938271594,-24.88888888888897]],[2,[0.0,0.0]],[3,[-14.856706650648782,-28.82414089604376]],[10,[-12.0,-55.99999999999994]],[13,[0.0,0.0]],[11,[-5.999999999999915,-33.33333333333343]],[1,[0.0,0.0]]],"stroke":[[6,0],[1,0],[13,0],[11,0],[2,0],[7,0],[8,0],[12,0],[10,0],[4,0],[5,0],[9,0],[3,0]]},"regions":{"add":[0],"remove":[],"segment_range":[[0,{"start":1,"end":13}]],"fill":[[0,0]]},"add_g1_continuous":[],"remove_g1_continuous":[]}},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::vector_data::modification::VectorModification","alias":null}},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::vector_data::modification::PathModifyNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[11279424538712841875,{"inputs":[{"Node":{"node_id":2489761779922717592,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"Fill":{"Solid":{"red":0.24313726,"green":0.18431373,"blue":0.19215687,"alpha":1.0}}},"exposed":false}},{"Value":{"tagged_value":{"OptionalColor":{"red":0.24313726,"green":0.18431373,"blue":0.19215687,"alpha":1.0}},"exposed":false}},{"Value":{"tagged_value":{"Gradient":{"stops":[[0.0,{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}],[1.0,{"red":1.0,"green":1.0,"blue":1.0,"alpha":1.0}]],"gradient_type":"Linear","start":[0.0,0.5],"end":[1.0,0.5],"transform":[1.0,0.0,0.0,1.0,0.0,0.0]}},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::FillNode"}},"visible":true,"skip_deduplication":false}],[329,{"inputs":[{"Node":{"node_id":327,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"OptionalColor":{"red":0.24313726,"green":0.18431373,"blue":0.19215687,"alpha":1.0}},"exposed":false}},{"Value":{"tagged_value":{"F64":2.0},"exposed":false}},{"Value":{"tagged_value":{"StrokeAlign":"Center"},"exposed":false}},{"Value":{"tagged_value":{"StrokeCap":"Butt"},"exposed":false}},{"Value":{"tagged_value":{"StrokeJoin":"Miter"},"exposed":false}},{"Value":{"tagged_value":{"F64":4.0},"exposed":false}},{"Value":{"tagged_value":{"PaintOrder":"StrokeAbove"},"exposed":false}},{"Value":{"tagged_value":{"VecF64":[]},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::StrokeNode"}},"visible":true,"skip_deduplication":false}],[4452902364641883403,{"inputs":[{"Value":{"tagged_value":{"GraphicGroup":{"instance":[],"transform":[],"alpha_blending":[],"source_node_id":[]}},"exposed":true}},{"Node":{"node_id":8861964493222160710,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[16894739051789815098,{"inputs":[{"Node":{"node_id":17245613731534563958,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"DVec2":[337.1982047610469,692.7466487935636]},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[50.0,50.0]},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[0.0,0.0]},"exposed":false}},{"Value":{"tagged_value":{"DVec2":[0.5,0.5]},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":1}},{"Network":{"import_type":{"Concrete":{"name":"f64","alias":null}},"import_index":2}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":3}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":4}},{"Network":{"import_type":{"Concrete":{"name":"glam::f64::dvec2::DVec2","alias":null}},"import_index":5}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::transform_nodes::TransformNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[220,{"inputs":[{"Node":{"node_id":224,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"Fill":{"Solid":{"red":0.24313726,"green":0.18431373,"blue":0.19215687,"alpha":1.0}}},"exposed":false}},{"Value":{"tagged_value":{"OptionalColor":{"red":0.24313726,"green":0.18431373,"blue":0.19215687,"alpha":1.0}},"exposed":false}},{"Value":{"tagged_value":{"Gradient":{"stops":[[0.0,{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}],[1.0,{"red":1.0,"green":1.0,"blue":1.0,"alpha":1.0}]],"gradient_type":"Linear","start":[0.0,0.5],"end":[1.0,0.5],"transform":[1.0,0.0,0.0,1.0,0.0,0.0]}},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::FillNode"}},"visible":true,"skip_deduplication":false}],[422,{"inputs":[{"Value":{"tagged_value":{"GraphicGroup":{"instance":[],"transform":[],"alpha_blending":[],"source_node_id":[]}},"exposed":true}},{"Node":{"node_id":430,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[453,{"inputs":[{"Node":{"node_id":457,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"Fill":"None"},"exposed":false}},{"Value":{"tagged_value":{"OptionalColor":null},"exposed":false}},{"Value":{"tagged_value":{"Gradient":{"stops":[[0.0,{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}],[1.0,{"red":1.0,"green":1.0,"blue":1.0,"alpha":1.0}]],"gradient_type":"Linear","start":[0.0,0.5],"end":[1.0,0.5],"transform":[1.0,0.0,0.0,1.0,0.0,0.0]}},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::FillNode"}},"visible":true,"skip_deduplication":false}],[111,{"inputs":[{"Node":{"node_id":114,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"Fill":{"Solid":{"red":0.24313726,"green":0.18431373,"blue":0.19215687,"alpha":1.0}}},"exposed":false}},{"Value":{"tagged_value":{"OptionalColor":{"red":0.24313726,"green":0.18431373,"blue":0.19215687,"alpha":1.0}},"exposed":false}},{"Value":{"tagged_value":{"Gradient":{"stops":[[0.0,{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}],[1.0,{"red":1.0,"green":1.0,"blue":1.0,"alpha":1.0}]],"gradient_type":"Linear","start":[0.0,0.5],"end":[1.0,0.5],"transform":[1.0,0.0,0.0,1.0,0.0,0.0]}},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::FillNode"}},"visible":true,"skip_deduplication":false}],[13606781735926093266,{"inputs":[{"Value":{"tagged_value":{"VectorData":{"instance":[{"style":{"stroke":{"color":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0},"weight":0.0,"dash_lengths":[],"dash_offset":0.0,"cap":"Butt","join":"Miter","join_miter_limit":4.0,"align":"Center","transform":[1.0,0.0,0.0,1.0,0.0,0.0],"non_scaling":false,"paint_order":"StrokeAbove"},"fill":"None"},"colinear_manipulators":[],"point_domain":{"id":[],"position":[]},"segment_domain":{"id":[],"start_point":[],"end_point":[],"handles":[],"stroke":[]},"region_domain":{"id":[],"segment_range":[],"fill":[]},"upstream_graphic_group":null}],"transform":[[1.0,0.0,0.0,1.0,0.0,0.0]],"alpha_blending":[{"blend_mode":"Normal","opacity":1.0,"fill":1.0,"clip":false}],"source_node_id":[null]}},"exposed":true}},{"Value":{"tagged_value":{"VectorModification":{"points":{"add":[1,2,3,4,5,6,7,8,9,10],"remove":[],"delta":[[4,[699.4958847736627,594.497256515775]],[5,[744.3996087994716,586.9732002235431]],[10,[712.0500685871053,614.4420508944315]],[1,[645.3333333333333,614.013717421125]],[8,[708.7139917695473,601.783950617284]],[2,[658.574074074074,609.6851851851851]],[3,[680.2695473251027,600.730452674897]],[6,[717.5809327846364,593.2681755829904]],[7,[702.5246913580245,600.8931773149878]],[9,[713.2108672458469,610.5533455265964]]]},"segments":{"add":[1,2,3,4,5,6,7,8,9,10],"remove":[],"start_point":[[4,4],[8,8],[9,9],[1,1],[7,7],[6,6],[5,5],[10,10],[2,2],[3,3]],"end_point":[[7,8],[3,4],[6,7],[2,3],[1,2],[9,10],[10,1],[5,6],[4,5],[8,9]],"handle_primary":[[6,[-10.886145404663694,2.8971193415636662]],[1,[0.0,0.0]],[2,[4.740740740740762,-4.148148148148152]],[5,[0.0,0.0]],[4,[4.444444444444002,-5.662551440328798]],[9,[0.0,0.0]],[7,[0.0,0.0]],[3,[7.374485596707928,-0.92181069958815]],[8,[0.0,0.0]],[10,[-58.35223289132739,3.851425709744945]]],"handle_end":[[10,null],[9,[-0.08779149519853036,-2.2109123484780184]],[7,[-2.89711934156378,-1.975308641975289]],[1,[-4.740740740740762,4.148148148148152]],[3,[-1.6866098186769705,2.1488658430550913]],[4,[-5.794238683127446,-2.0192043895747247]],[2,[-6.174173455107166,0.7717716818881399]],[8,[-2.5361987501905787,-3.706752019509281]],[5,[10.516302710276136,-2.79869346321857]],[6,[0.0,0.0]]],"stroke":[[5,0],[6,0],[4,0],[10,0],[2,0],[7,0],[3,0],[9,0],[8,0],[1,0]]},"regions":{"add":[0],"remove":[],"segment_range":[[0,{"start":1,"end":10}]],"fill":[[0,0]]},"add_g1_continuous":[],"remove_g1_continuous":[]}},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::vector_data::modification::VectorModification","alias":null}},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::vector_data::modification::PathModifyNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[2999157202967297847,{"inputs":[{"Value":{"tagged_value":{"VectorData":{"instance":[{"style":{"stroke":{"color":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0},"weight":0.0,"dash_lengths":[],"dash_offset":0.0,"cap":"Butt","join":"Miter","join_miter_limit":4.0,"align":"Center","transform":[1.0,0.0,0.0,1.0,0.0,0.0],"non_scaling":false,"paint_order":"StrokeAbove"},"fill":"None"},"colinear_manipulators":[],"point_domain":{"id":[],"position":[]},"segment_domain":{"id":[],"start_point":[],"end_point":[],"handles":[],"stroke":[]},"region_domain":{"id":[],"segment_range":[],"fill":[]},"upstream_graphic_group":null}],"transform":[[1.0,0.0,0.0,1.0,0.0,0.0]],"alpha_blending":[{"blend_mode":"Normal","opacity":1.0,"fill":1.0,"clip":false}],"source_node_id":[null]}},"exposed":true}},{"Value":{"tagged_value":{"VectorModification":{"points":{"add":[1,2,3,4],"remove":[],"delta":[[3,[1.0362898771040632,0.9994054840058096]],[4,[0.0,1.0]],[2,[0.8379395417513005,-0.05940639119491883]],[1,[-0.09890842105846484,-0.06578040790199424]]]},"segments":{"add":[1,2,3,4],"remove":[],"start_point":[[1,1],[4,4],[3,3],[2,2]],"end_point":[[4,1],[2,3],[3,4],[1,2]],"handle_primary":[[4,[0.0,0.0]],[3,[0.0,0.0]],[2,[0.0,0.0]],[1,[0.0,0.0]]],"handle_end":[[1,[0.0,0.0]],[2,[0.0,0.0]],[4,[0.0,0.0]],[3,[0.0,0.0]]],"stroke":[[2,0],[1,0],[4,0],[3,0]]},"regions":{"add":[0],"remove":[],"segment_range":[[0,{"start":1,"end":4}]],"fill":[[0,0]]},"add_g1_continuous":[],"remove_g1_continuous":[]}},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::vector_data::modification::VectorModification","alias":null}},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::vector_data::modification::PathModifyNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[173,{"inputs":[{"Node":{"node_id":174,"output_index":0,"lambda":false}},{"Node":{"node_id":214,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[16360261423333265502,{"inputs":[{"Node":{"node_id":287,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"OptionalColor":{"red":0.24313726,"green":0.18431373,"blue":0.19215687,"alpha":1.0}},"exposed":false}},{"Value":{"tagged_value":{"F64":2.0},"exposed":false}},{"Value":{"tagged_value":{"StrokeAlign":"Center"},"exposed":false}},{"Value":{"tagged_value":{"StrokeCap":"Butt"},"exposed":false}},{"Value":{"tagged_value":{"StrokeJoin":"Miter"},"exposed":false}},{"Value":{"tagged_value":{"F64":4.0},"exposed":false}},{"Value":{"tagged_value":{"PaintOrder":"StrokeAbove"},"exposed":false}},{"Value":{"tagged_value":{"VecF64":[]},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::StrokeNode"}},"visible":true,"skip_deduplication":false}],[16831252454255560063,{"inputs":[{"Node":{"node_id":14080831508667499826,"output_index":0,"lambda":false}},{"Node":{"node_id":17257434333682934071,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[406,{"inputs":[{"Value":{"tagged_value":{"VectorData":{"instance":[{"style":{"stroke":{"color":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0},"weight":0.0,"dash_lengths":[],"dash_offset":0.0,"cap":"Butt","join":"Miter","join_miter_limit":4.0,"align":"Center","transform":[1.0,0.0,0.0,1.0,0.0,0.0],"non_scaling":false,"paint_order":"StrokeAbove"},"fill":"None"},"colinear_manipulators":[],"point_domain":{"id":[],"position":[]},"segment_domain":{"id":[],"start_point":[],"end_point":[],"handles":[],"stroke":[]},"region_domain":{"id":[],"segment_range":[],"fill":[]},"upstream_graphic_group":null}],"transform":[[1.0,0.0,0.0,1.0,0.0,0.0]],"alpha_blending":[{"blend_mode":"Normal","opacity":1.0,"fill":1.0,"clip":false}],"source_node_id":[null]}},"exposed":true}},{"Value":{"tagged_value":{"VectorModification":{"points":{"add":[1,2,3,4,5,6],"remove":[],"delta":[[6,[428.9444444444444,568.9444444444443]],[1,[401.70713305898494,260.36282578875165]],[5,[332.5,581.8333333333333]],[3,[369.7510288065844,308.3847736625514]],[4,[353.38888888888886,444.5]],[2,[380.6371742112481,265.1035665294926]]]},"segments":{"add":[1,2,3,4,5,6],"remove":[],"start_point":[[6,6],[1,1],[3,3],[2,2],[5,5],[4,4]],"end_point":[[3,4],[5,6],[2,3],[1,2],[6,1],[4,5]],"handle_primary":[[5,[0.0,0.0]],[4,[-5.333333333333314,40.0]],[2,[-10.643715697978225,7.851921416541302]],[3,[-1.3105663299890011,14.89279920442118]],[1,[-10.359396433470463,-3.160493827160451]],[6,[0.0,0.0]]],"handle_end":[[4,[4.0,-30.666666666666742]],[6,[0.0,0.0]],[2,[0.9657064471879266,-10.97393689986285]],[5,[0.0,0.0]],[3,[5.333333333333314,-40.0]],[1,null]],"stroke":[[3,0],[5,0],[6,0],[2,0],[1,0],[4,0]]},"regions":{"add":[0],"remove":[],"segment_range":[[0,{"start":1,"end":6}]],"fill":[[0,0]]},"add_g1_continuous":[],"remove_g1_continuous":[]}},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::vector_data::modification::VectorModification","alias":null}},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::vector_data::modification::PathModifyNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[9286544882258200464,{"inputs":[{"Value":{"tagged_value":{"VectorData":{"instance":[{"style":{"stroke":{"color":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0},"weight":0.0,"dash_lengths":[],"dash_offset":0.0,"cap":"Butt","join":"Miter","join_miter_limit":4.0,"align":"Center","transform":[1.0,0.0,0.0,1.0,0.0,0.0],"non_scaling":false,"paint_order":"StrokeAbove"},"fill":"None"},"colinear_manipulators":[],"point_domain":{"id":[],"position":[]},"segment_domain":{"id":[],"start_point":[],"end_point":[],"handles":[],"stroke":[]},"region_domain":{"id":[],"segment_range":[],"fill":[]},"upstream_graphic_group":null}],"transform":[[1.0,0.0,0.0,1.0,0.0,0.0]],"alpha_blending":[{"blend_mode":"Normal","opacity":1.0,"fill":1.0,"clip":false}],"source_node_id":[null]}},"exposed":true}},{"Value":{"tagged_value":{"VectorModification":{"points":{"add":[1,2,3,4],"remove":[],"delta":[[2,[472.818244170096,545.5973936899862]],[3,[455.2160493827161,586.837448559671]],[4,[464.82921810699577,552.1378600823044]],[1,[480.8950617283949,532.7798353909467]]]},"segments":{"add":[1,2,3,4],"remove":[],"start_point":[[4,4],[1,1],[2,2],[3,3]],"end_point":[[2,3],[4,1],[3,4],[1,2]],"handle_primary":[[1,[0.0,0.0]],[2,[-5.249967385837806,9.166609721304098]],[3,[0.0,0.0]],[4,[4.236143848022095,-8.765075372687306]]],"handle_end":[[3,[-10.501290993452583,21.72839506172852]],[4,[-3.58969669257732,1.843621399176868]],[2,[0.0,0.0]],[1,[5.530864197530832,-9.657064471879266]]],"stroke":[[3,0],[4,0],[2,0],[1,0]]},"regions":{"add":[0],"remove":[],"segment_range":[[0,{"start":1,"end":4}]],"fill":[[0,0]]},"add_g1_continuous":[],"remove_g1_continuous":[]}},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::vector_data::modification::VectorModification","alias":null}},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::vector_data::modification::PathModifyNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[266,{"inputs":[{"Value":{"tagged_value":{"VectorData":{"instance":[{"style":{"stroke":{"color":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0},"weight":0.0,"dash_lengths":[],"dash_offset":0.0,"cap":"Butt","join":"Miter","join_miter_limit":4.0,"align":"Center","transform":[1.0,0.0,0.0,1.0,0.0,0.0],"non_scaling":false,"paint_order":"StrokeAbove"},"fill":"None"},"colinear_manipulators":[],"point_domain":{"id":[],"position":[]},"segment_domain":{"id":[],"start_point":[],"end_point":[],"handles":[],"stroke":[]},"region_domain":{"id":[],"segment_range":[],"fill":[]},"upstream_graphic_group":null}],"transform":[[1.0,0.0,0.0,1.0,0.0,0.0]],"alpha_blending":[{"blend_mode":"Normal","opacity":1.0,"fill":1.0,"clip":false}],"source_node_id":[null]}},"exposed":true}},{"Value":{"tagged_value":{"VectorModification":{"points":{"add":[1,2,3,4,5,6,7,8],"remove":[],"delta":[[8,[877.5736601163951,577.8827160493829]],[2,[903.0185185185188,539.9074074074074]],[3,[907.9074074074074,539.3148148148149]],[1,[890.376543209877,558.3271604938273]],[5,[916.9444444444443,525.3888888888889]],[4,[906.574074074074,531.3148148148149]],[7,[902.8209876543212,578.672839506173]],[6,[931.067901234568,549.8333333333334]]]},"segments":{"add":[1,2,3,4,5,6,7,8],"remove":[],"start_point":[[2,2],[3,3],[8,8],[4,4],[1,1],[7,7],[6,6],[5,5]],"end_point":[[1,2],[6,7],[8,1],[5,6],[2,3],[3,4],[4,5],[7,8]],"handle_primary":[[5,[12.296296296296418,0.14814814814803867]],[3,[0.0,0.0]],[1,[0.0,0.0]],[2,[0.0,0.0]],[6,[0.0,0.0]],[4,[0.05385802469163536,0.0]],[8,[0.0,0.0]],[7,[0.0,0.0]]],"handle_end":[[3,[0.2962962962964184,4.888888888889028]],[4,[-3.0120068298679143,-0.036289238914037014]],[5,[0.0,0.0]],[7,[0.0,0.0]],[8,[0.0,0.0]],[2,[0.0,0.0]],[1,[-16.592592592592723,23.703703703703923]],[6,[0.0,0.0]]],"stroke":[[5,0],[7,0],[8,0],[6,0],[4,0],[1,0],[2,0],[3,0]]},"regions":{"add":[0],"remove":[],"segment_range":[[0,{"start":1,"end":8}]],"fill":[[0,0]]},"add_g1_continuous":[],"remove_g1_continuous":[]}},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::vector_data::modification::VectorModification","alias":null}},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::vector_data::modification::PathModifyNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[126,{"inputs":[{"Value":{"tagged_value":{"VectorData":{"instance":[{"style":{"stroke":{"color":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0},"weight":0.0,"dash_lengths":[],"dash_offset":0.0,"cap":"Butt","join":"Miter","join_miter_limit":4.0,"align":"Center","transform":[1.0,0.0,0.0,1.0,0.0,0.0],"non_scaling":false,"paint_order":"StrokeAbove"},"fill":"None"},"colinear_manipulators":[],"point_domain":{"id":[],"position":[]},"segment_domain":{"id":[],"start_point":[],"end_point":[],"handles":[],"stroke":[]},"region_domain":{"id":[],"segment_range":[],"fill":[]},"upstream_graphic_group":null}],"transform":[[1.0,0.0,0.0,1.0,0.0,0.0]],"alpha_blending":[{"blend_mode":"Normal","opacity":1.0,"fill":1.0,"clip":false}],"source_node_id":[null]}},"exposed":true}},{"Value":{"tagged_value":{"VectorModification":{"points":{"add":[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17],"remove":[],"delta":[[14,[188.5493827160494,680.4012345679012]],[2,[79.11728395061729,724.0555555555555]],[15,[196.05555555555557,678.8209876543209]],[13,[177.0925925925926,696.4012345679012]],[6,[123.75925925925928,720.3024691358024]],[3,[94.12962962962963,696.9938271604938]],[16,[211.0679012345679,719.5123456790124]],[9,[158.40763603109284,655.1124066453283]],[1,[83.98971193415636,727.8086419753087]],[10,[158.3271604938272,661.4382716049382]],[12,[169.3888888888889,709.0432098765432]],[7,[131.06790123456793,702.1296296296296]],[4,[102.03086419753087,696.7962962962963]],[8,[148.8456790123457,665.3888888888888]],[11,[162.67283950617286,705.2901234567901]],[5,[115.66049382716052,719.5123456790124]],[17,[209.09259259259255,727.8086419753085]]]},"segments":{"add":[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17],"remove":[],"start_point":[[17,17],[6,6],[4,4],[2,2],[12,12],[16,16],[13,13],[1,1],[7,7],[3,3],[10,10],[15,15],[14,14],[9,9],[5,5],[11,11],[8,8]],"end_point":[[13,14],[14,15],[6,7],[16,17],[3,4],[7,8],[2,3],[12,13],[4,5],[10,11],[11,12],[17,1],[8,9],[15,16],[9,10],[5,6],[1,2]],"handle_primary":[[5,[0.9523778763475974,1.643318688599834]],[7,[2.962962962962962,-6.320987654321016]],[13,[3.555555555555543,-7.308641975308547]],[1,[-3.7139917695473343,-0.22427983539080287]],[15,[2.370370370370381,3.950617283950692]],[9,[1.416857186404485,0.2219173906416927]],[3,[2.3703703703704093,-2.5679012345678984]],[12,[0.0,0.0]],[8,[2.172839506172835,-5.3333333333332575]],[6,[0.0,0.0]],[4,[3.753086419753103,4.9382716049382225]],[14,[2.3703703703703525,-2.5679012345678984]],[10,[-0.24572721430195088,3.082066920469856]],[2,[3.2490948717098007,-6.29142916067417]],[11,[0.0,0.0]],[16,[0.0,0.0]],[17,[-3.028806584362002,2.897119341564121]]],"handle_end":[[17,[4.846281557722946,0.29265633783461453]],[12,[-3.5555555555555713,7.308641975308547]],[10,[1.1851851851851904,-8.296296296296305]],[11,[-4.148148148148152,-0.39506172839503506]],[15,[-3.753086419753089,-24.493827160493765]],[7,[-2.172839506172835,5.3333333333332575]],[13,[-2.370370370370381,2.5679012345678984]],[2,[-2.3703703703703525,2.5679012345678984]],[1,[-2.4142661179698734,4.6748971193414945]],[3,[-3.753086419753074,-4.9382716049382225]],[4,[-1.119341563786023,-1.9314128943758533]],[16,[3.77785186523289,-3.613597436310215]],[5,[-4.148148148148167,0.5925925925926094]],[8,[-2.3218581751052625,-0.3636645334502191]],[6,[-2.962962962962962,6.320987654321016]],[9,[0.31458619112936503,-3.9457399786616634]],[14,[-2.370370370370381,-3.950617283950692]]],"stroke":[[2,0],[15,0],[7,0],[6,0],[4,0],[5,0],[11,0],[9,0],[13,0],[1,0],[12,0],[16,0],[14,0],[10,0],[17,0],[3,0],[8,0]]},"regions":{"add":[0],"remove":[],"segment_range":[[0,{"start":1,"end":17}]],"fill":[[0,0]]},"add_g1_continuous":[],"remove_g1_continuous":[]}},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::vector_data::modification::VectorModification","alias":null}},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::vector_data::modification::PathModifyNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[16164610528699022118,{"inputs":[{"Node":{"node_id":7134154821675013808,"output_index":0,"lambda":false}},{"Node":{"node_id":12875520257830460085,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[600590258445096812,{"inputs":[{"Node":{"node_id":9778003574990260202,"output_index":0,"lambda":false}},{"Node":{"node_id":12435496696188763850,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[188,{"inputs":[{"Value":{"tagged_value":{"VectorData":{"instance":[{"style":{"stroke":{"color":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0},"weight":0.0,"dash_lengths":[],"dash_offset":0.0,"cap":"Butt","join":"Miter","join_miter_limit":4.0,"align":"Center","transform":[1.0,0.0,0.0,1.0,0.0,0.0],"non_scaling":false,"paint_order":"StrokeAbove"},"fill":"None"},"colinear_manipulators":[],"point_domain":{"id":[],"position":[]},"segment_domain":{"id":[],"start_point":[],"end_point":[],"handles":[],"stroke":[]},"region_domain":{"id":[],"segment_range":[],"fill":[]},"upstream_graphic_group":null}],"transform":[[1.0,0.0,0.0,1.0,0.0,0.0]],"alpha_blending":[{"blend_mode":"Normal","opacity":1.0,"fill":1.0,"clip":false}],"source_node_id":[null]}},"exposed":true}},{"Value":{"tagged_value":{"VectorModification":{"points":{"add":[1,2,3],"remove":[],"delta":[[3,[1026.2777777777778,610.4999999999999]],[2,[987.6111111111112,593.3888888888889]],[1,[1027.3333333333333,523.5555555555555]]]},"segments":{"add":[1,2,3],"remove":[],"start_point":[[1,1],[3,3],[2,2]],"end_point":[[2,3],[1,2],[3,1]],"handle_primary":[[1,[0.0,0.0]],[2,[0.0,0.0]],[3,[0.0,0.0]]],"handle_end":[[2,[-16.66666666666663,0.22222222222228535]],[1,[28.22222222222217,-65.11111111111109]],[3,[0.0,0.0]]],"stroke":[[3,0],[2,0],[1,0]]},"regions":{"add":[0],"remove":[],"segment_range":[[0,{"start":1,"end":3}]],"fill":[[0,0]]},"add_g1_continuous":[],"remove_g1_continuous":[]}},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::vector_data::modification::VectorModification","alias":null}},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::vector_data::modification::PathModifyNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[3885641499621884510,{"inputs":[{"Value":{"tagged_value":{"GraphicGroup":{"instance":[],"transform":[],"alpha_blending":[],"source_node_id":[]}},"exposed":true}},{"Node":{"node_id":600590258445096812,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[421,{"inputs":[{"Node":{"node_id":422,"output_index":0,"lambda":false}},{"Node":{"node_id":424,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[79,{"inputs":[{"Value":{"tagged_value":{"GraphicGroup":{"instance":[],"transform":[],"alpha_blending":[],"source_node_id":[]}},"exposed":true}},{"Node":{"node_id":493,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[250,{"inputs":[{"Node":{"node_id":254,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"Fill":{"Gradient":{"stops":[[0.0,{"red":0.3764706,"green":0.23529412,"blue":0.20784314,"alpha":1.0}],[1.0,{"red":0.50980395,"green":0.26666668,"blue":0.2,"alpha":1.0}]],"gradient_type":"Linear","start":[0.6377392483726765,0.3630996922378644],"end":[0.6306417402456479,0.9306187973093224],"transform":[632.5762009234635,-34.77347770644815,7.911125258864406,143.91397960043895,1102.6156431423424,426.6593636915554]}}},"exposed":false}},{"Value":{"tagged_value":{"OptionalColor":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}},"exposed":false}},{"Value":{"tagged_value":{"Gradient":{"stops":[[0.0,{"red":0.3764706,"green":0.23529412,"blue":0.20784314,"alpha":1.0}],[1.0,{"red":0.50980395,"green":0.26666668,"blue":0.2,"alpha":1.0}]],"gradient_type":"Linear","start":[0.6377392483726765,0.3630996922378644],"end":[0.6306417402456479,0.9306187973093224],"transform":[632.5762009234635,-34.77347770644815,7.911125258864406,143.91397960043895,1102.6156431423424,426.6593636915554]}},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::FillNode"}},"visible":true,"skip_deduplication":false}],[281,{"inputs":[{"Value":{"tagged_value":{"VectorData":{"instance":[{"style":{"stroke":{"color":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0},"weight":0.0,"dash_lengths":[],"dash_offset":0.0,"cap":"Butt","join":"Miter","join_miter_limit":4.0,"align":"Center","transform":[1.0,0.0,0.0,1.0,0.0,0.0],"non_scaling":false,"paint_order":"StrokeAbove"},"fill":"None"},"colinear_manipulators":[],"point_domain":{"id":[],"position":[]},"segment_domain":{"id":[],"start_point":[],"end_point":[],"handles":[],"stroke":[]},"region_domain":{"id":[],"segment_range":[],"fill":[]},"upstream_graphic_group":null}],"transform":[[1.0,0.0,0.0,1.0,0.0,0.0]],"alpha_blending":[{"blend_mode":"Normal","opacity":1.0,"fill":1.0,"clip":false}],"source_node_id":[null]}},"exposed":true}},{"Value":{"tagged_value":{"VectorModification":{"points":{"add":[1,2,3,4,5,6,7,8],"remove":[],"delta":[[6,[923.4629629629628,289.38888888888886]],[1,[1026.168038408779,250.70576131687224]],[4,[929.6851851851852,121.58641975308646]],[5,[923.3641975308644,158.72222222222226]],[7,[926.7222222222222,528.7962962962963]],[2,[998.8209876543212,150.42592592592595]],[8,[1026.2777777777776,592.5]],[3,[972.746913580247,118.22839506172843]]]},"segments":{"add":[1,2,3,4,5,6,7,8],"remove":[],"start_point":[[3,3],[8,8],[6,6],[1,1],[5,5],[2,2],[4,4],[7,7]],"end_point":[[7,8],[1,2],[4,5],[3,4],[2,3],[8,1],[5,6],[6,7]],"handle_primary":[[1,[-10.22770919067159,-29.761316872427727]],[6,[0.2962962962964184,19.259259259259295]],[8,[0.0,0.0]],[7,[0.0,0.0]],[4,[-5.135802469135797,10.864197530864176]],[2,[-4.543209876543415,-11.06172839506172]],[3,[-17.77777777777783,-3.753086419753074]],[5,[0.0,11.061728395061747]]],"handle_end":[[3,[5.135802469135797,-10.864197530864176]],[4,[0.0,-11.061728395061747]],[8,null],[1,[4.543209876543187,11.06172839506172]],[6,[-2.370370370370324,-53.03703703703695]],[2,[17.77777777777783,3.753086419753089]],[5,[-0.2962962962964184,-19.259259259259295]],[7,[0.0,0.0]]],"stroke":[[5,0],[2,0],[7,0],[4,0],[1,0],[6,0],[3,0],[8,0]]},"regions":{"add":[0],"remove":[],"segment_range":[[0,{"start":1,"end":8}]],"fill":[[0,0]]},"add_g1_continuous":[],"remove_g1_continuous":[]}},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::vector_data::modification::VectorModification","alias":null}},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::vector_data::modification::PathModifyNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[5382879283978921947,{"inputs":[{"Value":{"tagged_value":{"VectorData":{"instance":[{"style":{"stroke":{"color":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0},"weight":0.0,"dash_lengths":[],"dash_offset":0.0,"cap":"Butt","join":"Miter","join_miter_limit":4.0,"align":"Center","transform":[1.0,0.0,0.0,1.0,0.0,0.0],"non_scaling":false,"paint_order":"StrokeAbove"},"fill":"None"},"colinear_manipulators":[],"point_domain":{"id":[],"position":[]},"segment_domain":{"id":[],"start_point":[],"end_point":[],"handles":[],"stroke":[]},"region_domain":{"id":[],"segment_range":[],"fill":[]},"upstream_graphic_group":null}],"transform":[[1.0,0.0,0.0,1.0,0.0,0.0]],"alpha_blending":[{"blend_mode":"Normal","opacity":1.0,"fill":1.0,"clip":false}],"source_node_id":[null]}},"exposed":true}},{"Value":{"tagged_value":{"VectorModification":{"points":{"add":[1,2,3,4,5,6],"remove":[],"delta":[[1,[740.3456790123458,588.2030178326476]],[5,[767.1831275720166,614.1625514403293]],[3,[794.0473251028808,582.3820301783265]],[4,[789.2187928669412,601.4967933823075]],[6,[751.1172839506169,611.1776406035664]],[2,[755.3312757201647,586.2448559670783]]]},"segments":{"add":[1,2,3,4,5,6],"remove":[],"start_point":[[6,6],[4,4],[2,2],[3,3],[1,1],[5,5]],"end_point":[[4,5],[5,6],[1,2],[6,1],[3,4],[2,3]],"handle_primary":[[1,[0.0,0.0]],[4,[-8.427983539094612,8.539557783673331]],[3,[0.0,0.0]],[2,[9.481481481481524,0.4824094931645959]],[5,[-11.149519890260535,0.2794994541025062]],[6,[0.0,0.0]]],"handle_end":[[2,[-9.305898491083669,-1.1412894375856697]],[1,[-9.481481481481524,-0.4824094931645959]],[5,[0.0,0.0]],[4,[11.149519890260535,-0.2794994541025062]],[3,[8.427983539094612,-8.539557783673331]],[6,[0.0,0.0]]],"stroke":[[5,0],[1,0],[3,0],[2,0],[6,0],[4,0]]},"regions":{"add":[0],"remove":[],"segment_range":[[0,{"start":1,"end":6}]],"fill":[[0,0]]},"add_g1_continuous":[],"remove_g1_continuous":[]}},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::vector_data::modification::VectorModification","alias":null}},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::vector_data::modification::PathModifyNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[312,{"inputs":[{"Node":{"node_id":316,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"Fill":{"Solid":{"red":0.5058824,"green":0.26666668,"blue":0.20392157,"alpha":1.0}}},"exposed":false}},{"Value":{"tagged_value":{"OptionalColor":{"red":0.5058824,"green":0.26666668,"blue":0.20392157,"alpha":1.0}},"exposed":false}},{"Value":{"tagged_value":{"Gradient":{"stops":[[0.0,{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}],[1.0,{"red":1.0,"green":1.0,"blue":1.0,"alpha":1.0}]],"gradient_type":"Linear","start":[0.0,0.5],"end":[1.0,0.5],"transform":[1.0,0.0,0.0,1.0,0.0,0.0]}},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::FillNode"}},"visible":true,"skip_deduplication":false}],[5105625446268484763,{"inputs":[{"Node":{"node_id":9422094883894860610,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"Fill":{"Solid":{"red":0.5058824,"green":0.26666668,"blue":0.20392157,"alpha":1.0}}},"exposed":false}},{"Value":{"tagged_value":{"OptionalColor":{"red":0.5058824,"green":0.26666668,"blue":0.20392157,"alpha":1.0}},"exposed":false}},{"Value":{"tagged_value":{"Gradient":{"stops":[[0.0,{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}],[1.0,{"red":1.0,"green":1.0,"blue":1.0,"alpha":1.0}]],"gradient_type":"Linear","start":[0.0,0.5],"end":[1.0,0.5],"transform":[1.0,0.0,0.0,1.0,0.0,0.0]}},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::FillNode"}},"visible":true,"skip_deduplication":false}],[989999757220954936,{"inputs":[{"Node":{"node_id":10544930474333783117,"output_index":0,"lambda":false}},{"Node":{"node_id":5105625446268484763,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[172,{"inputs":[{"Node":{"node_id":173,"output_index":0,"lambda":false}},{"Node":{"node_id":208,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[436,{"inputs":[{"Node":{"node_id":439,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"Fill":{"Gradient":{"stops":[[0.0,{"red":0.7490196,"green":0.3764706,"blue":0.19215687,"alpha":1.0}],[0.08176100628930963,{"red":0.827451,"green":0.42352942,"blue":0.19215687,"alpha":1.0}],[1.0,{"red":0.84705883,"green":0.48235294,"blue":0.20784314,"alpha":1.0}]],"gradient_type":"Linear","start":[0.5000000000000004,0.0],"end":[0.5000000000000004,1.0],"transform":[481.5000000000001,0.0,0.0,158.99999999999997,876.9999999999998,682.9999999999998]}}},"exposed":false}},{"Value":{"tagged_value":{"OptionalColor":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}},"exposed":false}},{"Value":{"tagged_value":{"Gradient":{"stops":[[0.0,{"red":0.7490196,"green":0.3764706,"blue":0.19215687,"alpha":1.0}],[0.08176100628930963,{"red":0.827451,"green":0.42352942,"blue":0.19215687,"alpha":1.0}],[1.0,{"red":0.84705883,"green":0.48235294,"blue":0.20784314,"alpha":1.0}]],"gradient_type":"Linear","start":[0.5000000000000004,0.0],"end":[0.5000000000000004,1.0],"transform":[481.5000000000001,0.0,0.0,158.99999999999997,876.9999999999998,682.9999999999998]}},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::FillNode"}},"visible":true,"skip_deduplication":false}],[94,{"inputs":[{"Value":{"tagged_value":{"VectorData":{"instance":[{"style":{"stroke":{"color":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0},"weight":0.0,"dash_lengths":[],"dash_offset":0.0,"cap":"Butt","join":"Miter","join_miter_limit":4.0,"align":"Center","transform":[1.0,0.0,0.0,1.0,0.0,0.0],"non_scaling":false,"paint_order":"StrokeAbove"},"fill":"None"},"colinear_manipulators":[],"point_domain":{"id":[],"position":[]},"segment_domain":{"id":[],"start_point":[],"end_point":[],"handles":[],"stroke":[]},"region_domain":{"id":[],"segment_range":[],"fill":[]},"upstream_graphic_group":null}],"transform":[[1.0,0.0,0.0,1.0,0.0,0.0]],"alpha_blending":[{"blend_mode":"Normal","opacity":1.0,"fill":1.0,"clip":false}],"source_node_id":[null]}},"exposed":true}},{"Value":{"tagged_value":{"VectorModification":{"points":{"add":[1,2,3,4],"remove":[],"delta":[[3,[0.5,1.0]],[2,[1.0,0.5]],[1,[0.5,0.0]],[4,[0.0,0.5]]]},"segments":{"add":[1,2,3,4],"remove":[],"start_point":[[2,2],[4,4],[3,3],[1,1]],"end_point":[[4,1],[3,4],[2,3],[1,2]],"handle_primary":[[4,[0.0,-0.275892388889507]],[3,[-0.275892388889507,0.0]],[2,[0.0,0.27589238888950707]],[1,[0.27589238888950707,0.0]]],"handle_end":[[2,[0.27589238888950707,0.0]],[1,[0.0,-0.275892388889507]],[4,[-0.275892388889507,0.0]],[3,[0.0,0.27589238888950707]]],"stroke":[[1,0],[4,0],[3,0],[2,0]]},"regions":{"add":[0],"remove":[],"segment_range":[[0,{"start":1,"end":4}]],"fill":[[0,0]]},"add_g1_continuous":[],"remove_g1_continuous":[]}},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::vector_data::modification::VectorModification","alias":null}},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::vector_data::modification::PathModifyNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[467,{"inputs":[{"Node":{"node_id":465,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"OptionalColor":{"red":0.24313726,"green":0.18431373,"blue":0.19215687,"alpha":1.0}},"exposed":false}},{"Value":{"tagged_value":{"F64":2.0},"exposed":false}},{"Value":{"tagged_value":{"StrokeAlign":"Center"},"exposed":false}},{"Value":{"tagged_value":{"StrokeCap":"Butt"},"exposed":false}},{"Value":{"tagged_value":{"StrokeJoin":"Round"},"exposed":false}},{"Value":{"tagged_value":{"F64":4.0},"exposed":false}},{"Value":{"tagged_value":{"PaintOrder":"StrokeAbove"},"exposed":false}},{"Value":{"tagged_value":{"VecF64":[]},"exposed":false}},{"Value":{"tagged_value":{"F64":0.0},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::StrokeNode"}},"visible":true,"skip_deduplication":false}],[327,{"inputs":[{"Node":{"node_id":331,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"Fill":{"Solid":{"red":0.24313726,"green":0.18431373,"blue":0.19215687,"alpha":1.0}}},"exposed":false}},{"Value":{"tagged_value":{"OptionalColor":{"red":0.24313726,"green":0.18431373,"blue":0.19215687,"alpha":1.0}},"exposed":false}},{"Value":{"tagged_value":{"Gradient":{"stops":[[0.0,{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}],[1.0,{"red":1.0,"green":1.0,"blue":1.0,"alpha":1.0}]],"gradient_type":"Linear","start":[0.0,0.5],"end":[1.0,0.5],"transform":[1.0,0.0,0.0,1.0,0.0,0.0]}},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::FillNode"}},"visible":true,"skip_deduplication":false}],[218,{"inputs":[{"Value":{"tagged_value":{"VectorData":{"instance":[{"style":{"stroke":{"color":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0},"weight":0.0,"dash_lengths":[],"dash_offset":0.0,"cap":"Butt","join":"Miter","join_miter_limit":4.0,"align":"Center","transform":[1.0,0.0,0.0,1.0,0.0,0.0],"non_scaling":false,"paint_order":"StrokeAbove"},"fill":"None"},"colinear_manipulators":[],"point_domain":{"id":[],"position":[]},"segment_domain":{"id":[],"start_point":[],"end_point":[],"handles":[],"stroke":[]},"region_domain":{"id":[],"segment_range":[],"fill":[]},"upstream_graphic_group":null}],"transform":[[1.0,0.0,0.0,1.0,0.0,0.0]],"alpha_blending":[{"blend_mode":"Normal","opacity":1.0,"fill":1.0,"clip":false}],"source_node_id":[null]}},"exposed":true}},{"Value":{"tagged_value":{"VectorModification":{"points":{"add":[1,2,3,4,5,6,7,8],"remove":[],"delta":[[6,[888.3518518518518,541.9814814814815]],[7,[886.574074074074,540.0555555555557]],[8,[891.0185185185185,531.9074074074074]],[1,[901.9820911446426,504.0199918711579]],[2,[890.7057613168722,514.4753086419753]],[3,[872.8621399176955,563.858024691358]],[5,[880.5,566.7222222222222]],[4,[874.0473251028807,569.7181069958847]]]},"segments":{"add":[1,2,3,4,5,6,7,8],"remove":[],"start_point":[[1,1],[3,3],[5,5],[4,4],[2,2],[6,6],[8,8],[7,7]],"end_point":[[1,2],[4,5],[7,8],[6,7],[5,6],[2,3],[8,1],[3,4]],"handle_primary":[[6,[0.0,0.0]],[4,[0.0,0.0]],[2,[-3.0946502057612406,7.835390946502002]],[8,[0.0,0.0]],[5,[0.0,0.0]],[1,[0.0,0.0]],[7,[0.0,0.0]],[3,[0.0,0.0]]],"handle_end":[[4,[0.0,0.0]],[1,[3.0946502057612406,-7.835390946502002]],[2,[7.111111111111086,-11.522633744855966]],[8,[-7.693415637860312,3.5987654320987303]],[3,[0.0,0.0]],[6,[0.0,0.0]],[5,[0.0,0.0]],[7,[0.0,0.0]]],"stroke":[[7,0],[6,0],[2,0],[4,0],[3,0],[8,0],[1,0],[5,0]]},"regions":{"add":[0],"remove":[],"segment_range":[[0,{"start":1,"end":8}]],"fill":[[0,0]]},"add_g1_continuous":[],"remove_g1_continuous":[]}},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::vector_data::modification::VectorModification","alias":null}},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::vector_data::modification::PathModifyNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[78,{"inputs":[{"Node":{"node_id":79,"output_index":0,"lambda":false}},{"Node":{"node_id":477,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[451,{"inputs":[{"Value":{"tagged_value":{"GraphicGroup":{"instance":[],"transform":[],"alpha_blending":[],"source_node_id":[]}},"exposed":true}},{"Node":{"node_id":471,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[109,{"inputs":[{"Value":{"tagged_value":{"VectorData":{"instance":[{"style":{"stroke":{"color":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0},"weight":0.0,"dash_lengths":[],"dash_offset":0.0,"cap":"Butt","join":"Miter","join_miter_limit":4.0,"align":"Center","transform":[1.0,0.0,0.0,1.0,0.0,0.0],"non_scaling":false,"paint_order":"StrokeAbove"},"fill":"None"},"colinear_manipulators":[],"point_domain":{"id":[],"position":[]},"segment_domain":{"id":[],"start_point":[],"end_point":[],"handles":[],"stroke":[]},"region_domain":{"id":[],"segment_range":[],"fill":[]},"upstream_graphic_group":null}],"transform":[[1.0,0.0,0.0,1.0,0.0,0.0]],"alpha_blending":[{"blend_mode":"Normal","opacity":1.0,"fill":1.0,"clip":false}],"source_node_id":[null]}},"exposed":true}},{"Value":{"tagged_value":{"VectorModification":{"points":{"add":[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52],"remove":[],"delta":[[1,[865.1205730638582,195.5865278374037]],[44,[1156.927131949119,259.8397940478278]],[49,[1038.402865487009,182.635914058747]],[50,[1016.655293659099,296.810666155275]],[40,[1180.3057716641222,344.11163488097947]],[30,[1277.62615559402,478.946580214022]],[33,[1284.1504271423933,435.99512585389954]],[38,[1223.8009153199428,370.7524103701693]],[21,[990.5582074656068,498.5193948591411]],[3,[943.8009280356002,277.78154080585364]],[27,[1093.315484352482,509.93687006879384]],[26,[1143.3348995566753,518.6358987999579]],[51,[994.3640325354912,266.3640655962009]],[48,[1078.092184072945,124.46115941908752]],[23,[972.616460707581,519.7232773913535]],[39,[1145.5096567394662,398.4805644507546]],[29,[1205.8591685619167,441.9757081065748]],[9,[770.907732003715,320.7329951659761]],[46,[1098.7523773094597,263.6456191177121]],[6,[838.3252046702362,291.37377319829744]],[19,[988.3834502828158,483.83978387530175]],[34,[1256.9659623575055,413.8640589204806]],[4,[956.3057818366484,357.1601779777255]],[13,[885.0824841002429,442.5193974022726]],[43,[1210.2086829274988,227.76212560166044]],[35,[1281.975669959602,393.04367149377714]],[24,[1014.480536476308,543.1019171063567]],[41,[1216.7329544758718,262.5582405263166]],[15,[728.4999669392903,519.7232773913535]],[25,[1110.71354181481,529.509684713913]],[12,[783.956275100461,383.2572641712176]],[7,[758.9465674983644,277.2378515101559]],[14,[783.956275100461,458.8300762732051]],[22,[1000.3446147881664,518.0922095042602]],[52,[939.3251404063708,207.7548507796705]],[45,[1105.8203381535304,315.83979150469634]],[36,[1387.451393324966,404.4611467034299]],[42,[1287.4125629165796,203.2961072952616]],[47,[1073.742669707363,200.0339715210751]],[32,[1323.839745728329,479.4902695097197]],[8,[810.5970505896508,321.8203737573716]],[16,[763.8397711596442,482.7524052839062]],[5,[914.9853953636192,333.78153826272217]],[31,[1336.888288825075,539.8397813321702]],[11,[730.1310348263835,333.2378489670244]],[2,[910.288570576692,217.7758226144784]],[10,[670.8689015953286,344.1116348809794]],[20,[969.8980142290924,494.7135697892568]],[37,[1302.6358631961166,363.1407602304008]],[17,[813.8591863638374,482.2087159882085]],[18,[909.5485024066418,487.10191964948825]],[28,[1134.0921815298134,465.8980371172759]]]},"segments":{"add":[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52],"remove":[],"start_point":[[43,43],[27,27],[15,15],[11,11],[10,10],[1,1],[34,34],[39,39],[4,4],[49,49],[2,2],[40,40],[31,31],[3,3],[35,35],[42,42],[20,20],[19,19],[44,44],[45,45],[5,5],[8,8],[7,7],[18,18],[37,37],[33,33],[46,46],[24,24],[41,41],[32,32],[36,36],[22,22],[52,52],[6,6],[14,14],[26,26],[23,23],[30,30],[47,47],[21,21],[50,50],[29,29],[51,51],[17,17],[25,25],[16,16],[9,9],[48,48],[28,28],[13,13],[12,12],[38,38]],"end_point":[[7,8],[44,45],[28,29],[35,36],[1,2],[3,4],[49,50],[12,13],[46,47],[40,41],[52,1],[45,46],[32,33],[15,16],[4,5],[22,23],[8,9],[6,7],[2,3],[38,39],[24,25],[20,21],[31,32],[14,15],[5,6],[36,37],[16,17],[42,43],[39,40],[19,20],[51,52],[43,44],[34,35],[25,26],[13,14],[9,10],[48,49],[18,19],[27,28],[47,48],[37,38],[50,51],[41,42],[33,34],[23,24],[30,31],[26,27],[10,11],[29,30],[11,12],[17,18],[21,22]],"handle_primary":[[5,[-19.02912534942118,-15.766989575234843]],[42,[0.0,0.0]],[38,[-17.941746758026056,-1.0873785913955205]],[14,[-44.03883295151786,20.11650394081687]],[22,[0.0,0.0]],[6,[-25.00970760209657,-1.0873785913954634]],[23,[0.0,0.0]],[4,[0.0,0.0]],[19,[0.0,0.0]],[10,[0.0,0.0]],[32,[-24.466018306398837,-28.81553267198086]],[40,[12.504853801048512,-14.135921688141591]],[12,[41.864075768726934,30.606794749262978]],[33,[-13.048543096746243,-19.57281464511908]],[36,[0.0,0.0]],[50,[0.0,0.0]],[20,[0.0,0.0]],[15,[0.0,0.0]],[21,[0.0,0.0]],[17,[31.53397915046969,11.961164505350553]],[3,[7.06796084407074,48.3883473171]],[24,[39.145629290237935,9.786407322559626]],[37,[-48.38834731709994,-2.174757182791041]],[13,[0.0,0.0]],[51,[-18.48543605372367,-25.009707602096626]],[2,[16.937999067312603,14.3156740497256]],[9,[-26.64077548918988,2.7184464784887723]],[28,[0.0,0.0]],[11,[26.097086193492142,5.980582252675276]],[29,[20.116503940816983,1.631067887093252]],[39,[0.0,0.0]],[44,[-21.74757182791018,14.135921688141591]],[46,[-6.524271548372781,-16.310678870932577]],[31,[0.0,0.0]],[27,[0.0,0.0]],[7,[0.0,0.0]],[16,[14.13592168814148,-1.631067887093252]],[30,[26.097086193492032,5.436892956977488]],[48,[0.0,0.0]],[26,[0.0,0.0]],[52,[-26.097086193492142,-12.504853801048256]],[43,[-16.310678870932634,13.048543096746071]],[34,[0.0,0.0]],[49,[-10.873785913954862,28.81553267198086]],[45,[0.0,0.0]],[35,[8.699028731163935,-10.3300966182573]],[1,[0.0,0.0]],[8,[0.0,0.0]],[18,[18.485436053723447,-2.7184464784887723]],[41,[15.427586663144211,-29.493915679540574]],[25,[14.679610983839666,-8.155339435466317]],[47,[-1.6310678870931952,-7.611650139768528]]],"handle_end":[[14,[0.0,0.0]],[46,[1.6310678870931952,7.611650139768528]],[6,[0.0,0.0]],[49,[-5.98058225267539,-75.02912280628982]],[33,[0.0,0.0]],[50,[18.48543605372356,25.009707602096626]],[51,[26.097086193492032,12.50485380104834]],[28,[-20.11650394081721,-1.6310678870931952]],[52,[21.791261123607796,0.5873785913955203]],[9,[27.18446478488761,-22.291261123607853]],[18,[-11.41747520965282,-9.242718026861724]],[37,[17.941746758026056,1.0873785913955205]],[47,[-22.83495041930587,36.42718281174942]],[22,[3.805825069884122,-4.3495143655819675]],[42,[16.310678870932634,-13.048543096746071]],[45,[6.524271548372553,16.310678870932577]],[5,[25.00970760209657,1.0873785913954634]],[20,[-4.8932036612795855,-5.980582252675276]],[15,[-14.13592168814148,1.631067887093252]],[21,[-4.3495143655819675,-3.262135774186504]],[17,[-18.48543605372356,2.7184464784887723]],[23,[-39.14562929023816,-9.786407322559626]],[40,[-18.48543605372356,35.33980422035398]],[4,[19.02912534942141,15.766989575234843]],[1,[-14.628148339931158,-12.363432230293256]],[27,[-8.15533943546643,25.00970760209657]],[7,[-5.436892956977545,-19.029125349421292]],[39,[-9.034630967226803,10.21306109338667]],[36,[48.388347317099715,2.174757182790927]],[13,[44.03883295151786,-20.11650394081687]],[8,[26.64077548918988,-2.7184464784887723]],[29,[-26.097086193492032,-5.436892956977488]],[2,[-7.067960844070626,-48.3883473171]],[31,[24.466018306399064,28.81553267198086]],[44,[0.0,0.0]],[19,[3.805825069884008,-5.436892956977601]],[26,[30.446600559074568,-5.980582252675276]],[38,[0.0,0.0]],[16,[-31.53397915046969,-11.961164505350553]],[11,[-41.864075768726934,-30.606794749263088]],[48,[10.87378591395509,-28.81553267198086]],[3,[5.436892956977545,-25.553396897794357]],[35,[-71.76698703210332,-41.864075768726934]],[32,[13.048543096746243,19.57281464511908]],[12,[-31.533979150469577,-8.15533943546626]],[41,[-32.07766844616731,15.223300279537028]],[24,[-14.67961098383944,8.155339435466317]],[43,[21.74757182791018,-14.135921688141565]],[34,[-8.699028731163935,10.330096618257244]],[25,[-12.504853801048284,-3.262135774186504]],[30,[-0.5436892956979591,-24.46601830639895]],[10,[-26.097086193492142,-5.980582252675276]]],"stroke":[[31,0],[52,0],[32,0],[39,0],[45,0],[49,0],[30,0],[10,0],[51,0],[1,0],[37,0],[34,0],[43,0],[7,0],[12,0],[50,0],[3,0],[2,0],[18,0],[22,0],[47,0],[38,0],[15,0],[42,0],[27,0],[11,0],[23,0],[20,0],[33,0],[44,0],[36,0],[6,0],[9,0],[13,0],[8,0],[14,0],[28,0],[40,0],[21,0],[17,0],[26,0],[24,0],[35,0],[5,0],[48,0],[4,0],[25,0],[29,0],[19,0],[46,0],[41,0],[16,0]]},"regions":{"add":[0],"remove":[],"segment_range":[[0,{"start":1,"end":52}]],"fill":[[0,0]]},"add_g1_continuous":[],"remove_g1_continuous":[]}},"exposed":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Concrete":{"name":"graphene_core::instances::Instances","alias":null}},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}},{"Network":{"import_type":{"Concrete":{"name":"graphene_core::vector::vector_data::modification::VectorModification","alias":null}},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::vector::vector_data::modification::PathModifyNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}],[12325841371509826180,{"inputs":[{"Node":{"node_id":6980979116665635870,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"Fill":{"Gradient":{"stops":[[0.0,{"red":0.3764706,"green":0.23529412,"blue":0.20784314,"alpha":1.0}],[1.0,{"red":0.5058824,"green":0.26666668,"blue":0.20392157,"alpha":1.0}]],"gradient_type":"Linear","start":[0.08732233199581252,0.5212000945774993],"end":[0.9287098983518448,0.5070261975055625],"transform":[139.824941251317,-21.014379437271643,45.64496496886203,416.4689172758892,1005.0,432.99999999999955]}}},"exposed":false}},{"Value":{"tagged_value":{"OptionalColor":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}},"exposed":false}},{"Value":{"tagged_value":{"Gradient":{"stops":[[0.0,{"red":0.3764706,"green":0.23529412,"blue":0.20784314,"alpha":1.0}],[1.0,{"red":0.5058824,"green":0.26666668,"blue":0.20392157,"alpha":1.0}]],"gradient_type":"Linear","start":[0.08732233199581252,0.5212000945774993],"end":[0.9287098983518448,0.5070261975055625],"transform":[139.824941251317,-21.014379437271643,45.64496496886203,416.4689172758892,1005.0,432.99999999999955]}},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::FillNode"}},"visible":true,"skip_deduplication":false}],[140,{"inputs":[{"Node":{"node_id":143,"output_index":0,"lambda":false}},{"Value":{"tagged_value":{"Fill":{"Solid":{"red":0.24313726,"green":0.18431373,"blue":0.19215687,"alpha":1.0}}},"exposed":false}},{"Value":{"tagged_value":{"OptionalColor":{"red":0.24313726,"green":0.18431373,"blue":0.19215687,"alpha":1.0}},"exposed":false}},{"Value":{"tagged_value":{"Gradient":{"stops":[[0.0,{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}],[1.0,{"red":1.0,"green":1.0,"blue":1.0,"alpha":1.0}]],"gradient_type":"Linear","start":[0.0,0.5],"end":[1.0,0.5],"transform":[1.0,0.0,0.0,1.0,0.0,0.0]}},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::FillNode"}},"visible":true,"skip_deduplication":false}],[171,{"inputs":[{"Node":{"node_id":172,"output_index":0,"lambda":false}},{"Node":{"node_id":202,"output_index":0,"lambda":false}}],"manual_composition":null,"implementation":{"Network":{"exports":[{"Node":{"node_id":3,"output_index":0,"lambda":false}}],"nodes":[[0,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":1}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToElementNode"}},"visible":true,"skip_deduplication":false}],[3,{"inputs":[{"Node":{"node_id":1,"output_index":0,"lambda":false}},{"Node":{"node_id":2,"output_index":0,"lambda":false}},{"Reflection":"DocumentNodePath"}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::LayerNode"}},"visible":true,"skip_deduplication":false}],[2,{"inputs":[{"Node":{"node_id":0,"output_index":0,"lambda":false}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::memo::MonitorNode"}},"visible":true,"skip_deduplication":true}],[1,{"inputs":[{"Network":{"import_type":{"Generic":"T"},"import_index":0}}],"manual_composition":{"Generic":"T"},"implementation":{"ProtoNode":{"name":"graphene_core::graphic_element::ToGroupNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]},"network_metadata":{"persistent_metadata":{"node_metadata":[[292,{"persistent_metadata":{"reference":"Merge","display_name":"","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":0}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[120,{"persistent_metadata":{"reference":"Merge","display_name":"Ground Shadow","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":0}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[200,{"persistent_metadata":{"reference":"Path","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Modification"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"Path Modify","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[138,{"persistent_metadata":{"reference":"Path","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Modification"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"Path Modify","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[11345069121502219134,{"persistent_metadata":{"reference":"Fill","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Fill"},"widget_override":null},{"input_data":{"input_name":"Backup Color"},"widget_override":null},{"input_data":{"input_name":"Backup Gradient"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[262,{"persistent_metadata":{"reference":"Fill","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Fill"},"widget_override":null},{"input_data":{"input_name":"Backup Color"},"widget_override":null},{"input_data":{"input_name":"Backup Gradient"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[82,{"persistent_metadata":{"reference":"Merge","display_name":"Right Plinth","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":6}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[109,{"persistent_metadata":{"reference":"Path","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Modification"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"Path Modify","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[6272196533192700024,{"persistent_metadata":{"reference":"Transform","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Translation","unit":" px","x":"X","y":"Y"},"widget_override":"vec2"},{"input_data":{"input_name":"Rotation"},"widget_override":"transform_rotation"},{"input_data":{"input_name":"Scale","unit":"x","y":"H","x":"W"},"widget_override":"vec2"},{"input_data":{"input_name":"Skew"},"widget_override":"hidden"},{"input_data":{"input_name":"Pivot"},"widget_override":"hidden"}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"Transform","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[440,{"persistent_metadata":{"reference":"Path","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Modification"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"Path Modify","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[175,{"persistent_metadata":{"reference":"Merge","display_name":"","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":0}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[212,{"persistent_metadata":{"reference":"Path","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Modification"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"Path Modify","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[117,{"persistent_metadata":{"reference":"Merge","display_name":"Stones","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Absolute":[-25,28]}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[214,{"persistent_metadata":{"reference":"Fill","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Fill"},"widget_override":null},{"input_data":{"input_name":"Backup Color"},"widget_override":null},{"input_data":{"input_name":"Backup Gradient"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[90,{"persistent_metadata":{"reference":"Fill","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Fill"},"widget_override":null},{"input_data":{"input_name":"Backup Color"},"widget_override":null},{"input_data":{"input_name":"Backup Gradient"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[174,{"persistent_metadata":{"reference":"Merge","display_name":"","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":0}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[446,{"persistent_metadata":{"reference":"Path","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Modification"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"Path Modify","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[224,{"persistent_metadata":{"reference":"Path","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Modification"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"Path Modify","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[487,{"persistent_metadata":{"reference":"Fill","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Fill"},"widget_override":null},{"input_data":{"input_name":"Backup Color"},"widget_override":null},{"input_data":{"input_name":"Backup Gradient"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[318,{"persistent_metadata":{"reference":"Merge","display_name":"Face","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Absolute":[-25,139]}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[14113040319560793790,{"persistent_metadata":{"reference":"Fill","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Fill"},"widget_override":null},{"input_data":{"input_name":"Backup Color"},"widget_override":null},{"input_data":{"input_name":"Backup Gradient"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[36935169817407978,{"persistent_metadata":{"reference":"Merge","display_name":"","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Absolute":[-35,160]}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[13606781735926093266,{"persistent_metadata":{"reference":"Path","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Modification"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"Path Modify","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[4452902364641883403,{"persistent_metadata":{"reference":"Merge","display_name":"Soft Shadow","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":0}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[9570557034533539493,{"persistent_metadata":{"reference":"Path","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Modification"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"Path Modify","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[14579754335592291854,{"persistent_metadata":{"reference":"Fill","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Fill"},"widget_override":null},{"input_data":{"input_name":"Backup Color"},"widget_override":null},{"input_data":{"input_name":"Backup Gradient"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[248,{"persistent_metadata":{"reference":"Path","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Modification"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"Path Modify","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[11891167879168294182,{"persistent_metadata":{"reference":"Path","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Modification"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"Path Modify","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[422,{"persistent_metadata":{"reference":"Merge","display_name":"Right Half","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":0}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[424,{"persistent_metadata":{"reference":"Fill","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Fill"},"widget_override":null},{"input_data":{"input_name":"Backup Color"},"widget_override":null},{"input_data":{"input_name":"Backup Gradient"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[171,{"persistent_metadata":{"reference":"Merge","display_name":"","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":0}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[16815500381887058038,{"persistent_metadata":{"reference":"Artboard","display_name":"","input_properties":[{"input_data":{"input_name":"Artboards"},"widget_override":null},{"input_data":{"input_name":"Contents"},"widget_override":"hidden"},{"input_data":{"y":"Y","input_name":"Location","unit":" px","x":"X"},"widget_override":"vec2"},{"input_data":{"input_name":"Dimensions","x":"W","unit":" px","y":"H"},"widget_override":"vec2"},{"input_data":{"input_name":"Background"},"widget_override":"artboard_background"},{"input_data":{"input_name":"Clip"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Absolute":[-1,1]}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-2,-3]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Append Artboards","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[6,-4]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"To Artboard","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-10,-3]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[274,{"persistent_metadata":{"reference":"Merge","display_name":"Face","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Absolute":[-25,121]}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[12435496696188763850,{"persistent_metadata":{"reference":"Fill","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Fill"},"widget_override":null},{"input_data":{"input_name":"Backup Color"},"widget_override":null},{"input_data":{"input_name":"Backup Gradient"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[218,{"persistent_metadata":{"reference":"Path","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Modification"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"Path Modify","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[3885641499621884510,{"persistent_metadata":{"reference":"Merge","display_name":"Rock Outcropping","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":6}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[5175066652268973319,{"persistent_metadata":{"reference":"Path","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Modification"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"Path Modify","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[162,{"persistent_metadata":{"reference":"Merge","display_name":"Right Slab Spire","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":60}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[229,{"persistent_metadata":{"reference":"Transform","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"unit":" px","x":"X","input_name":"Translation","y":"Y"},"widget_override":"vec2"},{"input_data":{"input_name":"Rotation"},"widget_override":"transform_rotation"},{"input_data":{"y":"H","x":"W","input_name":"Scale","unit":"x"},"widget_override":"vec2"},{"input_data":{"input_name":"Skew"},"widget_override":"hidden"},{"input_data":{"input_name":"Pivot"},"widget_override":"hidden"}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"Transform","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[118,{"persistent_metadata":{"reference":"Merge","display_name":"Highlight","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":0}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[12875520257830460085,{"persistent_metadata":{"reference":"Fill","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Fill"},"widget_override":null},{"input_data":{"input_name":"Backup Color"},"widget_override":null},{"input_data":{"input_name":"Backup Gradient"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[316,{"persistent_metadata":{"reference":"Path","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Modification"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"Path Modify","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[442,{"persistent_metadata":{"reference":"Fill","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Fill"},"widget_override":null},{"input_data":{"input_name":"Backup Color"},"widget_override":null},{"input_data":{"input_name":"Backup Gradient"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[1635416892097245588,{"persistent_metadata":{"reference":"Merge","display_name":"Shading","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":0}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[11807598261442997948,{"persistent_metadata":{"reference":"Path","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Modification"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"Path Modify","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[600590258445096812,{"persistent_metadata":{"reference":"Merge","display_name":"","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Absolute":[-35,169]}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[176,{"persistent_metadata":{"reference":"Merge","display_name":"","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":0}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[180,{"persistent_metadata":{"reference":"Merge","display_name":"","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":0}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[445,{"persistent_metadata":{"reference":"Transform","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"x":"X","y":"Y","input_name":"Translation","unit":" px"},"widget_override":"vec2"},{"input_data":{"input_name":"Rotation"},"widget_override":"transform_rotation"},{"input_data":{"x":"W","y":"H","unit":"x","input_name":"Scale"},"widget_override":"vec2"},{"input_data":{"input_name":"Skew"},"widget_override":"hidden"},{"input_data":{"input_name":"Pivot"},"widget_override":"hidden"}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"Transform","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[17911294938421300842,{"persistent_metadata":{"reference":"Fill","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Fill"},"widget_override":null},{"input_data":{"input_name":"Backup Color"},"widget_override":null},{"input_data":{"input_name":"Backup Gradient"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[143,{"persistent_metadata":{"reference":"Transform","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"x":"X","input_name":"Translation","unit":" px","y":"Y"},"widget_override":"vec2"},{"input_data":{"input_name":"Rotation"},"widget_override":"transform_rotation"},{"input_data":{"y":"H","input_name":"Scale","unit":"x","x":"W"},"widget_override":"vec2"},{"input_data":{"input_name":"Skew"},"widget_override":"hidden"},{"input_data":{"input_name":"Pivot"},"widget_override":"hidden"}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"Transform","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[16360261423333265502,{"persistent_metadata":{"reference":"Stroke","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Color"},"widget_override":null},{"input_data":{"input_name":"Weight"},"widget_override":null},{"input_data":{"input_name":"Dash Lengths"},"widget_override":null},{"input_data":{"input_name":"Dash Offset"},"widget_override":null},{"input_data":{"input_name":"Line Cap"},"widget_override":null},{"input_data":{"input_name":"Line Join"},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{"input_name":"Miter Limit"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[6015109908395573189,{"persistent_metadata":{"reference":"Transform","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"y":"Y","input_name":"Translation","x":"X","unit":" px"},"widget_override":"vec2"},{"input_data":{"input_name":"Rotation"},"widget_override":"transform_rotation"},{"input_data":{"unit":"x","y":"H","input_name":"Scale","x":"W"},"widget_override":"vec2"},{"input_data":{"input_name":"Skew"},"widget_override":"hidden"},{"input_data":{"input_name":"Pivot"},"widget_override":"hidden"}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"Transform","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[477,{"persistent_metadata":{"reference":"Merge","display_name":"Face","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Absolute":[-15,253]}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[14080831508667499826,{"persistent_metadata":{"reference":"Merge","display_name":"","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":0}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[105,{"persistent_metadata":{"reference":"Fill","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Fill"},"widget_override":null},{"input_data":{"input_name":"Backup Color"},"widget_override":null},{"input_data":{"input_name":"Backup Gradient"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[76,{"persistent_metadata":{"reference":"Merge","display_name":"Ground","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":144}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[3719764965605527929,{"persistent_metadata":{"reference":"Path","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Modification"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"Path Modify","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[103,{"persistent_metadata":{"reference":"Merge","display_name":"Right Plinth","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":0}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[396,{"persistent_metadata":{"reference":"Fill","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Fill"},"widget_override":null},{"input_data":{"input_name":"Backup Color"},"widget_override":null},{"input_data":{"input_name":"Backup Gradient"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[448,{"persistent_metadata":{"reference":"Merge","display_name":"Shadow Fissure","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Absolute":[-15,238]}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[134,{"persistent_metadata":{"reference":"Fill","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Fill"},"widget_override":null},{"input_data":{"input_name":"Backup Color"},"widget_override":null},{"input_data":{"input_name":"Backup Gradient"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[306,{"persistent_metadata":{"reference":"Fill","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Fill"},"widget_override":null},{"input_data":{"input_name":"Backup Color"},"widget_override":null},{"input_data":{"input_name":"Backup Gradient"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[266,{"persistent_metadata":{"reference":"Path","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Modification"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"Path Modify","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[10486443711686704000,{"persistent_metadata":{"reference":"Fill","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Fill"},"widget_override":null},{"input_data":{"input_name":"Backup Color"},"widget_override":null},{"input_data":{"input_name":"Backup Gradient"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[97478832511923699,{"persistent_metadata":{"reference":"Transform","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Translation","y":"Y","unit":" px","x":"X"},"widget_override":"vec2"},{"input_data":{"input_name":"Rotation"},"widget_override":"transform_rotation"},{"input_data":{"x":"W","y":"H","input_name":"Scale","unit":"x"},"widget_override":"vec2"},{"input_data":{"input_name":"Skew"},"widget_override":"hidden"},{"input_data":{"input_name":"Pivot"},"widget_override":"hidden"}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"Transform","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[1598976462838094167,{"persistent_metadata":{"reference":"Path","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Modification"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"Path Modify","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[12717405604755313921,{"persistent_metadata":{"reference":"Merge","display_name":"","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":0}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[9286544882258200464,{"persistent_metadata":{"reference":"Path","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Modification"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"Path Modify","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[173,{"persistent_metadata":{"reference":"Merge","display_name":"","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":0}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[77,{"persistent_metadata":{"reference":"Merge","display_name":"Spike Spire","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":33}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[18142347460553706128,{"persistent_metadata":{"reference":"Opacity","display_name":"","input_properties":[{"input_data":{"input_name":"Value"},"widget_override":null},{"input_data":{"input_name":"Factor"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[290,{"persistent_metadata":{"reference":"Merge","display_name":"","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":0}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[12768614558324028960,{"persistent_metadata":{"reference":"Merge","display_name":"Slope","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":0}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[433,{"persistent_metadata":{"reference":"Transform","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"unit":" px","x":"X","input_name":"Translation","y":"Y"},"widget_override":"vec2"},{"input_data":{"input_name":"Rotation"},"widget_override":"transform_rotation"},{"input_data":{"y":"H","input_name":"Scale","unit":"x","x":"W"},"widget_override":"vec2"},{"input_data":{"input_name":"Skew"},"widget_override":"hidden"},{"input_data":{"input_name":"Pivot"},"widget_override":"hidden"}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"Transform","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[497,{"persistent_metadata":{"reference":"Path","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Modification"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"Path Modify","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[17173383864410319040,{"persistent_metadata":{"reference":"Merge","display_name":"","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":0}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[409,{"persistent_metadata":{"reference":"Merge","display_name":"Ground","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":15}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[275,{"persistent_metadata":{"reference":"Merge","display_name":"Shadow","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":0}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[406,{"persistent_metadata":{"reference":"Path","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Modification"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"Path Modify","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[128,{"persistent_metadata":{"reference":"Fill","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Fill"},"widget_override":null},{"input_data":{"input_name":"Backup Color"},"widget_override":null},{"input_data":{"input_name":"Backup Gradient"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[182,{"persistent_metadata":{"reference":"Merge","display_name":"","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":0}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[281,{"persistent_metadata":{"reference":"Path","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Modification"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-53,121]}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"Path Modify","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[165,{"persistent_metadata":{"reference":"Merge","display_name":"Rocky Slope","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":15}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[312,{"persistent_metadata":{"reference":"Fill","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Fill"},"widget_override":null},{"input_data":{"input_name":"Backup Color"},"widget_override":null},{"input_data":{"input_name":"Backup Gradient"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[79,{"persistent_metadata":{"reference":"Merge","display_name":"Sky","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":6}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[208,{"persistent_metadata":{"reference":"Fill","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Fill"},"widget_override":null},{"input_data":{"input_name":"Backup Color"},"widget_override":null},{"input_data":{"input_name":"Backup Gradient"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[402,{"persistent_metadata":{"reference":"Fill","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Fill"},"widget_override":null},{"input_data":{"input_name":"Backup Color"},"widget_override":null},{"input_data":{"input_name":"Backup Gradient"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[394,{"persistent_metadata":{"reference":"Merge","display_name":"Shadow","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":0}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[400,{"persistent_metadata":{"reference":"Path","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Modification"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"Path Modify","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[88,{"persistent_metadata":{"reference":"Merge","display_name":"Left Plinth","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":0}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[413,{"persistent_metadata":{"reference":"Merge","display_name":"From Left Slab Spire","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":6}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[184,{"persistent_metadata":{"reference":"Fill","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Fill"},"widget_override":null},{"input_data":{"input_name":"Backup Color"},"widget_override":null},{"input_data":{"input_name":"Backup Gradient"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[12325841371509826180,{"persistent_metadata":{"reference":"Fill","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Fill"},"widget_override":null},{"input_data":{"input_name":"Backup Color"},"widget_override":null},{"input_data":{"input_name":"Backup Gradient"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[108,{"persistent_metadata":{"reference":"Transform","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Translation","unit":" px","y":"Y","x":"X"},"widget_override":"vec2"},{"input_data":{"input_name":"Rotation"},"widget_override":"transform_rotation"},{"input_data":{"unit":"x","y":"H","input_name":"Scale","x":"W"},"widget_override":"vec2"},{"input_data":{"input_name":"Skew"},"widget_override":"hidden"},{"input_data":{"input_name":"Pivot"},"widget_override":"hidden"}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"Transform","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[144,{"persistent_metadata":{"reference":"Path","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Modification"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"Path Modify","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[15277819403265847073,{"persistent_metadata":{"reference":"Merge","display_name":"","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":0}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[206,{"persistent_metadata":{"reference":"Path","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Modification"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"Path Modify","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[481,{"persistent_metadata":{"reference":"Fill","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Fill"},"widget_override":null},{"input_data":{"input_name":"Backup Color"},"widget_override":null},{"input_data":{"input_name":"Backup Gradient"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[227,{"persistent_metadata":{"reference":"Opacity","display_name":"","input_properties":[{"input_data":{"input_name":"Value"},"widget_override":null},{"input_data":{"input_name":"Factor"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[11377169273880889832,{"persistent_metadata":{"reference":"Merge","display_name":"","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":0}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[16894739051789815098,{"persistent_metadata":{"reference":"Transform","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Translation","unit":" px","x":"X","y":"Y"},"widget_override":"vec2"},{"input_data":{"input_name":"Rotation"},"widget_override":"transform_rotation"},{"input_data":{"unit":"x","input_name":"Scale","x":"W","y":"H"},"widget_override":"vec2"},{"input_data":{"input_name":"Skew"},"widget_override":"hidden"},{"input_data":{"input_name":"Pivot"},"widget_override":"hidden"}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"Transform","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[427,{"persistent_metadata":{"reference":"Transform","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"unit":" px","x":"X","input_name":"Translation","y":"Y"},"widget_override":"vec2"},{"input_data":{"input_name":"Rotation"},"widget_override":"transform_rotation"},{"input_data":{"y":"H","x":"W","input_name":"Scale","unit":"x"},"widget_override":"vec2"},{"input_data":{"input_name":"Skew"},"widget_override":"hidden"},{"input_data":{"input_name":"Pivot"},"widget_override":"hidden"}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"Transform","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[453,{"persistent_metadata":{"reference":"Fill","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Fill"},"widget_override":null},{"input_data":{"input_name":"Backup Color"},"widget_override":null},{"input_data":{"input_name":"Backup Gradient"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-43,238]}}},"network_metadata":null}}],[94,{"persistent_metadata":{"reference":"Path","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Modification"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"Path Modify","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[191,{"persistent_metadata":{"reference":"Opacity","display_name":"","input_properties":[{"input_data":{"input_name":"Value"},"widget_override":null},{"input_data":{"input_name":"Factor"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[168,{"persistent_metadata":{"reference":"Merge","display_name":"","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Absolute":[-25,58]}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[17245613731534563958,{"persistent_metadata":{"reference":"Path","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Modification"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"Path Modify","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[15552693212536925398,{"persistent_metadata":{"reference":"Fill","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Fill"},"widget_override":null},{"input_data":{"input_name":"Backup Color"},"widget_override":null},{"input_data":{"input_name":"Backup Gradient"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[7135480377162524224,{"persistent_metadata":{"reference":"Transform","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"x":"X","unit":" px","y":"Y","input_name":"Translation"},"widget_override":"vec2"},{"input_data":{"input_name":"Rotation"},"widget_override":"transform_rotation"},{"input_data":{"unit":"x","y":"H","input_name":"Scale","x":"W"},"widget_override":"vec2"},{"input_data":{"input_name":"Skew"},"widget_override":"hidden"},{"input_data":{"input_name":"Pivot"},"widget_override":"hidden"}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"Transform","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[250,{"persistent_metadata":{"reference":"Fill","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Fill"},"widget_override":null},{"input_data":{"input_name":"Backup Color"},"widget_override":null},{"input_data":{"input_name":"Backup Gradient"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[202,{"persistent_metadata":{"reference":"Fill","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Fill"},"widget_override":null},{"input_data":{"input_name":"Backup Color"},"widget_override":null},{"input_data":{"input_name":"Backup Gradient"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[11427960919145580782,{"persistent_metadata":{"reference":"Merge","display_name":"","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":0}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[393,{"persistent_metadata":{"reference":"Merge","display_name":"Face","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Absolute":[-25,193]}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[268,{"persistent_metadata":{"reference":"Fill","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Fill"},"widget_override":null},{"input_data":{"input_name":"Backup Color"},"widget_override":null},{"input_data":{"input_name":"Backup Gradient"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[4913361824430066698,{"persistent_metadata":{"reference":"Fill","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Fill"},"widget_override":null},{"input_data":{"input_name":"Backup Color"},"widget_override":null},{"input_data":{"input_name":"Backup Gradient"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[190,{"persistent_metadata":{"reference":"Fill","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Fill"},"widget_override":null},{"input_data":{"input_name":"Backup Color"},"widget_override":null},{"input_data":{"input_name":"Backup Gradient"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[449,{"persistent_metadata":{"reference":"Merge","display_name":"Shadow Lower","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":0}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[1644624352314732667,{"persistent_metadata":{"reference":"Transform","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"unit":" px","input_name":"Translation","y":"Y","x":"X"},"widget_override":"vec2"},{"input_data":{"input_name":"Rotation"},"widget_override":"transform_rotation"},{"input_data":{"y":"H","input_name":"Scale","unit":"x","x":"W"},"widget_override":"vec2"},{"input_data":{"input_name":"Skew"},"widget_override":"hidden"},{"input_data":{"input_name":"Pivot"},"widget_override":"hidden"}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"Transform","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[119,{"persistent_metadata":{"reference":"Merge","display_name":"Highlight","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":0}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[230,{"persistent_metadata":{"reference":"Path","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Modification"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"Path Modify","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[434,{"persistent_metadata":{"reference":"Path","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Modification"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"Path Modify","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[408,{"persistent_metadata":{"reference":"Merge","display_name":"Reflections","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":6}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[412,{"persistent_metadata":{"reference":"Merge","display_name":"From Center Slab Spire","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":0}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[291,{"persistent_metadata":{"reference":"Merge","display_name":"","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":0}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[226,{"persistent_metadata":{"reference":"Fill","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Fill"},"widget_override":null},{"input_data":{"input_name":"Backup Color"},"widget_override":null},{"input_data":{"input_name":"Backup Gradient"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[283,{"persistent_metadata":{"reference":"Fill","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Fill"},"widget_override":null},{"input_data":{"input_name":"Backup Color"},"widget_override":null},{"input_data":{"input_name":"Backup Gradient"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[172,{"persistent_metadata":{"reference":"Merge","display_name":"","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":0}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[4454263454059119441,{"persistent_metadata":{"reference":"Path","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Modification"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"Path Modify","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[11279424538712841875,{"persistent_metadata":{"reference":"Fill","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Fill"},"widget_override":null},{"input_data":{"input_name":"Backup Color"},"widget_override":null},{"input_data":{"input_name":"Backup Gradient"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[15483449862348058100,{"persistent_metadata":{"reference":"Fill","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Fill"},"widget_override":null},{"input_data":{"input_name":"Backup Color"},"widget_override":null},{"input_data":{"input_name":"Backup Gradient"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[450,{"persistent_metadata":{"reference":"Merge","display_name":"Face","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":0}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[15848750910363784662,{"persistent_metadata":{"reference":"Merge","display_name":"","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":0}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[9778003574990260202,{"persistent_metadata":{"reference":"Merge","display_name":"","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":0}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[1453710883947581217,{"persistent_metadata":{"reference":"Stroke","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Color"},"widget_override":null},{"input_data":{"input_name":"Weight"},"widget_override":null},{"input_data":{"input_name":"Dash Lengths"},"widget_override":null},{"input_data":{"input_name":"Dash Offset"},"widget_override":null},{"input_data":{"input_name":"Line Cap"},"widget_override":null},{"input_data":{"input_name":"Line Join"},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{"input_name":"Miter Limit"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[439,{"persistent_metadata":{"reference":"Transform","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Translation","unit":" px","x":"X","y":"Y"},"widget_override":"vec2"},{"input_data":{"input_name":"Rotation"},"widget_override":"transform_rotation"},{"input_data":{"input_name":"Scale","x":"W","y":"H","unit":"x"},"widget_override":"vec2"},{"input_data":{"input_name":"Skew"},"widget_override":"hidden"},{"input_data":{"input_name":"Pivot"},"widget_override":"hidden"}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"Transform","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[100,{"persistent_metadata":{"reference":"Path","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Modification"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"Path Modify","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[196,{"persistent_metadata":{"reference":"Fill","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Fill"},"widget_override":null},{"input_data":{"input_name":"Backup Color"},"widget_override":null},{"input_data":{"input_name":"Backup Gradient"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[493,{"persistent_metadata":{"reference":"Fill","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Fill"},"widget_override":null},{"input_data":{"input_name":"Backup Color"},"widget_override":null},{"input_data":{"input_name":"Backup Gradient"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[194,{"persistent_metadata":{"reference":"Path","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Modification"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"Path Modify","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[17257434333682934071,{"persistent_metadata":{"reference":"Fill","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Fill"},"widget_override":null},{"input_data":{"input_name":"Backup Color"},"widget_override":null},{"input_data":{"input_name":"Backup Gradient"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[430,{"persistent_metadata":{"reference":"Fill","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Fill"},"widget_override":null},{"input_data":{"input_name":"Backup Color"},"widget_override":null},{"input_data":{"input_name":"Backup Gradient"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[6980979116665635870,{"persistent_metadata":{"reference":"Transform","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"unit":" px","x":"X","input_name":"Translation","y":"Y"},"widget_override":"vec2"},{"input_data":{"input_name":"Rotation"},"widget_override":"transform_rotation"},{"input_data":{"unit":"x","input_name":"Scale","x":"W","y":"H"},"widget_override":"vec2"},{"input_data":{"input_name":"Skew"},"widget_override":"hidden"},{"input_data":{"input_name":"Pivot"},"widget_override":"hidden"}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"Transform","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[259,{"persistent_metadata":{"reference":"Transform","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"unit":" px","input_name":"Translation","y":"Y","x":"X"},"widget_override":"vec2"},{"input_data":{"input_name":"Rotation"},"widget_override":"transform_rotation"},{"input_data":{"input_name":"Scale","unit":"x","x":"W","y":"H"},"widget_override":"vec2"},{"input_data":{"input_name":"Skew"},"widget_override":"hidden"},{"input_data":{"input_name":"Pivot"},"widget_override":"hidden"}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"Transform","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[87,{"persistent_metadata":{"reference":"Merge","display_name":"Ball","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Absolute":[-25,10]}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[14433811491576609500,{"persistent_metadata":{"reference":"Fill","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Fill"},"widget_override":null},{"input_data":{"input_name":"Backup Color"},"widget_override":null},{"input_data":{"input_name":"Backup Gradient"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[170,{"persistent_metadata":{"reference":"Merge","display_name":"","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":0}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[465,{"persistent_metadata":{"reference":"Fill","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Fill"},"widget_override":null},{"input_data":{"input_name":"Backup Color"},"widget_override":null},{"input_data":{"input_name":"Backup Gradient"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[102,{"persistent_metadata":{"reference":"Merge","display_name":"Agave Plant","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Absolute":[-25,19]}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[329,{"persistent_metadata":{"reference":"Stroke","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Color"},"widget_override":null},{"input_data":{"input_name":"Weight"},"widget_override":null},{"input_data":{"input_name":"Dash Lengths"},"widget_override":null},{"input_data":{"input_name":"Dash Offset"},"widget_override":null},{"input_data":{"input_name":"Line Cap"},"widget_override":null},{"input_data":{"input_name":"Line Join"},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{"input_name":"Miter Limit"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[11155094820673141470,{"persistent_metadata":{"reference":"Fill","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Fill"},"widget_override":null},{"input_data":{"input_name":"Backup Color"},"widget_override":null},{"input_data":{"input_name":"Backup Gradient"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[14205611254835578455,{"persistent_metadata":{"reference":"Transform","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Translation","unit":" px","x":"X","y":"Y"},"widget_override":"vec2"},{"input_data":{"input_name":"Rotation"},"widget_override":"transform_rotation"},{"input_data":{"unit":"x","input_name":"Scale","x":"W","y":"H"},"widget_override":"vec2"},{"input_data":{"input_name":"Skew"},"widget_override":"hidden"},{"input_data":{"input_name":"Pivot"},"widget_override":"hidden"}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Absolute":[-25,208]}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"Transform","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[419,{"persistent_metadata":{"reference":"Path","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Modification"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"Path Modify","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[111,{"persistent_metadata":{"reference":"Fill","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Fill"},"widget_override":null},{"input_data":{"input_name":"Backup Color"},"widget_override":null},{"input_data":{"input_name":"Backup Gradient"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[463,{"persistent_metadata":{"reference":"Path","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Modification"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"Path Modify","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[169,{"persistent_metadata":{"reference":"Merge","display_name":"","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":0}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[140,{"persistent_metadata":{"reference":"Fill","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Fill"},"widget_override":null},{"input_data":{"input_name":"Backup Color"},"widget_override":null},{"input_data":{"input_name":"Backup Gradient"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[16164610528699022118,{"persistent_metadata":{"reference":"Merge","display_name":"Spike Spire Corner Slope","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Absolute":[-15,202]}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[260,{"persistent_metadata":{"reference":"Path","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Modification"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"Path Modify","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[9422094883894860610,{"persistent_metadata":{"reference":"Path","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Modification"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"Path Modify","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[436,{"persistent_metadata":{"reference":"Fill","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Fill"},"widget_override":null},{"input_data":{"input_name":"Backup Color"},"widget_override":null},{"input_data":{"input_name":"Backup Gradient"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[12068777759187203228,{"persistent_metadata":{"reference":"Path","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Modification"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"Path Modify","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[244,{"persistent_metadata":{"reference":"Fill","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Fill"},"widget_override":null},{"input_data":{"input_name":"Backup Color"},"widget_override":null},{"input_data":{"input_name":"Backup Gradient"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[7148230379224894975,{"persistent_metadata":{"reference":"Path","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Modification"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"Path Modify","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[232,{"persistent_metadata":{"reference":"Fill","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Fill"},"widget_override":null},{"input_data":{"input_name":"Backup Color"},"widget_override":null},{"input_data":{"input_name":"Backup Gradient"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[8861964493222160710,{"persistent_metadata":{"reference":"Fill","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Fill"},"widget_override":null},{"input_data":{"input_name":"Backup Color"},"widget_override":null},{"input_data":{"input_name":"Backup Gradient"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[469,{"persistent_metadata":{"reference":"Path","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Modification"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"Path Modify","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[457,{"persistent_metadata":{"reference":"Path","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Modification"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-36,238]}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"Path Modify","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[331,{"persistent_metadata":{"reference":"Path","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Modification"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"Path Modify","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[475,{"persistent_metadata":{"reference":"Path","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Modification"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"Path Modify","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[6873123446543957690,{"persistent_metadata":{"reference":"Merge","display_name":"","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":0}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[10278740841813346388,{"persistent_metadata":{"reference":"Path","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Modification"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"Path Modify","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[310,{"persistent_metadata":{"reference":"Path","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Modification"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"Path Modify","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[272,{"persistent_metadata":{"reference":"Path","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Modification"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"Path Modify","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[7134154821675013808,{"persistent_metadata":{"reference":"Merge","display_name":"Left Slope Shading","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":0}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[6710503329407068595,{"persistent_metadata":{"reference":"Merge","display_name":"","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Absolute":[-35,106]}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[166,{"persistent_metadata":{"reference":"Merge","display_name":"Left Slab Spire","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":33}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[161,{"persistent_metadata":{"reference":"Merge","display_name":"Rocky Outcropping","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Absolute":[-15,55]}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[16831252454255560063,{"persistent_metadata":{"reference":"Merge","display_name":"","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":0}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[5714505144727602368,{"persistent_metadata":{"reference":"Transform","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"unit":" px","y":"Y","input_name":"Translation","x":"X"},"widget_override":"vec2"},{"input_data":{"input_name":"Rotation"},"widget_override":"transform_rotation"},{"input_data":{"x":"W","input_name":"Scale","unit":"x","y":"H"},"widget_override":"vec2"},{"input_data":{"input_name":"Skew"},"widget_override":"hidden"},{"input_data":{"input_name":"Pivot"},"widget_override":"hidden"}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"Transform","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[319,{"persistent_metadata":{"reference":"Merge","display_name":"Shadow","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":0}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[10544930474333783117,{"persistent_metadata":{"reference":"Merge","display_name":"","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":0}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[254,{"persistent_metadata":{"reference":"Path","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Modification"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"Path Modify","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[179,{"persistent_metadata":{"reference":"Merge","display_name":"","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":0}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[321,{"persistent_metadata":{"reference":"Fill","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Fill"},"widget_override":null},{"input_data":{"input_name":"Backup Color"},"widget_override":null},{"input_data":{"input_name":"Backup Gradient"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-53,139]}}},"network_metadata":null}}],[257,{"persistent_metadata":{"reference":"Opacity","display_name":"","input_properties":[{"input_data":{"input_name":"Value"},"widget_override":null},{"input_data":{"input_name":"Factor"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[491,{"persistent_metadata":{"reference":"Path","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Modification"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"Path Modify","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[181,{"persistent_metadata":{"reference":"Merge","display_name":"","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":0}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[304,{"persistent_metadata":{"reference":"Path","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Modification"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"Path Modify","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[418,{"persistent_metadata":{"reference":"Transform","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"x":"X","y":"Y","unit":" px","input_name":"Translation"},"widget_override":"vec2"},{"input_data":{"input_name":"Rotation"},"widget_override":"transform_rotation"},{"input_data":{"unit":"x","input_name":"Scale","y":"H","x":"W"},"widget_override":"vec2"},{"input_data":{"input_name":"Skew"},"widget_override":"hidden"},{"input_data":{"input_name":"Pivot"},"widget_override":"hidden"}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"Transform","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[485,{"persistent_metadata":{"reference":"Path","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Modification"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"Path Modify","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[126,{"persistent_metadata":{"reference":"Path","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Modification"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"Path Modify","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[459,{"persistent_metadata":{"reference":"Fill","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Fill"},"widget_override":null},{"input_data":{"input_name":"Backup Color"},"widget_override":null},{"input_data":{"input_name":"Backup Gradient"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[16821952675128396603,{"persistent_metadata":{"reference":"Merge","display_name":"Main Slope","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Absolute":[-25,157]}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[85,{"persistent_metadata":{"reference":"Merge","display_name":"Left Slope","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":21}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[14335659566300901430,{"persistent_metadata":{"reference":"Merge","display_name":"Soft Shadow","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":0}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[236,{"persistent_metadata":{"reference":"Path","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Modification"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"Path Modify","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[256,{"persistent_metadata":{"reference":"Fill","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Fill"},"widget_override":null},{"input_data":{"input_name":"Backup Color"},"widget_override":null},{"input_data":{"input_name":"Backup Gradient"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[193,{"persistent_metadata":{"reference":"Transform","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Translation","x":"X","y":"Y","unit":" px"},"widget_override":"vec2"},{"input_data":{"input_name":"Rotation"},"widget_override":"transform_rotation"},{"input_data":{"input_name":"Scale","x":"W","y":"H","unit":"x"},"widget_override":"vec2"},{"input_data":{"input_name":"Skew"},"widget_override":"hidden"},{"input_data":{"input_name":"Pivot"},"widget_override":"hidden"}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"Transform","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[5382879283978921947,{"persistent_metadata":{"reference":"Path","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Modification"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"Path Modify","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[83,{"persistent_metadata":{"reference":"Merge","display_name":"Stone Cluster","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":6}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[5105625446268484763,{"persistent_metadata":{"reference":"Fill","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Fill"},"widget_override":null},{"input_data":{"input_name":"Backup Color"},"widget_override":null},{"input_data":{"input_name":"Backup Gradient"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[428,{"persistent_metadata":{"reference":"Path","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Modification"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"Path Modify","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[78,{"persistent_metadata":{"reference":"Merge","display_name":"Distant Spire","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":12}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[989999757220954936,{"persistent_metadata":{"reference":"Merge","display_name":"","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":0}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[325,{"persistent_metadata":{"reference":"Path","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Modification"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-46,139]}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"Path Modify","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[11472292186872186521,{"persistent_metadata":{"reference":"Transform","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Translation","y":"Y","x":"X","unit":" px"},"widget_override":"vec2"},{"input_data":{"input_name":"Rotation"},"widget_override":"transform_rotation"},{"input_data":{"unit":"x","y":"H","input_name":"Scale","x":"W"},"widget_override":"vec2"},{"input_data":{"input_name":"Skew"},"widget_override":"hidden"},{"input_data":{"input_name":"Pivot"},"widget_override":"hidden"}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Absolute":[-35,43]}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"Transform","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[496,{"persistent_metadata":{"reference":"Transform","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"y":"Y","x":"X","unit":" px","input_name":"Translation"},"widget_override":"vec2"},{"input_data":{"input_name":"Rotation"},"widget_override":"transform_rotation"},{"input_data":{"unit":"x","y":"H","x":"W","input_name":"Scale"},"widget_override":"vec2"},{"input_data":{"input_name":"Skew"},"widget_override":"hidden"},{"input_data":{"input_name":"Pivot"},"widget_override":"hidden"}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"Transform","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[75,{"persistent_metadata":{"reference":"Merge","display_name":"Slab Spires","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":45}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[177,{"persistent_metadata":{"reference":"Merge","display_name":"","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":0}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[327,{"persistent_metadata":{"reference":"Fill","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Fill"},"widget_override":null},{"input_data":{"input_name":"Backup Color"},"widget_override":null},{"input_data":{"input_name":"Backup Gradient"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[421,{"persistent_metadata":{"reference":"Merge","display_name":"Left Half","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Absolute":[-35,223]}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[5364427239360309137,{"persistent_metadata":{"reference":"Opacity","display_name":"","input_properties":[{"input_data":{"input_name":"Value"},"widget_override":null},{"input_data":{"input_name":"Factor"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[74,{"persistent_metadata":{"reference":"Merge","display_name":"Foreground","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Absolute":[-5,4]}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[96,{"persistent_metadata":{"reference":"Fill","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Fill"},"widget_override":null},{"input_data":{"input_name":"Backup Color"},"widget_override":null},{"input_data":{"input_name":"Backup Gradient"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[99,{"persistent_metadata":{"reference":"Transform","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Translation","x":"X","y":"Y","unit":" px"},"widget_override":"vec2"},{"input_data":{"input_name":"Rotation"},"widget_override":"transform_rotation"},{"input_data":{"y":"H","unit":"x","input_name":"Scale","x":"W"},"widget_override":"vec2"},{"input_data":{"input_name":"Skew"},"widget_override":"hidden"},{"input_data":{"input_name":"Pivot"},"widget_override":"hidden"}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"Transform","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[159,{"persistent_metadata":{"reference":"Path","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Modification"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"Path Modify","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[238,{"persistent_metadata":{"reference":"Fill","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Fill"},"widget_override":null},{"input_data":{"input_name":"Backup Color"},"widget_override":null},{"input_data":{"input_name":"Backup Gradient"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[93,{"persistent_metadata":{"reference":"Transform","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"unit":" px","input_name":"Translation","y":"Y","x":"X"},"widget_override":"vec2"},{"input_data":{"input_name":"Rotation"},"widget_override":"transform_rotation"},{"input_data":{"input_name":"Scale","x":"W","unit":"x","y":"H"},"widget_override":"vec2"},{"input_data":{"input_name":"Skew"},"widget_override":"hidden"},{"input_data":{"input_name":"Pivot"},"widget_override":"hidden"}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"Transform","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[3930114406985796561,{"persistent_metadata":{"reference":"Opacity","display_name":"","input_properties":[{"input_data":{"input_name":"Value"},"widget_override":null},{"input_data":{"input_name":"Factor"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[6926019345498826421,{"persistent_metadata":{"reference":"Merge","display_name":"","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":0}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[277,{"persistent_metadata":{"reference":"Fill","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Fill"},"widget_override":null},{"input_data":{"input_name":"Backup Color"},"widget_override":null},{"input_data":{"input_name":"Backup Gradient"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[478,{"persistent_metadata":{"reference":"Merge","display_name":"Shadow","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":0}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[188,{"persistent_metadata":{"reference":"Path","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Modification"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"Path Modify","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[2489761779922717592,{"persistent_metadata":{"reference":"Path","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Modification"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"Path Modify","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[9603838021022368374,{"persistent_metadata":{"reference":"Path","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Modification"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"Path Modify","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[4633399390154487467,{"persistent_metadata":{"reference":"Opacity","display_name":"","input_properties":[{"input_data":{"input_name":"Value"},"widget_override":null},{"input_data":{"input_name":"Factor"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[81,{"persistent_metadata":{"reference":"Merge","display_name":"Left Plinth","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Absolute":[-15,7]}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[3707802522175443254,{"persistent_metadata":{"reference":"Fill","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Fill"},"widget_override":null},{"input_data":{"input_name":"Backup Color"},"widget_override":null},{"input_data":{"input_name":"Backup Gradient"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[115,{"persistent_metadata":{"reference":"Path","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Modification"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"Path Modify","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[17020523203516467057,{"persistent_metadata":{"reference":"Fill","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Fill"},"widget_override":null},{"input_data":{"input_name":"Backup Color"},"widget_override":null},{"input_data":{"input_name":"Backup Gradient"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[17414691604179185270,{"persistent_metadata":{"reference":"Path","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Modification"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"Path Modify","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[451,{"persistent_metadata":{"reference":"Merge","display_name":"Shadow Upper","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":0}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[122,{"persistent_metadata":{"reference":"Fill","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Fill"},"widget_override":null},{"input_data":{"input_name":"Backup Color"},"widget_override":null},{"input_data":{"input_name":"Backup Gradient"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[323,{"persistent_metadata":{"reference":"Stroke","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Color"},"widget_override":null},{"input_data":{"input_name":"Weight"},"widget_override":null},{"input_data":{"input_name":"Dash Lengths"},"widget_override":null},{"input_data":{"input_name":"Dash Offset"},"widget_override":null},{"input_data":{"input_name":"Line Cap"},"widget_override":null},{"input_data":{"input_name":"Line Join"},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{"input_name":"Miter Limit"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[471,{"persistent_metadata":{"reference":"Fill","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Fill"},"widget_override":null},{"input_data":{"input_name":"Backup Color"},"widget_override":null},{"input_data":{"input_name":"Backup Gradient"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[155,{"persistent_metadata":{"reference":"Fill","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Fill"},"widget_override":null},{"input_data":{"input_name":"Backup Color"},"widget_override":null},{"input_data":{"input_name":"Backup Gradient"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[2999157202967297847,{"persistent_metadata":{"reference":"Path","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Modification"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"Path Modify","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[220,{"persistent_metadata":{"reference":"Fill","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Fill"},"widget_override":null},{"input_data":{"input_name":"Backup Color"},"widget_override":null},{"input_data":{"input_name":"Backup Gradient"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[178,{"persistent_metadata":{"reference":"Merge","display_name":"","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":0}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[404,{"persistent_metadata":{"reference":"Stroke","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Color"},"widget_override":null},{"input_data":{"input_name":"Weight"},"widget_override":null},{"input_data":{"input_name":"Dash Lengths"},"widget_override":null},{"input_data":{"input_name":"Dash Offset"},"widget_override":null},{"input_data":{"input_name":"Line Cap"},"widget_override":null},{"input_data":{"input_name":"Line Join"},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{"input_name":"Miter Limit"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[415,{"persistent_metadata":{"reference":"Fill","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Fill"},"widget_override":null},{"input_data":{"input_name":"Backup Color"},"widget_override":null},{"input_data":{"input_name":"Backup Gradient"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[114,{"persistent_metadata":{"reference":"Transform","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"x":"X","input_name":"Translation","unit":" px","y":"Y"},"widget_override":"vec2"},{"input_data":{"input_name":"Rotation"},"widget_override":"transform_rotation"},{"input_data":{"unit":"x","input_name":"Scale","y":"H","x":"W"},"widget_override":"vec2"},{"input_data":{"input_name":"Skew"},"widget_override":"hidden"},{"input_data":{"input_name":"Pivot"},"widget_override":"hidden"}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"Transform","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[411,{"persistent_metadata":{"reference":"Merge","display_name":"From Spike Spire","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Absolute":[-25,217]}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}],[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[287,{"persistent_metadata":{"reference":"Path","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Modification"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"Path Modify","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[132,{"persistent_metadata":{"reference":"Path","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Modification"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"Path Modify","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[300,{"persistent_metadata":{"reference":"Fill","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Fill"},"widget_override":null},{"input_data":{"input_name":"Backup Color"},"widget_override":null},{"input_data":{"input_name":"Backup Gradient"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[398,{"persistent_metadata":{"reference":"Stroke","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Color"},"widget_override":null},{"input_data":{"input_name":"Weight"},"widget_override":null},{"input_data":{"input_name":"Dash Lengths"},"widget_override":null},{"input_data":{"input_name":"Dash Offset"},"widget_override":null},{"input_data":{"input_name":"Line Cap"},"widget_override":null},{"input_data":{"input_name":"Line Join"},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{"input_name":"Miter Limit"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[455,{"persistent_metadata":{"reference":"Stroke","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Color"},"widget_override":null},{"input_data":{"input_name":"Weight"},"widget_override":null},{"input_data":{"input_name":"Dash Lengths"},"widget_override":null},{"input_data":{"input_name":"Dash Offset"},"widget_override":null},{"input_data":{"input_name":"Line Cap"},"widget_override":null},{"input_data":{"input_name":"Line Join"},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{"input_name":"Miter Limit"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}],[164,{"persistent_metadata":{"reference":"Merge","display_name":"Center Slab Spire","input_properties":[{"input_data":{"input_name":"Graphical Data"},"widget_override":null},{"input_data":{"input_name":"Over"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Layer":{"position":{"Stack":15}}},"network_metadata":{"persistent_metadata":{"node_metadata":[[2,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-7,-1]}}},"network_metadata":null}}],[1,{"persistent_metadata":{"reference":null,"display_name":"To Group","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-3]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"To Element","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[-14,-1]}}},"network_metadata":null}}],[3,{"persistent_metadata":{"reference":null,"display_name":"Layer","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[1,-3]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[242,{"persistent_metadata":{"reference":"Path","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Modification"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":null,"display_name":"Path Modify","input_properties":[{"input_data":{"input_name":""},"widget_override":null},{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[7,0]}}},"network_metadata":null}}],[0,{"persistent_metadata":{"reference":null,"display_name":"Monitor","input_properties":[{"input_data":{"input_name":""},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}}}],[467,{"persistent_metadata":{"reference":"Stroke","display_name":"","input_properties":[{"input_data":{"input_name":"Vector Data"},"widget_override":null},{"input_data":{"input_name":"Color"},"widget_override":null},{"input_data":{"input_name":"Weight"},"widget_override":null},{"input_data":{"input_name":"Dash Lengths"},"widget_override":null},{"input_data":{"input_name":"Dash Offset"},"widget_override":null},{"input_data":{"input_name":"Line Cap"},"widget_override":null},{"input_data":{"input_name":"Line Join"},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{},"widget_override":null},{"input_data":{"input_name":"Miter Limit"},"widget_override":null}],"output_names":[],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":"Chain"}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[459.0,-501.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,1450.0,80.0],"node_graph_top_right":[1468.796875,0.0]},"selection_undo_history":[[],[],[]],"selection_redo_history":[]}}},"collapsed":[],"name":"valley-of-spires.graphite","commit_hash":"","document_ptz":{"pan":[-507.74999999999994,-385.9351851851852],"tilt":0.0,"zoom":1.0,"flip":false},"document_mode":"DesignMode","view_mode":"Normal","overlays_visibility_settings":{"all":true,"artboard_name":true,"compass_rose":true,"quick_measurement":true,"transform_measurement":true,"transform_cage":true,"hover_outline":true,"selection_outline":true,"pivot":true,"path":true,"anchors":true,"handles":true},"rulers_visible":true,"snapping_state":{"snapping_enabled":true,"grid_snapping":false,"artboards":true,"tolerance":8.0,"bounding_box":{"center_point":true,"corner_point":true,"edge_midpoint":true,"align_with_edges":true,"distribute_evenly":true},"path":{"anchor_point":true,"line_midpoint":true,"along_path":true,"normal_to_path":true,"tangent_to_path":true,"path_intersection_point":true,"align_with_anchor_point":true,"perpendicular_from_endpoint":true},"grid":{"origin":[0.0,0.0],"grid_type":{"Rectangular":{"spacing":[1.0,1.0]}},"rectangular_spacing":[1.0,1.0],"isometric_y_spacing":1.0,"isometric_angle_a":30.0,"isometric_angle_b":30.0,"grid_color":{"red":0.6038274,"green":0.6038274,"blue":0.6038274,"alpha":1.0},"dot_display":false}},"graph_view_overlay_open":false,"graph_fade_artwork_percentage":80.0} \ No newline at end of file diff --git a/deny.toml b/deny.toml new file mode 100644 index 0000000000000000000000000000000000000000..556f12c11ea8b8af97262c89674d476bd1a3274d --- /dev/null +++ b/deny.toml @@ -0,0 +1,194 @@ +# This template contains all of the possible sections and their default values + +# Note that all fields that take a lint level have these possible values: +# * deny - An error will be produced and the check will fail +# * warn - A warning will be produced, but the check will not fail +# * allow - No warning or error will be produced, though in some cases a note +# will be + +# The values provided in this template are the default values that will be used +# when any section or field is not specified in your own configuration + +[graph] +# If 1 or more target triples (and optionally, target_features) are specified, +# only the specified targets will be checked when running `cargo deny check`. +# This means, if a particular package is only ever used as a target specific +# dependency, such as, for example, the `nix` crate only being used via the +# `target_family = "unix"` configuration, that only having windows targets in +# this list would mean the nix crate, as well as any of its exclusive +# dependencies not shared by any other crates, would be ignored, as the target +# list here is effectively saying which targets you are building for. +targets = [ + # The triple can be any string, but only the target triples built in to + # rustc (as of 1.40) can be checked against actual config expressions + #{ triple = "x86_64-unknown-linux-musl" }, + # You can also specify which target_features you promise are enabled for a + # particular target. target_features are currently not validated against + # the actual valid features supported by the target architecture. + #{ triple = "wasm32-unknown-unknown", features = ["atomics"] }, +] + +# Tauri produces too many nonsense warnings. +exclude = ["tauri", "tauri-build"] + + +# This section is considered when running `cargo deny check advisories` +# More documentation for the advisories section can be found here: +# https://embarkstudios.github.io/cargo-deny/checks/advisories/cfg.html +[advisories] +# The path where the advisory database is cloned/fetched into +db-path = "~/.cargo/advisory-db" +# The url(s) of the advisory databases to use +db-urls = ["https://github.com/rustsec/advisory-db"] +# A list of advisory IDs to ignore. Note that ignored advisories will still +# output a note when they are encountered. +ignore = [ + "RUSTSEC-2024-0370", # Unmaintained but still fully functional crate `proc-macro-error` + "RUSTSEC-2024-0388", # Unmaintained but still fully functional crate `derivative` + "RUSTSEC-2025-0007", # Unmaintained but still fully functional crate `ring` + "RUSTSEC-2024-0436", # Unmaintained but still fully functional crate `paste` + "RUSTSEC-2025-0014", # Unmaintained but still fully functional crate `humantime` +] +# Threshold for security vulnerabilities, any vulnerability with a CVSS score +# lower than the range specified will be ignored. Note that ignored advisories +# will still output a note when they are encountered. +# * None - CVSS Score 0.0 +# * Low - CVSS Score 0.1 - 3.9 +# * Medium - CVSS Score 4.0 - 6.9 +# * High - CVSS Score 7.0 - 8.9 +# * Critical - CVSS Score 9.0 - 10.0 +#severity-threshold = + +# This section is considered when running `cargo deny check licenses` +# More documentation for the licenses section can be found here: +# https://embarkstudios.github.io/cargo-deny/checks/licenses/cfg.html +[licenses] +# List of explicitly allowed licenses +# See https://spdx.org/licenses/ for list of possible licenses +# [possible values: any SPDX 3.11 short identifier (+ optional exception)]. +# +# Keep this list in sync with those in `/about.toml` and `/frontend/vite.config.ts`. +allow = [ + "Apache-2.0 WITH LLVM-exception", + "Apache-2.0", + "BSD-2-Clause", + "BSD-3-Clause", + "BSL-1.0", + "CC0-1.0", + "ISC", + "MIT", + "MPL-2.0", + "OpenSSL", + "Unicode-3.0", + "Zlib", + "NCSA", +] +# The confidence threshold for detecting a license from license text. +# The higher the value, the more closely the license text must be to the +# canonical license text of a valid SPDX license file. +# [possible values: any between 0.0 and 1.0]. +confidence-threshold = 0.8 +# Allow 1 or more licenses on a per-crate basis, so that particular licenses +# aren't accepted for every possible crate as with the normal allow list +exceptions = [ + # Each entry is the crate and version constraint, and its specific allow + # list + #{ allow = ["Zlib"], name = "adler32", version = "*" }, +] + +# Some crates don't have (easily) machine readable licensing information, +# adding a clarification entry for it allows you to manually specify the +# licensing information +[[licenses.clarify]] +# The name of the crate the clarification applies to +name = "ring" +# The optional version constraint for the crate +#version = "*" +# The SPDX expression for the license requirements of the crate +expression = "MIT AND ISC AND OpenSSL" +# One or more files in the crate's source used as the "source of truth" for +# the license expression. If the contents match, the clarification will be used +# when running the license check, otherwise the clarification will be ignored +# and the crate will be checked normally, which may produce warnings or errors +# depending on the rest of your configuration +license-files = [ + # Each entry is a crate relative path, and the (opaque) hash of its contents + { path = "LICENSE", hash = 0xbd0eed23 }, +] + +[licenses.private] +# If true, ignores workspace crates that aren't published, or are only +# published to private registries +ignore = false +# One or more private registries that you might publish crates to, if a crate +# is only published to private registries, and ignore is true, the crate will +# not have its license(s) checked +registries = [ + #"https://sekretz.com/registry +] + +# This section is considered when running `cargo deny check bans`. +# More documentation about the 'bans' section can be found here: +# https://embarkstudios.github.io/cargo-deny/checks/bans/cfg.html +[bans] +# Lint level for when multiple versions of the same crate are detected +multiple-versions = "allow" + +# Lint level for when a crate version requirement is `*` +wildcards = "allow" +# The graph highlighting used when creating dotgraphs for crates +# with multiple versions +# * lowest-version - The path to the lowest versioned duplicate is highlighted +# * simplest-path - The path to the version with the fewest edges is highlighted +# * all - Both lowest-version and simplest-path are used +highlight = "all" +# List of crates that are allowed. Use with care! +allow = [ + #{ name = "ansi_term", version = "=0.11.0" }, +] +# List of crates to deny +deny = [ + # Each entry the name of a crate and a version range. If version is + # not specified, all versions will be matched. + #{ name = "ansi_term", version = "=0.11.0" }, + # + # Wrapper crates can optionally be specified to allow the crate when it + # is a direct dependency of the otherwise banned crate + #{ name = "ansi_term", version = "=0.11.0", wrappers = [] }, +] +# Certain crates/versions that will be skipped when doing duplicate detection. +skip = [ + #{ name = "ansi_term", version = "=0.11.0" }, + #{ name = "cfg-if", version = "=0.1.10" }, +] +# Similarly to `skip` allows you to skip certain crates during duplicate +# detection. Unlike skip, it also includes the entire tree of transitive +# dependencies starting at the specified crate, up to a certain depth, which is +# by default infinite +skip-tree = [ + #{ name = "ansi_term", version = "=0.11.0", depth = 20 }, +] + +# This section is considered when running `cargo deny check sources`. +# More documentation about the 'sources' section can be found here: +# https://embarkstudios.github.io/cargo-deny/checks/sources/cfg.html +[sources] +# Lint level for what to happen when a crate from a crate registry that is not +# in the allow list is encountered +unknown-registry = "warn" +# Lint level for what to happen when a crate from a git repository that is not +# in the allow list is encountered +unknown-git = "warn" +# List of URLs for allowed crate registries. Defaults to the crates.io index +# if not specified. If it is specified but empty, no registries are allowed. +allow-registry = ["https://github.com/rust-lang/crates.io-index"] +# List of URLs for allowed Git repositories +allow-git = [] + +[sources.allow-org] +# 1 or more github.com organizations to allow git sources for +github = ["linebender", "Rust-GPU", "specta-rs"] +# 1 or more gitlab.com organizations to allow git sources for +#gitlab = [""] +# 1 or more bitbucket.org organizations to allow git sources for +#bitbucket = [""] diff --git a/editor/Cargo.toml b/editor/Cargo.toml new file mode 100644 index 0000000000000000000000000000000000000000..1f6af599caa2352825e13db4bf914ec7129c60e0 --- /dev/null +++ b/editor/Cargo.toml @@ -0,0 +1,71 @@ +[package] +name = "graphite-editor" +publish = false +version = "0.0.0" +rust-version = "1.85" +authors = ["Graphite Authors "] +edition = "2024" +readme = "../README.md" +homepage = "https://graphite.rs" +repository = "https://github.com/GraphiteEditor/Graphite" +license = "Apache-2.0" + +[features] +default = ["wasm"] +wasm = ["wasm-bindgen", "graphene-std/wasm", "wasm-bindgen-futures"] +gpu = ["interpreted-executor/gpu", "wgpu-executor"] +tauri = ["ron", "decouple-execution"] +decouple-execution = [] +resvg = ["graphene-std/resvg"] +vello = ["graphene-std/vello", "resvg"] +ron = ["dep:ron"] + +[dependencies] +# Local dependencies +graphite-proc-macros = { workspace = true } +graph-craft = { workspace = true } +interpreted-executor = { workspace = true } +graphene-std = { workspace = true } +preprocessor = { workspace = true } + +# Workspace dependencies +js-sys = { workspace = true } +log = { workspace = true } +bitflags = { workspace = true } +thiserror = { workspace = true } +serde = { workspace = true } +serde_json = { workspace = true } +bezier-rs = { workspace = true } +kurbo = { workspace = true } +futures = { workspace = true } +glam = { workspace = true } +derivative = { workspace = true } +specta = { workspace = true } +dyn-any = { workspace = true } +num_enum = { workspace = true } +usvg = { workspace = true } +once_cell = { workspace = true } +web-sys = { workspace = true } + +# Required dependencies +spin = "0.9.8" + +# Optional local dependencies +wgpu-executor = { workspace = true, optional = true } + +# Optional workspace dependencies +wasm-bindgen = { workspace = true, optional = true } +wasm-bindgen-futures = { workspace = true, optional = true } +ron = { workspace = true, optional = true } + +[dev-dependencies] +# Workspace dependencies +env_logger = { workspace = true } +futures = { workspace = true } +tokio = { workspace = true } + +[lints.rust] +# TODO: figure out why we check these features when they do not exist +unexpected_cfgs = { level = "warn", check-cfg = [ + 'cfg(feature, values("resvg", "vello"))', +] } diff --git a/editor/build.rs b/editor/build.rs new file mode 100644 index 0000000000000000000000000000000000000000..7fc95d9c54a84d56fedd538db0aafab1086bcb82 --- /dev/null +++ b/editor/build.rs @@ -0,0 +1,24 @@ +use std::process::Command; + +const GRAPHITE_RELEASE_SERIES: &str = "Alpha 4"; + +fn main() { + // Execute a Git command for its stdout. Early exit if it fails for any of the possible reasons. + let try_git_command = |args: &[&str]| -> Option { + let git_output = Command::new("git").args(args).output().ok()?; + let maybe_empty = String::from_utf8(git_output.stdout).ok()?; + let command_result = (!maybe_empty.is_empty()).then_some(maybe_empty)?; + Some(command_result) + }; + // Execute a Git command for its output. Return "unknown" if it fails for any of the possible reasons. + let git_command = |args| -> String { try_git_command(args).unwrap_or_else(|| String::from("unknown")) }; + + // Rather than printing to any terminal, these commands set environment variables in the Cargo toolchain. + // They are accessed with the `env!("...")` macro in the codebase. + println!("cargo:rustc-env=GRAPHITE_GIT_COMMIT_DATE={}", git_command(&["log", "-1", "--format=%cd"])); + println!("cargo:rustc-env=GRAPHITE_GIT_COMMIT_HASH={}", git_command(&["rev-parse", "HEAD"])); + let branch = std::env::var("GITHUB_HEAD_REF").unwrap_or_default(); + let branch = if branch.is_empty() { git_command(&["name-rev", "--name-only", "HEAD"]) } else { branch }; + println!("cargo:rustc-env=GRAPHITE_GIT_COMMIT_BRANCH={branch}"); + println!("cargo:rustc-env=GRAPHITE_RELEASE_SERIES={GRAPHITE_RELEASE_SERIES}"); +} diff --git a/editor/src/application.rs b/editor/src/application.rs new file mode 100644 index 0000000000000000000000000000000000000000..fdb8c60334770b600f4d3729d311a2f988d2e0fe --- /dev/null +++ b/editor/src/application.rs @@ -0,0 +1,57 @@ +use crate::dispatcher::Dispatcher; +use crate::messages::prelude::*; +pub use graphene_std::uuid::*; + +// TODO: serialize with serde to save the current editor state +pub struct Editor { + pub dispatcher: Dispatcher, +} + +impl Editor { + /// Construct the editor. + /// Remember to provide a random seed with `editor::set_uuid_seed(seed)` before any editors can be used. + pub fn new() -> Self { + Self { dispatcher: Dispatcher::new() } + } + + #[cfg(test)] + pub(crate) fn new_local_executor() -> (Self, crate::node_graph_executor::NodeRuntime) { + let (runtime, executor) = crate::node_graph_executor::NodeGraphExecutor::new_with_local_runtime(); + let dispatcher = Dispatcher::with_executor(executor); + (Self { dispatcher }, runtime) + } + + pub fn handle_message>(&mut self, message: T) -> Vec { + self.dispatcher.handle_message(message, true); + + std::mem::take(&mut self.dispatcher.responses) + } + + pub fn poll_node_graph_evaluation(&mut self, responses: &mut VecDeque) -> Result<(), String> { + self.dispatcher.poll_node_graph_evaluation(responses) + } +} + +impl Default for Editor { + fn default() -> Self { + Self::new() + } +} + +pub const GRAPHITE_RELEASE_SERIES: &str = env!("GRAPHITE_RELEASE_SERIES"); +pub const GRAPHITE_GIT_COMMIT_DATE: &str = env!("GRAPHITE_GIT_COMMIT_DATE"); +pub const GRAPHITE_GIT_COMMIT_HASH: &str = env!("GRAPHITE_GIT_COMMIT_HASH"); +pub const GRAPHITE_GIT_COMMIT_BRANCH: &str = env!("GRAPHITE_GIT_COMMIT_BRANCH"); + +pub fn commit_info_localized(localized_commit_date: &str) -> String { + format!( + "Release Series: {}\n\ + Branch: {}\n\ + Commit: {}\n\ + {}", + GRAPHITE_RELEASE_SERIES, + GRAPHITE_GIT_COMMIT_BRANCH, + &GRAPHITE_GIT_COMMIT_HASH[..8], + localized_commit_date + ) +} diff --git a/editor/src/consts.rs b/editor/src/consts.rs new file mode 100644 index 0000000000000000000000000000000000000000..9adba6d9082ca379a061768591641910e7a183a1 --- /dev/null +++ b/editor/src/consts.rs @@ -0,0 +1,151 @@ +// GRAPH +pub const GRID_SIZE: u32 = 24; +pub const EXPORTS_TO_TOP_EDGE_PIXEL_GAP: u32 = 72; +pub const EXPORTS_TO_RIGHT_EDGE_PIXEL_GAP: u32 = 120; +pub const IMPORTS_TO_TOP_EDGE_PIXEL_GAP: u32 = 72; +pub const IMPORTS_TO_LEFT_EDGE_PIXEL_GAP: u32 = 120; + +// VIEWPORT +pub const VIEWPORT_ZOOM_WHEEL_RATE: f64 = (1. / 600.) * 3.; +pub const VIEWPORT_ZOOM_MOUSE_RATE: f64 = 1. / 400.; +pub const VIEWPORT_ZOOM_SCALE_MIN: f64 = 0.000_000_1; +pub const VIEWPORT_ZOOM_SCALE_MAX: f64 = 10_000.; +pub const VIEWPORT_ZOOM_MIN_FRACTION_COVER: f64 = 0.01; +pub const VIEWPORT_ZOOM_LEVELS: [f64; 74] = [ + 0.0001, 0.000125, 0.00016, 0.0002, 0.00025, 0.00032, 0.0004, 0.0005, 0.00064, 0.0008, 0.001, 0.0016, 0.002, 0.0025, 0.0032, 0.004, 0.005, 0.0064, 0.008, 0.01, 0.01125, 0.015, 0.02, 0.025, 0.03, + 0.04, 0.05, 0.06, 0.08, 0.1, 0.125, 0.15, 0.2, 0.25, 0.33333333, 0.4, 0.5, 0.66666666, 0.8, 1., 1.25, 1.6, 2., 2.5, 3.2, 4., 5., 6.4, 8., 10., 12.5, 16., 20., 25., 32., 40., 50., 64., 80., 100., + 128., 160., 200., 256., 320., 400., 512., 640., 800., 1024., 1280., 1600., 2048., 2560., +]; +/// Higher values create a steeper curve (a faster zoom rate change) +pub const VIEWPORT_ZOOM_WHEEL_RATE_CHANGE: f64 = 3.; + +/// Helps push values that end in approximately half, plus or minus some floating point imprecision, towards the same side of the round() function. +pub const VIEWPORT_GRID_ROUNDING_BIAS: f64 = 0.002; + +pub const VIEWPORT_SCROLL_RATE: f64 = 0.6; + +pub const VIEWPORT_ROTATE_SNAP_INTERVAL: f64 = 15.; + +pub const VIEWPORT_ZOOM_TO_FIT_PADDING_SCALE_FACTOR: f64 = 0.95; + +pub const DRAG_BEYOND_VIEWPORT_MAX_OVEREXTENSION_PIXELS: f64 = 50.; +pub const DRAG_BEYOND_VIEWPORT_SPEED_FACTOR: f64 = 20.; + +// SNAPPING POINT +pub const SNAP_POINT_TOLERANCE: f64 = 5.; +/// These are layers whose bounding boxes are used for alignment. +pub const MAX_ALIGNMENT_CANDIDATES: usize = 100; +/// These are layers that are used for the layer snapper. +pub const MAX_SNAP_CANDIDATES: usize = 10; +/// These are points (anchors and bounding box corners etc.) in the layer snapper. +pub const MAX_LAYER_SNAP_POINTS: usize = 100; + +pub const DRAG_THRESHOLD: f64 = 1.; + +// TRANSFORMING LAYER +pub const ROTATE_INCREMENT: f64 = 15.; +pub const SCALE_INCREMENT: f64 = 0.1; +pub const SLOWING_DIVISOR: f64 = 10.; +pub const NUDGE_AMOUNT: f64 = 1.; +pub const BIG_NUDGE_AMOUNT: f64 = 10.; + +// TOOLS +pub const DEFAULT_STROKE_WIDTH: f64 = 2.; + +// SELECT TOOL +pub const SELECTION_TOLERANCE: f64 = 5.; +pub const DRAG_DIRECTION_MODE_DETERMINATION_THRESHOLD: f64 = 15.; +pub const SELECTION_DRAG_ANGLE: f64 = 90.; + +// PIVOT +pub const PIVOT_CROSSHAIR_THICKNESS: f64 = 1.; +pub const PIVOT_CROSSHAIR_LENGTH: f64 = 9.; +pub const PIVOT_DIAMETER: f64 = 5.; + +// COMPASS ROSE +pub const COMPASS_ROSE_RING_INNER_DIAMETER: f64 = 13.; +pub const COMPASS_ROSE_MAIN_RING_DIAMETER: f64 = 15.; +pub const COMPASS_ROSE_HOVER_RING_DIAMETER: f64 = 23.; +pub const COMPASS_ROSE_ARROW_SIZE: f64 = 5.; +// Angle to either side of the compass arrows where they are targetted by the cursor (in degrees, must be less than 45°) +pub const COMPASS_ROSE_ARROW_CLICK_TARGET_ANGLE: f64 = 20.; + +// TRANSFORM OVERLAY +pub const ANGLE_MEASURE_RADIUS_FACTOR: f64 = 0.04; +pub const ARC_MEASURE_RADIUS_FACTOR_RANGE: (f64, f64) = (0.05, 0.15); + +// TRANSFORM CAGE +pub const RESIZE_HANDLE_SIZE: f64 = 6.; +pub const BOUNDS_SELECT_THRESHOLD: f64 = 10.; +pub const BOUNDS_ROTATE_THRESHOLD: f64 = 20.; +pub const MIN_LENGTH_FOR_MIDPOINT_VISIBILITY: f64 = 20.; +pub const MIN_LENGTH_FOR_CORNERS_VISIBILITY: f64 = 12.; +/// The width or height that the transform cage needs to be (at least) before the corner resize handle click targets take up their full surroundings. Otherwise, when less than this value, the interior edge resize handle takes precedence so the corner handles don't eat into the edge area, making it harder to resize the cage from its edges. +pub const MIN_LENGTH_FOR_EDGE_RESIZE_PRIORITY_OVER_CORNERS: f64 = 10.; +/// When the width or height of the transform cage is less than this value, only the exterior of the bounding box will act as a click target for resizing. +pub const MIN_LENGTH_FOR_RESIZE_TO_INCLUDE_INTERIOR: f64 = 40.; +/// When dragging the edge of a cage with Alt, it centers around the pivot. +/// However if the pivot is on or near the same edge you are dragging, we should avoid scaling by a massive factor caused by the small denominator. +/// +/// The motion of the user's cursor by an `x` pixel offset results in `x * scale_factor` pixels of offset on the other side. +pub const MAXIMUM_ALT_SCALE_FACTOR: f64 = 25.; +/// The width or height that the transform cage needs before it is considered to have no width or height. +pub const MAX_LENGTH_FOR_NO_WIDTH_OR_HEIGHT: f64 = 1e-4; + +// SKEW TRIANGLES +pub const SKEW_TRIANGLE_SIZE: f64 = 7.; +pub const SKEW_TRIANGLE_OFFSET: f64 = 4.; +pub const MIN_LENGTH_FOR_SKEW_TRIANGLE_VISIBILITY: f64 = 48.; + +// PATH TOOL +pub const MANIPULATOR_GROUP_MARKER_SIZE: f64 = 6.; +pub const SELECTION_THRESHOLD: f64 = 10.; +pub const HIDE_HANDLE_DISTANCE: f64 = 3.; +pub const HANDLE_ROTATE_SNAP_ANGLE: f64 = 15.; +pub const SEGMENT_INSERTION_DISTANCE: f64 = 5.; +pub const SEGMENT_OVERLAY_SIZE: f64 = 10.; +pub const HANDLE_LENGTH_FACTOR: f64 = 0.5; + +// PEN TOOL +pub const CREATE_CURVE_THRESHOLD: f64 = 5.; + +// SPLINE TOOL +pub const PATH_JOIN_THRESHOLD: f64 = 5.; + +// LINE TOOL +pub const LINE_ROTATE_SNAP_ANGLE: f64 = 15.; + +// BRUSH TOOL +pub const BRUSH_SIZE_CHANGE_KEYBOARD: f64 = 5.; +pub const DEFAULT_BRUSH_SIZE: f64 = 20.; + +// GIZMOS +pub const POINT_RADIUS_HANDLE_SNAP_THRESHOLD: f64 = 8.; +pub const POINT_RADIUS_HANDLE_SEGMENT_THRESHOLD: f64 = 7.9; +pub const NUMBER_OF_POINTS_DIAL_SPOKE_EXTENSION: f64 = 1.2; +pub const NUMBER_OF_POINTS_DIAL_SPOKE_LENGTH: f64 = 10.; +pub const GIZMO_HIDE_THRESHOLD: f64 = 20.; + +// SCROLLBARS +pub const SCROLLBAR_SPACING: f64 = 0.1; +pub const ASYMPTOTIC_EFFECT: f64 = 0.5; +pub const SCALE_EFFECT: f64 = 0.5; + +// COLORS +pub const COLOR_OVERLAY_BLUE: &str = "#00a8ff"; +pub const COLOR_OVERLAY_BLUE_50: &str = "rgba(0, 168, 255, 0.5)"; +pub const COLOR_OVERLAY_YELLOW: &str = "#ffc848"; +pub const COLOR_OVERLAY_GREEN: &str = "#63ce63"; +pub const COLOR_OVERLAY_RED: &str = "#ef5454"; +pub const COLOR_OVERLAY_GRAY: &str = "#cccccc"; +pub const COLOR_OVERLAY_WHITE: &str = "#ffffff"; +pub const COLOR_OVERLAY_LABEL_BACKGROUND: &str = "#000000cc"; + +// DOCUMENT +pub const DEFAULT_DOCUMENT_NAME: &str = "Untitled Document"; +pub const FILE_SAVE_SUFFIX: &str = ".graphite"; +pub const MAX_UNDO_HISTORY_LEN: usize = 100; // TODO: Add this to user preferences +pub const AUTO_SAVE_TIMEOUT_SECONDS: u64 = 15; + +// INPUT +pub const DOUBLE_CLICK_MILLISECONDS: u64 = 500; diff --git a/editor/src/dispatcher.rs b/editor/src/dispatcher.rs new file mode 100644 index 0000000000000000000000000000000000000000..a8891033ee09a6676d2bd9858dde71c52494489e --- /dev/null +++ b/editor/src/dispatcher.rs @@ -0,0 +1,562 @@ +use crate::messages::debug::utility_types::MessageLoggingVerbosity; +use crate::messages::dialog::DialogMessageData; +use crate::messages::portfolio::document::node_graph::document_node_definitions; +use crate::messages::prelude::*; + +#[derive(Debug, Default)] +pub struct Dispatcher { + buffered_queue: Option>>, + message_queues: Vec>, + pub responses: Vec, + pub message_handlers: DispatcherMessageHandlers, +} + +#[derive(Debug, Default)] +pub struct DispatcherMessageHandlers { + animation_message_handler: AnimationMessageHandler, + broadcast_message_handler: BroadcastMessageHandler, + debug_message_handler: DebugMessageHandler, + dialog_message_handler: DialogMessageHandler, + globals_message_handler: GlobalsMessageHandler, + input_preprocessor_message_handler: InputPreprocessorMessageHandler, + key_mapping_message_handler: KeyMappingMessageHandler, + layout_message_handler: LayoutMessageHandler, + pub portfolio_message_handler: PortfolioMessageHandler, + preferences_message_handler: PreferencesMessageHandler, + tool_message_handler: ToolMessageHandler, + workspace_message_handler: WorkspaceMessageHandler, +} + +impl DispatcherMessageHandlers { + pub fn with_executor(executor: crate::node_graph_executor::NodeGraphExecutor) -> Self { + Self { + portfolio_message_handler: PortfolioMessageHandler::with_executor(executor), + ..Default::default() + } + } +} + +/// For optimization, these are messages guaranteed to be redundant when repeated. +/// The last occurrence of the message in the message queue is sufficient to ensure correct behavior. +/// In addition, these messages do not change any state in the backend (aside from caches). +const SIDE_EFFECT_FREE_MESSAGES: &[MessageDiscriminant] = &[ + MessageDiscriminant::Portfolio(PortfolioMessageDiscriminant::Document(DocumentMessageDiscriminant::PropertiesPanel( + PropertiesPanelMessageDiscriminant::Refresh, + ))), + MessageDiscriminant::Portfolio(PortfolioMessageDiscriminant::Document(DocumentMessageDiscriminant::DocumentStructureChanged)), + MessageDiscriminant::Portfolio(PortfolioMessageDiscriminant::Document(DocumentMessageDiscriminant::Overlays(OverlaysMessageDiscriminant::Draw))), + MessageDiscriminant::Portfolio(PortfolioMessageDiscriminant::Document(DocumentMessageDiscriminant::RenderRulers)), + MessageDiscriminant::Portfolio(PortfolioMessageDiscriminant::Document(DocumentMessageDiscriminant::RenderScrollbars)), + MessageDiscriminant::Frontend(FrontendMessageDiscriminant::UpdateDocumentLayerStructure), + MessageDiscriminant::Frontend(FrontendMessageDiscriminant::TriggerFontLoad), +]; +const DEBUG_MESSAGE_BLOCK_LIST: &[MessageDiscriminant] = &[MessageDiscriminant::Broadcast(BroadcastMessageDiscriminant::TriggerEvent(BroadcastEventDiscriminant::AnimationFrame))]; +// TODO: Find a way to combine these with the list above. We use strings for now since these are the standard variant names used by multiple messages. But having these also type-checked would be best. +const DEBUG_MESSAGE_ENDING_BLOCK_LIST: &[&str] = &["PointerMove", "PointerOutsideViewport", "Overlays", "Draw", "CurrentTime", "Time"]; + +impl Dispatcher { + pub fn new() -> Self { + Self::default() + } + + pub fn with_executor(executor: crate::node_graph_executor::NodeGraphExecutor) -> Self { + Self { + message_handlers: DispatcherMessageHandlers::with_executor(executor), + ..Default::default() + } + } + + // If the deepest queues (higher index in queues list) are now empty (after being popped from) then remove them + fn cleanup_queues(&mut self, leave_last: bool) { + while self.message_queues.last().filter(|queue| queue.is_empty()).is_some() { + if leave_last && self.message_queues.len() == 1 { + break; + } + self.message_queues.pop(); + } + } + + /// Add a message to a queue so that it can be executed. + /// If `process_after_all_current` is set, all currently queued messages (including children) will be processed first. + /// If not set, it (and its children) will be processed as soon as possible. + pub fn schedule_execution(message_queues: &mut Vec>, process_after_all_current: bool, messages: impl IntoIterator) { + match message_queues.first_mut() { + // If there are currently messages being processed and we are processing after them, add to the end of the first queue + Some(queue) if process_after_all_current => queue.extend(messages), + // In all other cases, make a new inner queue and add our message there + _ => message_queues.push(VecDeque::from_iter(messages)), + } + } + + pub fn handle_message>(&mut self, message: T, process_after_all_current: bool) { + let message = message.into(); + // Add all additional messages to the buffer if it exists (except from the end buffer message) + if !matches!(message, Message::EndBuffer(_)) { + if let Some(buffered_queue) = &mut self.buffered_queue { + Self::schedule_execution(buffered_queue, true, [message]); + + return; + } + } + + // If we are not maintaining the buffer, simply add to the current queue + Self::schedule_execution(&mut self.message_queues, process_after_all_current, [message]); + + while let Some(message) = self.message_queues.last_mut().and_then(VecDeque::pop_front) { + // Skip processing of this message if it will be processed later (at the end of the shallowest level queue) + if SIDE_EFFECT_FREE_MESSAGES.contains(&message.to_discriminant()) { + let already_in_queue = self.message_queues.first().filter(|queue| queue.contains(&message)).is_some(); + if already_in_queue { + self.log_deferred_message(&message, &self.message_queues, self.message_handlers.debug_message_handler.message_logging_verbosity); + self.cleanup_queues(false); + continue; + } else if self.message_queues.len() > 1 { + self.log_deferred_message(&message, &self.message_queues, self.message_handlers.debug_message_handler.message_logging_verbosity); + self.cleanup_queues(true); + self.message_queues[0].add(message); + continue; + } + } + + // Print the message at a verbosity level of `info` + self.log_message(&message, &self.message_queues, self.message_handlers.debug_message_handler.message_logging_verbosity); + + // Create a new queue for the child messages + let mut queue = VecDeque::new(); + + // Process the action by forwarding it to the relevant message handler, or saving the FrontendMessage to be sent to the frontend + match message { + Message::StartBuffer => { + self.buffered_queue = Some(std::mem::take(&mut self.message_queues)); + } + Message::EndBuffer(render_metadata) => { + // Assign the message queue to the currently buffered queue + if let Some(buffered_queue) = self.buffered_queue.take() { + self.cleanup_queues(false); + assert!(self.message_queues.is_empty(), "message queues are always empty when ending a buffer"); + self.message_queues = buffered_queue; + }; + + let graphene_std::renderer::RenderMetadata { + upstream_footprints: footprints, + local_transforms, + click_targets, + clip_targets, + } = render_metadata; + + // Run these update state messages immediately + let messages = [ + DocumentMessage::UpdateUpstreamTransforms { + upstream_footprints: footprints, + local_transforms, + }, + DocumentMessage::UpdateClickTargets { click_targets }, + DocumentMessage::UpdateClipTargets { clip_targets }, + ]; + Self::schedule_execution(&mut self.message_queues, false, messages.map(Message::from)); + } + Message::NoOp => {} + Message::Init => { + // Load persistent data from the browser database + queue.add(FrontendMessage::TriggerLoadFirstAutoSaveDocument); + queue.add(FrontendMessage::TriggerLoadPreferences); + + // Display the menu bar at the top of the window + queue.add(MenuBarMessage::SendLayout); + + // Send the information for tooltips and categories for each node/input. + queue.add(FrontendMessage::SendUIMetadata { + node_descriptions: document_node_definitions::collect_node_descriptions(), + node_types: document_node_definitions::collect_node_types(), + }); + + // Finish loading persistent data from the browser database + queue.add(FrontendMessage::TriggerLoadRestAutoSaveDocuments); + } + Message::Animation(message) => { + self.message_handlers.animation_message_handler.process_message(message, &mut queue, ()); + } + Message::Batched(messages) => { + messages.iter().for_each(|message| self.handle_message(message.to_owned(), false)); + } + Message::Broadcast(message) => self.message_handlers.broadcast_message_handler.process_message(message, &mut queue, ()), + Message::Debug(message) => { + self.message_handlers.debug_message_handler.process_message(message, &mut queue, ()); + } + Message::Dialog(message) => { + let data = DialogMessageData { + portfolio: &self.message_handlers.portfolio_message_handler, + preferences: &self.message_handlers.preferences_message_handler, + }; + self.message_handlers.dialog_message_handler.process_message(message, &mut queue, data); + } + Message::Frontend(message) => { + // Handle these messages immediately by returning early + if let FrontendMessage::TriggerFontLoad { .. } = message { + self.responses.push(message); + self.cleanup_queues(false); + + // Return early to avoid running the code after the match block + return; + } else { + // `FrontendMessage`s are saved and will be sent to the frontend after the message queue is done being processed + self.responses.push(message); + } + } + Message::Globals(message) => { + self.message_handlers.globals_message_handler.process_message(message, &mut queue, ()); + } + Message::InputPreprocessor(message) => { + let keyboard_platform = GLOBAL_PLATFORM.get().copied().unwrap_or_default().as_keyboard_platform_layout(); + + self.message_handlers + .input_preprocessor_message_handler + .process_message(message, &mut queue, InputPreprocessorMessageData { keyboard_platform }); + } + Message::KeyMapping(message) => { + let input = &self.message_handlers.input_preprocessor_message_handler; + let actions = self.collect_actions(); + + self.message_handlers + .key_mapping_message_handler + .process_message(message, &mut queue, KeyMappingMessageData { input, actions }); + } + Message::Layout(message) => { + let action_input_mapping = &|action_to_find: &MessageDiscriminant| self.message_handlers.key_mapping_message_handler.action_input_mapping(action_to_find); + + self.message_handlers.layout_message_handler.process_message(message, &mut queue, action_input_mapping); + } + Message::Portfolio(message) => { + let ipp = &self.message_handlers.input_preprocessor_message_handler; + let preferences = &self.message_handlers.preferences_message_handler; + let current_tool = &self.message_handlers.tool_message_handler.tool_state.tool_data.active_tool_type; + let message_logging_verbosity = self.message_handlers.debug_message_handler.message_logging_verbosity; + let reset_node_definitions_on_open = self.message_handlers.portfolio_message_handler.reset_node_definitions_on_open; + let timing_information = self.message_handlers.animation_message_handler.timing_information(); + let animation = &self.message_handlers.animation_message_handler; + + self.message_handlers.portfolio_message_handler.process_message( + message, + &mut queue, + PortfolioMessageData { + ipp, + preferences, + current_tool, + message_logging_verbosity, + reset_node_definitions_on_open, + timing_information, + animation, + }, + ); + } + Message::Preferences(message) => { + self.message_handlers.preferences_message_handler.process_message(message, &mut queue, ()); + } + Message::Tool(message) => { + let document_id = self.message_handlers.portfolio_message_handler.active_document_id().unwrap(); + let Some(document) = self.message_handlers.portfolio_message_handler.documents.get_mut(&document_id) else { + warn!("Called ToolMessage without an active document.\nGot {message:?}"); + return; + }; + + let data = ToolMessageData { + document_id, + document, + input: &self.message_handlers.input_preprocessor_message_handler, + persistent_data: &self.message_handlers.portfolio_message_handler.persistent_data, + node_graph: &self.message_handlers.portfolio_message_handler.executor, + preferences: &self.message_handlers.preferences_message_handler, + }; + + self.message_handlers.tool_message_handler.process_message(message, &mut queue, data); + } + Message::Workspace(message) => { + self.message_handlers.workspace_message_handler.process_message(message, &mut queue, ()); + } + } + + // If there are child messages, append the queue to the list of queues + if !queue.is_empty() { + self.message_queues.push(queue); + } + + self.cleanup_queues(false); + } + } + + pub fn collect_actions(&self) -> ActionList { + // TODO: Reduce the number of heap allocations + let mut list = Vec::new(); + list.extend(self.message_handlers.dialog_message_handler.actions()); + list.extend(self.message_handlers.animation_message_handler.actions()); + list.extend(self.message_handlers.input_preprocessor_message_handler.actions()); + list.extend(self.message_handlers.key_mapping_message_handler.actions()); + list.extend(self.message_handlers.debug_message_handler.actions()); + if let Some(document) = self.message_handlers.portfolio_message_handler.active_document() { + if !document.graph_view_overlay_open { + list.extend(self.message_handlers.tool_message_handler.actions()); + } + } + list.extend(self.message_handlers.portfolio_message_handler.actions()); + list + } + + pub fn poll_node_graph_evaluation(&mut self, responses: &mut VecDeque) -> Result<(), String> { + self.message_handlers.portfolio_message_handler.poll_node_graph_evaluation(responses) + } + + /// Create the tree structure for logging the messages as a tree + fn create_indents(queues: &[VecDeque]) -> String { + String::from_iter(queues.iter().enumerate().skip(1).map(|(index, queue)| { + if index == queues.len() - 1 { + if queue.is_empty() { "└── " } else { "├── " } + } else if queue.is_empty() { + " " + } else { + "│ " + } + })) + } + + /// Logs a message that is about to be executed, either as a tree + /// with a discriminant or the entire payload (depending on settings) + fn log_message(&self, message: &Message, queues: &[VecDeque], message_logging_verbosity: MessageLoggingVerbosity) { + let discriminant = MessageDiscriminant::from(message); + let is_blocked = DEBUG_MESSAGE_BLOCK_LIST.contains(&discriminant) || DEBUG_MESSAGE_ENDING_BLOCK_LIST.iter().any(|blocked_name| discriminant.local_name().ends_with(blocked_name)); + + if !is_blocked { + match message_logging_verbosity { + MessageLoggingVerbosity::Off => {} + MessageLoggingVerbosity::Names => { + info!("{}{:?}", Self::create_indents(queues), message.to_discriminant()); + } + MessageLoggingVerbosity::Contents => { + if !(matches!(message, Message::InputPreprocessor(_))) { + info!("Message: {}{:?}", Self::create_indents(queues), message); + } + } + } + } + } + + /// Logs into the tree that the message is in the side effect free messages and its execution will be deferred + fn log_deferred_message(&self, message: &Message, queues: &[VecDeque], message_logging_verbosity: MessageLoggingVerbosity) { + if let MessageLoggingVerbosity::Names = message_logging_verbosity { + info!("{}Deferred \"{:?}\" because it's a SIDE_EFFECT_FREE_MESSAGE", Self::create_indents(queues), message.to_discriminant()); + } + } +} + +#[cfg(test)] +mod test { + pub use crate::test_utils::test_prelude::*; + + /// Create an editor with three layers + /// 1. A red rectangle + /// 2. A blue shape + /// 3. A green ellipse + async fn create_editor_with_three_layers() -> EditorTestUtils { + let mut editor = EditorTestUtils::create(); + + editor.new_document().await; + + editor.select_primary_color(Color::RED).await; + editor.draw_rect(100., 200., 300., 400.).await; + + editor.select_primary_color(Color::BLUE).await; + editor.draw_polygon(10., 1200., 1300., 400.).await; + + editor.select_primary_color(Color::GREEN).await; + editor.draw_ellipse(104., 1200., 1300., 400.).await; + + editor + } + + /// - create rect, shape and ellipse + /// - copy + /// - paste + /// - assert that ellipse was copied + #[tokio::test] + async fn copy_paste_single_layer() { + let mut editor = create_editor_with_three_layers().await; + + let layers_before_copy = editor.active_document().metadata().all_layers().collect::>(); + editor.handle_message(PortfolioMessage::Copy { clipboard: Clipboard::Internal }).await; + editor + .handle_message(PortfolioMessage::PasteIntoFolder { + clipboard: Clipboard::Internal, + parent: LayerNodeIdentifier::ROOT_PARENT, + insert_index: 0, + }) + .await; + + let layers_after_copy = editor.active_document().metadata().all_layers().collect::>(); + + assert_eq!(layers_before_copy.len(), 3); + assert_eq!(layers_after_copy.len(), 4); + + // Existing layers are unaffected + for i in 0..=2 { + assert_eq!(layers_before_copy[i], layers_after_copy[i + 1]); + } + } + + #[cfg_attr(miri, ignore)] + /// - create rect, shape and ellipse + /// - select shape + /// - copy + /// - paste + /// - assert that shape was copied + #[tokio::test] + async fn copy_paste_single_layer_from_middle() { + let mut editor = create_editor_with_three_layers().await; + + let layers_before_copy = editor.active_document().metadata().all_layers().collect::>(); + let shape_id = editor.active_document().metadata().all_layers().nth(1).unwrap(); + + editor.handle_message(NodeGraphMessage::SelectedNodesSet { nodes: vec![shape_id.to_node()] }).await; + editor.handle_message(PortfolioMessage::Copy { clipboard: Clipboard::Internal }).await; + editor + .handle_message(PortfolioMessage::PasteIntoFolder { + clipboard: Clipboard::Internal, + parent: LayerNodeIdentifier::ROOT_PARENT, + insert_index: 0, + }) + .await; + + let layers_after_copy = editor.active_document().metadata().all_layers().collect::>(); + + assert_eq!(layers_before_copy.len(), 3); + assert_eq!(layers_after_copy.len(), 4); + + // Existing layers are unaffected + for i in 0..=2 { + assert_eq!(layers_before_copy[i], layers_after_copy[i + 1]); + } + } + + #[cfg_attr(miri, ignore)] + /// - create rect, shape and ellipse + /// - select ellipse and rect + /// - copy + /// - delete + /// - create another rect + /// - paste + /// - paste + #[tokio::test] + async fn copy_paste_deleted_layers() { + let mut editor = create_editor_with_three_layers().await; + assert_eq!(editor.active_document().metadata().all_layers().count(), 3); + + let layers_before_copy = editor.active_document().metadata().all_layers().collect::>(); + let rect_id = layers_before_copy[0]; + let shape_id = layers_before_copy[1]; + let ellipse_id = layers_before_copy[2]; + + editor + .handle_message(NodeGraphMessage::SelectedNodesSet { + nodes: vec![rect_id.to_node(), ellipse_id.to_node()], + }) + .await; + editor.handle_message(PortfolioMessage::Copy { clipboard: Clipboard::Internal }).await; + editor.handle_message(NodeGraphMessage::DeleteSelectedNodes { delete_children: true }).await; + editor.draw_rect(0., 800., 12., 200.).await; + editor + .handle_message(PortfolioMessage::PasteIntoFolder { + clipboard: Clipboard::Internal, + parent: LayerNodeIdentifier::ROOT_PARENT, + insert_index: 0, + }) + .await; + editor + .handle_message(PortfolioMessage::PasteIntoFolder { + clipboard: Clipboard::Internal, + parent: LayerNodeIdentifier::ROOT_PARENT, + insert_index: 0, + }) + .await; + + let layers_after_copy = editor.active_document().metadata().all_layers().collect::>(); + + assert_eq!(layers_before_copy.len(), 3); + assert_eq!(layers_after_copy.len(), 6); + + println!("{:?} {:?}", layers_after_copy, layers_before_copy); + + assert_eq!(layers_after_copy[5], shape_id); + } + + #[tokio::test] + /// This test will fail when you make changes to the underlying serialization format for a document. + async fn check_if_demo_art_opens() { + use crate::messages::layout::utility_types::widget_prelude::*; + + let print_problem_to_terminal_on_failure = |value: &String| { + println!(); + println!("-------------------------------------------------"); + println!("Failed test due to receiving a DisplayDialogError while loading a Graphite demo file."); + println!(); + println!("NOTE:"); + println!("Document upgrading isn't performed in tests like when opening in the actual editor."); + println!("You may need to open and re-save a document in the editor to apply its migrations."); + println!(); + println!("DisplayDialogError details:"); + println!(); + println!("Description:"); + println!("{value}"); + println!("-------------------------------------------------"); + println!(); + + panic!() + }; + + let mut editor = EditorTestUtils::create(); + + // UNCOMMENT THIS FOR RUNNING UNDER MIRI + // + // let files = [ + // include_str!("../../demo-artwork/changing-seasons.graphite"), + // include_str!("../../demo-artwork/isometric-fountain.graphite"), + // include_str!("../../demo-artwork/painted-dreams.graphite"), + // include_str!("../../demo-artwork/procedural-string-lights.graphite"), + // include_str!("../../demo-artwork/parametric-dunescape.graphite"), + // include_str!("../../demo-artwork/red-dress.graphite"), + // include_str!("../../demo-artwork/valley-of-spires.graphite"), + // ]; + // for (id, document_serialized_content) in files.iter().enumerate() { + // let document_name = format!("document {id}"); + + for (document_name, _, file_name) in crate::messages::dialog::simple_dialogs::ARTWORK { + let document_serialized_content = std::fs::read_to_string(format!("../demo-artwork/{file_name}")).unwrap(); + + assert_eq!( + document_serialized_content.lines().count(), + 1, + "Demo artwork '{document_name}' has more than 1 line (remember to open and re-save it in Graphite)", + ); + + let responses = editor.editor.handle_message(PortfolioMessage::OpenDocumentFile { + document_name: document_name.into(), + document_serialized_content, + }); + + // Check if the graph renders + if let Err(e) = editor.eval_graph().await { + print_problem_to_terminal_on_failure(&format!("Failed to evaluate the graph for document '{document_name}':\n{e}")); + } + + for response in responses { + // Check for the existence of the file format incompatibility warning dialog after opening the test file + if let FrontendMessage::UpdateDialogColumn1 { layout_target: _, diff } = response { + if let DiffUpdate::SubLayout(sub_layout) = &diff[0].new_value { + if let LayoutGroup::Row { widgets } = &sub_layout[0] { + if let Widget::TextLabel(TextLabel { value, .. }) = &widgets[0].widget { + print_problem_to_terminal_on_failure(value); + } + } + } + } + } + } + } +} diff --git a/editor/src/generate_ts_types.rs b/editor/src/generate_ts_types.rs new file mode 100644 index 0000000000000000000000000000000000000000..659b860f16bc304ca0e7e5afcaf341d0b89a8077 --- /dev/null +++ b/editor/src/generate_ts_types.rs @@ -0,0 +1,34 @@ +/// Running this test will generate a `types.ts` file at the root of the repo, +/// containing every type annotated with `specta::Type` +// #[cfg(all(test, feature = "specta-export"))] +#[ignore] +#[test] +fn generate_ts_types() { + // TODO: Un-comment this out when we figure out how to reenable the "typescript` Specta feature flag + + // use crate::messages::prelude::FrontendMessage; + // use specta::ts::{export_named_datatype, BigIntExportBehavior, ExportConfig}; + // use specta::{NamedType, TypeMap}; + // use std::fs::File; + // use std::io::Write; + + // let config = ExportConfig::new().bigint(BigIntExportBehavior::Number); + + // let mut type_map = TypeMap::default(); + + // let datatype = FrontendMessage::definition_named_data_type(&mut type_map); + + // let mut export = String::new(); + + // export += &export_named_datatype(&config, &datatype, &type_map).unwrap(); + + // type_map + // .iter() + // .map(|(_, v)| v) + // .flat_map(|v| export_named_datatype(&config, v, &type_map)) + // .for_each(|e| export += &format!("\n\n{e}")); + + // let mut file = File::create("../types.ts").unwrap(); + + // write!(file, "{export}").ok(); +} diff --git a/editor/src/lib.rs b/editor/src/lib.rs new file mode 100644 index 0000000000000000000000000000000000000000..80d80b53056ddfc6aede2d0fb839af2bba7612a1 --- /dev/null +++ b/editor/src/lib.rs @@ -0,0 +1,17 @@ +extern crate graphite_proc_macros; + +// `macro_use` puts these macros into scope for all descendant code files +#[macro_use] +mod macros; +mod generate_ts_types; +#[macro_use] +extern crate log; + +pub mod application; +pub mod consts; +pub mod dispatcher; +pub mod messages; +pub mod node_graph_executor; +#[cfg(test)] +pub mod test_utils; +pub mod utility_traits; diff --git a/editor/src/macros.rs b/editor/src/macros.rs new file mode 100644 index 0000000000000000000000000000000000000000..a5b43b4a38808e9318e6ec5b353d196df120bacb --- /dev/null +++ b/editor/src/macros.rs @@ -0,0 +1,56 @@ +/// Syntax sugar for initializing an `ActionList` +/// +/// # Example +/// +/// ```ignore +/// actions!(DocumentMessage::Undo, DocumentMessage::Redo); +/// ``` +/// +/// expands to: +/// ```ignore +/// vec![vec![DocumentMessage::Undo, DocumentMessage::Redo]]; +/// ``` +/// +/// and +/// ```ignore +/// actions!(DocumentMessage; +/// Undo, +/// Redo, +/// ); +/// ``` +/// +/// expands to: +/// ```ignore +/// vec![vec![DocumentMessage::Undo, DocumentMessage::Redo]]; +/// ``` +/// +macro_rules! actions { + ($($v:expr_2021),* $(,)?) => {{ + vec![$(vec![$v.into()]),*] + }}; + + ($name:ident; $($v:ident),* $(,)?) => {{ + vec![vec![$(($name::$v).into()),*]] + }}; +} + +/// Does the same thing as the `actions!` macro but wraps everything in: +/// +/// ```ignore +/// fn actions(&self) -> ActionList { +/// actions!(…) +/// } +/// ``` +macro_rules! advertise_actions { + ($($v:expr_2021),* $(,)?) => { + fn actions(&self) -> $crate::utility_traits::ActionList { + actions!($($v),*) + } + }; + + ($name:ident; $($v:ident),* $(,)?) => { + fn actions(&self) -> $crate::utility_traits::ActionList { + actions!($name; $($v),*) + } + } +} diff --git a/editor/src/messages/animation/animation_message.rs b/editor/src/messages/animation/animation_message.rs new file mode 100644 index 0000000000000000000000000000000000000000..13166800960d6f4ea7327b15ad395287b3f3f564 --- /dev/null +++ b/editor/src/messages/animation/animation_message.rs @@ -0,0 +1,17 @@ +use crate::messages::prelude::*; + +use super::animation_message_handler::AnimationTimeMode; + +#[impl_message(Message, Animation)] +#[derive(PartialEq, Clone, Debug, serde::Serialize, serde::Deserialize)] +pub enum AnimationMessage { + ToggleLivePreview, + EnableLivePreview, + DisableLivePreview, + RestartAnimation, + SetFrameIndex(f64), + SetTime(f64), + UpdateTime, + IncrementFrameCounter, + SetAnimationTimeMode(AnimationTimeMode), +} diff --git a/editor/src/messages/animation/animation_message_handler.rs b/editor/src/messages/animation/animation_message_handler.rs new file mode 100644 index 0000000000000000000000000000000000000000..eb7ceba2e070682f514ef3d9303f03302826870a --- /dev/null +++ b/editor/src/messages/animation/animation_message_handler.rs @@ -0,0 +1,133 @@ +use std::time::Duration; + +use crate::messages::prelude::*; + +use super::TimingInformation; + +#[derive(PartialEq, Clone, Default, Debug, serde::Serialize, serde::Deserialize)] +pub enum AnimationTimeMode { + #[default] + TimeBased, + FrameBased, +} + +#[derive(Default, Debug, Clone, PartialEq)] +enum AnimationState { + #[default] + Stopped, + Playing { + start: f64, + }, + Paused { + start: f64, + pause_time: f64, + }, +} + +#[derive(Default, Debug, Clone, PartialEq)] +pub struct AnimationMessageHandler { + /// Used to re-send the UI on the next frame after playback starts + live_preview_recently_zero: bool, + timestamp: f64, + frame_index: f64, + animation_state: AnimationState, + fps: f64, + animation_time_mode: AnimationTimeMode, +} +impl AnimationMessageHandler { + pub(crate) fn timing_information(&self) -> TimingInformation { + let animation_time = self.timestamp - self.animation_start(); + let animation_time = match self.animation_time_mode { + AnimationTimeMode::TimeBased => Duration::from_millis(animation_time as u64), + AnimationTimeMode::FrameBased => Duration::from_secs((self.frame_index / self.fps) as u64), + }; + TimingInformation { time: self.timestamp, animation_time } + } + + pub(crate) fn animation_start(&self) -> f64 { + match self.animation_state { + AnimationState::Stopped => self.timestamp, + AnimationState::Playing { start } => start, + AnimationState::Paused { start, pause_time } => start + self.timestamp - pause_time, + } + } + + pub fn is_playing(&self) -> bool { + matches!(self.animation_state, AnimationState::Playing { .. }) + } +} + +impl MessageHandler for AnimationMessageHandler { + fn process_message(&mut self, message: AnimationMessage, responses: &mut VecDeque, _data: ()) { + match message { + AnimationMessage::ToggleLivePreview => match self.animation_state { + AnimationState::Stopped => responses.add(AnimationMessage::EnableLivePreview), + AnimationState::Playing { .. } => responses.add(AnimationMessage::DisableLivePreview), + AnimationState::Paused { .. } => responses.add(AnimationMessage::EnableLivePreview), + }, + AnimationMessage::EnableLivePreview => { + self.animation_state = AnimationState::Playing { start: self.animation_start() }; + + // Update the restart and pause/play buttons + responses.add(PortfolioMessage::UpdateDocumentWidgets); + } + AnimationMessage::DisableLivePreview => { + match self.animation_state { + AnimationState::Stopped => (), + AnimationState::Playing { start } => self.animation_state = AnimationState::Paused { start, pause_time: self.timestamp }, + AnimationState::Paused { .. } => (), + } + + // Update the restart and pause/play buttons + responses.add(PortfolioMessage::UpdateDocumentWidgets); + } + AnimationMessage::SetFrameIndex(frame) => { + self.frame_index = frame; + responses.add(PortfolioMessage::SubmitActiveGraphRender); + // Update the restart and pause/play buttons + responses.add(PortfolioMessage::UpdateDocumentWidgets); + } + AnimationMessage::SetTime(time) => { + self.timestamp = time; + responses.add(AnimationMessage::UpdateTime); + } + AnimationMessage::IncrementFrameCounter => { + if self.is_playing() { + self.frame_index += 1.; + responses.add(AnimationMessage::UpdateTime); + } + } + AnimationMessage::UpdateTime => { + if self.is_playing() { + responses.add(PortfolioMessage::SubmitActiveGraphRender); + + if self.live_preview_recently_zero { + // Update the restart and pause/play buttons + responses.add(PortfolioMessage::UpdateDocumentWidgets); + self.live_preview_recently_zero = false; + } + } + } + AnimationMessage::RestartAnimation => { + self.frame_index = 0.; + self.animation_state = match self.animation_state { + AnimationState::Playing { .. } => AnimationState::Playing { start: self.timestamp }, + _ => AnimationState::Stopped, + }; + self.live_preview_recently_zero = true; + responses.add(PortfolioMessage::SubmitActiveGraphRender); + // Update the restart and pause/play buttons + responses.add(PortfolioMessage::UpdateDocumentWidgets); + } + AnimationMessage::SetAnimationTimeMode(animation_time_mode) => { + self.animation_time_mode = animation_time_mode; + } + } + } + + advertise_actions!(AnimationMessageDiscriminant; + ToggleLivePreview, + SetFrameIndex, + RestartAnimation, + ); +} diff --git a/editor/src/messages/animation/mod.rs b/editor/src/messages/animation/mod.rs new file mode 100644 index 0000000000000000000000000000000000000000..c92c9de5d667f42d9fc894cf032cd9f99dcdbbe6 --- /dev/null +++ b/editor/src/messages/animation/mod.rs @@ -0,0 +1,9 @@ +mod animation_message; +mod animation_message_handler; + +#[doc(inline)] +pub use animation_message::{AnimationMessage, AnimationMessageDiscriminant}; +#[doc(inline)] +pub use animation_message_handler::AnimationMessageHandler; + +pub use graphene_std::application_io::TimingInformation; diff --git a/editor/src/messages/broadcast/broadcast_event.rs b/editor/src/messages/broadcast/broadcast_event.rs new file mode 100644 index 0000000000000000000000000000000000000000..ebe2318aaea91b0e444477e5e875e22c5d43da6c --- /dev/null +++ b/editor/src/messages/broadcast/broadcast_event.rs @@ -0,0 +1,12 @@ +use crate::messages::prelude::*; + +#[derive(PartialEq, Eq, Clone, Debug, serde::Serialize, serde::Deserialize, Hash)] +#[impl_message(Message, BroadcastMessage, TriggerEvent)] +pub enum BroadcastEvent { + /// Triggered by requestAnimationFrame in JS + AnimationFrame, + CanvasTransformed, + ToolAbort, + SelectionChanged, + WorkingColorChanged, +} diff --git a/editor/src/messages/broadcast/broadcast_message.rs b/editor/src/messages/broadcast/broadcast_message.rs new file mode 100644 index 0000000000000000000000000000000000000000..984d4e56a0f974de129e4e64b345d173c4152418 --- /dev/null +++ b/editor/src/messages/broadcast/broadcast_message.rs @@ -0,0 +1,19 @@ +use crate::messages::prelude::*; + +#[impl_message(Message, Broadcast)] +#[derive(PartialEq, Clone, Debug, serde::Serialize, serde::Deserialize)] +pub enum BroadcastMessage { + // Sub-messages + #[child] + TriggerEvent(BroadcastEvent), + + // Messages + SubscribeEvent { + on: BroadcastEvent, + send: Box, + }, + UnsubscribeEvent { + on: BroadcastEvent, + message: Box, + }, +} diff --git a/editor/src/messages/broadcast/broadcast_message_handler.rs b/editor/src/messages/broadcast/broadcast_message_handler.rs new file mode 100644 index 0000000000000000000000000000000000000000..51d64b5852952d6269814685f63ee02535f2aa77 --- /dev/null +++ b/editor/src/messages/broadcast/broadcast_message_handler.rs @@ -0,0 +1,27 @@ +use crate::messages::prelude::*; + +#[derive(Debug, Clone, Default)] +pub struct BroadcastMessageHandler { + listeners: HashMap>, +} + +impl MessageHandler for BroadcastMessageHandler { + fn process_message(&mut self, message: BroadcastMessage, responses: &mut VecDeque, _data: ()) { + match message { + // Sub-messages + BroadcastMessage::TriggerEvent(event) => { + for message in self.listeners.entry(event).or_default() { + responses.add_front(message.clone()) + } + } + + // Messages + BroadcastMessage::SubscribeEvent { on, send } => self.listeners.entry(on).or_default().push(*send), + BroadcastMessage::UnsubscribeEvent { on, message } => self.listeners.entry(on).or_default().retain(|msg| *msg != *message), + } + } + + fn actions(&self) -> ActionList { + actions!(BroadcastEventDiscriminant;) + } +} diff --git a/editor/src/messages/broadcast/mod.rs b/editor/src/messages/broadcast/mod.rs new file mode 100644 index 0000000000000000000000000000000000000000..a6ecb88979e219b3efbb8dfcb32c36f4436ae489 --- /dev/null +++ b/editor/src/messages/broadcast/mod.rs @@ -0,0 +1,9 @@ +mod broadcast_message; +mod broadcast_message_handler; + +pub mod broadcast_event; + +#[doc(inline)] +pub use broadcast_message::{BroadcastMessage, BroadcastMessageDiscriminant}; +#[doc(inline)] +pub use broadcast_message_handler::BroadcastMessageHandler; diff --git a/editor/src/messages/debug/debug_message.rs b/editor/src/messages/debug/debug_message.rs new file mode 100644 index 0000000000000000000000000000000000000000..67f5487dedd14afd8d4cb7ff7920940b5a83ffd0 --- /dev/null +++ b/editor/src/messages/debug/debug_message.rs @@ -0,0 +1,10 @@ +use crate::messages::prelude::*; + +#[impl_message(Message, Debug)] +#[derive(PartialEq, Eq, Clone, Debug, Hash, serde::Serialize, serde::Deserialize)] +pub enum DebugMessage { + ToggleTraceLogs, + MessageOff, + MessageNames, + MessageContents, +} diff --git a/editor/src/messages/debug/debug_message_handler.rs b/editor/src/messages/debug/debug_message_handler.rs new file mode 100644 index 0000000000000000000000000000000000000000..6044ce91089b282594985020fd47ad005dcb48c7 --- /dev/null +++ b/editor/src/messages/debug/debug_message_handler.rs @@ -0,0 +1,49 @@ +use super::utility_types::MessageLoggingVerbosity; +use crate::messages::prelude::*; + +#[derive(Debug, Default)] +pub struct DebugMessageHandler { + pub message_logging_verbosity: MessageLoggingVerbosity, +} + +impl MessageHandler for DebugMessageHandler { + fn process_message(&mut self, message: DebugMessage, responses: &mut VecDeque, _data: ()) { + match message { + DebugMessage::ToggleTraceLogs => { + if log::max_level() == log::LevelFilter::Debug { + log::set_max_level(log::LevelFilter::Trace); + } else { + log::set_max_level(log::LevelFilter::Debug); + } + + // Refresh the checkmark beside the menu entry for this + responses.add(MenuBarMessage::SendLayout); + } + DebugMessage::MessageOff => { + self.message_logging_verbosity = MessageLoggingVerbosity::Off; + + // Refresh the checkmark beside the menu entry for this + responses.add(MenuBarMessage::SendLayout); + } + DebugMessage::MessageNames => { + self.message_logging_verbosity = MessageLoggingVerbosity::Names; + + // Refresh the checkmark beside the menu entry for this + responses.add(MenuBarMessage::SendLayout); + } + DebugMessage::MessageContents => { + self.message_logging_verbosity = MessageLoggingVerbosity::Contents; + + // Refresh the checkmark beside the menu entry for this + responses.add(MenuBarMessage::SendLayout); + } + } + } + + advertise_actions!(DebugMessageDiscriminant; + ToggleTraceLogs, + MessageOff, + MessageNames, + MessageContents, + ); +} diff --git a/editor/src/messages/debug/mod.rs b/editor/src/messages/debug/mod.rs new file mode 100644 index 0000000000000000000000000000000000000000..79ad968d154d097a534e70bddf1f653599101f56 --- /dev/null +++ b/editor/src/messages/debug/mod.rs @@ -0,0 +1,9 @@ +mod debug_message; +mod debug_message_handler; + +pub mod utility_types; + +#[doc(inline)] +pub use debug_message::{DebugMessage, DebugMessageDiscriminant}; +#[doc(inline)] +pub use debug_message_handler::DebugMessageHandler; diff --git a/editor/src/messages/debug/utility_types.rs b/editor/src/messages/debug/utility_types.rs new file mode 100644 index 0000000000000000000000000000000000000000..027dd14f2a6181220fa2112863c790af5f499682 --- /dev/null +++ b/editor/src/messages/debug/utility_types.rs @@ -0,0 +1,7 @@ +#[derive(Debug, Default, Clone, Copy, Eq, PartialEq)] +pub enum MessageLoggingVerbosity { + #[default] + Off, + Names, + Contents, +} diff --git a/editor/src/messages/dialog/dialog_message.rs b/editor/src/messages/dialog/dialog_message.rs new file mode 100644 index 0000000000000000000000000000000000000000..baee1e65829520f94edcce74ca5d217fc226c785 --- /dev/null +++ b/editor/src/messages/dialog/dialog_message.rs @@ -0,0 +1,38 @@ +use crate::messages::prelude::*; + +#[impl_message(Message, Dialog)] +#[derive(PartialEq, Clone, Debug, serde::Serialize, serde::Deserialize)] +pub enum DialogMessage { + // Sub-messages + #[child] + ExportDialog(ExportDialogMessage), + #[child] + NewDocumentDialog(NewDocumentDialogMessage), + #[child] + PreferencesDialog(PreferencesDialogMessage), + + // Messages + CloseAllDocumentsWithConfirmation, + CloseDialogAndThen { + followups: Vec, + }, + DisplayDialogError { + title: String, + description: String, + }, + RequestAboutGraphiteDialog, + RequestAboutGraphiteDialogWithLocalizedCommitDate { + localized_commit_date: String, + localized_commit_year: String, + }, + RequestComingSoonDialog { + issue: Option, + }, + RequestDemoArtworkDialog, + RequestExportDialog, + RequestLicensesDialogWithLocalizedCommitDate { + localized_commit_year: String, + }, + RequestNewDocumentDialog, + RequestPreferencesDialog, +} diff --git a/editor/src/messages/dialog/dialog_message_handler.rs b/editor/src/messages/dialog/dialog_message_handler.rs new file mode 100644 index 0000000000000000000000000000000000000000..3e9c80e46ada75022db22d322d86653682a67870 --- /dev/null +++ b/editor/src/messages/dialog/dialog_message_handler.rs @@ -0,0 +1,118 @@ +use super::simple_dialogs::{self, AboutGraphiteDialog, ComingSoonDialog, DemoArtworkDialog, LicensesDialog}; +use crate::messages::layout::utility_types::widget_prelude::*; +use crate::messages::prelude::*; + +pub struct DialogMessageData<'a> { + pub portfolio: &'a PortfolioMessageHandler, + pub preferences: &'a PreferencesMessageHandler, +} + +/// Stores the dialogs which require state. These are the ones that have their own message handlers, and are not the ones defined in `simple_dialogs`. +#[derive(Debug, Default, Clone)] +pub struct DialogMessageHandler { + export_dialog: ExportDialogMessageHandler, + new_document_dialog: NewDocumentDialogMessageHandler, + preferences_dialog: PreferencesDialogMessageHandler, +} + +impl MessageHandler> for DialogMessageHandler { + fn process_message(&mut self, message: DialogMessage, responses: &mut VecDeque, data: DialogMessageData) { + let DialogMessageData { portfolio, preferences } = data; + + match message { + DialogMessage::ExportDialog(message) => self.export_dialog.process_message(message, responses, ExportDialogMessageData { portfolio }), + DialogMessage::NewDocumentDialog(message) => self.new_document_dialog.process_message(message, responses, ()), + DialogMessage::PreferencesDialog(message) => self.preferences_dialog.process_message(message, responses, PreferencesDialogMessageData { preferences }), + + DialogMessage::CloseAllDocumentsWithConfirmation => { + let dialog = simple_dialogs::CloseAllDocumentsDialog { + unsaved_document_names: portfolio.unsaved_document_names(), + }; + dialog.send_dialog_to_frontend(responses); + } + DialogMessage::CloseDialogAndThen { followups } => { + for message in followups.into_iter() { + responses.add(message); + } + + // This come after followups, so that the followups (which can cause the dialog to open) happen first, then we close it afterwards. + // If it comes before, the dialog reopens (and appears to not close at all). + responses.add(FrontendMessage::DisplayDialogDismiss); + } + DialogMessage::DisplayDialogError { title, description } => { + let dialog = simple_dialogs::ErrorDialog { title, description }; + dialog.send_dialog_to_frontend(responses); + } + DialogMessage::RequestAboutGraphiteDialog => { + responses.add(FrontendMessage::TriggerAboutGraphiteLocalizedCommitDate { + commit_date: env!("GRAPHITE_GIT_COMMIT_DATE").into(), + }); + } + DialogMessage::RequestAboutGraphiteDialogWithLocalizedCommitDate { + localized_commit_date, + localized_commit_year, + } => { + let dialog = AboutGraphiteDialog { + localized_commit_date, + localized_commit_year, + }; + + dialog.send_dialog_to_frontend(responses); + } + DialogMessage::RequestComingSoonDialog { issue } => { + let dialog = ComingSoonDialog { issue }; + dialog.send_dialog_to_frontend(responses); + } + DialogMessage::RequestDemoArtworkDialog => { + let dialog = DemoArtworkDialog; + dialog.send_dialog_to_frontend(responses); + } + DialogMessage::RequestExportDialog => { + if let Some(document) = portfolio.active_document() { + let artboards = document + .metadata() + .all_layers() + .filter(|&layer| document.network_interface.is_artboard(&layer.to_node(), &[])) + .map(|layer| { + let name = document + .network_interface + .node_metadata(&layer.to_node(), &[]) + .map(|node| node.persistent_metadata.display_name.clone()) + .and_then(|name| if name.is_empty() { None } else { Some(name) }) + .unwrap_or_else(|| "Artboard".to_string()); + (layer, name) + }) + .collect(); + + self.export_dialog.artboards = artboards; + self.export_dialog.has_selection = document.network_interface.selected_nodes().selected_layers(document.metadata()).next().is_some(); + self.export_dialog.send_dialog_to_frontend(responses); + } + } + DialogMessage::RequestLicensesDialogWithLocalizedCommitDate { localized_commit_year } => { + let dialog = LicensesDialog { localized_commit_year }; + + dialog.send_dialog_to_frontend(responses); + } + DialogMessage::RequestNewDocumentDialog => { + self.new_document_dialog = NewDocumentDialogMessageHandler { + name: portfolio.generate_new_document_name(), + infinite: false, + dimensions: glam::UVec2::new(1920, 1080), + }; + self.new_document_dialog.send_dialog_to_frontend(responses); + } + DialogMessage::RequestPreferencesDialog => { + self.preferences_dialog = PreferencesDialogMessageHandler {}; + self.preferences_dialog.send_dialog_to_frontend(responses, preferences); + } + } + } + + advertise_actions!(DialogMessageDiscriminant; + CloseAllDocumentsWithConfirmation, + RequestExportDialog, + RequestNewDocumentDialog, + RequestPreferencesDialog, + ); +} diff --git a/editor/src/messages/dialog/export_dialog/export_dialog_message.rs b/editor/src/messages/dialog/export_dialog/export_dialog_message.rs new file mode 100644 index 0000000000000000000000000000000000000000..20b0f8486abf26b32b04e655f7b5f7f0fb47cb9f --- /dev/null +++ b/editor/src/messages/dialog/export_dialog/export_dialog_message.rs @@ -0,0 +1,13 @@ +use crate::messages::frontend::utility_types::{ExportBounds, FileType}; +use crate::messages::prelude::*; + +#[impl_message(Message, DialogMessage, ExportDialog)] +#[derive(PartialEq, Clone, Debug, serde::Serialize, serde::Deserialize)] +pub enum ExportDialogMessage { + FileType(FileType), + ScaleFactor(f64), + TransparentBackground(bool), + ExportBounds(ExportBounds), + + Submit, +} diff --git a/editor/src/messages/dialog/export_dialog/export_dialog_message_handler.rs b/editor/src/messages/dialog/export_dialog/export_dialog_message_handler.rs new file mode 100644 index 0000000000000000000000000000000000000000..1bcf4b7003c231b6ba2939415bdb2ed0fceec8fe --- /dev/null +++ b/editor/src/messages/dialog/export_dialog/export_dialog_message_handler.rs @@ -0,0 +1,164 @@ +use crate::messages::frontend::utility_types::{ExportBounds, FileType}; +use crate::messages::layout::utility_types::widget_prelude::*; +use crate::messages::portfolio::document::utility_types::document_metadata::LayerNodeIdentifier; +use crate::messages::prelude::*; + +pub struct ExportDialogMessageData<'a> { + pub portfolio: &'a PortfolioMessageHandler, +} + +/// A dialog to allow users to customize their file export. +#[derive(Debug, Clone)] +pub struct ExportDialogMessageHandler { + pub file_type: FileType, + pub scale_factor: f64, + pub bounds: ExportBounds, + pub transparent_background: bool, + pub artboards: HashMap, + pub has_selection: bool, +} + +impl Default for ExportDialogMessageHandler { + fn default() -> Self { + Self { + file_type: Default::default(), + scale_factor: 1., + bounds: Default::default(), + transparent_background: false, + artboards: Default::default(), + has_selection: false, + } + } +} + +impl MessageHandler> for ExportDialogMessageHandler { + fn process_message(&mut self, message: ExportDialogMessage, responses: &mut VecDeque, data: ExportDialogMessageData) { + let ExportDialogMessageData { portfolio } = data; + + match message { + ExportDialogMessage::FileType(export_type) => self.file_type = export_type, + ExportDialogMessage::ScaleFactor(factor) => self.scale_factor = factor, + ExportDialogMessage::TransparentBackground(transparent_background) => self.transparent_background = transparent_background, + ExportDialogMessage::ExportBounds(export_area) => self.bounds = export_area, + + ExportDialogMessage::Submit => responses.add_front(PortfolioMessage::SubmitDocumentExport { + file_name: portfolio.active_document().map(|document| document.name.clone()).unwrap_or_default(), + file_type: self.file_type, + scale_factor: self.scale_factor, + bounds: self.bounds, + transparent_background: self.file_type != FileType::Jpg && self.transparent_background, + }), + } + + self.send_dialog_to_frontend(responses); + } + + advertise_actions! {ExportDialogUpdate;} +} + +impl DialogLayoutHolder for ExportDialogMessageHandler { + const ICON: &'static str = "File"; + const TITLE: &'static str = "Export"; + + fn layout_buttons(&self) -> Layout { + let widgets = vec![ + TextButton::new("Export") + .emphasized(true) + .on_update(|_| { + DialogMessage::CloseDialogAndThen { + followups: vec![ExportDialogMessage::Submit.into()], + } + .into() + }) + .widget_holder(), + TextButton::new("Cancel").on_update(|_| FrontendMessage::DisplayDialogDismiss.into()).widget_holder(), + ]; + + Layout::WidgetLayout(WidgetLayout::new(vec![LayoutGroup::Row { widgets }])) + } +} + +impl LayoutHolder for ExportDialogMessageHandler { + fn layout(&self) -> Layout { + let entries = [(FileType::Png, "PNG"), (FileType::Jpg, "JPG"), (FileType::Svg, "SVG")] + .into_iter() + .map(|(val, name)| RadioEntryData::new(format!("{val:?}")).label(name).on_update(move |_| ExportDialogMessage::FileType(val).into())) + .collect(); + + let export_type = vec![ + TextLabel::new("File Type").table_align(true).min_width(100).widget_holder(), + Separator::new(SeparatorType::Unrelated).widget_holder(), + RadioInput::new(entries).selected_index(Some(self.file_type as u32)).widget_holder(), + ]; + + let resolution = vec![ + TextLabel::new("Scale Factor").table_align(true).min_width(100).widget_holder(), + Separator::new(SeparatorType::Unrelated).widget_holder(), + NumberInput::new(Some(self.scale_factor)) + .unit("") + .min(0.) + .max((1_u64 << f64::MANTISSA_DIGITS) as f64) + .disabled(self.file_type == FileType::Svg) + .on_update(|number_input: &NumberInput| ExportDialogMessage::ScaleFactor(number_input.value.unwrap()).into()) + .min_width(200) + .widget_holder(), + ]; + + let standard_bounds = vec![ + (ExportBounds::AllArtwork, "All Artwork".to_string(), false), + (ExportBounds::Selection, "Selection".to_string(), !self.has_selection), + ]; + let artboards = self.artboards.iter().map(|(&layer, name)| (ExportBounds::Artboard(layer), name.to_string(), false)).collect(); + let groups = [standard_bounds, artboards]; + + let current_bounds = if !self.has_selection && self.bounds == ExportBounds::Selection { + ExportBounds::AllArtwork + } else { + self.bounds + }; + let index = groups.iter().flatten().position(|(bounds, _, _)| *bounds == current_bounds).unwrap(); + + let mut entries = groups + .into_iter() + .map(|group| { + group + .into_iter() + .map(|(val, name, disabled)| { + MenuListEntry::new(format!("{val:?}")) + .label(name) + .on_commit(move |_| ExportDialogMessage::ExportBounds(val).into()) + .disabled(disabled) + }) + .collect::>() + }) + .collect::>(); + + if entries[1].is_empty() { + entries.remove(1); + } + + let export_area = vec![ + TextLabel::new("Bounds").table_align(true).min_width(100).widget_holder(), + Separator::new(SeparatorType::Unrelated).widget_holder(), + DropdownInput::new(entries).selected_index(Some(index as u32)).widget_holder(), + ]; + + let mut checkbox_id = CheckboxId::default(); + let transparent_background = vec![ + TextLabel::new("Transparency").table_align(true).min_width(100).for_checkbox(&mut checkbox_id).widget_holder(), + Separator::new(SeparatorType::Unrelated).widget_holder(), + CheckboxInput::new(self.transparent_background) + .disabled(self.file_type == FileType::Jpg) + .on_update(move |value: &CheckboxInput| ExportDialogMessage::TransparentBackground(value.checked).into()) + .for_label(checkbox_id.clone()) + .widget_holder(), + ]; + + Layout::WidgetLayout(WidgetLayout::new(vec![ + LayoutGroup::Row { widgets: export_type }, + LayoutGroup::Row { widgets: resolution }, + LayoutGroup::Row { widgets: export_area }, + LayoutGroup::Row { widgets: transparent_background }, + ])) + } +} diff --git a/editor/src/messages/dialog/export_dialog/mod.rs b/editor/src/messages/dialog/export_dialog/mod.rs new file mode 100644 index 0000000000000000000000000000000000000000..440684ef89585c7b640857c290ed2907a8fb66a2 --- /dev/null +++ b/editor/src/messages/dialog/export_dialog/mod.rs @@ -0,0 +1,7 @@ +mod export_dialog_message; +mod export_dialog_message_handler; + +#[doc(inline)] +pub use export_dialog_message::{ExportDialogMessage, ExportDialogMessageDiscriminant}; +#[doc(inline)] +pub use export_dialog_message_handler::{ExportDialogMessageData, ExportDialogMessageHandler}; diff --git a/editor/src/messages/dialog/mod.rs b/editor/src/messages/dialog/mod.rs new file mode 100644 index 0000000000000000000000000000000000000000..692991a30d0c0c62807cd72574405cc7db5fc3f7 --- /dev/null +++ b/editor/src/messages/dialog/mod.rs @@ -0,0 +1,19 @@ +//! Handles dialogs that appear as floating menus in the center of the editor window. +//! +//! Dialogs are represented as structs that implement the `DialogLayoutHolder` trait. +//! +//! To open a dialog, call the function `send_dialog_to_frontend()` on the dialog struct. +//! Then dialog can be opened by sending the `FrontendMessage::DisplayDialog` message; + +mod dialog_message; +mod dialog_message_handler; + +pub mod export_dialog; +pub mod new_document_dialog; +pub mod preferences_dialog; +pub mod simple_dialogs; + +#[doc(inline)] +pub use dialog_message::{DialogMessage, DialogMessageDiscriminant}; +#[doc(inline)] +pub use dialog_message_handler::{DialogMessageData, DialogMessageHandler}; diff --git a/editor/src/messages/dialog/new_document_dialog/mod.rs b/editor/src/messages/dialog/new_document_dialog/mod.rs new file mode 100644 index 0000000000000000000000000000000000000000..c179de74d19268405d22ec403675d7070ef45822 --- /dev/null +++ b/editor/src/messages/dialog/new_document_dialog/mod.rs @@ -0,0 +1,7 @@ +mod new_document_dialog_message; +mod new_document_dialog_message_handler; + +#[doc(inline)] +pub use new_document_dialog_message::{NewDocumentDialogMessage, NewDocumentDialogMessageDiscriminant}; +#[doc(inline)] +pub use new_document_dialog_message_handler::NewDocumentDialogMessageHandler; diff --git a/editor/src/messages/dialog/new_document_dialog/new_document_dialog_message.rs b/editor/src/messages/dialog/new_document_dialog/new_document_dialog_message.rs new file mode 100644 index 0000000000000000000000000000000000000000..26502196c5e6b5a98dba98ff4e5095237f6813b6 --- /dev/null +++ b/editor/src/messages/dialog/new_document_dialog/new_document_dialog_message.rs @@ -0,0 +1,12 @@ +use crate::messages::prelude::*; + +#[impl_message(Message, DialogMessage, NewDocumentDialog)] +#[derive(PartialEq, Clone, Debug, serde::Serialize, serde::Deserialize)] +pub enum NewDocumentDialogMessage { + Name(String), + Infinite(bool), + DimensionsX(f64), + DimensionsY(f64), + + Submit, +} diff --git a/editor/src/messages/dialog/new_document_dialog/new_document_dialog_message_handler.rs b/editor/src/messages/dialog/new_document_dialog/new_document_dialog_message_handler.rs new file mode 100644 index 0000000000000000000000000000000000000000..2e94f876c7ecafc42e44aa7ba6fdeaa3d6fbdb17 --- /dev/null +++ b/editor/src/messages/dialog/new_document_dialog/new_document_dialog_message_handler.rs @@ -0,0 +1,122 @@ +use crate::messages::layout::utility_types::widget_prelude::*; +use crate::messages::prelude::*; +use glam::{IVec2, UVec2}; +use graph_craft::document::NodeId; + +/// A dialog to allow users to set some initial options about a new document. +#[derive(Debug, Clone, Default)] +pub struct NewDocumentDialogMessageHandler { + pub name: String, + pub infinite: bool, + pub dimensions: UVec2, +} + +impl MessageHandler for NewDocumentDialogMessageHandler { + fn process_message(&mut self, message: NewDocumentDialogMessage, responses: &mut VecDeque, _data: ()) { + match message { + NewDocumentDialogMessage::Name(name) => self.name = name, + NewDocumentDialogMessage::Infinite(infinite) => self.infinite = infinite, + NewDocumentDialogMessage::DimensionsX(x) => self.dimensions.x = x as u32, + NewDocumentDialogMessage::DimensionsY(y) => self.dimensions.y = y as u32, + NewDocumentDialogMessage::Submit => { + responses.add(PortfolioMessage::NewDocumentWithName { name: self.name.clone() }); + + let create_artboard = !self.infinite && self.dimensions.x > 0 && self.dimensions.y > 0; + if create_artboard { + responses.add(Message::StartBuffer); + responses.add(GraphOperationMessage::NewArtboard { + id: NodeId::new(), + artboard: graphene_std::Artboard::new(IVec2::ZERO, self.dimensions.as_ivec2()), + }); + } + + // TODO: Figure out how to get StartBuffer to work here so we can delete this and use `DocumentMessage::ZoomCanvasToFitAll` instead + // Currently, it is necessary to use `FrontendMessage::TriggerDelayedZoomCanvasToFitAll` rather than `DocumentMessage::ZoomCanvasToFitAll` because the size of the viewport is not yet populated + responses.add(Message::StartBuffer); + responses.add(FrontendMessage::TriggerDelayedZoomCanvasToFitAll); + responses.add(DocumentMessage::DeselectAllLayers); + } + } + + self.send_dialog_to_frontend(responses); + } + + advertise_actions! {NewDocumentDialogUpdate;} +} + +impl DialogLayoutHolder for NewDocumentDialogMessageHandler { + const ICON: &'static str = "File"; + const TITLE: &'static str = "New Document"; + + fn layout_buttons(&self) -> Layout { + let widgets = vec![ + TextButton::new("OK") + .emphasized(true) + .on_update(|_| { + DialogMessage::CloseDialogAndThen { + followups: vec![NewDocumentDialogMessage::Submit.into()], + } + .into() + }) + .widget_holder(), + TextButton::new("Cancel").on_update(|_| FrontendMessage::DisplayDialogDismiss.into()).widget_holder(), + ]; + + Layout::WidgetLayout(WidgetLayout::new(vec![LayoutGroup::Row { widgets }])) + } +} + +impl LayoutHolder for NewDocumentDialogMessageHandler { + fn layout(&self) -> Layout { + let name = vec![ + TextLabel::new("Name").table_align(true).min_width(90).widget_holder(), + Separator::new(SeparatorType::Unrelated).widget_holder(), + TextInput::new(&self.name) + .on_update(|text_input: &TextInput| NewDocumentDialogMessage::Name(text_input.value.clone()).into()) + .min_width(204) // Matches the 100px of both NumberInputs below + the 4px of the Unrelated-type separator + .widget_holder(), + ]; + + let mut checkbox_id = CheckboxId::default(); + let infinite = vec![ + TextLabel::new("Infinite Canvas").table_align(true).min_width(90).for_checkbox(&mut checkbox_id).widget_holder(), + Separator::new(SeparatorType::Unrelated).widget_holder(), + CheckboxInput::new(self.infinite) + .on_update(|checkbox_input: &CheckboxInput| NewDocumentDialogMessage::Infinite(checkbox_input.checked).into()) + .for_label(checkbox_id.clone()) + .widget_holder(), + ]; + + let scale = vec![ + TextLabel::new("Dimensions").table_align(true).min_width(90).widget_holder(), + Separator::new(SeparatorType::Unrelated).widget_holder(), + NumberInput::new(Some(self.dimensions.x as f64)) + .label("W") + .unit(" px") + .min(0.) + .max((1_u64 << f64::MANTISSA_DIGITS) as f64) + .is_integer(true) + .disabled(self.infinite) + .min_width(100) + .on_update(|number_input: &NumberInput| NewDocumentDialogMessage::DimensionsX(number_input.value.unwrap()).into()) + .widget_holder(), + Separator::new(SeparatorType::Related).widget_holder(), + NumberInput::new(Some(self.dimensions.y as f64)) + .label("H") + .unit(" px") + .min(0.) + .max((1_u64 << f64::MANTISSA_DIGITS) as f64) + .is_integer(true) + .disabled(self.infinite) + .min_width(100) + .on_update(|number_input: &NumberInput| NewDocumentDialogMessage::DimensionsY(number_input.value.unwrap()).into()) + .widget_holder(), + ]; + + Layout::WidgetLayout(WidgetLayout::new(vec![ + LayoutGroup::Row { widgets: name }, + LayoutGroup::Row { widgets: infinite }, + LayoutGroup::Row { widgets: scale }, + ])) + } +} diff --git a/editor/src/messages/dialog/preferences_dialog/mod.rs b/editor/src/messages/dialog/preferences_dialog/mod.rs new file mode 100644 index 0000000000000000000000000000000000000000..c7dd00bb00576d69bbe4a5ed6875db3eb8c1513a --- /dev/null +++ b/editor/src/messages/dialog/preferences_dialog/mod.rs @@ -0,0 +1,7 @@ +mod preferences_dialog_message; +mod preferences_dialog_message_handler; + +#[doc(inline)] +pub use preferences_dialog_message::{PreferencesDialogMessage, PreferencesDialogMessageDiscriminant}; +#[doc(inline)] +pub use preferences_dialog_message_handler::{PreferencesDialogMessageData, PreferencesDialogMessageHandler}; diff --git a/editor/src/messages/dialog/preferences_dialog/preferences_dialog_message.rs b/editor/src/messages/dialog/preferences_dialog/preferences_dialog_message.rs new file mode 100644 index 0000000000000000000000000000000000000000..736fe7c10aab030140eba088141daf960e3d8f16 --- /dev/null +++ b/editor/src/messages/dialog/preferences_dialog/preferences_dialog_message.rs @@ -0,0 +1,7 @@ +use crate::messages::prelude::*; + +#[impl_message(Message, DialogMessage, PreferencesDialog)] +#[derive(Eq, PartialEq, Clone, Debug, serde::Serialize, serde::Deserialize)] +pub enum PreferencesDialogMessage { + Confirm, +} diff --git a/editor/src/messages/dialog/preferences_dialog/preferences_dialog_message_handler.rs b/editor/src/messages/dialog/preferences_dialog/preferences_dialog_message_handler.rs new file mode 100644 index 0000000000000000000000000000000000000000..6e92d60bcf5dc18c98c2b99d233b94e2effb872c --- /dev/null +++ b/editor/src/messages/dialog/preferences_dialog/preferences_dialog_message_handler.rs @@ -0,0 +1,291 @@ +use crate::consts::{VIEWPORT_ZOOM_WHEEL_RATE, VIEWPORT_ZOOM_WHEEL_RATE_CHANGE}; +use crate::messages::layout::utility_types::widget_prelude::*; +use crate::messages::portfolio::document::utility_types::wires::GraphWireStyle; +use crate::messages::preferences::SelectionMode; +use crate::messages::prelude::*; + +pub struct PreferencesDialogMessageData<'a> { + pub preferences: &'a PreferencesMessageHandler, +} + +/// A dialog to allow users to customize Graphite editor options +#[derive(Debug, Clone, Default)] +pub struct PreferencesDialogMessageHandler {} + +impl MessageHandler> for PreferencesDialogMessageHandler { + fn process_message(&mut self, message: PreferencesDialogMessage, responses: &mut VecDeque, data: PreferencesDialogMessageData) { + let PreferencesDialogMessageData { preferences } = data; + + match message { + PreferencesDialogMessage::Confirm => {} + } + + self.send_dialog_to_frontend(responses, preferences); + } + + advertise_actions! {PreferencesDialogUpdate;} +} + +// This doesn't actually implement the `DialogLayoutHolder` trait like the other dialog message handlers. +// That's because we need to give `send_layout` the `preferences` argument, which is not part of the trait. +// However, it's important to keep the methods in sync with those from the trait for consistency. +impl PreferencesDialogMessageHandler { + const ICON: &'static str = "Settings"; + const TITLE: &'static str = "Editor Preferences"; + + fn layout(&self, preferences: &PreferencesMessageHandler) -> Layout { + // ========== + // NAVIGATION + // ========== + + let navigation_header = vec![TextLabel::new("Navigation").italic(true).widget_holder()]; + + let zoom_rate_tooltip = "Adjust how fast zooming occurs when using the scroll wheel or pinch gesture (relative to a default of 50)"; + let zoom_rate_label = vec![ + Separator::new(SeparatorType::Unrelated).widget_holder(), + Separator::new(SeparatorType::Unrelated).widget_holder(), + TextLabel::new("Zoom Rate").tooltip(zoom_rate_tooltip).widget_holder(), + ]; + let zoom_rate = vec![ + Separator::new(SeparatorType::Unrelated).widget_holder(), + Separator::new(SeparatorType::Unrelated).widget_holder(), + NumberInput::new(Some(map_zoom_rate_to_display(preferences.viewport_zoom_wheel_rate))) + .tooltip(zoom_rate_tooltip) + .mode_range() + .int() + .min(1.) + .max(100.) + .on_update(|number_input: &NumberInput| { + if let Some(display_value) = number_input.value { + let actual_rate = map_display_to_zoom_rate(display_value); + PreferencesMessage::ViewportZoomWheelRate { rate: actual_rate }.into() + } else { + PreferencesMessage::ViewportZoomWheelRate { rate: VIEWPORT_ZOOM_WHEEL_RATE }.into() + } + }) + .widget_holder(), + ]; + + let mut checkbox_id = CheckboxId::default(); + let zoom_with_scroll_tooltip = "Use the scroll wheel for zooming instead of vertically panning (not recommended for trackpads)"; + let zoom_with_scroll = vec![ + Separator::new(SeparatorType::Unrelated).widget_holder(), + Separator::new(SeparatorType::Unrelated).widget_holder(), + CheckboxInput::new(preferences.zoom_with_scroll) + .tooltip(zoom_with_scroll_tooltip) + .on_update(|checkbox_input: &CheckboxInput| { + PreferencesMessage::ModifyLayout { + zoom_with_scroll: checkbox_input.checked, + } + .into() + }) + .for_label(checkbox_id.clone()) + .widget_holder(), + TextLabel::new("Zoom with Scroll") + .table_align(true) + .tooltip(zoom_with_scroll_tooltip) + .for_checkbox(&mut checkbox_id) + .widget_holder(), + ]; + + // ======= + // EDITING + // ======= + + let editing_header = vec![TextLabel::new("Editing").italic(true).widget_holder()]; + + let selection_label = vec![ + Separator::new(SeparatorType::Unrelated).widget_holder(), + Separator::new(SeparatorType::Unrelated).widget_holder(), + TextLabel::new("Selection").widget_holder(), + ]; + + let selection_mode = RadioInput::new(vec![ + RadioEntryData::new(SelectionMode::Touched.to_string()) + .label(SelectionMode::Touched.to_string()) + .tooltip(SelectionMode::Touched.tooltip_description()) + .on_update(move |_| { + PreferencesMessage::SelectionMode { + selection_mode: SelectionMode::Touched, + } + .into() + }), + RadioEntryData::new(SelectionMode::Enclosed.to_string()) + .label(SelectionMode::Enclosed.to_string()) + .tooltip(SelectionMode::Enclosed.tooltip_description()) + .on_update(move |_| { + PreferencesMessage::SelectionMode { + selection_mode: SelectionMode::Enclosed, + } + .into() + }), + RadioEntryData::new(SelectionMode::Directional.to_string()) + .label(SelectionMode::Directional.to_string()) + .tooltip(SelectionMode::Directional.tooltip_description()) + .on_update(move |_| { + PreferencesMessage::SelectionMode { + selection_mode: SelectionMode::Directional, + } + .into() + }), + ]) + .selected_index(Some(preferences.selection_mode as u32)) + .widget_holder(); + let selection_mode = vec![ + Separator::new(SeparatorType::Unrelated).widget_holder(), + Separator::new(SeparatorType::Unrelated).widget_holder(), + selection_mode, + ]; + + // ============ + // EXPERIMENTAL + // ============ + + let experimental_header = vec![TextLabel::new("Experimental").italic(true).widget_holder()]; + + let node_graph_section_tooltip = "Appearance of the wires running between node connections in the graph"; + let node_graph_wires_label = vec![ + Separator::new(SeparatorType::Unrelated).widget_holder(), + Separator::new(SeparatorType::Unrelated).widget_holder(), + TextLabel::new("Node Graph Wires").tooltip(node_graph_section_tooltip).widget_holder(), + ]; + let graph_wire_style = RadioInput::new(vec![ + RadioEntryData::new(GraphWireStyle::Direct.to_string()) + .label(GraphWireStyle::Direct.to_string()) + .tooltip(GraphWireStyle::Direct.tooltip_description()) + .on_update(move |_| PreferencesMessage::GraphWireStyle { style: GraphWireStyle::Direct }.into()), + RadioEntryData::new(GraphWireStyle::GridAligned.to_string()) + .label(GraphWireStyle::GridAligned.to_string()) + .tooltip(GraphWireStyle::GridAligned.tooltip_description()) + .on_update(move |_| PreferencesMessage::GraphWireStyle { style: GraphWireStyle::GridAligned }.into()), + ]) + .selected_index(Some(preferences.graph_wire_style as u32)) + .widget_holder(); + let graph_wire_style = vec![ + Separator::new(SeparatorType::Unrelated).widget_holder(), + Separator::new(SeparatorType::Unrelated).widget_holder(), + graph_wire_style, + ]; + + let mut checkbox_id = CheckboxId::default(); + let vello_tooltip = "Use the experimental Vello renderer (your browser must support WebGPU)"; + let use_vello = vec![ + Separator::new(SeparatorType::Unrelated).widget_holder(), + Separator::new(SeparatorType::Unrelated).widget_holder(), + CheckboxInput::new(preferences.use_vello && preferences.supports_wgpu()) + .tooltip(vello_tooltip) + .disabled(!preferences.supports_wgpu()) + .on_update(|checkbox_input: &CheckboxInput| PreferencesMessage::UseVello { use_vello: checkbox_input.checked }.into()) + .for_label(checkbox_id.clone()) + .widget_holder(), + TextLabel::new("Vello Renderer") + .table_align(true) + .tooltip(vello_tooltip) + .disabled(!preferences.supports_wgpu()) + .for_checkbox(&mut checkbox_id) + .widget_holder(), + ]; + + let mut checkbox_id = CheckboxId::default(); + let vector_mesh_tooltip = + "Allow tools to produce vector meshes, where more than two segments can connect to an anchor point.\n\nCurrently this does not properly handle stroke joins and fills."; + let vector_meshes = vec![ + Separator::new(SeparatorType::Unrelated).widget_holder(), + Separator::new(SeparatorType::Unrelated).widget_holder(), + CheckboxInput::new(preferences.vector_meshes) + .tooltip(vector_mesh_tooltip) + .on_update(|checkbox_input: &CheckboxInput| PreferencesMessage::VectorMeshes { enabled: checkbox_input.checked }.into()) + .for_label(checkbox_id.clone()) + .widget_holder(), + TextLabel::new("Vector Meshes") + .table_align(true) + .tooltip(vector_mesh_tooltip) + .for_checkbox(&mut checkbox_id) + .widget_holder(), + ]; + + Layout::WidgetLayout(WidgetLayout::new(vec![ + LayoutGroup::Row { widgets: navigation_header }, + LayoutGroup::Row { widgets: zoom_rate_label }, + LayoutGroup::Row { widgets: zoom_rate }, + LayoutGroup::Row { widgets: zoom_with_scroll }, + LayoutGroup::Row { widgets: editing_header }, + LayoutGroup::Row { widgets: selection_label }, + LayoutGroup::Row { widgets: selection_mode }, + LayoutGroup::Row { widgets: experimental_header }, + LayoutGroup::Row { widgets: node_graph_wires_label }, + LayoutGroup::Row { widgets: graph_wire_style }, + LayoutGroup::Row { widgets: use_vello }, + LayoutGroup::Row { widgets: vector_meshes }, + ])) + } + + pub fn send_layout(&self, responses: &mut VecDeque, layout_target: LayoutTarget, preferences: &PreferencesMessageHandler) { + responses.add(LayoutMessage::SendLayout { + layout: self.layout(preferences), + layout_target, + }) + } + + fn layout_column_2(&self) -> Layout { + Layout::default() + } + + fn send_layout_column_2(&self, responses: &mut VecDeque, layout_target: LayoutTarget) { + responses.add(LayoutMessage::SendLayout { + layout: self.layout_column_2(), + layout_target, + }); + } + + fn layout_buttons(&self) -> Layout { + let widgets = vec![ + TextButton::new("OK") + .emphasized(true) + .on_update(|_| { + DialogMessage::CloseDialogAndThen { + followups: vec![PreferencesDialogMessage::Confirm.into()], + } + .into() + }) + .widget_holder(), + TextButton::new("Reset to Defaults").on_update(|_| PreferencesMessage::ResetToDefaults.into()).widget_holder(), + ]; + + Layout::WidgetLayout(WidgetLayout::new(vec![LayoutGroup::Row { widgets }])) + } + + fn send_layout_buttons(&self, responses: &mut VecDeque, layout_target: LayoutTarget) { + responses.add(LayoutMessage::SendLayout { + layout: self.layout_buttons(), + layout_target, + }); + } + + pub fn send_dialog_to_frontend(&self, responses: &mut VecDeque, preferences: &PreferencesMessageHandler) { + self.send_layout(responses, LayoutTarget::DialogColumn1, preferences); + self.send_layout_column_2(responses, LayoutTarget::DialogColumn2); + self.send_layout_buttons(responses, LayoutTarget::DialogButtons); + responses.add(FrontendMessage::DisplayDialog { + icon: Self::ICON.into(), + title: Self::TITLE.into(), + }); + } +} + +/// Maps display values (1-100) to actual zoom rates. +fn map_display_to_zoom_rate(display: f64) -> f64 { + // Calculate the relative distance from the reference point (50) + let distance_from_reference = display - 50.; + let scaling_factor = (VIEWPORT_ZOOM_WHEEL_RATE_CHANGE * distance_from_reference / 50.).exp(); + VIEWPORT_ZOOM_WHEEL_RATE * scaling_factor +} + +/// Maps actual zoom rates back to display values (1-100). +fn map_zoom_rate_to_display(rate: f64) -> f64 { + // Calculate the scaling factor from the reference rate + let scaling_factor = rate / VIEWPORT_ZOOM_WHEEL_RATE; + let distance_from_reference = 50. * scaling_factor.ln() / VIEWPORT_ZOOM_WHEEL_RATE_CHANGE; + let display = 50. + distance_from_reference; + display.clamp(1., 100.).round() +} diff --git a/editor/src/messages/dialog/simple_dialogs/about_graphite_dialog.rs b/editor/src/messages/dialog/simple_dialogs/about_graphite_dialog.rs new file mode 100644 index 0000000000000000000000000000000000000000..13c52dbc0f8107121d8d017b275a5d050c9f5e28 --- /dev/null +++ b/editor/src/messages/dialog/simple_dialogs/about_graphite_dialog.rs @@ -0,0 +1,72 @@ +use crate::application::commit_info_localized; +use crate::messages::layout::utility_types::widget_prelude::*; +use crate::messages::prelude::*; + +/// A dialog for displaying information on [BuildMetadata] viewable via *Help* > *About Graphite* in the menu bar. +pub struct AboutGraphiteDialog { + pub localized_commit_date: String, + pub localized_commit_year: String, +} + +impl DialogLayoutHolder for AboutGraphiteDialog { + const ICON: &'static str = "GraphiteLogo"; + const TITLE: &'static str = "About Graphite"; + + fn layout_buttons(&self) -> Layout { + let widgets = vec![TextButton::new("OK").emphasized(true).on_update(|_| FrontendMessage::DisplayDialogDismiss.into()).widget_holder()]; + + Layout::WidgetLayout(WidgetLayout::new(vec![LayoutGroup::Row { widgets }])) + } + + fn layout_column_2(&self) -> Layout { + let links = [ + ("Heart", "Donate", "https://graphite.rs/donate/"), + ("Volunteer", "Volunteer", "https://graphite.rs/volunteer/"), + ("GraphiteLogo", "Website", "https://graphite.rs"), + ("Credits", "Credits", "https://github.com/GraphiteEditor/Graphite/graphs/contributors"), + ]; + let mut widgets = links + .into_iter() + .map(|(icon, label, url)| { + TextButton::new(label) + .icon(Some(icon.into())) + .flush(true) + .on_update(|_| FrontendMessage::TriggerVisitLink { url: url.into() }.into()) + .widget_holder() + }) + .collect::>(); + + // Cloning here and below seems to be necessary to appease the borrow checker, as far as I can tell. + let localized_commit_year = self.localized_commit_year.clone(); + widgets.push( + TextButton::new("Licenses") + .icon(Some("License".into())) + .flush(true) + .on_update(move |_| { + DialogMessage::RequestLicensesDialogWithLocalizedCommitDate { + localized_commit_year: localized_commit_year.clone(), + } + .into() + }) + .widget_holder(), + ); + + Layout::WidgetLayout(WidgetLayout::new(vec![LayoutGroup::Column { widgets }])) + } +} + +impl LayoutHolder for AboutGraphiteDialog { + fn layout(&self) -> Layout { + Layout::WidgetLayout(WidgetLayout::new(vec![ + LayoutGroup::Row { + widgets: vec![TextLabel::new("About this release").bold(true).widget_holder()], + }, + LayoutGroup::Row { + widgets: vec![TextLabel::new(commit_info_localized(&self.localized_commit_date)).multiline(true).widget_holder()], + }, + LayoutGroup::Row { + widgets: vec![TextLabel::new(format!("Copyright © {} Graphite contributors", self.localized_commit_year)).widget_holder()], + }, + ])) + } +} diff --git a/editor/src/messages/dialog/simple_dialogs/close_all_documents_dialog.rs b/editor/src/messages/dialog/simple_dialogs/close_all_documents_dialog.rs new file mode 100644 index 0000000000000000000000000000000000000000..070972f0523734e9d1237556249460b98326b120 --- /dev/null +++ b/editor/src/messages/dialog/simple_dialogs/close_all_documents_dialog.rs @@ -0,0 +1,44 @@ +use crate::messages::layout::utility_types::widget_prelude::*; +use crate::messages::prelude::*; + +/// A dialog for confirming the closing of all documents viewable via `File -> Close All` in the menu bar. +pub struct CloseAllDocumentsDialog { + pub unsaved_document_names: Vec, +} + +impl DialogLayoutHolder for CloseAllDocumentsDialog { + const ICON: &'static str = "Warning"; + const TITLE: &'static str = "Closing All Documents"; + + fn layout_buttons(&self) -> Layout { + let widgets = vec![ + TextButton::new("Discard All") + .emphasized(true) + .on_update(|_| { + DialogMessage::CloseDialogAndThen { + followups: vec![PortfolioMessage::CloseAllDocuments.into()], + } + .into() + }) + .widget_holder(), + TextButton::new("Cancel").on_update(|_| FrontendMessage::DisplayDialogDismiss.into()).widget_holder(), + ]; + + Layout::WidgetLayout(WidgetLayout::new(vec![LayoutGroup::Row { widgets }])) + } +} + +impl LayoutHolder for CloseAllDocumentsDialog { + fn layout(&self) -> Layout { + let unsaved_list = "• ".to_string() + &self.unsaved_document_names.join("\n• "); + + Layout::WidgetLayout(WidgetLayout::new(vec![ + LayoutGroup::Row { + widgets: vec![TextLabel::new("Save documents before closing them?").bold(true).multiline(true).widget_holder()], + }, + LayoutGroup::Row { + widgets: vec![TextLabel::new(format!("Documents with unsaved changes:\n{unsaved_list}")).multiline(true).widget_holder()], + }, + ])) + } +} diff --git a/editor/src/messages/dialog/simple_dialogs/close_document_dialog.rs b/editor/src/messages/dialog/simple_dialogs/close_document_dialog.rs new file mode 100644 index 0000000000000000000000000000000000000000..d370b2fde8cf67f10c39e2c06ae9c272bdcf0489 --- /dev/null +++ b/editor/src/messages/dialog/simple_dialogs/close_document_dialog.rs @@ -0,0 +1,63 @@ +use crate::messages::broadcast::broadcast_event::BroadcastEvent; +use crate::messages::layout::utility_types::widget_prelude::*; +use crate::messages::prelude::*; + +/// A dialog for confirming the closing a document with unsaved changes. +pub struct CloseDocumentDialog { + pub document_name: String, + pub document_id: DocumentId, +} + +impl DialogLayoutHolder for CloseDocumentDialog { + const ICON: &'static str = "Warning"; + const TITLE: &'static str = "Closing Document"; + + fn layout_buttons(&self) -> Layout { + let document_id = self.document_id; + let widgets = vec![ + TextButton::new("Save") + .emphasized(true) + .on_update(|_| { + DialogMessage::CloseDialogAndThen { + followups: vec![DocumentMessage::SaveDocument.into()], + } + .into() + }) + .widget_holder(), + TextButton::new("Discard") + .on_update(move |_| { + DialogMessage::CloseDialogAndThen { + followups: vec![BroadcastEvent::ToolAbort.into(), PortfolioMessage::CloseDocument { document_id }.into()], + } + .into() + }) + .widget_holder(), + TextButton::new("Cancel").on_update(|_| FrontendMessage::DisplayDialogDismiss.into()).widget_holder(), + ]; + + Layout::WidgetLayout(WidgetLayout::new(vec![LayoutGroup::Row { widgets }])) + } +} + +impl LayoutHolder for CloseDocumentDialog { + fn layout(&self) -> Layout { + let max_length = 60; + let max_one_line_length = 40; + + let mut name = self.document_name.clone(); + + name.truncate(max_length); + let ellipsis = if self.document_name.len() > max_length { "…" } else { "" }; + + let break_lines = if self.document_name.len() > max_one_line_length { '\n' } else { ' ' }; + + Layout::WidgetLayout(WidgetLayout::new(vec![ + LayoutGroup::Row { + widgets: vec![TextLabel::new("Save document before closing it?").bold(true).widget_holder()], + }, + LayoutGroup::Row { + widgets: vec![TextLabel::new(format!("\"{name}{ellipsis}\"{break_lines}has unsaved changes")).multiline(true).widget_holder()], + }, + ])) + } +} diff --git a/editor/src/messages/dialog/simple_dialogs/coming_soon_dialog.rs b/editor/src/messages/dialog/simple_dialogs/coming_soon_dialog.rs new file mode 100644 index 0000000000000000000000000000000000000000..b72c2301a201b24d6aa1da10f255827cc9792f5c --- /dev/null +++ b/editor/src/messages/dialog/simple_dialogs/coming_soon_dialog.rs @@ -0,0 +1,48 @@ +use crate::messages::layout::utility_types::widget_prelude::*; +use crate::messages::prelude::*; + +/// A dialog to notify users of an unfinished issue, optionally with an issue number. +pub struct ComingSoonDialog { + pub issue: Option, +} + +impl DialogLayoutHolder for ComingSoonDialog { + const ICON: &'static str = "Delay"; + const TITLE: &'static str = "Coming Soon"; + + fn layout_buttons(&self) -> Layout { + let widgets = vec![TextButton::new("OK").emphasized(true).on_update(|_| FrontendMessage::DisplayDialogDismiss.into()).widget_holder()]; + + Layout::WidgetLayout(WidgetLayout::new(vec![LayoutGroup::Row { widgets }])) + } +} + +impl LayoutHolder for ComingSoonDialog { + fn layout(&self) -> Layout { + let header = vec![TextLabel::new("You've stumbled upon a placeholder").bold(true).widget_holder()]; + let row1 = vec![TextLabel::new("This feature is not implemented yet.").widget_holder()]; + + let mut rows = vec![LayoutGroup::Row { widgets: header }, LayoutGroup::Row { widgets: row1 }]; + + if let Some(issue) = self.issue { + let row2 = vec![TextLabel::new("But you can help build it! Visit its issue:").widget_holder()]; + let row3 = vec![ + TextButton::new(format!("GitHub Issue #{issue}")) + .icon(Some("Website".into())) + .flush(true) + .on_update(move |_| { + FrontendMessage::TriggerVisitLink { + url: format!("https://github.com/GraphiteEditor/Graphite/issues/{issue}"), + } + .into() + }) + .widget_holder(), + ]; + + rows.push(LayoutGroup::Row { widgets: row2 }); + rows.push(LayoutGroup::Row { widgets: row3 }); + } + + Layout::WidgetLayout(WidgetLayout::new(rows)) + } +} diff --git a/editor/src/messages/dialog/simple_dialogs/demo_artwork_dialog.rs b/editor/src/messages/dialog/simple_dialogs/demo_artwork_dialog.rs new file mode 100644 index 0000000000000000000000000000000000000000..8a6b59a479ace8161bf35042ab84d024419663cd --- /dev/null +++ b/editor/src/messages/dialog/simple_dialogs/demo_artwork_dialog.rs @@ -0,0 +1,64 @@ +use crate::messages::layout::utility_types::widget_prelude::*; +use crate::messages::prelude::*; + +/// A dialog to let the user browse a gallery of demo artwork that can be opened. +pub struct DemoArtworkDialog; + +/// `(name, thumbnail, filename)` +pub const ARTWORK: [(&str, &str, &str); 7] = [ + ("Isometric Fountain", "ThumbnailIsometricFountain", "isometric-fountain.graphite"), + ("Changing Seasons", "ThumbnailChangingSeasons", "changing-seasons.graphite"), + ("Painted Dreams", "ThumbnailPaintedDreams", "painted-dreams.graphite"), + ("Parametric Dunescape", "ThumbnailParametricDunescape", "parametric-dunescape.graphite"), + ("Red Dress", "ThumbnailRedDress", "red-dress.graphite"), + ("Procedural String Lights", "ThumbnailProceduralStringLights", "procedural-string-lights.graphite"), + ("Valley of Spires", "ThumbnailValleyOfSpires", "valley-of-spires.graphite"), +]; + +impl DialogLayoutHolder for DemoArtworkDialog { + const ICON: &'static str = "Image"; + const TITLE: &'static str = "Demo Artwork"; + + fn layout_buttons(&self) -> Layout { + let widgets = vec![TextButton::new("Close").emphasized(true).on_update(|_| FrontendMessage::DisplayDialogDismiss.into()).widget_holder()]; + + Layout::WidgetLayout(WidgetLayout::new(vec![LayoutGroup::Row { widgets }])) + } +} + +impl LayoutHolder for DemoArtworkDialog { + fn layout(&self) -> Layout { + let mut rows_of_images_with_buttons: Vec<_> = ARTWORK + .chunks(4) + .flat_map(|chunk| { + fn make_dialog(name: &str, filename: &str) -> Message { + DialogMessage::CloseDialogAndThen { + followups: vec![ + FrontendMessage::TriggerFetchAndOpenDocument { + name: name.to_string(), + filename: filename.to_string(), + } + .into(), + ], + } + .into() + } + + let images = chunk + .iter() + .map(|(name, thumbnail, filename)| ImageButton::new(*thumbnail).width(Some("256px".into())).on_update(|_| make_dialog(name, filename)).widget_holder()) + .collect(); + + let buttons = chunk + .iter() + .map(|(name, _, filename)| TextButton::new(*name).min_width(256).flush(true).on_update(|_| make_dialog(name, filename)).widget_holder()) + .collect(); + + vec![LayoutGroup::Row { widgets: images }, LayoutGroup::Row { widgets: buttons }, LayoutGroup::Row { widgets: vec![] }] + }) + .collect(); + let _ = rows_of_images_with_buttons.pop(); + + Layout::WidgetLayout(WidgetLayout::new(rows_of_images_with_buttons)) + } +} diff --git a/editor/src/messages/dialog/simple_dialogs/error_dialog.rs b/editor/src/messages/dialog/simple_dialogs/error_dialog.rs new file mode 100644 index 0000000000000000000000000000000000000000..cf944754166f36ab1c87f71ba2d1ccfdc9cbcfc4 --- /dev/null +++ b/editor/src/messages/dialog/simple_dialogs/error_dialog.rs @@ -0,0 +1,32 @@ +use crate::messages::layout::utility_types::widget_prelude::*; +use crate::messages::prelude::*; + +/// A dialog to notify users of a non-fatal error. +pub struct ErrorDialog { + pub title: String, + pub description: String, +} + +impl DialogLayoutHolder for ErrorDialog { + const ICON: &'static str = "Warning"; + const TITLE: &'static str = "Error"; + + fn layout_buttons(&self) -> Layout { + let widgets = vec![TextButton::new("OK").emphasized(true).on_update(|_| FrontendMessage::DisplayDialogDismiss.into()).widget_holder()]; + + Layout::WidgetLayout(WidgetLayout::new(vec![LayoutGroup::Row { widgets }])) + } +} + +impl LayoutHolder for ErrorDialog { + fn layout(&self) -> Layout { + Layout::WidgetLayout(WidgetLayout::new(vec![ + LayoutGroup::Row { + widgets: vec![TextLabel::new(&self.title).bold(true).widget_holder()], + }, + LayoutGroup::Row { + widgets: vec![TextLabel::new(&self.description).multiline(true).widget_holder()], + }, + ])) + } +} diff --git a/editor/src/messages/dialog/simple_dialogs/licenses_dialog.rs b/editor/src/messages/dialog/simple_dialogs/licenses_dialog.rs new file mode 100644 index 0000000000000000000000000000000000000000..694a9986d5f201163b362e9a211026101df476d3 --- /dev/null +++ b/editor/src/messages/dialog/simple_dialogs/licenses_dialog.rs @@ -0,0 +1,63 @@ +use crate::messages::layout::utility_types::widget_prelude::*; +use crate::messages::prelude::*; + +pub struct LicensesDialog { + pub localized_commit_year: String, +} + +impl DialogLayoutHolder for LicensesDialog { + const ICON: &'static str = "License12px"; + const TITLE: &'static str = "Licenses"; + + fn layout_buttons(&self) -> Layout { + let widgets = vec![TextButton::new("OK").emphasized(true).on_update(|_| FrontendMessage::DisplayDialogDismiss.into()).widget_holder()]; + + Layout::WidgetLayout(WidgetLayout::new(vec![LayoutGroup::Row { widgets }])) + } + + fn layout_column_2(&self) -> Layout { + let icons_license_link = "https://raw.githubusercontent.com/GraphiteEditor/Graphite/master/frontend/assets/LICENSE.md"; + let links = [ + ("GraphiteLogo", "Graphite Logo", "https://graphite.rs/logo/"), + ("IconsGrid", "Graphite Icons", icons_license_link), + ("License", "Graphite License", "https://graphite.rs/license/"), + ("License", "Other Licenses", "/third-party-licenses.txt"), + ]; + let widgets = links + .into_iter() + .map(|(icon, label, url)| { + TextButton::new(label) + .icon(Some(icon.into())) + .flush(true) + .on_update(|_| FrontendMessage::TriggerVisitLink { url: url.into() }.into()) + .widget_holder() + }) + .collect(); + + Layout::WidgetLayout(WidgetLayout::new(vec![LayoutGroup::Column { widgets }])) + } +} + +impl LayoutHolder for LicensesDialog { + fn layout(&self) -> Layout { + let description = concat!( + "The Graphite logo and brand identity are copyright © [YEAR]\nGraphite Labs, LLC. See \"Graphite Logo\" for usage policy.", + "\n\n", + "The Graphite editor's icons and design assets are copyright\n© [YEAR] Graphite Labs, LLC. See \"Graphite Icons\" for details.", + "\n\n", + "Graphite code is copyright © [YEAR] Graphite contributors\nand is made available under the Apache 2.0 license. See\n\"Graphite License\" for details.", + "\n\n", + "Graphite is distributed with third-party open source code\ndependencies. See \"Other Licenses\" for details.", + ) + .replace("[YEAR]", &self.localized_commit_year); + + Layout::WidgetLayout(WidgetLayout::new(vec![ + LayoutGroup::Row { + widgets: vec![TextLabel::new("Graphite is free, open source software").bold(true).widget_holder()], + }, + LayoutGroup::Row { + widgets: vec![TextLabel::new(description).multiline(true).widget_holder()], + }, + ])) + } +} diff --git a/editor/src/messages/dialog/simple_dialogs/mod.rs b/editor/src/messages/dialog/simple_dialogs/mod.rs new file mode 100644 index 0000000000000000000000000000000000000000..a330efac20ea9ee265274ef63762770de5b4e579 --- /dev/null +++ b/editor/src/messages/dialog/simple_dialogs/mod.rs @@ -0,0 +1,16 @@ +mod about_graphite_dialog; +mod close_all_documents_dialog; +mod close_document_dialog; +mod coming_soon_dialog; +mod demo_artwork_dialog; +mod error_dialog; +mod licenses_dialog; + +pub use about_graphite_dialog::AboutGraphiteDialog; +pub use close_all_documents_dialog::CloseAllDocumentsDialog; +pub use close_document_dialog::CloseDocumentDialog; +pub use coming_soon_dialog::ComingSoonDialog; +pub use demo_artwork_dialog::ARTWORK; +pub use demo_artwork_dialog::DemoArtworkDialog; +pub use error_dialog::ErrorDialog; +pub use licenses_dialog::LicensesDialog; diff --git a/editor/src/messages/frontend/frontend_message.rs b/editor/src/messages/frontend/frontend_message.rs new file mode 100644 index 0000000000000000000000000000000000000000..c24ebc405c591fbb0129423d94a6260ee351632f --- /dev/null +++ b/editor/src/messages/frontend/frontend_message.rs @@ -0,0 +1,307 @@ +use super::utility_types::{FrontendDocumentDetails, MouseCursorIcon}; +use crate::messages::layout::utility_types::widget_prelude::*; +use crate::messages::portfolio::document::node_graph::utility_types::{ + BoxSelection, ContextMenuInformation, FrontendClickTargets, FrontendGraphInput, FrontendGraphOutput, FrontendNode, FrontendNodeType, Transform, +}; +use crate::messages::portfolio::document::utility_types::nodes::{JsRawBuffer, LayerPanelEntry, RawBuffer}; +use crate::messages::portfolio::document::utility_types::wires::{WirePath, WirePathUpdate}; +use crate::messages::prelude::*; +use crate::messages::tool::utility_types::HintData; +use graph_craft::document::NodeId; +use graphene_std::raster::color::Color; +use graphene_std::text::Font; + +#[impl_message(Message, Frontend)] +#[derive(PartialEq, Clone, Debug, serde::Serialize, serde::Deserialize, specta::Type)] +pub enum FrontendMessage { + // Display prefix: make the frontend show something, like a dialog + DisplayDialog { + title: String, + icon: String, + }, + DisplayDialogDismiss, + DisplayDialogPanic { + #[serde(rename = "panicInfo")] + panic_info: String, + }, + DisplayEditableTextbox { + text: String, + #[serde(rename = "lineHeightRatio")] + line_height_ratio: f64, + #[serde(rename = "fontSize")] + font_size: f64, + color: Color, + url: String, + transform: [f64; 6], + #[serde(rename = "maxWidth")] + max_width: Option, + #[serde(rename = "maxHeight")] + max_height: Option, + }, + DisplayEditableTextboxTransform { + transform: [f64; 6], + }, + DisplayRemoveEditableTextbox, + + // Send prefix: Send global, static data to the frontend that is never updated + SendUIMetadata { + #[serde(rename = "nodeDescriptions")] + node_descriptions: Vec<(String, String)>, + #[serde(rename = "nodeTypes")] + node_types: Vec, + }, + + // Trigger prefix: cause a browser API to do something + TriggerAboutGraphiteLocalizedCommitDate { + #[serde(rename = "commitDate")] + commit_date: String, + }, + TriggerDelayedZoomCanvasToFitAll, + TriggerDownloadImage { + svg: String, + name: String, + mime: String, + size: (f64, f64), + }, + TriggerDownloadTextFile { + document: String, + name: String, + }, + TriggerFetchAndOpenDocument { + name: String, + filename: String, + }, + TriggerFontLoad { + font: Font, + }, + TriggerImport, + TriggerIndexedDbRemoveDocument { + #[serde(rename = "documentId")] + document_id: DocumentId, + }, + TriggerIndexedDbWriteDocument { + document: String, + details: FrontendDocumentDetails, + }, + TriggerLoadFirstAutoSaveDocument, + TriggerLoadRestAutoSaveDocuments, + TriggerLoadPreferences, + TriggerOpenDocument, + TriggerPaste, + TriggerSavePreferences { + preferences: PreferencesMessageHandler, + }, + TriggerSaveActiveDocument { + #[serde(rename = "documentId")] + document_id: DocumentId, + }, + TriggerTextCommit, + TriggerTextCopy { + #[serde(rename = "copyText")] + copy_text: String, + }, + TriggerVisitLink { + url: String, + }, + + // Update prefix: give the frontend a new value or state for it to use + UpdateActiveDocument { + #[serde(rename = "documentId")] + document_id: DocumentId, + }, + UpdateImportsExports { + imports: Vec<(FrontendGraphOutput, i32, i32)>, + exports: Vec<(FrontendGraphInput, i32, i32)>, + #[serde(rename = "addImport")] + add_import: Option<(i32, i32)>, + #[serde(rename = "addExport")] + add_export: Option<(i32, i32)>, + }, + UpdateInSelectedNetwork { + #[serde(rename = "inSelectedNetwork")] + in_selected_network: bool, + }, + UpdateBox { + #[serde(rename = "box")] + box_selection: Option, + }, + UpdateContextMenuInformation { + #[serde(rename = "contextMenuInformation")] + context_menu_information: Option, + }, + UpdateClickTargets { + #[serde(rename = "clickTargets")] + click_targets: Option, + }, + UpdateGraphViewOverlay { + open: bool, + }, + UpdateSpreadsheetState { + open: bool, + node: Option, + }, + UpdateSpreadsheetLayout { + #[serde(rename = "layoutTarget")] + layout_target: LayoutTarget, + diff: Vec, + }, + UpdateImportReorderIndex { + #[serde(rename = "importIndex")] + index: Option, + }, + UpdateExportReorderIndex { + #[serde(rename = "exportIndex")] + index: Option, + }, + UpdateLayerWidths { + #[serde(rename = "layerWidths")] + layer_widths: HashMap, + #[serde(rename = "chainWidths")] + chain_widths: HashMap, + #[serde(rename = "hasLeftInputWire")] + has_left_input_wire: HashMap, + }, + UpdateDialogButtons { + #[serde(rename = "layoutTarget")] + layout_target: LayoutTarget, + diff: Vec, + }, + UpdateDialogColumn1 { + #[serde(rename = "layoutTarget")] + layout_target: LayoutTarget, + diff: Vec, + }, + UpdateDialogColumn2 { + #[serde(rename = "layoutTarget")] + layout_target: LayoutTarget, + diff: Vec, + }, + UpdateDocumentArtwork { + svg: String, + }, + UpdateDocumentBarLayout { + #[serde(rename = "layoutTarget")] + layout_target: LayoutTarget, + diff: Vec, + }, + UpdateDocumentLayerDetails { + data: LayerPanelEntry, + }, + UpdateDocumentLayerStructure { + #[serde(rename = "dataBuffer")] + data_buffer: RawBuffer, + }, + UpdateDocumentLayerStructureJs { + #[serde(rename = "dataBuffer")] + data_buffer: JsRawBuffer, + }, + UpdateDocumentModeLayout { + #[serde(rename = "layoutTarget")] + layout_target: LayoutTarget, + diff: Vec, + }, + UpdateDocumentRulers { + origin: (f64, f64), + spacing: f64, + interval: f64, + visible: bool, + }, + UpdateDocumentScrollbars { + position: (f64, f64), + size: (f64, f64), + multiplier: (f64, f64), + }, + UpdateEyedropperSamplingState { + #[serde(rename = "mousePosition")] + mouse_position: Option<(f64, f64)>, + #[serde(rename = "primaryColor")] + primary_color: String, + #[serde(rename = "secondaryColor")] + secondary_color: String, + #[serde(rename = "setColorChoice")] + set_color_choice: Option, + }, + UpdateGraphFadeArtwork { + percentage: f64, + }, + UpdateInputHints { + #[serde(rename = "hintData")] + hint_data: HintData, + }, + UpdateLayersPanelControlBarLeftLayout { + #[serde(rename = "layoutTarget")] + layout_target: LayoutTarget, + diff: Vec, + }, + UpdateLayersPanelControlBarRightLayout { + #[serde(rename = "layoutTarget")] + layout_target: LayoutTarget, + diff: Vec, + }, + UpdateLayersPanelBottomBarLayout { + #[serde(rename = "layoutTarget")] + layout_target: LayoutTarget, + diff: Vec, + }, + UpdateMenuBarLayout { + #[serde(rename = "layoutTarget")] + layout_target: LayoutTarget, + layout: Vec, + }, + UpdateMouseCursor { + cursor: MouseCursorIcon, + }, + UpdateNodeGraphNodes { + nodes: Vec, + }, + UpdateVisibleNodes { + nodes: Vec, + }, + UpdateNodeGraphWires { + wires: Vec, + }, + ClearAllNodeGraphWires, + UpdateNodeGraphControlBarLayout { + #[serde(rename = "layoutTarget")] + layout_target: LayoutTarget, + diff: Vec, + }, + UpdateNodeGraphSelection { + selected: Vec, + }, + UpdateNodeGraphTransform { + transform: Transform, + }, + UpdateNodeThumbnail { + id: NodeId, + value: String, + }, + UpdateOpenDocumentsList { + #[serde(rename = "openDocuments")] + open_documents: Vec, + }, + UpdatePropertyPanelSectionsLayout { + #[serde(rename = "layoutTarget")] + layout_target: LayoutTarget, + diff: Vec, + }, + UpdateToolOptionsLayout { + #[serde(rename = "layoutTarget")] + layout_target: LayoutTarget, + diff: Vec, + }, + UpdateToolShelfLayout { + #[serde(rename = "layoutTarget")] + layout_target: LayoutTarget, + diff: Vec, + }, + UpdateWirePathInProgress { + #[serde(rename = "wirePath")] + wire_path: Option, + }, + UpdateWorkingColorsLayout { + #[serde(rename = "layoutTarget")] + layout_target: LayoutTarget, + diff: Vec, + }, +} diff --git a/editor/src/messages/frontend/mod.rs b/editor/src/messages/frontend/mod.rs new file mode 100644 index 0000000000000000000000000000000000000000..81d963f56add14ac9ca5f91669f1854dccb8ca47 --- /dev/null +++ b/editor/src/messages/frontend/mod.rs @@ -0,0 +1,6 @@ +mod frontend_message; + +pub mod utility_types; + +#[doc(inline)] +pub use frontend_message::{FrontendMessage, FrontendMessageDiscriminant}; diff --git a/editor/src/messages/frontend/utility_types.rs b/editor/src/messages/frontend/utility_types.rs new file mode 100644 index 0000000000000000000000000000000000000000..cb55047daa3b09b229e91fdae096d2c8eaf9df59 --- /dev/null +++ b/editor/src/messages/frontend/utility_types.rs @@ -0,0 +1,56 @@ +use crate::messages::portfolio::document::utility_types::document_metadata::LayerNodeIdentifier; +use crate::messages::prelude::*; + +#[derive(PartialEq, Eq, Clone, Debug, serde::Serialize, serde::Deserialize, specta::Type)] +pub struct FrontendDocumentDetails { + #[serde(rename = "isAutoSaved")] + pub is_auto_saved: bool, + #[serde(rename = "isSaved")] + pub is_saved: bool, + pub name: String, + pub id: DocumentId, +} + +#[derive(Clone, Copy, Debug, Default, Eq, PartialEq, serde::Serialize, serde::Deserialize, specta::Type)] +pub enum MouseCursorIcon { + #[default] + Default, + None, + ZoomIn, + ZoomOut, + Grabbing, + Crosshair, + Text, + Move, + NSResize, + EWResize, + NESWResize, + NWSEResize, + Rotate, +} + +#[derive(Clone, Copy, Debug, Default, Eq, PartialEq, serde::Serialize, serde::Deserialize, specta::Type)] +pub enum FileType { + #[default] + Png, + Jpg, + Svg, +} + +impl FileType { + pub fn to_mime(self) -> &'static str { + match self { + FileType::Png => "image/png", + FileType::Jpg => "image/jpeg", + FileType::Svg => "image/svg+xml", + } + } +} + +#[derive(Clone, Copy, Debug, Default, Eq, PartialEq, serde::Serialize, serde::Deserialize, specta::Type)] +pub enum ExportBounds { + #[default] + AllArtwork, + Selection, + Artboard(LayerNodeIdentifier), +} diff --git a/editor/src/messages/globals/global_variables.rs b/editor/src/messages/globals/global_variables.rs new file mode 100644 index 0000000000000000000000000000000000000000..b3fb71da0614035595d64067eeca302d253a0a2d --- /dev/null +++ b/editor/src/messages/globals/global_variables.rs @@ -0,0 +1,4 @@ +use crate::messages::portfolio::utility_types::Platform; +use std::sync::OnceLock; + +pub static GLOBAL_PLATFORM: OnceLock = OnceLock::new(); diff --git a/editor/src/messages/globals/globals_message.rs b/editor/src/messages/globals/globals_message.rs new file mode 100644 index 0000000000000000000000000000000000000000..11a39e9cc1190749eb90b2e4810fa62392148ddf --- /dev/null +++ b/editor/src/messages/globals/globals_message.rs @@ -0,0 +1,8 @@ +use crate::messages::portfolio::utility_types::Platform; +use crate::messages::prelude::*; + +#[impl_message(Message, Globals)] +#[derive(PartialEq, Eq, Clone, Debug, serde::Serialize, serde::Deserialize)] +pub enum GlobalsMessage { + SetPlatform { platform: Platform }, +} diff --git a/editor/src/messages/globals/globals_message_handler.rs b/editor/src/messages/globals/globals_message_handler.rs new file mode 100644 index 0000000000000000000000000000000000000000..5651555f6023a3f1cf9fff87a408ef7da3d802ea --- /dev/null +++ b/editor/src/messages/globals/globals_message_handler.rs @@ -0,0 +1,19 @@ +use crate::messages::prelude::*; + +#[derive(Debug, Default)] +pub struct GlobalsMessageHandler {} + +impl MessageHandler for GlobalsMessageHandler { + fn process_message(&mut self, message: GlobalsMessage, _responses: &mut VecDeque, _data: ()) { + match message { + GlobalsMessage::SetPlatform { platform } => { + if GLOBAL_PLATFORM.get() != Some(&platform) { + GLOBAL_PLATFORM.set(platform).expect("Failed to set GLOBAL_PLATFORM"); + } + } + } + } + + advertise_actions!(GlobalsMessageDiscriminant; + ); +} diff --git a/editor/src/messages/globals/mod.rs b/editor/src/messages/globals/mod.rs new file mode 100644 index 0000000000000000000000000000000000000000..65cc989f6e13dbe08ebb16c5a605b664804e1196 --- /dev/null +++ b/editor/src/messages/globals/mod.rs @@ -0,0 +1,9 @@ +mod globals_message; +mod globals_message_handler; + +pub mod global_variables; + +#[doc(inline)] +pub use globals_message::{GlobalsMessage, GlobalsMessageDiscriminant}; +#[doc(inline)] +pub use globals_message_handler::GlobalsMessageHandler; diff --git a/editor/src/messages/input_mapper/input_mapper_message.rs b/editor/src/messages/input_mapper/input_mapper_message.rs new file mode 100644 index 0000000000000000000000000000000000000000..b09d09e309627879312d05889077e21e8f36cd54 --- /dev/null +++ b/editor/src/messages/input_mapper/input_mapper_message.rs @@ -0,0 +1,23 @@ +use crate::messages::input_mapper::utility_types::input_keyboard::Key; +use crate::messages::input_mapper::utility_types::input_mouse::MouseButton; +use crate::messages::prelude::*; + +#[impl_message(Message, KeyMappingMessage, Lookup)] +#[derive(PartialEq, Eq, Clone, Debug, Hash, serde::Serialize, serde::Deserialize)] +pub enum InputMapperMessage { + // Sub-messages + #[child] + KeyDown(Key), + #[child] + KeyUp(Key), + #[child] + KeyDownNoRepeat(Key), + #[child] + KeyUpNoRepeat(Key), + #[child] + DoubleClick(MouseButton), + + // Messages + PointerMove, + WheelScroll, +} diff --git a/editor/src/messages/input_mapper/input_mapper_message_handler.rs b/editor/src/messages/input_mapper/input_mapper_message_handler.rs new file mode 100644 index 0000000000000000000000000000000000000000..eba3867213b4d95815385712ff230671525f1bd6 --- /dev/null +++ b/editor/src/messages/input_mapper/input_mapper_message_handler.rs @@ -0,0 +1,131 @@ +use super::utility_types::input_keyboard::KeysGroup; +use super::utility_types::misc::Mapping; +use crate::messages::input_mapper::utility_types::input_keyboard::{self, Key}; +use crate::messages::input_mapper::utility_types::misc::MappingEntry; +use crate::messages::portfolio::utility_types::KeyboardPlatformLayout; +use crate::messages::prelude::*; +use std::fmt::Write; + +pub struct InputMapperMessageData<'a> { + pub input: &'a InputPreprocessorMessageHandler, + pub actions: ActionList, +} + +#[derive(Debug, Default)] +pub struct InputMapperMessageHandler { + mapping: Mapping, +} + +impl MessageHandler> for InputMapperMessageHandler { + fn process_message(&mut self, message: InputMapperMessage, responses: &mut VecDeque, data: InputMapperMessageData) { + let InputMapperMessageData { input, actions } = data; + + if let Some(message) = self.mapping.match_input_message(message, &input.keyboard, actions) { + responses.add(message); + } + } + advertise_actions!(); +} + +impl InputMapperMessageHandler { + pub fn set_mapping(&mut self, mapping: Mapping) { + self.mapping = mapping; + } + + pub fn hints(&self, actions: ActionList) -> String { + let mut output = String::new(); + let mut actions = actions + .into_iter() + .flatten() + .filter(|a| !matches!(*a, MessageDiscriminant::Tool(ToolMessageDiscriminant::ActivateTool) | MessageDiscriminant::Debug(_))); + self.mapping + .key_down + .iter() + .enumerate() + .filter_map(|(i, m)| { + let ma = m.0.iter().find_map(|m| actions.find_map(|a| (a == m.action.to_discriminant()).then(|| m.action.to_discriminant()))); + + ma.map(|a| ((i as u8).try_into().unwrap(), a)) + }) + .for_each(|(k, a): (Key, _)| { + let _ = write!(output, "{}: {}, ", k.to_discriminant().local_name(), a.local_name().split('.').next_back().unwrap()); + }); + output.replace("Key", "") + } + + pub fn action_input_mapping(&self, action_to_find: &MessageDiscriminant) -> Option { + let all_key_mapping_entries = std::iter::empty() + .chain(self.mapping.key_up.iter()) + .chain(self.mapping.key_down.iter()) + .chain(self.mapping.key_up_no_repeat.iter()) + .chain(self.mapping.key_down_no_repeat.iter()) + .chain(self.mapping.double_click.iter()) + .chain(std::iter::once(&self.mapping.wheel_scroll)) + .chain(std::iter::once(&self.mapping.pointer_move)); + let all_mapping_entries = all_key_mapping_entries.flat_map(|entry| entry.0.iter()); + + // Filter for the desired message + let found_actions = all_mapping_entries.filter(|entry| entry.action.to_discriminant() == *action_to_find); + + // Get the `Key` for this platform's accelerator key + let keyboard_layout = || GLOBAL_PLATFORM.get().copied().unwrap_or_default().as_keyboard_platform_layout(); + let platform_accel_key = match keyboard_layout() { + KeyboardPlatformLayout::Standard => Key::Control, + KeyboardPlatformLayout::Mac => Key::Command, + }; + + let entry_to_key = |entry: &MappingEntry| { + // Get the modifier keys for the entry (and convert them to Key) + let mut keys = entry + .modifiers + .iter() + .map(|i| { + // TODO: Use a safe solution eventually + assert!( + i < input_keyboard::NUMBER_OF_KEYS, + "Attempting to convert a Key with enum index {i}, which is larger than the number of Key enums", + ); + (i as u8).try_into().unwrap() + }) + .collect::>(); + + // Append the key button for the entry + use InputMapperMessage as IMM; + match entry.input { + IMM::KeyDown(key) | IMM::KeyUp(key) | IMM::KeyDownNoRepeat(key) | IMM::KeyUpNoRepeat(key) => keys.push(key), + _ => (), + } + + keys.sort_by(|&a, &b| { + // Order according to platform guidelines mentioned at https://ux.stackexchange.com/questions/58185/normative-ordering-for-modifier-key-combinations + const ORDER: [Key; 4] = [Key::Control, Key::Alt, Key::Shift, Key::Command]; + + // Treat the `Accel` virtual key as the platform's accel key for sorting comparison purposes + let a = if a == Key::Accel { platform_accel_key } else { a }; + let b = if b == Key::Accel { platform_accel_key } else { b }; + + // Find where the keys are in the order, or put them at the end if they're not found + let a = ORDER.iter().position(|&key| key == a).unwrap_or(ORDER.len()); + let b = ORDER.iter().position(|&key| key == b).unwrap_or(ORDER.len()); + + // Compare the positions of both keys + a.cmp(&b) + }); + + KeysGroup(keys) + }; + + // If a canonical key combination is found, return it + if let Some(canonical) = found_actions.clone().find(|entry| entry.canonical).map(entry_to_key) { + return Some(canonical); + } + + // Find the key combinations for all keymaps matching the desired action + assert!(std::mem::size_of::() >= std::mem::size_of::()); + let mut key_sequences = found_actions.map(entry_to_key).collect::>(); + + // Return the shortest key sequence, if any + key_sequences.sort_by_key(|keys| keys.0.len()); + key_sequences.first().cloned() + } +} diff --git a/editor/src/messages/input_mapper/input_mappings.rs b/editor/src/messages/input_mapper/input_mappings.rs new file mode 100644 index 0000000000000000000000000000000000000000..6bb703cd0a829499ea76c65718187996af22958b --- /dev/null +++ b/editor/src/messages/input_mapper/input_mappings.rs @@ -0,0 +1,505 @@ +use crate::consts::{BIG_NUDGE_AMOUNT, BRUSH_SIZE_CHANGE_KEYBOARD, NUDGE_AMOUNT}; +use crate::messages::input_mapper::key_mapping::MappingVariant; +use crate::messages::input_mapper::utility_types::input_keyboard::{Key, KeyStates}; +use crate::messages::input_mapper::utility_types::input_mouse::MouseButton; +use crate::messages::input_mapper::utility_types::macros::*; +use crate::messages::input_mapper::utility_types::misc::MappingEntry; +use crate::messages::input_mapper::utility_types::misc::{KeyMappingEntries, Mapping}; +use crate::messages::portfolio::document::node_graph::utility_types::Direction; +use crate::messages::portfolio::document::utility_types::clipboards::Clipboard; +use crate::messages::portfolio::document::utility_types::misc::GroupFolderType; +use crate::messages::prelude::*; +use crate::messages::tool::tool_messages::brush_tool::BrushToolMessageOptionsUpdate; +use crate::messages::tool::tool_messages::select_tool::SelectToolPointerKeys; +use glam::DVec2; + +impl From for Mapping { + fn from(value: MappingVariant) -> Self { + match value { + MappingVariant::Default => input_mappings(), + MappingVariant::ZoomWithScroll => zoom_with_scroll(), + } + } +} + +pub fn input_mappings() -> Mapping { + use InputMapperMessage::*; + use Key::*; + + // NOTICE: + // If a new mapping you added here isn't working (and perhaps another lower-precedence one is instead), make sure to advertise + // it as an available action in the respective message handler file (such as the bottom of `document_message_handler.rs`). + + let mappings = mapping![ + // =============== + // HIGHER PRIORITY + // =============== + // + // NavigationMessage + entry!(PointerMove; refresh_keys=[Shift], action_dispatch=NavigationMessage::PointerMove { snap: Shift }), + entry!(KeyUp(MouseLeft); action_dispatch=NavigationMessage::EndCanvasPTZ { abort_transform: false }), + entry!(KeyUp(MouseMiddle); action_dispatch=NavigationMessage::EndCanvasPTZ { abort_transform: false }), + entry!(KeyUp(MouseRight); action_dispatch=NavigationMessage::EndCanvasPTZ { abort_transform: false }), + entry!(KeyDown(MouseRight); action_dispatch=NavigationMessage::EndCanvasPTZ { abort_transform: true }), + entry!(KeyDown(Escape); action_dispatch=NavigationMessage::EndCanvasPTZ { abort_transform: true }), + entry!(KeyDown(MouseLeft); action_dispatch=NavigationMessage::EndCanvasPTZWithClick { commit_key: MouseLeft }), + entry!(KeyDown(MouseMiddle); action_dispatch=NavigationMessage::EndCanvasPTZWithClick { commit_key: MouseMiddle }), + entry!(KeyDown(MouseRight); action_dispatch=NavigationMessage::EndCanvasPTZWithClick { commit_key: MouseRight }), + // + // =============== + // NORMAL PRIORITY + // =============== + // + // Hack to prevent Left Click + Accel + Z combo (this effectively blocks you from making a double undo with AbortTransaction) + entry!(KeyDown(KeyZ); modifiers=[Accel, MouseLeft], action_dispatch=DocumentMessage::Noop), + // + // NodeGraphMessage + entry!(KeyDown(MouseLeft); action_dispatch=NodeGraphMessage::PointerDown {shift_click: false, control_click: false, alt_click: false, right_click: false}), + entry!(KeyDown(MouseLeft); modifiers=[Shift], action_dispatch=NodeGraphMessage::PointerDown {shift_click: true, control_click: false, alt_click: false, right_click: false}), + entry!(KeyDown(MouseLeft); modifiers=[Accel], action_dispatch=NodeGraphMessage::PointerDown {shift_click: false, control_click: true, alt_click: false, right_click: false}), + entry!(KeyDown(MouseLeft); modifiers=[Shift, Accel], action_dispatch=NodeGraphMessage::PointerDown {shift_click: true, control_click: true, alt_click: false, right_click: false}), + entry!(KeyDown(MouseLeft); modifiers=[Alt], action_dispatch=NodeGraphMessage::PointerDown {shift_click: false, control_click: false, alt_click: true, right_click: false}), + entry!(KeyDown(MouseRight); action_dispatch=NodeGraphMessage::PointerDown {shift_click: false, control_click: false, alt_click: false, right_click: true}), + entry!(DoubleClick(MouseButton::Left); action_dispatch=NodeGraphMessage::EnterNestedNetwork), + entry!(PointerMove; refresh_keys=[Shift], action_dispatch=NodeGraphMessage::PointerMove {shift: Shift}), + entry!(KeyUp(MouseLeft); action_dispatch=NodeGraphMessage::PointerUp), + entry!(KeyDown(Delete); modifiers=[Accel], action_dispatch=NodeGraphMessage::DeleteSelectedNodes { delete_children: false }), + entry!(KeyDown(Backspace); modifiers=[Accel], action_dispatch=NodeGraphMessage::DeleteSelectedNodes { delete_children: false }), + entry!(KeyDown(Delete); action_dispatch=NodeGraphMessage::DeleteSelectedNodes { delete_children: true }), + entry!(KeyDown(Backspace); action_dispatch=NodeGraphMessage::DeleteSelectedNodes { delete_children: true }), + entry!(KeyDown(KeyX); modifiers=[Accel], action_dispatch=NodeGraphMessage::Cut), + entry!(KeyDown(KeyC); modifiers=[Accel], action_dispatch=NodeGraphMessage::Copy), + entry!(KeyDown(KeyD); modifiers=[Accel], action_dispatch=NodeGraphMessage::DuplicateSelectedNodes), + entry!(KeyDown(KeyH); modifiers=[Accel], action_dispatch=NodeGraphMessage::ToggleSelectedVisibility), + entry!(KeyDown(KeyL); modifiers=[Accel], action_dispatch=NodeGraphMessage::ToggleSelectedLocked), + entry!(KeyDown(KeyL); modifiers=[Alt], action_dispatch=NodeGraphMessage::ToggleSelectedAsLayersOrNodes), + entry!(KeyDown(KeyC); modifiers=[Alt], action_dispatch=NodeGraphMessage::SendClickTargets), + entry!(KeyDown(KeyM); modifiers=[Accel], action_dispatch=NodeGraphMessage::MergeSelectedNodes), + entry!(KeyUp(KeyC); action_dispatch=NodeGraphMessage::EndSendClickTargets), + entry!(KeyDown(ArrowUp); action_dispatch=NodeGraphMessage::ShiftSelectedNodes { direction: Direction::Up, rubber_band: false }), + entry!(KeyDown(ArrowRight); action_dispatch=NodeGraphMessage::ShiftSelectedNodes { direction: Direction::Right, rubber_band: false }), + entry!(KeyDown(ArrowDown); action_dispatch=NodeGraphMessage::ShiftSelectedNodes { direction: Direction::Down, rubber_band: false }), + entry!(KeyDown(ArrowLeft); action_dispatch=NodeGraphMessage::ShiftSelectedNodes { direction: Direction::Left, rubber_band: false }), + // + // TransformLayerMessage + entry!(KeyDown(Enter); action_dispatch=TransformLayerMessage::ApplyTransformOperation { final_transform: true }), + entry!(KeyDown(MouseLeft); action_dispatch=TransformLayerMessage::ApplyTransformOperation { final_transform: true }), + entry!(KeyDown(MouseRight); action_dispatch=TransformLayerMessage::CancelTransformOperation), + entry!(KeyDown(Escape); action_dispatch=TransformLayerMessage::CancelTransformOperation), + entry!(KeyDown(KeyX); action_dispatch=TransformLayerMessage::ConstrainX), + entry!(KeyDown(KeyY); action_dispatch=TransformLayerMessage::ConstrainY), + entry!(KeyDown(Backspace); action_dispatch=TransformLayerMessage::TypeBackspace), + entry!(KeyDown(Minus); action_dispatch=TransformLayerMessage::TypeNegate), + entry!(KeyDown(Comma); action_dispatch=TransformLayerMessage::TypeDecimalPoint), + entry!(KeyDown(Period); action_dispatch=TransformLayerMessage::TypeDecimalPoint), + entry!(PointerMove; refresh_keys=[Control, Shift], action_dispatch=TransformLayerMessage::PointerMove { slow_key: Shift, increments_key: Control }), + // + // SelectToolMessage + entry!(PointerMove; refresh_keys=[Control, Alt, Shift], action_dispatch=SelectToolMessage::PointerMove(SelectToolPointerKeys { axis_align: Shift, snap_angle: Shift, center: Alt, duplicate: Alt })), + entry!(KeyDown(MouseLeft); action_dispatch=SelectToolMessage::DragStart { extend_selection: Shift, remove_from_selection: Alt, select_deepest: Accel, lasso_select: Control, skew: Control }), + entry!(KeyUp(MouseLeft); action_dispatch=SelectToolMessage::DragStop { remove_from_selection: Alt }), + entry!(KeyDown(Enter); action_dispatch=SelectToolMessage::Enter), + entry!(DoubleClick(MouseButton::Left); action_dispatch=SelectToolMessage::EditLayer), + entry!(KeyDown(MouseRight); action_dispatch=SelectToolMessage::Abort), + entry!(KeyDown(Escape); action_dispatch=SelectToolMessage::Abort), + // + // ArtboardToolMessage + entry!(KeyDown(MouseLeft); action_dispatch=ArtboardToolMessage::PointerDown), + entry!(PointerMove; refresh_keys=[Shift, Alt], action_dispatch=ArtboardToolMessage::PointerMove { constrain_axis_or_aspect: Shift, center: Alt }), + entry!(KeyUp(MouseLeft); action_dispatch=ArtboardToolMessage::PointerUp), + entry!(KeyDown(Delete); action_dispatch=ArtboardToolMessage::DeleteSelected), + entry!(KeyDown(Backspace); action_dispatch=ArtboardToolMessage::DeleteSelected), + entry!(KeyDown(ArrowUp); modifiers=[Shift, ArrowLeft], action_dispatch=ArtboardToolMessage::NudgeSelected { delta_x: -BIG_NUDGE_AMOUNT, delta_y: -BIG_NUDGE_AMOUNT, resize: Alt, resize_opposite_corner: Control }), + entry!(KeyDown(ArrowUp); modifiers=[Shift, ArrowRight], action_dispatch=ArtboardToolMessage::NudgeSelected { delta_x: BIG_NUDGE_AMOUNT, delta_y: -BIG_NUDGE_AMOUNT, resize: Alt, resize_opposite_corner: Control }), + entry!(KeyDown(ArrowUp); modifiers=[Shift], action_dispatch=ArtboardToolMessage::NudgeSelected { delta_x: 0., delta_y: -BIG_NUDGE_AMOUNT, resize: Alt, resize_opposite_corner: Control }), + entry!(KeyDown(ArrowDown); modifiers=[Shift, ArrowLeft], action_dispatch=ArtboardToolMessage::NudgeSelected { delta_x: -BIG_NUDGE_AMOUNT, delta_y: BIG_NUDGE_AMOUNT, resize: Alt, resize_opposite_corner: Control }), + entry!(KeyDown(ArrowDown); modifiers=[Shift, ArrowRight], action_dispatch=ArtboardToolMessage::NudgeSelected { delta_x: BIG_NUDGE_AMOUNT, delta_y: BIG_NUDGE_AMOUNT, resize: Alt, resize_opposite_corner: Control }), + entry!(KeyDown(ArrowDown); modifiers=[Shift], action_dispatch=ArtboardToolMessage::NudgeSelected { delta_x: 0., delta_y: BIG_NUDGE_AMOUNT, resize: Alt, resize_opposite_corner: Control }), + entry!(KeyDown(ArrowLeft); modifiers=[Shift, ArrowUp], action_dispatch=ArtboardToolMessage::NudgeSelected { delta_x: -BIG_NUDGE_AMOUNT, delta_y: -BIG_NUDGE_AMOUNT, resize: Alt, resize_opposite_corner: Control }), + entry!(KeyDown(ArrowLeft); modifiers=[Shift, ArrowDown], action_dispatch=ArtboardToolMessage::NudgeSelected { delta_x: -BIG_NUDGE_AMOUNT, delta_y: BIG_NUDGE_AMOUNT, resize: Alt, resize_opposite_corner: Control }), + entry!(KeyDown(ArrowLeft); modifiers=[Shift], action_dispatch=ArtboardToolMessage::NudgeSelected { delta_x: -BIG_NUDGE_AMOUNT, delta_y: 0., resize: Alt, resize_opposite_corner: Control }), + entry!(KeyDown(ArrowRight); modifiers=[Shift, ArrowUp], action_dispatch=ArtboardToolMessage::NudgeSelected { delta_x: BIG_NUDGE_AMOUNT, delta_y: -BIG_NUDGE_AMOUNT, resize: Alt, resize_opposite_corner: Control }), + entry!(KeyDown(ArrowRight); modifiers=[Shift, ArrowDown], action_dispatch=ArtboardToolMessage::NudgeSelected { delta_x: BIG_NUDGE_AMOUNT, delta_y: BIG_NUDGE_AMOUNT, resize: Alt, resize_opposite_corner: Control }), + entry!(KeyDown(ArrowRight); modifiers=[Shift], action_dispatch=ArtboardToolMessage::NudgeSelected { delta_x: BIG_NUDGE_AMOUNT, delta_y: 0., resize: Alt, resize_opposite_corner: Control }), + entry!(KeyDown(ArrowUp); modifiers=[ArrowLeft], action_dispatch=ArtboardToolMessage::NudgeSelected { delta_x: -NUDGE_AMOUNT, delta_y: -NUDGE_AMOUNT, resize: Alt, resize_opposite_corner: Control }), + entry!(KeyDown(ArrowUp); modifiers=[ArrowRight], action_dispatch=ArtboardToolMessage::NudgeSelected { delta_x: NUDGE_AMOUNT, delta_y: -NUDGE_AMOUNT, resize: Alt, resize_opposite_corner: Control }), + entry!(KeyDown(ArrowUp); action_dispatch=ArtboardToolMessage::NudgeSelected { delta_x: 0., delta_y: -NUDGE_AMOUNT, resize: Alt, resize_opposite_corner: Control }), + entry!(KeyDown(ArrowDown); modifiers=[ArrowLeft], action_dispatch=ArtboardToolMessage::NudgeSelected { delta_x: -NUDGE_AMOUNT, delta_y: NUDGE_AMOUNT, resize: Alt, resize_opposite_corner: Control }), + entry!(KeyDown(ArrowDown); modifiers=[ArrowRight], action_dispatch=ArtboardToolMessage::NudgeSelected { delta_x: NUDGE_AMOUNT, delta_y: NUDGE_AMOUNT, resize: Alt, resize_opposite_corner: Control }), + entry!(KeyDown(ArrowDown); action_dispatch=ArtboardToolMessage::NudgeSelected { delta_x: 0., delta_y: NUDGE_AMOUNT, resize: Alt, resize_opposite_corner: Control }), + entry!(KeyDown(ArrowLeft); modifiers=[ArrowUp], action_dispatch=ArtboardToolMessage::NudgeSelected { delta_x: -NUDGE_AMOUNT, delta_y: -NUDGE_AMOUNT, resize: Alt, resize_opposite_corner: Control }), + entry!(KeyDown(ArrowLeft); modifiers=[ArrowDown], action_dispatch=ArtboardToolMessage::NudgeSelected { delta_x: -NUDGE_AMOUNT, delta_y: NUDGE_AMOUNT, resize: Alt, resize_opposite_corner: Control }), + entry!(KeyDown(ArrowLeft); action_dispatch=ArtboardToolMessage::NudgeSelected { delta_x: -NUDGE_AMOUNT, delta_y: 0., resize: Alt, resize_opposite_corner: Control }), + entry!(KeyDown(ArrowRight); modifiers=[ArrowUp], action_dispatch=ArtboardToolMessage::NudgeSelected { delta_x: NUDGE_AMOUNT, delta_y: -NUDGE_AMOUNT, resize: Alt, resize_opposite_corner: Control }), + entry!(KeyDown(ArrowRight); modifiers=[ArrowDown], action_dispatch=ArtboardToolMessage::NudgeSelected { delta_x: NUDGE_AMOUNT, delta_y: NUDGE_AMOUNT, resize: Alt, resize_opposite_corner: Control }), + entry!(KeyDown(ArrowRight); action_dispatch=ArtboardToolMessage::NudgeSelected { delta_x: NUDGE_AMOUNT, delta_y: 0., resize: Alt, resize_opposite_corner: Control }), + entry!(KeyDown(MouseRight); action_dispatch=ArtboardToolMessage::Abort), + entry!(KeyDown(Escape); action_dispatch=ArtboardToolMessage::Abort), + // + // NavigateToolMessage + entry!(KeyDown(MouseLeft); action_dispatch=NavigateToolMessage::ZoomCanvasBegin), + entry!(KeyDown(MouseLeft); modifiers=[Alt], action_dispatch=NavigateToolMessage::TiltCanvasBegin), + entry!(PointerMove; refresh_keys=[Shift], action_dispatch=NavigateToolMessage::PointerMove { snap: Shift }), + entry!(KeyUp(MouseLeft); action_dispatch=NavigateToolMessage::PointerUp { zoom_in: true }), + entry!(KeyUp(MouseLeft); modifiers=[Shift], action_dispatch=NavigateToolMessage::PointerUp { zoom_in: false }), + // + // EyedropperToolMessage + entry!(KeyDown(MouseLeft); action_dispatch=EyedropperToolMessage::SamplePrimaryColorBegin), + entry!(KeyDown(MouseLeft); modifiers=[Shift], action_dispatch=EyedropperToolMessage::SampleSecondaryColorBegin), + entry!(KeyUp(MouseLeft); action_dispatch=EyedropperToolMessage::SamplePrimaryColorEnd), + entry!(KeyUp(MouseLeft); modifiers=[Shift], action_dispatch=EyedropperToolMessage::SampleSecondaryColorEnd), + entry!(PointerMove; action_dispatch=EyedropperToolMessage::PointerMove), + entry!(KeyDown(MouseRight); action_dispatch=EyedropperToolMessage::Abort), + entry!(KeyDown(Escape); action_dispatch=EyedropperToolMessage::Abort), + // + // TextToolMessage + entry!(PointerMove; refresh_keys=[Alt, Shift], action_dispatch=TextToolMessage::PointerMove { center: Alt, lock_ratio: Shift }), + entry!(KeyDown(MouseLeft); action_dispatch=TextToolMessage::DragStart), + entry!(KeyUp(MouseLeft); action_dispatch=TextToolMessage::DragStop), + entry!(KeyDown(MouseRight); action_dispatch=TextToolMessage::Abort), + entry!(KeyDown(Escape); action_dispatch=TextToolMessage::Abort), + entry!(KeyDown(Enter); modifiers=[Accel], action_dispatch=TextToolMessage::Abort), + // + // GradientToolMessage + entry!(KeyDown(MouseLeft); action_dispatch=GradientToolMessage::PointerDown), + entry!(PointerMove; refresh_keys=[Shift], action_dispatch=GradientToolMessage::PointerMove { constrain_axis: Shift }), + entry!(KeyUp(MouseLeft); action_dispatch=GradientToolMessage::PointerUp), + entry!(DoubleClick(MouseButton::Left); action_dispatch=GradientToolMessage::InsertStop), + entry!(KeyDown(Delete); action_dispatch=GradientToolMessage::DeleteStop), + entry!(KeyDown(Backspace); action_dispatch=GradientToolMessage::DeleteStop), + entry!(KeyDown(MouseRight); action_dispatch=GradientToolMessage::Abort), + entry!(KeyDown(Escape); action_dispatch=GradientToolMessage::Abort), + // + // ShapeToolMessage + entry!(KeyDown(MouseLeft); action_dispatch=ShapeToolMessage::DragStart), + entry!(KeyUp(MouseLeft); action_dispatch=ShapeToolMessage::DragStop), + entry!(KeyDown(MouseRight); action_dispatch=ShapeToolMessage::Abort), + entry!(KeyDown(Escape); action_dispatch=ShapeToolMessage::Abort), + entry!(KeyDown(BracketLeft); action_dispatch=ShapeToolMessage::DecreaseSides), + entry!(KeyDown(BracketRight); action_dispatch=ShapeToolMessage::IncreaseSides), + entry!(PointerMove; refresh_keys=[Alt, Shift, Control], action_dispatch=ShapeToolMessage::PointerMove([Alt, Shift, Control, Shift])), + entry!(KeyDown(ArrowUp); modifiers=[Shift, ArrowLeft], action_dispatch=ShapeToolMessage::NudgeSelectedLayers { delta_x: -BIG_NUDGE_AMOUNT, delta_y: -BIG_NUDGE_AMOUNT, resize: Alt, resize_opposite_corner: Control }), + entry!(KeyDown(ArrowUp); modifiers=[Shift, ArrowRight], action_dispatch=ShapeToolMessage::NudgeSelectedLayers { delta_x: BIG_NUDGE_AMOUNT, delta_y: -BIG_NUDGE_AMOUNT, resize: Alt, resize_opposite_corner: Control }), + entry!(KeyDown(ArrowUp); modifiers=[Shift], action_dispatch=ShapeToolMessage::NudgeSelectedLayers { delta_x: 0., delta_y: -BIG_NUDGE_AMOUNT, resize: Alt, resize_opposite_corner: Control }), + entry!(KeyDown(ArrowDown); modifiers=[Shift, ArrowLeft], action_dispatch=ShapeToolMessage::NudgeSelectedLayers { delta_x: -BIG_NUDGE_AMOUNT, delta_y: BIG_NUDGE_AMOUNT, resize: Alt, resize_opposite_corner: Control }), + entry!(KeyDown(ArrowDown); modifiers=[Shift, ArrowRight], action_dispatch=ShapeToolMessage::NudgeSelectedLayers { delta_x: BIG_NUDGE_AMOUNT, delta_y: BIG_NUDGE_AMOUNT, resize: Alt, resize_opposite_corner: Control }), + entry!(KeyDown(ArrowDown); modifiers=[Shift], action_dispatch=ShapeToolMessage::NudgeSelectedLayers { delta_x: 0., delta_y: BIG_NUDGE_AMOUNT, resize: Alt, resize_opposite_corner: Control }), + entry!(KeyDown(ArrowLeft); modifiers=[Shift, ArrowUp], action_dispatch=ShapeToolMessage::NudgeSelectedLayers { delta_x: -BIG_NUDGE_AMOUNT, delta_y: -BIG_NUDGE_AMOUNT, resize: Alt, resize_opposite_corner: Control }), + entry!(KeyDown(ArrowLeft); modifiers=[Shift, ArrowDown], action_dispatch=ShapeToolMessage::NudgeSelectedLayers { delta_x: -BIG_NUDGE_AMOUNT, delta_y: BIG_NUDGE_AMOUNT, resize: Alt, resize_opposite_corner: Control }), + entry!(KeyDown(ArrowLeft); modifiers=[Shift], action_dispatch=ShapeToolMessage::NudgeSelectedLayers { delta_x: -BIG_NUDGE_AMOUNT, delta_y: 0., resize: Alt, resize_opposite_corner: Control }), + entry!(KeyDown(ArrowRight); modifiers=[Shift, ArrowUp], action_dispatch=ShapeToolMessage::NudgeSelectedLayers { delta_x: BIG_NUDGE_AMOUNT, delta_y: -BIG_NUDGE_AMOUNT, resize: Alt, resize_opposite_corner: Control }), + entry!(KeyDown(ArrowRight); modifiers=[Shift, ArrowDown], action_dispatch=ShapeToolMessage::NudgeSelectedLayers { delta_x: BIG_NUDGE_AMOUNT, delta_y: BIG_NUDGE_AMOUNT, resize: Alt, resize_opposite_corner: Control }), + entry!(KeyDown(ArrowRight); modifiers=[Shift], action_dispatch=ShapeToolMessage::NudgeSelectedLayers { delta_x: BIG_NUDGE_AMOUNT, delta_y: 0., resize: Alt, resize_opposite_corner: Control }), + entry!(KeyDown(ArrowUp); modifiers=[ArrowLeft], action_dispatch=ShapeToolMessage::NudgeSelectedLayers { delta_x: -NUDGE_AMOUNT, delta_y: -NUDGE_AMOUNT, resize: Alt, resize_opposite_corner: Control }), + entry!(KeyDown(ArrowUp); modifiers=[ArrowRight], action_dispatch=ShapeToolMessage::NudgeSelectedLayers { delta_x: NUDGE_AMOUNT, delta_y: -NUDGE_AMOUNT, resize: Alt, resize_opposite_corner: Control }), + entry!(KeyDown(ArrowUp); action_dispatch=ShapeToolMessage::NudgeSelectedLayers { delta_x: 0., delta_y: -NUDGE_AMOUNT, resize: Alt, resize_opposite_corner: Control }), + entry!(KeyDown(ArrowDown); modifiers=[ArrowLeft], action_dispatch=ShapeToolMessage::NudgeSelectedLayers { delta_x: -NUDGE_AMOUNT, delta_y: NUDGE_AMOUNT, resize: Alt, resize_opposite_corner: Control }), + entry!(KeyDown(ArrowDown); modifiers=[ArrowRight], action_dispatch=ShapeToolMessage::NudgeSelectedLayers { delta_x: NUDGE_AMOUNT, delta_y: NUDGE_AMOUNT, resize: Alt, resize_opposite_corner: Control }), + entry!(KeyDown(ArrowDown); action_dispatch=ShapeToolMessage::NudgeSelectedLayers { delta_x: 0., delta_y: NUDGE_AMOUNT, resize: Alt, resize_opposite_corner: Control }), + entry!(KeyDown(ArrowLeft); modifiers=[ArrowUp], action_dispatch=ShapeToolMessage::NudgeSelectedLayers { delta_x: -NUDGE_AMOUNT, delta_y: -NUDGE_AMOUNT, resize: Alt, resize_opposite_corner: Control }), + entry!(KeyDown(ArrowLeft); modifiers=[ArrowDown], action_dispatch=ShapeToolMessage::NudgeSelectedLayers { delta_x: -NUDGE_AMOUNT, delta_y: NUDGE_AMOUNT, resize: Alt, resize_opposite_corner: Control }), + entry!(KeyDown(ArrowLeft); action_dispatch=ShapeToolMessage::NudgeSelectedLayers { delta_x: -NUDGE_AMOUNT, delta_y: 0., resize: Alt, resize_opposite_corner: Control }), + entry!(KeyDown(ArrowRight); modifiers=[ArrowUp], action_dispatch=ShapeToolMessage::NudgeSelectedLayers { delta_x: NUDGE_AMOUNT, delta_y: -NUDGE_AMOUNT, resize: Alt, resize_opposite_corner: Control }), + entry!(KeyDown(ArrowRight); modifiers=[ArrowDown], action_dispatch=ShapeToolMessage::NudgeSelectedLayers { delta_x: NUDGE_AMOUNT, delta_y: NUDGE_AMOUNT, resize: Alt, resize_opposite_corner: Control }), + entry!(KeyDown(ArrowRight); action_dispatch=ShapeToolMessage::NudgeSelectedLayers { delta_x: NUDGE_AMOUNT, delta_y: 0., resize: Alt, resize_opposite_corner: Control }), + entry!(KeyDown(ArrowUp); action_dispatch=ShapeToolMessage::IncreaseSides), + entry!(KeyDown(ArrowDown); action_dispatch=ShapeToolMessage::DecreaseSides), + // + // PathToolMessage + entry!(KeyDown(Delete); modifiers=[Accel], action_dispatch=PathToolMessage::DeleteAndBreakPath), + entry!(KeyDown(Backspace); modifiers=[Accel], action_dispatch=PathToolMessage::DeleteAndBreakPath), + entry!(KeyDown(Delete); modifiers=[Shift], action_dispatch=PathToolMessage::BreakPath), + entry!(KeyDown(Backspace); modifiers=[Shift], action_dispatch=PathToolMessage::BreakPath), + entry!(KeyDownNoRepeat(Tab); action_dispatch=PathToolMessage::SwapSelectedHandles), + entry!(KeyDown(MouseLeft); action_dispatch=PathToolMessage::MouseDown { extend_selection: Shift, lasso_select: Control, handle_drag_from_anchor: Alt, drag_restore_handle: Control, molding_in_segment_edit: KeyA }), + entry!(KeyDown(MouseRight); action_dispatch=PathToolMessage::RightClick), + entry!(KeyDown(Escape); action_dispatch=PathToolMessage::Escape), + entry!(KeyDown(KeyG); action_dispatch=PathToolMessage::GRS { key: KeyG }), + entry!(KeyDown(KeyR); action_dispatch=PathToolMessage::GRS { key: KeyR }), + entry!(KeyDown(KeyS); action_dispatch=PathToolMessage::GRS { key: KeyS }), + entry!(PointerMove; refresh_keys=[KeyC, Space, Control, Shift, Alt], action_dispatch=PathToolMessage::PointerMove { toggle_colinear: KeyC, equidistant: Alt, move_anchor_with_handles: Space, snap_angle: Shift, lock_angle: Control, delete_segment: Alt, break_colinear_molding: Alt }), + entry!(KeyDown(Delete); action_dispatch=PathToolMessage::Delete), + entry!(KeyDown(KeyA); modifiers=[Accel], action_dispatch=PathToolMessage::SelectAllAnchors), + entry!(KeyDown(KeyA); modifiers=[Accel, Shift], canonical, action_dispatch=PathToolMessage::DeselectAllPoints), + entry!(KeyDown(KeyA); modifiers=[Alt], action_dispatch=PathToolMessage::DeselectAllPoints), + entry!(KeyDown(Backspace); action_dispatch=PathToolMessage::Delete), + entry!(KeyUp(MouseLeft); action_dispatch=PathToolMessage::DragStop { extend_selection: Shift, shrink_selection: Alt }), + entry!(KeyDown(Enter); action_dispatch=PathToolMessage::Enter { extend_selection: Shift, shrink_selection: Alt }), + entry!(DoubleClick(MouseButton::Left); action_dispatch=PathToolMessage::FlipSmoothSharp), + entry!(KeyDown(ArrowRight); action_dispatch=PathToolMessage::NudgeSelectedPoints { delta_x: NUDGE_AMOUNT, delta_y: 0. }), + entry!(KeyDown(ArrowRight); modifiers=[Shift], action_dispatch=PathToolMessage::NudgeSelectedPoints { delta_x: BIG_NUDGE_AMOUNT, delta_y: 0. }), + entry!(KeyDown(ArrowRight); modifiers=[ArrowUp], action_dispatch=PathToolMessage::NudgeSelectedPoints { delta_x: NUDGE_AMOUNT, delta_y: -NUDGE_AMOUNT }), + entry!(KeyDown(ArrowRight); modifiers=[ArrowDown], action_dispatch=PathToolMessage::NudgeSelectedPoints { delta_x: NUDGE_AMOUNT, delta_y: NUDGE_AMOUNT }), + entry!(KeyDown(ArrowRight); modifiers=[Shift, ArrowUp], action_dispatch=PathToolMessage::NudgeSelectedPoints { delta_x: BIG_NUDGE_AMOUNT, delta_y: -BIG_NUDGE_AMOUNT }), + entry!(KeyDown(ArrowRight); modifiers=[Shift, ArrowDown], action_dispatch=PathToolMessage::NudgeSelectedPoints { delta_x: BIG_NUDGE_AMOUNT, delta_y: BIG_NUDGE_AMOUNT }), + entry!(KeyDown(ArrowUp); action_dispatch=PathToolMessage::NudgeSelectedPoints { delta_x: 0., delta_y: -NUDGE_AMOUNT }), + entry!(KeyDown(ArrowUp); modifiers=[Shift], action_dispatch=PathToolMessage::NudgeSelectedPoints { delta_x: 0., delta_y: -BIG_NUDGE_AMOUNT }), + entry!(KeyDown(ArrowUp); modifiers=[ArrowLeft], action_dispatch=PathToolMessage::NudgeSelectedPoints { delta_x: -NUDGE_AMOUNT, delta_y: -NUDGE_AMOUNT }), + entry!(KeyDown(ArrowUp); modifiers=[ArrowRight], action_dispatch=PathToolMessage::NudgeSelectedPoints { delta_x: NUDGE_AMOUNT, delta_y: -NUDGE_AMOUNT }), + entry!(KeyDown(ArrowUp); modifiers=[Shift, ArrowLeft], action_dispatch=PathToolMessage::NudgeSelectedPoints { delta_x: -BIG_NUDGE_AMOUNT, delta_y: -BIG_NUDGE_AMOUNT }), + entry!(KeyDown(ArrowUp); modifiers=[Shift, ArrowRight], action_dispatch=PathToolMessage::NudgeSelectedPoints { delta_x: BIG_NUDGE_AMOUNT, delta_y: -BIG_NUDGE_AMOUNT }), + entry!(KeyDown(ArrowLeft); action_dispatch=PathToolMessage::NudgeSelectedPoints { delta_x: -NUDGE_AMOUNT, delta_y: 0. }), + entry!(KeyDown(ArrowLeft); modifiers=[Shift], action_dispatch=PathToolMessage::NudgeSelectedPoints { delta_x: -BIG_NUDGE_AMOUNT, delta_y: 0. }), + entry!(KeyDown(ArrowLeft); modifiers=[ArrowUp], action_dispatch=PathToolMessage::NudgeSelectedPoints { delta_x: -NUDGE_AMOUNT, delta_y: -NUDGE_AMOUNT }), + entry!(KeyDown(ArrowLeft); modifiers=[ArrowDown], action_dispatch=PathToolMessage::NudgeSelectedPoints { delta_x: -NUDGE_AMOUNT, delta_y: NUDGE_AMOUNT }), + entry!(KeyDown(ArrowLeft); modifiers=[Shift, ArrowUp], action_dispatch=PathToolMessage::NudgeSelectedPoints { delta_x: -BIG_NUDGE_AMOUNT, delta_y: -BIG_NUDGE_AMOUNT }), + entry!(KeyDown(ArrowLeft); modifiers=[Shift, ArrowDown], action_dispatch=PathToolMessage::NudgeSelectedPoints { delta_x: -BIG_NUDGE_AMOUNT, delta_y: BIG_NUDGE_AMOUNT }), + entry!(KeyDown(ArrowDown); action_dispatch=PathToolMessage::NudgeSelectedPoints { delta_x: 0., delta_y: NUDGE_AMOUNT }), + entry!(KeyDown(ArrowDown); modifiers=[Shift], action_dispatch=PathToolMessage::NudgeSelectedPoints { delta_x: 0., delta_y: BIG_NUDGE_AMOUNT }), + entry!(KeyDown(ArrowDown); modifiers=[ArrowLeft], action_dispatch=PathToolMessage::NudgeSelectedPoints { delta_x: -NUDGE_AMOUNT, delta_y: NUDGE_AMOUNT }), + entry!(KeyDown(ArrowDown); modifiers=[ArrowRight], action_dispatch=PathToolMessage::NudgeSelectedPoints { delta_x: NUDGE_AMOUNT, delta_y: NUDGE_AMOUNT }), + entry!(KeyDown(ArrowDown); modifiers=[Shift, ArrowLeft], action_dispatch=PathToolMessage::NudgeSelectedPoints { delta_x: -BIG_NUDGE_AMOUNT, delta_y: BIG_NUDGE_AMOUNT }), + entry!(KeyDown(ArrowDown); modifiers=[Shift, ArrowRight], action_dispatch=PathToolMessage::NudgeSelectedPoints { delta_x: BIG_NUDGE_AMOUNT, delta_y: BIG_NUDGE_AMOUNT }), + entry!(KeyDown(KeyJ); modifiers=[Accel], action_dispatch=ToolMessage::Path(PathToolMessage::ClosePath)), + // + // PenToolMessage + entry!(PointerMove; refresh_keys=[Control, Alt, Shift, KeyC], action_dispatch=PenToolMessage::PointerMove { snap_angle: Shift, break_handle: Alt, lock_angle: Control, colinear: KeyC, move_anchor_with_handles: Space }), + entry!(KeyDownNoRepeat(Tab); action_dispatch=PenToolMessage::SwapHandles), + entry!(KeyDown(MouseLeft); action_dispatch=PenToolMessage::DragStart { append_to_selected: Shift }), + entry!(KeyUp(MouseLeft); action_dispatch=PenToolMessage::DragStop), + entry!(KeyDown(MouseRight); action_dispatch=PenToolMessage::Abort), + entry!(KeyDown(Escape); action_dispatch=PenToolMessage::Abort), + entry!(KeyDown(Enter); action_dispatch=PenToolMessage::Confirm), + entry!(KeyDown(Delete); action_dispatch=PenToolMessage::RemovePreviousHandle), + entry!(KeyDown(Backspace); action_dispatch=PenToolMessage::RemovePreviousHandle), + entry!(KeyDown(KeyG); action_dispatch=PenToolMessage::GRS { grab: KeyG, rotate: KeyR, scale: KeyS }), + entry!(KeyDown(KeyR); action_dispatch=PenToolMessage::GRS { grab: KeyG, rotate: KeyR, scale: KeyS }), + entry!(KeyDown(KeyS); action_dispatch=PenToolMessage::GRS { grab: KeyG, rotate: KeyR, scale: KeyS }), + // + // FreehandToolMessage + entry!(PointerMove; action_dispatch=FreehandToolMessage::PointerMove), + entry!(KeyDown(MouseLeft); action_dispatch=FreehandToolMessage::DragStart { append_to_selected: Shift }), + entry!(KeyUp(MouseLeft); action_dispatch=FreehandToolMessage::DragStop), + entry!(KeyDown(MouseRight); action_dispatch=FreehandToolMessage::Abort), + entry!(KeyDown(Escape); action_dispatch=FreehandToolMessage::Abort), + // + // SplineToolMessage + entry!(PointerMove; action_dispatch=SplineToolMessage::PointerMove), + entry!(KeyDown(MouseLeft); action_dispatch=SplineToolMessage::DragStart { append_to_selected: Shift }), + entry!(KeyUp(MouseLeft); action_dispatch=SplineToolMessage::DragStop), + entry!(KeyDown(MouseRight); action_dispatch=SplineToolMessage::Confirm), + entry!(KeyDown(Escape); action_dispatch=SplineToolMessage::Confirm), + entry!(KeyDown(Enter); action_dispatch=SplineToolMessage::Confirm), + // + // FillToolMessage + entry!(PointerMove; refresh_keys=[Shift], action_dispatch=FillToolMessage::PointerMove), + entry!(KeyDown(MouseLeft); action_dispatch=FillToolMessage::FillPrimaryColor), + entry!(KeyDown(MouseLeft); modifiers=[Shift], action_dispatch=FillToolMessage::FillSecondaryColor), + entry!(KeyUp(MouseLeft); action_dispatch=FillToolMessage::PointerUp), + entry!(KeyDown(MouseRight); action_dispatch=FillToolMessage::Abort), + entry!(KeyDown(Escape); action_dispatch=FillToolMessage::Abort), + // + // BrushToolMessage + entry!(PointerMove; action_dispatch=BrushToolMessage::PointerMove), + entry!(KeyDown(MouseLeft); action_dispatch=BrushToolMessage::DragStart), + entry!(KeyUp(MouseLeft); action_dispatch=BrushToolMessage::DragStop), + entry!(KeyDown(BracketLeft); action_dispatch=BrushToolMessage::UpdateOptions(BrushToolMessageOptionsUpdate::ChangeDiameter(-BRUSH_SIZE_CHANGE_KEYBOARD))), + entry!(KeyDown(BracketRight); action_dispatch=BrushToolMessage::UpdateOptions(BrushToolMessageOptionsUpdate::ChangeDiameter(BRUSH_SIZE_CHANGE_KEYBOARD))), + entry!(KeyDown(MouseRight); action_dispatch=BrushToolMessage::Abort), + entry!(KeyDown(Escape); action_dispatch=BrushToolMessage::Abort), + // + // ToolMessage + entry!(KeyDown(KeyV); action_dispatch=ToolMessage::ActivateToolSelect), + entry!(KeyDown(KeyZ); action_dispatch=ToolMessage::ActivateToolNavigate), + entry!(KeyDown(KeyI); action_dispatch=ToolMessage::ActivateToolEyedropper), + entry!(KeyDown(KeyT); action_dispatch=ToolMessage::ActivateToolText), + entry!(KeyDown(KeyF); action_dispatch=ToolMessage::ActivateToolFill), + entry!(KeyDown(KeyH); action_dispatch=ToolMessage::ActivateToolGradient), + entry!(KeyDown(KeyA); action_dispatch=ToolMessage::ActivateToolPath), + entry!(KeyDown(KeyP); action_dispatch=ToolMessage::ActivateToolPen), + entry!(KeyDown(KeyN); action_dispatch=ToolMessage::ActivateToolFreehand), + entry!(KeyDown(KeyL); action_dispatch=ToolMessage::ActivateToolShapeLine), + entry!(KeyDown(KeyM); action_dispatch=ToolMessage::ActivateToolShapeRectangle), + entry!(KeyDown(KeyE); action_dispatch=ToolMessage::ActivateToolShapeEllipse), + entry!(KeyDown(KeyY); action_dispatch=ToolMessage::ActivateToolShape), + entry!(KeyDown(KeyB); action_dispatch=ToolMessage::ActivateToolBrush), + entry!(KeyDown(KeyD); action_dispatch=ToolMessage::ResetColors), + entry!(KeyDown(KeyX); modifiers=[Shift], action_dispatch=ToolMessage::SwapColors), + entry!(KeyDown(KeyC); modifiers=[Alt], action_dispatch=ToolMessage::SelectRandomWorkingColor { primary: true }), + entry!(KeyDown(KeyC); modifiers=[Alt, Shift], action_dispatch=ToolMessage::SelectRandomWorkingColor { primary: false }), + // + // DocumentMessage + entry!(KeyDown(Space); modifiers=[Control], action_dispatch=DocumentMessage::GraphViewOverlayToggle), + entry!(KeyUp(Escape); action_dispatch=DocumentMessage::Escape), + entry!(KeyDown(Delete); action_dispatch=DocumentMessage::DeleteSelectedLayers), + entry!(KeyDown(Backspace); action_dispatch=DocumentMessage::DeleteSelectedLayers), + entry!(KeyDown(KeyO); modifiers=[Alt], action_dispatch=DocumentMessage::ToggleOverlaysVisibility), + entry!(KeyDown(KeyS); modifiers=[Alt], action_dispatch=DocumentMessage::ToggleSnapping), + entry!(KeyDown(KeyH); modifiers=[Accel], action_dispatch=DocumentMessage::ToggleSelectedVisibility), + entry!(KeyDown(KeyL); modifiers=[Accel], action_dispatch=DocumentMessage::ToggleSelectedLocked), + entry!(KeyDown(KeyG); modifiers=[Alt], action_dispatch=DocumentMessage::ToggleGridVisibility), + entry!(KeyDown(KeyZ); modifiers=[Accel, Shift], canonical, action_dispatch=DocumentMessage::Redo), + entry!(KeyDown(KeyY); modifiers=[Accel], action_dispatch=DocumentMessage::Redo), + entry!(KeyDown(KeyZ); modifiers=[Accel], action_dispatch=DocumentMessage::Undo), + entry!(KeyDown(KeyA); modifiers=[Accel], action_dispatch=DocumentMessage::SelectAllLayers), + entry!(KeyDown(KeyA); modifiers=[Accel, Shift], canonical, action_dispatch=DocumentMessage::DeselectAllLayers), + entry!(KeyDown(KeyA); modifiers=[Alt], action_dispatch=DocumentMessage::DeselectAllLayers), + entry!(KeyDown(KeyS); modifiers=[Accel], action_dispatch=DocumentMessage::SaveDocument), + entry!(KeyDown(KeyD); modifiers=[Accel], canonical, action_dispatch=DocumentMessage::DuplicateSelectedLayers), + entry!(KeyDown(KeyJ); modifiers=[Accel], action_dispatch=DocumentMessage::DuplicateSelectedLayers), + entry!(KeyDown(KeyG); modifiers=[Accel], action_dispatch=DocumentMessage::GroupSelectedLayers { group_folder_type: GroupFolderType::Layer }), + entry!(KeyDown(KeyG); modifiers=[Accel, Shift], action_dispatch=DocumentMessage::UngroupSelectedLayers), + entry!(KeyDown(KeyN); modifiers=[Accel, Shift], action_dispatch=DocumentMessage::CreateEmptyFolder), + entry!(KeyDown(Escape); modifiers=[Shift], action_dispatch=DocumentMessage::SelectParentLayer), + entry!(KeyDown(BracketLeft); modifiers=[Alt], canonical, action_dispatch=DocumentMessage::SelectionStepBack), + entry!(KeyDown(BracketRight); modifiers=[Alt], canonical, action_dispatch=DocumentMessage::SelectionStepForward), + entry!(KeyDown(MouseBack); action_dispatch=DocumentMessage::SelectionStepBack), + entry!(KeyDown(MouseForward); action_dispatch=DocumentMessage::SelectionStepForward), + entry!(KeyDown(Digit0); modifiers=[Accel], action_dispatch=DocumentMessage::ZoomCanvasToFitAll), + entry!(KeyDown(Digit1); modifiers=[Accel], action_dispatch=DocumentMessage::ZoomCanvasTo100Percent), + entry!(KeyDown(Digit2); modifiers=[Accel], action_dispatch=DocumentMessage::ZoomCanvasTo200Percent), + entry!(KeyDown(BracketLeft); modifiers=[Accel, Shift], action_dispatch=DocumentMessage::SelectedLayersLowerToBack), + entry!(KeyDown(BracketRight); modifiers=[Accel, Shift], action_dispatch=DocumentMessage::SelectedLayersRaiseToFront), + entry!(KeyDown(BracketLeft); modifiers=[Accel], action_dispatch=DocumentMessage::SelectedLayersLower), + entry!(KeyDown(BracketRight); modifiers=[Accel], action_dispatch=DocumentMessage::SelectedLayersRaise), + entry!(KeyDown(ArrowUp); modifiers=[Shift, ArrowLeft], action_dispatch=DocumentMessage::NudgeSelectedLayers { delta_x: -BIG_NUDGE_AMOUNT, delta_y: -BIG_NUDGE_AMOUNT, resize: Alt, resize_opposite_corner: Control }), + entry!(KeyDown(ArrowUp); modifiers=[Shift, ArrowRight], action_dispatch=DocumentMessage::NudgeSelectedLayers { delta_x: BIG_NUDGE_AMOUNT, delta_y: -BIG_NUDGE_AMOUNT, resize: Alt, resize_opposite_corner: Control }), + entry!(KeyDown(ArrowUp); modifiers=[Shift], action_dispatch=DocumentMessage::NudgeSelectedLayers { delta_x: 0., delta_y: -BIG_NUDGE_AMOUNT, resize: Alt, resize_opposite_corner: Control }), + entry!(KeyDown(ArrowDown); modifiers=[Shift, ArrowLeft], action_dispatch=DocumentMessage::NudgeSelectedLayers { delta_x: -BIG_NUDGE_AMOUNT, delta_y: BIG_NUDGE_AMOUNT, resize: Alt, resize_opposite_corner: Control }), + entry!(KeyDown(ArrowDown); modifiers=[Shift, ArrowRight], action_dispatch=DocumentMessage::NudgeSelectedLayers { delta_x: BIG_NUDGE_AMOUNT, delta_y: BIG_NUDGE_AMOUNT, resize: Alt, resize_opposite_corner: Control }), + entry!(KeyDown(ArrowDown); modifiers=[Shift], action_dispatch=DocumentMessage::NudgeSelectedLayers { delta_x: 0., delta_y: BIG_NUDGE_AMOUNT, resize: Alt, resize_opposite_corner: Control }), + entry!(KeyDown(ArrowLeft); modifiers=[Shift, ArrowUp], action_dispatch=DocumentMessage::NudgeSelectedLayers { delta_x: -BIG_NUDGE_AMOUNT, delta_y: -BIG_NUDGE_AMOUNT, resize: Alt, resize_opposite_corner: Control }), + entry!(KeyDown(ArrowLeft); modifiers=[Shift, ArrowDown], action_dispatch=DocumentMessage::NudgeSelectedLayers { delta_x: -BIG_NUDGE_AMOUNT, delta_y: BIG_NUDGE_AMOUNT, resize: Alt, resize_opposite_corner: Control }), + entry!(KeyDown(ArrowLeft); modifiers=[Shift], action_dispatch=DocumentMessage::NudgeSelectedLayers { delta_x: -BIG_NUDGE_AMOUNT, delta_y: 0., resize: Alt, resize_opposite_corner: Control }), + entry!(KeyDown(ArrowRight); modifiers=[Shift, ArrowUp], action_dispatch=DocumentMessage::NudgeSelectedLayers { delta_x: BIG_NUDGE_AMOUNT, delta_y: -BIG_NUDGE_AMOUNT, resize: Alt, resize_opposite_corner: Control }), + entry!(KeyDown(ArrowRight); modifiers=[Shift, ArrowDown], action_dispatch=DocumentMessage::NudgeSelectedLayers { delta_x: BIG_NUDGE_AMOUNT, delta_y: BIG_NUDGE_AMOUNT, resize: Alt, resize_opposite_corner: Control }), + entry!(KeyDown(ArrowRight); modifiers=[Shift], action_dispatch=DocumentMessage::NudgeSelectedLayers { delta_x: BIG_NUDGE_AMOUNT, delta_y: 0., resize: Alt, resize_opposite_corner: Control }), + entry!(KeyDown(ArrowUp); modifiers=[ArrowLeft], action_dispatch=DocumentMessage::NudgeSelectedLayers { delta_x: -NUDGE_AMOUNT, delta_y: -NUDGE_AMOUNT, resize: Alt, resize_opposite_corner: Control }), + entry!(KeyDown(ArrowUp); modifiers=[ArrowRight], action_dispatch=DocumentMessage::NudgeSelectedLayers { delta_x: NUDGE_AMOUNT, delta_y: -NUDGE_AMOUNT, resize: Alt, resize_opposite_corner: Control }), + entry!(KeyDown(ArrowUp); action_dispatch=DocumentMessage::NudgeSelectedLayers { delta_x: 0., delta_y: -NUDGE_AMOUNT, resize: Alt, resize_opposite_corner: Control }), + entry!(KeyDown(ArrowDown); modifiers=[ArrowLeft], action_dispatch=DocumentMessage::NudgeSelectedLayers { delta_x: -NUDGE_AMOUNT, delta_y: NUDGE_AMOUNT, resize: Alt, resize_opposite_corner: Control }), + entry!(KeyDown(ArrowDown); modifiers=[ArrowRight], action_dispatch=DocumentMessage::NudgeSelectedLayers { delta_x: NUDGE_AMOUNT, delta_y: NUDGE_AMOUNT, resize: Alt, resize_opposite_corner: Control }), + entry!(KeyDown(ArrowDown); action_dispatch=DocumentMessage::NudgeSelectedLayers { delta_x: 0., delta_y: NUDGE_AMOUNT, resize: Alt, resize_opposite_corner: Control }), + entry!(KeyDown(ArrowLeft); modifiers=[ArrowUp], action_dispatch=DocumentMessage::NudgeSelectedLayers { delta_x: -NUDGE_AMOUNT, delta_y: -NUDGE_AMOUNT, resize: Alt, resize_opposite_corner: Control }), + entry!(KeyDown(ArrowLeft); modifiers=[ArrowDown], action_dispatch=DocumentMessage::NudgeSelectedLayers { delta_x: -NUDGE_AMOUNT, delta_y: NUDGE_AMOUNT, resize: Alt, resize_opposite_corner: Control }), + entry!(KeyDown(ArrowLeft); action_dispatch=DocumentMessage::NudgeSelectedLayers { delta_x: -NUDGE_AMOUNT, delta_y: 0., resize: Alt, resize_opposite_corner: Control }), + entry!(KeyDown(ArrowRight); modifiers=[ArrowUp], action_dispatch=DocumentMessage::NudgeSelectedLayers { delta_x: NUDGE_AMOUNT, delta_y: -NUDGE_AMOUNT, resize: Alt, resize_opposite_corner: Control }), + entry!(KeyDown(ArrowRight); modifiers=[ArrowDown], action_dispatch=DocumentMessage::NudgeSelectedLayers { delta_x: NUDGE_AMOUNT, delta_y: NUDGE_AMOUNT, resize: Alt, resize_opposite_corner: Control }), + entry!(KeyDown(ArrowRight); action_dispatch=DocumentMessage::NudgeSelectedLayers { delta_x: NUDGE_AMOUNT, delta_y: 0., resize: Alt, resize_opposite_corner: Control }), + // + // TransformLayerMessage + entry!(KeyDown(KeyG); action_dispatch=TransformLayerMessage::BeginGrab), + entry!(KeyDown(KeyR); action_dispatch=TransformLayerMessage::BeginRotate), + entry!(KeyDown(KeyS); action_dispatch=TransformLayerMessage::BeginScale), + entry!(KeyDown(Digit0); action_dispatch=TransformLayerMessage::TypeDigit { digit: 0 }), + entry!(KeyDown(Digit1); action_dispatch=TransformLayerMessage::TypeDigit { digit: 1 }), + entry!(KeyDown(Digit2); action_dispatch=TransformLayerMessage::TypeDigit { digit: 2 }), + entry!(KeyDown(Digit3); action_dispatch=TransformLayerMessage::TypeDigit { digit: 3 }), + entry!(KeyDown(Digit4); action_dispatch=TransformLayerMessage::TypeDigit { digit: 4 }), + entry!(KeyDown(Digit5); action_dispatch=TransformLayerMessage::TypeDigit { digit: 5 }), + entry!(KeyDown(Digit6); action_dispatch=TransformLayerMessage::TypeDigit { digit: 6 }), + entry!(KeyDown(Digit7); action_dispatch=TransformLayerMessage::TypeDigit { digit: 7 }), + entry!(KeyDown(Digit8); action_dispatch=TransformLayerMessage::TypeDigit { digit: 8 }), + entry!(KeyDown(Digit9); action_dispatch=TransformLayerMessage::TypeDigit { digit: 9 }), + // + // NavigationMessage + entry!(KeyDown(MouseMiddle); modifiers=[Alt], action_dispatch=NavigationMessage::BeginCanvasTilt { was_dispatched_from_menu: false }), + entry!(KeyDown(MouseLeft); modifiers=[Alt, Space], action_dispatch=NavigationMessage::BeginCanvasTilt { was_dispatched_from_menu: false }), + entry!(KeyDown(MouseMiddle); modifiers=[Control], action_dispatch=NavigationMessage::BeginCanvasZoom), + entry!(KeyDown(MouseLeft); modifiers=[Control, Space], action_dispatch=NavigationMessage::BeginCanvasZoom), + entry!(KeyDown(MouseMiddle); action_dispatch=NavigationMessage::BeginCanvasPan), + entry!(KeyDown(MouseLeft); modifiers=[Space], action_dispatch=NavigationMessage::BeginCanvasPan), + entry!(KeyDown(NumpadAdd); modifiers=[Accel], action_dispatch=NavigationMessage::CanvasZoomIncrease { center_on_mouse: false }), + entry!(KeyDown(Equal); modifiers=[Accel], action_dispatch=NavigationMessage::CanvasZoomIncrease { center_on_mouse: false }), + entry!(KeyDown(Minus); modifiers=[Accel], action_dispatch=NavigationMessage::CanvasZoomDecrease { center_on_mouse: false }), + entry!(KeyDown(KeyF); modifiers=[Alt], action_dispatch=NavigationMessage::CanvasFlip), + entry!(WheelScroll; modifiers=[Control], action_dispatch=NavigationMessage::CanvasZoomMouseWheel), + entry!(WheelScroll; modifiers=[Shift], action_dispatch=NavigationMessage::CanvasPanMouseWheel { use_y_as_x: true }), + entry!(WheelScroll; action_dispatch=NavigationMessage::CanvasPanMouseWheel { use_y_as_x: false }), + entry!(KeyDown(PageUp); modifiers=[Shift], action_dispatch=NavigationMessage::CanvasPanByViewportFraction { delta: DVec2::new(1., 0.) }), + entry!(KeyDown(PageDown); modifiers=[Shift], action_dispatch=NavigationMessage::CanvasPanByViewportFraction { delta: DVec2::new(-1., 0.) }), + entry!(KeyDown(PageUp); action_dispatch=NavigationMessage::CanvasPanByViewportFraction { delta: DVec2::new(0., 1.) }), + entry!(KeyDown(PageDown); action_dispatch=NavigationMessage::CanvasPanByViewportFraction { delta: DVec2::new(0., -1.) }), + entry!(KeyDown(Period); action_dispatch=NavigationMessage::FitViewportToSelection), + // + // PortfolioMessage + entry!(KeyDown(Tab); modifiers=[Control], action_dispatch=PortfolioMessage::NextDocument), + entry!(KeyDown(Tab); modifiers=[Control, Shift], action_dispatch=PortfolioMessage::PrevDocument), + entry!(KeyDown(KeyW); modifiers=[Accel], action_dispatch=PortfolioMessage::CloseActiveDocumentWithConfirmation), + entry!(KeyDown(KeyW); modifiers=[Accel,Alt], action_dispatch=PortfolioMessage::CloseAllDocumentsWithConfirmation), + entry!(KeyDown(KeyO); modifiers=[Accel], action_dispatch=PortfolioMessage::OpenDocument), + entry!(KeyDown(KeyI); modifiers=[Accel], action_dispatch=PortfolioMessage::Import), + entry!(KeyDown(KeyX); modifiers=[Accel], action_dispatch=PortfolioMessage::Cut { clipboard: Clipboard::Device }), + entry!(KeyDown(KeyC); modifiers=[Accel], action_dispatch=PortfolioMessage::Copy { clipboard: Clipboard::Device }), + entry!(KeyDown(KeyR); modifiers=[Alt], action_dispatch=PortfolioMessage::ToggleRulers), + // + // FrontendMessage + entry!(KeyDown(KeyV); modifiers=[Accel], action_dispatch=FrontendMessage::TriggerPaste), + // + // DialogMessage + entry!(KeyDown(KeyE); modifiers=[Accel], action_dispatch=DialogMessage::RequestExportDialog), + entry!(KeyDown(KeyN); modifiers=[Accel], action_dispatch=DialogMessage::RequestNewDocumentDialog), + entry!(KeyDown(Comma); modifiers=[Accel], action_dispatch=DialogMessage::RequestPreferencesDialog), + // + // DebugMessage + entry!(KeyDown(Digit0); modifiers=[Alt], action_dispatch=DebugMessage::MessageOff), + entry!(KeyDown(Digit1); modifiers=[Alt], action_dispatch=DebugMessage::MessageNames), + entry!(KeyDown(Digit2); modifiers=[Alt], action_dispatch=DebugMessage::MessageContents), + // AnimationMessage + entry!(KeyDown(Space); modifiers=[Shift], action_dispatch=AnimationMessage::ToggleLivePreview), + entry!(KeyDown(Home); modifiers=[Shift], action_dispatch=AnimationMessage::RestartAnimation), + ]; + let (mut key_up, mut key_down, mut key_up_no_repeat, mut key_down_no_repeat, mut double_click, mut wheel_scroll, mut pointer_move) = mappings; + + let sort = |list: &mut KeyMappingEntries| list.0.sort_by(|a, b| b.modifiers.count_ones().cmp(&a.modifiers.count_ones())); + // Sort the sublists of `key_up`, `key_down`, `key_up_no_repeat`, and `key_down_no_repeat` + for list in [&mut key_up, &mut key_down, &mut key_up_no_repeat, &mut key_down_no_repeat] { + for sublist in list { + sort(sublist); + } + } + // Sort the sublists of `double_click` + for sublist in &mut double_click { + sort(sublist) + } + // Sort `wheel_scroll` + sort(&mut wheel_scroll); + // Sort `pointer_move` + sort(&mut pointer_move); + + Mapping { + key_up, + key_down, + key_up_no_repeat, + key_down_no_repeat, + double_click, + wheel_scroll, + pointer_move, + } +} + +/// Default mappings except that scrolling without modifier keys held down is bound to zooming instead of vertical panning +pub fn zoom_with_scroll() -> Mapping { + use InputMapperMessage::*; + + let mut mapping = input_mappings(); + + let remove = [ + entry!(WheelScroll; modifiers=[Control], action_dispatch=NavigationMessage::CanvasZoomMouseWheel), + entry!(WheelScroll; modifiers=[Shift], action_dispatch=NavigationMessage::CanvasPanMouseWheel { use_y_as_x: true }), + entry!(WheelScroll; action_dispatch=NavigationMessage::CanvasPanMouseWheel { use_y_as_x: false }), + ]; + let add = [ + entry!(WheelScroll; modifiers=[Control], action_dispatch=NavigationMessage::CanvasPanMouseWheel { use_y_as_x: true }), + entry!(WheelScroll; modifiers=[Shift], action_dispatch=NavigationMessage::CanvasPanMouseWheel { use_y_as_x: false }), + entry!(WheelScroll; action_dispatch=NavigationMessage::CanvasZoomMouseWheel), + ]; + + apply_mapping_patch(&mut mapping, remove, add); + + mapping +} + +fn apply_mapping_patch<'a, const N: usize, const M: usize, const X: usize, const Y: usize>( + mapping: &mut Mapping, + remove: impl IntoIterator, + add: impl IntoIterator, +) { + for entry in remove.into_iter().flat_map(|inner| inner.iter()).flat_map(|inner| inner.iter()) { + mapping.remove(entry); + } + + for entry in add.into_iter().flat_map(|inner| inner.iter()).flat_map(|inner| inner.iter()) { + mapping.add(entry.clone()); + } +} diff --git a/editor/src/messages/input_mapper/key_mapping/key_mapping_message.rs b/editor/src/messages/input_mapper/key_mapping/key_mapping_message.rs new file mode 100644 index 0000000000000000000000000000000000000000..95cb5cc57f4e98fa96b179f0bab452ee8eecf6ff --- /dev/null +++ b/editor/src/messages/input_mapper/key_mapping/key_mapping_message.rs @@ -0,0 +1,19 @@ +use crate::messages::prelude::*; + +#[impl_message(Message, KeyMapping)] +#[derive(PartialEq, Eq, Clone, Debug, Hash, serde::Serialize, serde::Deserialize)] +pub enum KeyMappingMessage { + #[child] + Lookup(InputMapperMessage), + #[child] + ModifyMapping(MappingVariant), +} + +#[impl_message(Message, KeyMappingMessage, ModifyMapping)] +#[derive(PartialEq, Eq, Clone, Debug, Default, Hash, serde::Serialize, serde::Deserialize)] +pub enum MappingVariant { + #[default] + Default, + + ZoomWithScroll, +} diff --git a/editor/src/messages/input_mapper/key_mapping/key_mapping_message_handler.rs b/editor/src/messages/input_mapper/key_mapping/key_mapping_message_handler.rs new file mode 100644 index 0000000000000000000000000000000000000000..53c626bf54be12879de02600381bfbcab042378c --- /dev/null +++ b/editor/src/messages/input_mapper/key_mapping/key_mapping_message_handler.rs @@ -0,0 +1,31 @@ +use crate::messages::input_mapper::input_mapper_message_handler::InputMapperMessageData; +use crate::messages::input_mapper::utility_types::input_keyboard::KeysGroup; +use crate::messages::prelude::*; + +pub struct KeyMappingMessageData<'a> { + pub input: &'a InputPreprocessorMessageHandler, + pub actions: ActionList, +} + +#[derive(Debug, Default)] +pub struct KeyMappingMessageHandler { + mapping_handler: InputMapperMessageHandler, +} + +impl MessageHandler> for KeyMappingMessageHandler { + fn process_message(&mut self, message: KeyMappingMessage, responses: &mut VecDeque, data: KeyMappingMessageData) { + let KeyMappingMessageData { input, actions } = data; + + match message { + KeyMappingMessage::Lookup(input_message) => self.mapping_handler.process_message(input_message, responses, InputMapperMessageData { input, actions }), + KeyMappingMessage::ModifyMapping(new_layout) => self.mapping_handler.set_mapping(new_layout.into()), + } + } + advertise_actions!(); +} + +impl KeyMappingMessageHandler { + pub fn action_input_mapping(&self, action_to_find: &MessageDiscriminant) -> Option { + self.mapping_handler.action_input_mapping(action_to_find) + } +} diff --git a/editor/src/messages/input_mapper/key_mapping/mod.rs b/editor/src/messages/input_mapper/key_mapping/mod.rs new file mode 100644 index 0000000000000000000000000000000000000000..5b629044af61a9c44abe8114782ccc37bd2ecbde --- /dev/null +++ b/editor/src/messages/input_mapper/key_mapping/mod.rs @@ -0,0 +1,7 @@ +mod key_mapping_message; +mod key_mapping_message_handler; + +#[doc(inline)] +pub use key_mapping_message::{KeyMappingMessage, KeyMappingMessageDiscriminant, MappingVariant, MappingVariantDiscriminant}; +#[doc(inline)] +pub use key_mapping_message_handler::{KeyMappingMessageData, KeyMappingMessageHandler}; diff --git a/editor/src/messages/input_mapper/mod.rs b/editor/src/messages/input_mapper/mod.rs new file mode 100644 index 0000000000000000000000000000000000000000..14aff3e3ff982c2d8bc55075fc6bf94b867acc6c --- /dev/null +++ b/editor/src/messages/input_mapper/mod.rs @@ -0,0 +1,11 @@ +mod input_mapper_message; +mod input_mapper_message_handler; + +pub mod input_mappings; +pub mod key_mapping; +pub mod utility_types; + +#[doc(inline)] +pub use input_mapper_message::{InputMapperMessage, InputMapperMessageDiscriminant}; +#[doc(inline)] +pub use input_mapper_message_handler::{InputMapperMessageData, InputMapperMessageHandler}; diff --git a/editor/src/messages/input_mapper/utility_types/input_keyboard.rs b/editor/src/messages/input_mapper/utility_types/input_keyboard.rs new file mode 100644 index 0000000000000000000000000000000000000000..99a267550a717e49c22385b838a13aa9dc4da24a --- /dev/null +++ b/editor/src/messages/input_mapper/utility_types/input_keyboard.rs @@ -0,0 +1,529 @@ +use crate::messages::portfolio::utility_types::KeyboardPlatformLayout; +use crate::messages::prelude::*; +use bitflags::bitflags; +use std::fmt::{self, Display, Formatter}; +use std::ops::{BitAnd, BitAndAssign, BitOr, BitOrAssign, BitXor, BitXorAssign}; + +// TODO: Increase size of type +/// Edit this to specify the storage type used. +pub type StorageType = u128; + +// Base-2 logarithm of the storage type used to represents how many bits you need to fully address every bit in that storage type +const STORAGE_SIZE: u32 = (std::mem::size_of::() * 8).trailing_zeros(); +const STORAGE_SIZE_BITS: usize = 1 << STORAGE_SIZE; +const KEY_MASK_STORAGE_LENGTH: usize = (NUMBER_OF_KEYS + STORAGE_SIZE_BITS - 1) >> STORAGE_SIZE; + +pub type KeyStates = BitVector; + +pub fn all_required_modifiers_pressed(keyboard_state: &KeyStates, modifiers: &KeyStates) -> bool { + // Find which currently pressed keys are also the modifiers in this hotkey entry, then compare those against the required modifiers to see if there are zero missing + let pressed_modifiers = *keyboard_state & *modifiers; + let all_modifiers_without_pressed_modifiers = *modifiers ^ pressed_modifiers; + + all_modifiers_without_pressed_modifiers.is_empty() +} + +pub enum KeyPosition { + Pressed, + Released, +} + +bitflags! { + #[derive(Clone, Copy, Debug, PartialEq, Eq, Default, serde::Serialize, serde::Deserialize)] + #[repr(transparent)] + #[serde(transparent)] + pub struct ModifierKeys: u8 { + const SHIFT = 0b_0000_0001; + const ALT = 0b_0000_0010; + const CONTROL = 0b_0000_0100; + const META_OR_COMMAND = 0b_0000_1000; + } +} + +// Currently this is mostly based on the JS `KeyboardEvent.code` list: +// But in the future, especially once users can customize keyboard mappings, we should deviate more from this so we have actual symbols +// like `+` (which doesn't exist because it's the shifted version of `=` on the US keyboard, after which these scan codes are named). +// We'd ideally like to bind shortcuts to symbols, not scan codes, so the shortcut for "zoom in" is `Ctrl +` which the user can press +// (although we ignore the shift key, so the user doesn't have to press `Ctrl Shift +` on a US keyboard), even if the keyboard layout +// is for a different locale where the `+` key is somewhere entirely different, shifted or not. This would then also work for numpad `+`. +#[impl_message(Message, InputMapperMessage, KeyDown)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, serde::Serialize, serde::Deserialize, specta::Type, num_enum::TryFromPrimitive)] +#[repr(u8)] +pub enum Key { + // Writing system keys + Digit0, + Digit1, + Digit2, + Digit3, + Digit4, + Digit5, + Digit6, + Digit7, + Digit8, + Digit9, + // + KeyA, + KeyB, + KeyC, + KeyD, + KeyE, + KeyF, + KeyG, + KeyH, + KeyI, + KeyJ, + KeyK, + KeyL, + KeyM, + KeyN, + KeyO, + KeyP, + KeyQ, + KeyR, + KeyS, + KeyT, + KeyU, + KeyV, + KeyW, + KeyX, + KeyY, + KeyZ, + // + Backquote, + Backslash, + BracketLeft, + BracketRight, + Comma, + Equal, + Minus, + Period, + Quote, + Semicolon, + Slash, + + // Functional keys + Alt, + Meta, + Shift, + Control, + Backspace, + CapsLock, + ContextMenu, + Enter, + Space, + Tab, + + // Control pad keys + Delete, + End, + Help, + Home, + Insert, + PageDown, + PageUp, + + // Arrow pad keys + ArrowDown, + ArrowLeft, + ArrowRight, + ArrowUp, + + // Numpad keys + // Numpad0, + // Numpad1, + // Numpad2, + // Numpad3, + // Numpad4, + // Numpad5, + // Numpad6, + // Numpad7, + // Numpad8, + // Numpad9, + NumLock, + NumpadAdd, + // NumpadBackspace, + // NumpadClear, + // NumpadClearEntry, + // NumpadComma, + // NumpadDecimal, + // NumpadDivide, + // NumpadEnter, + // NumpadEqual, + NumpadHash, + // NumpadMemoryAdd, + // NumpadMemoryClear, + // NumpadMemoryRecall, + // NumpadMemoryStore, + // NumpadMemorySubtract, + NumpadMultiply, + NumpadParenLeft, + NumpadParenRight, + // NumpadStar, + // NumpadSubtract, + + // Function keys + Escape, + F1, + F2, + F3, + F4, + F5, + F6, + F7, + F8, + F9, + F10, + F11, + F12, + F13, + F14, + F15, + F16, + F17, + F18, + F19, + F20, + F21, + F22, + F23, + F24, + Fn, + FnLock, + PrintScreen, + ScrollLock, + Pause, + + // Unidentified keys + Unidentified, + + // Other keys that aren't part of the W3C spec + Command, + /// "Ctrl" on Windows/Linux, "Cmd" on Mac + Accel, + MouseLeft, + MouseRight, + MouseMiddle, + MouseBack, + MouseForward, + + // This has to be the last element in the enum + NumKeys, +} + +impl fmt::Display for Key { + // TODO: Relevant key labels should be localized when we get around to implementing localization/internationalization + fn fmt(&self, f: &mut fmt::Formatter) -> std::fmt::Result { + let key_name = format!("{self:?}"); + + // Writing system keys + const DIGIT_PREFIX: &str = "Digit"; + if key_name.len() == DIGIT_PREFIX.len() + 1 && &key_name[0..DIGIT_PREFIX.len()] == "Digit" { + return write!(f, "{}", key_name.chars().skip(DIGIT_PREFIX.len()).collect::()); + } + const KEY_PREFIX: &str = "Key"; + if key_name.len() == KEY_PREFIX.len() + 1 && &key_name[0..KEY_PREFIX.len()] == "Key" { + return write!(f, "{}", key_name.chars().skip(KEY_PREFIX.len()).collect::()); + } + + let keyboard_layout = || GLOBAL_PLATFORM.get().copied().unwrap_or_default().as_keyboard_platform_layout(); + + let name = match self { + // Writing system keys + Self::Backquote => "`", + Self::Backslash => "\\", + Self::BracketLeft => "[", + Self::BracketRight => "]", + Self::Comma => ",", + Self::Equal => "=", + Self::Minus => "-", + Self::Period => ".", + Self::Quote => "'", + Self::Semicolon => ";", + Self::Slash => "/", + + // Functional keys + Self::Alt => match keyboard_layout() { + KeyboardPlatformLayout::Standard => "Alt", + KeyboardPlatformLayout::Mac => "⌥", + }, + Self::Meta => match keyboard_layout() { + KeyboardPlatformLayout::Standard => "⊞", + KeyboardPlatformLayout::Mac => "⌘", + }, + Self::Shift => match keyboard_layout() { + KeyboardPlatformLayout::Standard => "Shift", + KeyboardPlatformLayout::Mac => "⇧", + }, + Self::Control => match keyboard_layout() { + KeyboardPlatformLayout::Standard => "Ctrl", + KeyboardPlatformLayout::Mac => "⌃", + }, + Self::Backspace => "⌫", + + // Control pad keys + Self::Delete => "Del", + Self::PageDown => "PgDn", + Self::PageUp => "PgUp", + + // Arrow pad keys + Self::ArrowDown => "↓", + Self::ArrowLeft => "←", + Self::ArrowRight => "→", + Self::ArrowUp => "↑", + + // Numpad keys + Self::NumpadAdd => "Numpad +", + Self::NumpadHash => "Numpad #", + Self::NumpadMultiply => "Numpad *", + Self::NumpadParenLeft => "Numpad (", + Self::NumpadParenRight => "Numpad )", + + // Function keys + Self::Escape => "Esc", + Self::PrintScreen => "PrtScr", + + // Other keys that aren't part of the W3C spec + Self::Command => "⌘", + Self::Accel => match keyboard_layout() { + KeyboardPlatformLayout::Standard => "Ctrl", + KeyboardPlatformLayout::Mac => "⌘", + }, + Self::MouseLeft => "LMB", + Self::MouseRight => "RMB", + Self::MouseMiddle => "MMB", + Self::MouseBack => "Mouse Back", + Self::MouseForward => "Mouse Fwd", + Self::NumKeys => "0–9", + + _ => key_name.as_str(), + }; + + write!(f, "{name}") + } +} + +impl From for LayoutKey { + fn from(key: Key) -> Self { + Self { + key: format!("{key:?}"), + label: key.to_string(), + } + } +} + +#[derive(Debug, Clone, PartialEq, Eq, Hash, serde::Serialize, serde::Deserialize, specta::Type)] +struct LayoutKey { + key: String, + label: String, +} + +pub const NUMBER_OF_KEYS: usize = Key::NumKeys as usize; + +/// Only `Key`s that exist on a physical keyboard should be used. +#[derive(Debug, Clone, Default, PartialEq, Eq, serde::Serialize, serde::Deserialize)] +pub struct KeysGroup(pub Vec); + +impl fmt::Display for KeysGroup { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + const JOINER_MARK: &str = " "; + + let mut joined = self + .0 + .iter() + .map(|key| { + let keyboard_layout = GLOBAL_PLATFORM.get().copied().unwrap_or_default().as_keyboard_platform_layout(); + let key_is_modifier = matches!(*key, Key::Control | Key::Command | Key::Alt | Key::Shift | Key::Meta | Key::Accel); + + if keyboard_layout == KeyboardPlatformLayout::Mac && key_is_modifier { + key.to_string() + } else { + key.to_string() + JOINER_MARK + } + }) + .collect::(); + + // Cut the joining character off the end, if present + if joined.ends_with(JOINER_MARK) { + joined.truncate(joined.len() - JOINER_MARK.len()); + } + + write!(f, "{joined}") + } +} + +impl From for String { + fn from(keys: KeysGroup) -> Self { + let layout_keys: LayoutKeysGroup = keys.into(); + serde_json::to_string(&layout_keys).expect("Failed to serialize KeysGroup") + } +} + +#[derive(Debug, Clone, Default, PartialEq, Eq, serde::Serialize, serde::Deserialize, specta::Type)] +pub struct LayoutKeysGroup(Vec); + +impl From for LayoutKeysGroup { + fn from(keys_group: KeysGroup) -> Self { + Self(keys_group.0.into_iter().map(|key| key.into()).collect()) + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, serde::Serialize, serde::Deserialize, specta::Type)] +pub enum MouseMotion { + None, + Lmb, + Rmb, + Mmb, + ScrollUp, + ScrollDown, + Drag, + LmbDouble, + LmbDrag, + RmbDrag, + RmbDouble, + MmbDrag, +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub struct BitVector([StorageType; LENGTH]); + +impl BitVector { + #[inline] + fn convert_index(bitvector_index: usize) -> (usize, StorageType) { + let bit = 1 << (bitvector_index & (STORAGE_SIZE_BITS as StorageType - 1) as usize); + let offset = bitvector_index >> STORAGE_SIZE; + (offset, bit) + } + + pub const fn new() -> Self { + Self([0; LENGTH]) + } + + pub fn set(&mut self, bitvector_index: usize) { + let (offset, bit) = Self::convert_index(bitvector_index); + self.0[offset] |= bit; + } + + pub fn unset(&mut self, bitvector_index: usize) { + let (offset, bit) = Self::convert_index(bitvector_index); + self.0[offset] &= !bit; + } + + pub fn toggle(&mut self, bitvector_index: usize) { + let (offset, bit) = Self::convert_index(bitvector_index); + self.0[offset] ^= bit; + } + + pub fn get(&self, bitvector_index: usize) -> bool { + let (offset, bit) = Self::convert_index(bitvector_index); + (self.0[offset] & bit) != 0 + } + + pub fn key(&self, key: Key) -> bool { + self.get(key as usize) + } + + pub fn is_empty(&self) -> bool { + let mut result = 0; + + for storage in self.0.iter() { + result |= storage; + } + + result == 0 + } + + pub fn count_ones(&self) -> u32 { + let mut result = 0; + + for storage in self.0.iter() { + result += storage.count_ones(); + } + + result + } + + pub fn iter(&self) -> impl Iterator + '_ { + BitVectorIter:: { bitvector: self, iter_index: 0 } + } +} + +impl Default for BitVector { + fn default() -> Self { + Self::new() + } +} + +struct BitVectorIter<'a, const LENGTH: usize> { + bitvector: &'a BitVector, + iter_index: usize, +} + +impl Iterator for BitVectorIter<'_, LENGTH> { + type Item = usize; + + fn next(&mut self) -> Option { + while self.iter_index < STORAGE_SIZE_BITS * LENGTH { + let bit_value = self.bitvector.get(self.iter_index); + + self.iter_index += 1; + + if bit_value { + return Some(self.iter_index - 1); + } + } + + None + } +} + +impl Display for BitVector { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + for storage in self.0.iter().rev() { + write!(f, "{:0width$b}", storage, width = STORAGE_SIZE_BITS)?; + } + + Ok(()) + } +} + +macro_rules! bit_ops { + ($(($op:ident, $func:ident)),* $(,)?) => { + $( + impl $op for BitVector { + type Output = Self; + fn $func(self, right: Self) -> Self::Output { + let mut result = Self::new(); + for ((left, right), new) in self.0.iter().zip(right.0.iter()).zip(result.0.iter_mut()) { + *new = $op::$func(left, right); + } + result + } + } + + impl $op for &BitVector { + type Output = BitVector; + fn $func(self, right: Self) -> Self::Output { + let mut result = BitVector::::new(); + for ((left, right), new) in self.0.iter().zip(right.0.iter()).zip(result.0.iter_mut()) { + *new = $op::$func(left, right); + } + result + } + } + )* + }; +} +macro_rules! bit_ops_assign { + ($(($op:ident, $func:ident)),* $(,)?) => { + $(impl $op for BitVector { + fn $func(&mut self, right: Self) { + for (left, right) in self.0.iter_mut().zip(right.0.iter()) { + $op::$func(left, right); + } + } + })* + }; +} + +bit_ops!((BitAnd, bitand), (BitOr, bitor), (BitXor, bitxor)); +bit_ops_assign!((BitAndAssign, bitand_assign), (BitOrAssign, bitor_assign), (BitXorAssign, bitxor_assign)); diff --git a/editor/src/messages/input_mapper/utility_types/input_mouse.rs b/editor/src/messages/input_mapper/utility_types/input_mouse.rs new file mode 100644 index 0000000000000000000000000000000000000000..a9b746608d17797aea5cfdacdbfee506a99a1ec8 --- /dev/null +++ b/editor/src/messages/input_mapper/utility_types/input_mouse.rs @@ -0,0 +1,150 @@ +use crate::consts::DRAG_THRESHOLD; +use crate::messages::prelude::*; +use bitflags::bitflags; +use glam::DVec2; +use std::collections::VecDeque; + +// Origin is top left +pub type DocumentPosition = DVec2; +pub type ViewportPosition = DVec2; +pub type EditorPosition = DVec2; + +#[derive(PartialEq, Clone, Debug, Default, serde::Serialize, serde::Deserialize)] +pub struct ViewportBounds { + pub top_left: DVec2, + pub bottom_right: DVec2, +} + +impl ViewportBounds { + pub fn from_slice(slice: &[f64]) -> Self { + Self { + top_left: DVec2::from_slice(&slice[0..2]), + bottom_right: DVec2::from_slice(&slice[2..4]), + } + } + + pub fn size(&self) -> DVec2 { + (self.bottom_right - self.top_left).ceil() + } + + pub fn center(&self) -> DVec2 { + (self.bottom_right - self.top_left).ceil() / 2. + } + + pub fn in_bounds(&self, position: ViewportPosition) -> bool { + position.x >= 0. && position.y >= 0. && position.x <= self.bottom_right.x && position.y <= self.bottom_right.y + } +} + +use std::hash::{Hash, Hasher}; + +#[derive(Debug, Copy, Clone, Default, serde::Serialize, serde::Deserialize)] +pub struct ScrollDelta { + pub x: f64, + pub y: f64, + pub z: f64, +} + +impl PartialEq for ScrollDelta { + fn eq(&self, other: &Self) -> bool { + self.x == other.x && self.y == other.y && self.z == other.z + } +} + +impl Eq for ScrollDelta {} + +impl Hash for ScrollDelta { + fn hash(&self, state: &mut H) { + let no_negative_zero = |value: f64| if value == 0. { 0. } else { value }; + + no_negative_zero(self.x).to_bits().hash(state); + no_negative_zero(self.y).to_bits().hash(state); + no_negative_zero(self.z).to_bits().hash(state); + } +} + +impl ScrollDelta { + pub fn new(x: f64, y: f64, z: f64) -> Self { + Self { x, y, z } + } + + pub fn as_dvec2(&self) -> DVec2 { + DVec2::new(self.x, self.y) + } + + pub fn scroll_delta(&self) -> f64 { + let (dx, dy) = (self.x, self.y); + dy.signum() * (dy * dy + f64::min(dy.abs(), dx.abs()).powi(2)).sqrt() + } +} + +// TODO: Document the difference between this and EditorMouseState +#[derive(Debug, Copy, Clone, Default, PartialEq, serde::Serialize, serde::Deserialize)] +pub struct MouseState { + pub position: ViewportPosition, + pub mouse_keys: MouseKeys, + pub scroll_delta: ScrollDelta, +} + +impl MouseState { + pub fn finish_transaction(&self, drag_start: DVec2, responses: &mut VecDeque) { + let drag_too_small = drag_start.distance(self.position) <= DRAG_THRESHOLD; + let response = if drag_too_small { DocumentMessage::AbortTransaction } else { DocumentMessage::EndTransaction }; + responses.add(response); + } +} + +// TODO: Document the difference between this and MouseState +#[derive(Debug, Copy, Clone, Default, PartialEq, serde::Serialize, serde::Deserialize)] +pub struct EditorMouseState { + pub editor_position: EditorPosition, + pub mouse_keys: MouseKeys, + pub scroll_delta: ScrollDelta, +} + +impl EditorMouseState { + pub fn from_keys_and_editor_position(keys: u8, editor_position: EditorPosition) -> Self { + let mouse_keys = MouseKeys::from_bits(keys).expect("Invalid decoding of MouseKeys"); + + Self { + editor_position, + mouse_keys, + scroll_delta: ScrollDelta::default(), + } + } + + pub fn to_mouse_state(&self, active_viewport_bounds: &ViewportBounds) -> MouseState { + MouseState { + position: self.editor_position - active_viewport_bounds.top_left, + mouse_keys: self.mouse_keys, + scroll_delta: self.scroll_delta, + } + } +} + +bitflags! { + /// Based on . + #[derive(Default, Clone, Copy, Debug, PartialEq, Eq, serde::Serialize, serde::Deserialize)] + #[repr(transparent)] + pub struct MouseKeys: u8 { + const NONE = 0b0000_0000; + const LEFT = 0b0000_0001; + const RIGHT = 0b0000_0010; + const MIDDLE = 0b0000_0100; + const BACK = 0b0000_1000; + const FORWARD = 0b0001_0000; + } +} + +#[impl_message(Message, InputMapperMessage, DoubleClick)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, serde::Serialize, serde::Deserialize, specta::Type, num_enum::TryFromPrimitive)] +#[repr(u8)] +pub enum MouseButton { + Left, + Right, + Middle, + Back, + Forward, +} + +pub const NUMBER_OF_MOUSE_BUTTONS: usize = 5; // Should be the number of variants in MouseButton diff --git a/editor/src/messages/input_mapper/utility_types/macros.rs b/editor/src/messages/input_mapper/utility_types/macros.rs new file mode 100644 index 0000000000000000000000000000000000000000..3fabbbeb2dc5168a9faa07a8c0b2e1ac69436756 --- /dev/null +++ b/editor/src/messages/input_mapper/utility_types/macros.rs @@ -0,0 +1,128 @@ +/// Constructs a `KeyStates` bit vector and sets the bit flags for all the given modifier `Key`s. +macro_rules! modifiers { + ($($m:ident),*) => {{ + #[allow(unused_mut)] + let mut state = KeyStates::new(); + $( + state.set(Key::$m as usize); + )* + state + }}; +} + +/// Builds a slice of `MappingEntry` struct(s) that are used to: +/// - ...dispatch the given `action_dispatch` as an output `Message` if its discriminant is a currently available action +/// - ...when the `InputMapperMessage` enum variant, as specified at the start and followed by a semicolon, is received +/// - ...while the optional `modifiers` being pressed. +/// +/// Syntax: +/// ```rs +/// entry_for_layout!(Key; modifiers?: Key[], refresh_keys?: Key[], action_dispatch: Message) +/// ``` +/// +/// The actions system controls which actions are currently available. Those are provided by the different message handlers based on the current application state and context. +/// Each handler adds or removes actions in the form of message discriminants. Here, we tie an input condition (such as a hotkey) to an action's full message. +/// When an action is currently available, and the user enters that input, the action's message is dispatched on the message bus. +macro_rules! entry { + // Pattern with canonical parameter + ($input:expr_2021; $(modifiers=[$($modifier:ident),*],)? $(refresh_keys=[$($refresh:ident),* $(,)?],)? canonical, action_dispatch=$action_dispatch:expr_2021$(,)?) => { + entry!($input; $($($modifier),*)?; $($($refresh),*)?; $action_dispatch; true) + }; + + // Pattern without canonical parameter + ($input:expr_2021; $(modifiers=[$($modifier:ident),*],)? $(refresh_keys=[$($refresh:ident),* $(,)?],)? action_dispatch=$action_dispatch:expr_2021$(,)?) => { + entry!($input; $($($modifier),*)?; $($($refresh),*)?; $action_dispatch; false) + }; + + // Implementation macro to avoid code duplication + ($input:expr; $($modifier:ident),*; $($refresh:ident),*; $action_dispatch:expr; $canonical:expr) => { + &[&[ + // Cause the `action_dispatch` message to be sent when the specified input occurs. + MappingEntry { + action: $action_dispatch.into(), + input: $input, + modifiers: modifiers!($($modifier),*), + canonical: $canonical, + }, + + // Also cause the `action_dispatch` message to be sent when any of the specified refresh keys change. + $( + MappingEntry { + action: $action_dispatch.into(), + input: InputMapperMessage::KeyDown(Key::$refresh), + modifiers: modifiers!(), + canonical: $canonical, + }, + MappingEntry { + action: $action_dispatch.into(), + input: InputMapperMessage::KeyUp(Key::$refresh), + modifiers: modifiers!(), + canonical: $canonical, + }, + MappingEntry { + action: $action_dispatch.into(), + input: InputMapperMessage::KeyDownNoRepeat(Key::$refresh), + modifiers: modifiers!(), + canonical: $canonical, + }, + MappingEntry { + action: $action_dispatch.into(), + input: InputMapperMessage::KeyUpNoRepeat(Key::$refresh), + modifiers: modifiers!(), + canonical: $canonical, + }, + )* + ]] + }; +} + +/// Constructs a `KeyMappingEntries` list for each input type and inserts every given entry into the list corresponding to its input type. +/// Returns a tuple of `KeyMappingEntries` in the order: +/// ```rs +/// (key_up, key_down, double_click, wheel_scroll, pointer_move) +/// ``` +macro_rules! mapping { + [$($entry:expr_2021),* $(,)?] => {{ + let mut key_up = KeyMappingEntries::key_array(); + let mut key_down = KeyMappingEntries::key_array(); + let mut key_up_no_repeat = KeyMappingEntries::key_array(); + let mut key_down_no_repeat = KeyMappingEntries::key_array(); + let mut double_click = KeyMappingEntries::mouse_buttons_arrays(); + let mut wheel_scroll = KeyMappingEntries::new(); + let mut pointer_move = KeyMappingEntries::new(); + + $( + // Each of the many entry slices, one specified per action + for entry_slice in $entry { + // Each entry in the slice (usually just one, except when `refresh_keys` adds additional key entries) + for entry in entry_slice.into_iter() { + let corresponding_list = match entry.input { + InputMapperMessage::KeyDown(key) => &mut key_down[key as usize], + InputMapperMessage::KeyUp(key) => &mut key_up[key as usize], + InputMapperMessage::KeyDownNoRepeat(key) => &mut key_down_no_repeat[key as usize], + InputMapperMessage::KeyUpNoRepeat(key) => &mut key_up_no_repeat[key as usize], + InputMapperMessage::DoubleClick(key) => &mut double_click[key as usize], + InputMapperMessage::WheelScroll => &mut wheel_scroll, + InputMapperMessage::PointerMove => &mut pointer_move, + }; + // Push each entry to the corresponding `KeyMappingEntries` list for its input type + corresponding_list.push(entry.clone()); + } + } + )* + + (key_up, key_down, key_up_no_repeat, key_down_no_repeat, double_click, wheel_scroll, pointer_move) + }}; +} + +/// Constructs an `ActionKeys` macro with a certain `Action` variant, conveniently wrapped in `Some()`. +macro_rules! action_keys { + ($action:expr_2021) => { + Some(crate::messages::input_mapper::utility_types::misc::ActionKeys::Action($action.into())) + }; +} + +pub(crate) use action_keys; +pub(crate) use entry; +pub(crate) use mapping; +pub(crate) use modifiers; diff --git a/editor/src/messages/input_mapper/utility_types/misc.rs b/editor/src/messages/input_mapper/utility_types/misc.rs new file mode 100644 index 0000000000000000000000000000000000000000..0c9a2205295d5c571d657de63ba6d739934be7e4 --- /dev/null +++ b/editor/src/messages/input_mapper/utility_types/misc.rs @@ -0,0 +1,172 @@ +use super::input_keyboard::{KeysGroup, LayoutKeysGroup, all_required_modifiers_pressed}; +use crate::messages::input_mapper::key_mapping::MappingVariant; +use crate::messages::input_mapper::utility_types::input_keyboard::{KeyStates, NUMBER_OF_KEYS}; +use crate::messages::input_mapper::utility_types::input_mouse::NUMBER_OF_MOUSE_BUTTONS; +use crate::messages::prelude::*; +use core::time::Duration; + +#[derive(Debug, Clone)] +pub struct Mapping { + pub key_up: [KeyMappingEntries; NUMBER_OF_KEYS], + pub key_down: [KeyMappingEntries; NUMBER_OF_KEYS], + pub key_up_no_repeat: [KeyMappingEntries; NUMBER_OF_KEYS], + pub key_down_no_repeat: [KeyMappingEntries; NUMBER_OF_KEYS], + pub double_click: [KeyMappingEntries; NUMBER_OF_MOUSE_BUTTONS], + pub wheel_scroll: KeyMappingEntries, + pub pointer_move: KeyMappingEntries, +} + +impl Default for Mapping { + fn default() -> Self { + MappingVariant::Default.into() + } +} + +impl Mapping { + pub fn match_input_message(&self, message: InputMapperMessage, keyboard_state: &KeyStates, actions: ActionList) -> Option { + let list = self.associated_entries(&message); + list.match_mapping(keyboard_state, actions) + } + + pub fn remove(&mut self, target_entry: &MappingEntry) { + let list = self.associated_entries_mut(&target_entry.input); + list.remove(target_entry); + } + + pub fn add(&mut self, new_entry: MappingEntry) { + let list = self.associated_entries_mut(&new_entry.input); + list.push(new_entry); + } + + fn associated_entries(&self, message: &InputMapperMessage) -> &KeyMappingEntries { + match message { + InputMapperMessage::KeyDown(key) => &self.key_down[*key as usize], + InputMapperMessage::KeyUp(key) => &self.key_up[*key as usize], + InputMapperMessage::KeyDownNoRepeat(key) => &self.key_down_no_repeat[*key as usize], + InputMapperMessage::KeyUpNoRepeat(key) => &self.key_up_no_repeat[*key as usize], + InputMapperMessage::DoubleClick(key) => &self.double_click[*key as usize], + InputMapperMessage::WheelScroll => &self.wheel_scroll, + InputMapperMessage::PointerMove => &self.pointer_move, + } + } + + fn associated_entries_mut(&mut self, message: &InputMapperMessage) -> &mut KeyMappingEntries { + match message { + InputMapperMessage::KeyDown(key) => &mut self.key_down[*key as usize], + InputMapperMessage::KeyUp(key) => &mut self.key_up[*key as usize], + InputMapperMessage::KeyDownNoRepeat(key) => &mut self.key_down_no_repeat[*key as usize], + InputMapperMessage::KeyUpNoRepeat(key) => &mut self.key_up_no_repeat[*key as usize], + InputMapperMessage::DoubleClick(key) => &mut self.double_click[*key as usize], + InputMapperMessage::WheelScroll => &mut self.wheel_scroll, + InputMapperMessage::PointerMove => &mut self.pointer_move, + } + } +} + +#[derive(Debug, Clone)] +pub struct KeyMappingEntries(pub Vec); + +impl KeyMappingEntries { + pub fn match_mapping(&self, keyboard_state: &KeyStates, actions: ActionList) -> Option { + for mapping in self.0.iter() { + // Skip this entry if any of the required modifiers are missing + if all_required_modifiers_pressed(keyboard_state, &mapping.modifiers) { + // Search for the action in the list of available actions to see if it's currently available to activate + let matching_action_found = actions.iter().flatten().any(|action| mapping.action.to_discriminant() == *action); + if matching_action_found { + return Some(mapping.action.clone()); + } + } + } + None + } + + pub fn push(&mut self, entry: MappingEntry) { + self.0.push(entry); + } + + pub fn remove(&mut self, target_entry: &MappingEntry) { + self.0.retain(|entry| entry != target_entry); + } + + pub const fn new() -> Self { + Self(Vec::new()) + } + + pub fn key_array() -> [Self; NUMBER_OF_KEYS] { + const DEFAULT: KeyMappingEntries = KeyMappingEntries::new(); + [DEFAULT; NUMBER_OF_KEYS] + } + + pub fn mouse_buttons_arrays() -> [Self; NUMBER_OF_MOUSE_BUTTONS] { + const DEFAULT: KeyMappingEntries = KeyMappingEntries::new(); + [DEFAULT; NUMBER_OF_MOUSE_BUTTONS] + } +} + +impl Default for KeyMappingEntries { + fn default() -> Self { + Self::new() + } +} + +#[derive(PartialEq, Clone, Debug)] +pub struct MappingEntry { + /// Serves two purposes: + /// - This is the message that gets dispatched when the hotkey is matched + /// - This message's discriminant is the action; it must be a currently active action to be considered as a shortcut + pub action: Message, + /// The user input event from an input device which this input mapping matches on + pub input: InputMapperMessage, + /// Any additional keys that must be also pressed for this input mapping to match + pub modifiers: KeyStates, + /// True indicates that this takes priority as the labeled hotkey shown in UI menus and tooltips instead of an alternate binding for the same action + pub canonical: bool, +} + +#[derive(Debug, Clone, Eq, PartialEq, serde::Serialize, serde::Deserialize, specta::Type)] +pub enum ActionKeys { + Action(MessageDiscriminant), + #[serde(rename = "keys")] + Keys(LayoutKeysGroup), +} + +impl ActionKeys { + pub fn to_keys(&mut self, action_input_mapping: &impl Fn(&MessageDiscriminant) -> Option) -> String { + match self { + Self::Action(action) => { + if let Some(keys) = action_input_mapping(action) { + let description = keys.to_string(); + *self = Self::Keys(keys.into()); + description + } else { + *self = Self::Keys(KeysGroup::default().into()); + String::new() + } + } + Self::Keys(keys) => { + warn!("Calling `.to_keys()` on a `ActionKeys::Keys` is a mistake/bug. Keys are: {keys:?}."); + String::new() + } + } + } +} + +#[derive(Copy, Clone, Debug, Default, Eq, PartialEq, serde::Serialize, serde::Deserialize)] +pub struct FrameTimeInfo { + timestamp: Duration, + prev_timestamp: Option, +} + +impl FrameTimeInfo { + pub fn frame_duration(&self) -> Option { + self.prev_timestamp.map(|prev| self.timestamp - prev) + } + + pub fn advance_timestamp(&mut self, next_timestamp: Duration) { + debug_assert!(next_timestamp >= self.timestamp); + + self.prev_timestamp = Some(self.timestamp); + self.timestamp = next_timestamp; + } +} diff --git a/editor/src/messages/input_mapper/utility_types/mod.rs b/editor/src/messages/input_mapper/utility_types/mod.rs new file mode 100644 index 0000000000000000000000000000000000000000..c0b5c8a21b1c317568c5c9a9cb3a2bca7ab01bcb --- /dev/null +++ b/editor/src/messages/input_mapper/utility_types/mod.rs @@ -0,0 +1,4 @@ +pub mod input_keyboard; +pub mod input_mouse; +pub mod macros; +pub mod misc; diff --git a/editor/src/messages/input_preprocessor/input_preprocessor_message.rs b/editor/src/messages/input_preprocessor/input_preprocessor_message.rs new file mode 100644 index 0000000000000000000000000000000000000000..53347542fc0250c7168ad75c0e12c4bf60bff266 --- /dev/null +++ b/editor/src/messages/input_preprocessor/input_preprocessor_message.rs @@ -0,0 +1,17 @@ +use crate::messages::input_mapper::utility_types::input_keyboard::{Key, ModifierKeys}; +use crate::messages::input_mapper::utility_types::input_mouse::{EditorMouseState, ViewportBounds}; +use crate::messages::prelude::*; + +#[impl_message(Message, InputPreprocessor)] +#[derive(PartialEq, Clone, Debug, serde::Serialize, serde::Deserialize)] +pub enum InputPreprocessorMessage { + BoundsOfViewports { bounds_of_viewports: Vec }, + DoubleClick { editor_mouse_state: EditorMouseState, modifier_keys: ModifierKeys }, + KeyDown { key: Key, key_repeat: bool, modifier_keys: ModifierKeys }, + KeyUp { key: Key, key_repeat: bool, modifier_keys: ModifierKeys }, + PointerDown { editor_mouse_state: EditorMouseState, modifier_keys: ModifierKeys }, + PointerMove { editor_mouse_state: EditorMouseState, modifier_keys: ModifierKeys }, + PointerUp { editor_mouse_state: EditorMouseState, modifier_keys: ModifierKeys }, + CurrentTime { timestamp: u64 }, + WheelScroll { editor_mouse_state: EditorMouseState, modifier_keys: ModifierKeys }, +} diff --git a/editor/src/messages/input_preprocessor/input_preprocessor_message_handler.rs b/editor/src/messages/input_preprocessor/input_preprocessor_message_handler.rs new file mode 100644 index 0000000000000000000000000000000000000000..bf90e5881f21a8c4b0338976bd6ff5e7c0ea70d1 --- /dev/null +++ b/editor/src/messages/input_preprocessor/input_preprocessor_message_handler.rs @@ -0,0 +1,304 @@ +use crate::messages::input_mapper::utility_types::input_keyboard::{Key, KeyStates, ModifierKeys}; +use crate::messages::input_mapper::utility_types::input_mouse::{MouseButton, MouseKeys, MouseState, ViewportBounds}; +use crate::messages::input_mapper::utility_types::misc::FrameTimeInfo; +use crate::messages::portfolio::utility_types::KeyboardPlatformLayout; +use crate::messages::prelude::*; +use glam::DVec2; +use std::time::Duration; + +pub struct InputPreprocessorMessageData { + pub keyboard_platform: KeyboardPlatformLayout, +} + +#[derive(Debug, Default)] +pub struct InputPreprocessorMessageHandler { + pub frame_time: FrameTimeInfo, + pub time: u64, + pub keyboard: KeyStates, + pub mouse: MouseState, + pub viewport_bounds: ViewportBounds, +} + +impl MessageHandler for InputPreprocessorMessageHandler { + fn process_message(&mut self, message: InputPreprocessorMessage, responses: &mut VecDeque, data: InputPreprocessorMessageData) { + let InputPreprocessorMessageData { keyboard_platform } = data; + + match message { + InputPreprocessorMessage::BoundsOfViewports { bounds_of_viewports } => { + assert_eq!(bounds_of_viewports.len(), 1, "Only one viewport is currently supported"); + + for bounds in bounds_of_viewports { + // TODO: Extend this to multiple viewports instead of setting it to the value of this last loop iteration + self.viewport_bounds = bounds; + + responses.add(NavigationMessage::CanvasPan { delta: DVec2::ZERO }); + responses.add(NodeGraphMessage::SetGridAlignedEdges); + } + } + InputPreprocessorMessage::DoubleClick { editor_mouse_state, modifier_keys } => { + self.update_states_of_modifier_keys(modifier_keys, keyboard_platform, responses); + + let mouse_state = editor_mouse_state.to_mouse_state(&self.viewport_bounds); + self.mouse.position = mouse_state.position; + + for key in mouse_state.mouse_keys { + responses.add(InputMapperMessage::DoubleClick(match key { + MouseKeys::LEFT => MouseButton::Left, + MouseKeys::RIGHT => MouseButton::Right, + MouseKeys::MIDDLE => MouseButton::Middle, + MouseKeys::BACK => MouseButton::Back, + MouseKeys::FORWARD => MouseButton::Forward, + _ => unimplemented!(), + })); + } + } + InputPreprocessorMessage::KeyDown { key, key_repeat, modifier_keys } => { + self.update_states_of_modifier_keys(modifier_keys, keyboard_platform, responses); + self.keyboard.set(key as usize); + if !key_repeat { + responses.add(InputMapperMessage::KeyDownNoRepeat(key)); + } + responses.add(InputMapperMessage::KeyDown(key)); + } + InputPreprocessorMessage::KeyUp { key, key_repeat, modifier_keys } => { + self.update_states_of_modifier_keys(modifier_keys, keyboard_platform, responses); + self.keyboard.unset(key as usize); + if !key_repeat { + responses.add(InputMapperMessage::KeyUpNoRepeat(key)); + } + responses.add(InputMapperMessage::KeyUp(key)); + } + InputPreprocessorMessage::PointerDown { editor_mouse_state, modifier_keys } => { + self.update_states_of_modifier_keys(modifier_keys, keyboard_platform, responses); + + let mouse_state = editor_mouse_state.to_mouse_state(&self.viewport_bounds); + self.mouse.position = mouse_state.position; + + self.translate_mouse_event(mouse_state, true, responses); + } + InputPreprocessorMessage::PointerMove { editor_mouse_state, modifier_keys } => { + self.update_states_of_modifier_keys(modifier_keys, keyboard_platform, responses); + + let mouse_state = editor_mouse_state.to_mouse_state(&self.viewport_bounds); + self.mouse.position = mouse_state.position; + + responses.add(InputMapperMessage::PointerMove); + + // While any pointer button is already down, additional button down events are not reported, but they are sent as `pointermove` events + self.translate_mouse_event(mouse_state, false, responses); + } + InputPreprocessorMessage::PointerUp { editor_mouse_state, modifier_keys } => { + self.update_states_of_modifier_keys(modifier_keys, keyboard_platform, responses); + + let mouse_state = editor_mouse_state.to_mouse_state(&self.viewport_bounds); + self.mouse.position = mouse_state.position; + + self.translate_mouse_event(mouse_state, false, responses); + } + InputPreprocessorMessage::CurrentTime { timestamp } => { + responses.add(AnimationMessage::SetTime(timestamp as f64)); + self.time = timestamp; + self.frame_time.advance_timestamp(Duration::from_millis(timestamp)); + } + InputPreprocessorMessage::WheelScroll { editor_mouse_state, modifier_keys } => { + self.update_states_of_modifier_keys(modifier_keys, keyboard_platform, responses); + + let mouse_state = editor_mouse_state.to_mouse_state(&self.viewport_bounds); + self.mouse.position = mouse_state.position; + self.mouse.scroll_delta = mouse_state.scroll_delta; + + responses.add(InputMapperMessage::WheelScroll); + } + }; + } + + // Clean user input and if possible reconstruct it. + // Store the changes in the keyboard if it is a key event. + // Transform canvas coordinates to document coordinates. + advertise_actions!(); +} + +impl InputPreprocessorMessageHandler { + fn translate_mouse_event(&mut self, mut new_state: MouseState, allow_first_button_down: bool, responses: &mut VecDeque) { + let click_mappings = [ + (MouseKeys::LEFT, Key::MouseLeft), + (MouseKeys::RIGHT, Key::MouseRight), + (MouseKeys::MIDDLE, Key::MouseMiddle), + (MouseKeys::BACK, Key::MouseBack), + (MouseKeys::FORWARD, Key::MouseForward), + ]; + + for (bit_flag, key) in click_mappings { + // Calculate the intersection between the two key states + let old_down = self.mouse.mouse_keys & bit_flag == bit_flag; + let new_down = new_state.mouse_keys & bit_flag == bit_flag; + if !old_down && new_down { + if allow_first_button_down || self.mouse.mouse_keys != MouseKeys::empty() { + self.keyboard.set(key as usize); + responses.add(InputMapperMessage::KeyDown(key)); + } else { + // Required to stop a keyup being emitted for a keydown outside canvas + new_state.mouse_keys ^= bit_flag; + } + } + if old_down && !new_down { + self.keyboard.unset(key as usize); + responses.add(InputMapperMessage::KeyUp(key)); + } + } + + self.mouse = new_state; + } + + fn update_states_of_modifier_keys(&mut self, pressed_modifier_keys: ModifierKeys, keyboard_platform: KeyboardPlatformLayout, responses: &mut VecDeque) { + let is_key_pressed = |key_to_check: ModifierKeys| pressed_modifier_keys.contains(key_to_check); + + // Update the state of the concrete modifier keys based on the source state + self.update_modifier_key(Key::Shift, is_key_pressed(ModifierKeys::SHIFT), responses); + self.update_modifier_key(Key::Alt, is_key_pressed(ModifierKeys::ALT), responses); + self.update_modifier_key(Key::Control, is_key_pressed(ModifierKeys::CONTROL), responses); + + // Update the state of either the concrete Meta or the Command keys based on which one is applicable for this platform + let meta_or_command = match keyboard_platform { + KeyboardPlatformLayout::Mac => Key::Command, + KeyboardPlatformLayout::Standard => Key::Meta, + }; + self.update_modifier_key(meta_or_command, is_key_pressed(ModifierKeys::META_OR_COMMAND), responses); + + // Update the state of the virtual Accel key (the primary accelerator key) based on the source state of the Control or Command key, whichever is relevant on this platform + let accel_virtual_key_state = match keyboard_platform { + KeyboardPlatformLayout::Mac => is_key_pressed(ModifierKeys::META_OR_COMMAND), + KeyboardPlatformLayout::Standard => is_key_pressed(ModifierKeys::CONTROL), + }; + self.update_modifier_key(Key::Accel, accel_virtual_key_state, responses); + } + + fn update_modifier_key(&mut self, key: Key, key_is_down: bool, responses: &mut VecDeque) { + let key_was_down = self.keyboard.get(key as usize); + + if key_was_down && !key_is_down { + self.keyboard.unset(key as usize); + responses.add(InputMapperMessage::KeyUp(key)); + } else if !key_was_down && key_is_down { + self.keyboard.set(key as usize); + responses.add(InputMapperMessage::KeyDown(key)); + } + } + + pub fn document_bounds(&self) -> [DVec2; 2] { + // IPP bounds are relative to the entire application + [(0., 0.).into(), self.viewport_bounds.bottom_right - self.viewport_bounds.top_left] + } +} + +#[cfg(test)] +mod test { + use crate::messages::input_mapper::utility_types::input_keyboard::{Key, ModifierKeys}; + use crate::messages::input_mapper::utility_types::input_mouse::{EditorMouseState, MouseKeys, ScrollDelta}; + use crate::messages::portfolio::utility_types::KeyboardPlatformLayout; + use crate::messages::prelude::*; + + #[test] + fn process_action_mouse_move_handle_modifier_keys() { + let mut input_preprocessor = InputPreprocessorMessageHandler::default(); + + let editor_mouse_state = EditorMouseState { + editor_position: (4., 809.).into(), + mouse_keys: MouseKeys::default(), + scroll_delta: ScrollDelta::default(), + }; + let modifier_keys = ModifierKeys::ALT; + let message = InputPreprocessorMessage::PointerMove { editor_mouse_state, modifier_keys }; + + let mut responses = VecDeque::new(); + + let data = InputPreprocessorMessageData { + keyboard_platform: KeyboardPlatformLayout::Standard, + }; + input_preprocessor.process_message(message, &mut responses, data); + + assert!(input_preprocessor.keyboard.get(Key::Alt as usize)); + assert_eq!(responses.pop_front(), Some(InputMapperMessage::KeyDown(Key::Alt).into())); + } + + #[test] + fn process_action_mouse_down_handle_modifier_keys() { + let mut input_preprocessor = InputPreprocessorMessageHandler::default(); + + let editor_mouse_state = EditorMouseState::default(); + let modifier_keys = ModifierKeys::CONTROL; + let message = InputPreprocessorMessage::PointerDown { editor_mouse_state, modifier_keys }; + + let mut responses = VecDeque::new(); + + let data = InputPreprocessorMessageData { + keyboard_platform: KeyboardPlatformLayout::Standard, + }; + input_preprocessor.process_message(message, &mut responses, data); + + assert!(input_preprocessor.keyboard.get(Key::Control as usize)); + assert_eq!(responses.pop_front(), Some(InputMapperMessage::KeyDown(Key::Control).into())); + } + + #[test] + fn process_action_mouse_up_handle_modifier_keys() { + let mut input_preprocessor = InputPreprocessorMessageHandler::default(); + + let editor_mouse_state = EditorMouseState::default(); + let modifier_keys = ModifierKeys::SHIFT; + let message = InputPreprocessorMessage::PointerUp { editor_mouse_state, modifier_keys }; + + let mut responses = VecDeque::new(); + + let data = InputPreprocessorMessageData { + keyboard_platform: KeyboardPlatformLayout::Standard, + }; + input_preprocessor.process_message(message, &mut responses, data); + + assert!(input_preprocessor.keyboard.get(Key::Shift as usize)); + assert_eq!(responses.pop_front(), Some(InputMapperMessage::KeyDown(Key::Shift).into())); + } + + #[test] + fn process_action_key_down_handle_modifier_keys() { + let mut input_preprocessor = InputPreprocessorMessageHandler::default(); + input_preprocessor.keyboard.set(Key::Control as usize); + + let key = Key::KeyA; + let key_repeat = false; + let modifier_keys = ModifierKeys::empty(); + let message = InputPreprocessorMessage::KeyDown { key, key_repeat, modifier_keys }; + + let mut responses = VecDeque::new(); + + let data = InputPreprocessorMessageData { + keyboard_platform: KeyboardPlatformLayout::Standard, + }; + input_preprocessor.process_message(message, &mut responses, data); + + assert!(!input_preprocessor.keyboard.get(Key::Control as usize)); + assert_eq!(responses.pop_front(), Some(InputMapperMessage::KeyUp(Key::Control).into())); + } + + #[test] + fn process_action_key_up_handle_modifier_keys() { + let mut input_preprocessor = InputPreprocessorMessageHandler::default(); + + let key = Key::KeyS; + let key_repeat = false; + let modifier_keys = ModifierKeys::CONTROL | ModifierKeys::SHIFT; + let message = InputPreprocessorMessage::KeyUp { key, key_repeat, modifier_keys }; + + let mut responses = VecDeque::new(); + + let data = InputPreprocessorMessageData { + keyboard_platform: KeyboardPlatformLayout::Standard, + }; + input_preprocessor.process_message(message, &mut responses, data); + + assert!(input_preprocessor.keyboard.get(Key::Control as usize)); + assert!(input_preprocessor.keyboard.get(Key::Shift as usize)); + assert!(responses.contains(&InputMapperMessage::KeyDown(Key::Control).into())); + assert!(responses.contains(&InputMapperMessage::KeyDown(Key::Control).into())); + } +} diff --git a/editor/src/messages/input_preprocessor/mod.rs b/editor/src/messages/input_preprocessor/mod.rs new file mode 100644 index 0000000000000000000000000000000000000000..99f44584964265b5ae658112fbaff3fe5007dab4 --- /dev/null +++ b/editor/src/messages/input_preprocessor/mod.rs @@ -0,0 +1,7 @@ +mod input_preprocessor_message; +mod input_preprocessor_message_handler; + +#[doc(inline)] +pub use input_preprocessor_message::{InputPreprocessorMessage, InputPreprocessorMessageDiscriminant}; +#[doc(inline)] +pub use input_preprocessor_message_handler::{InputPreprocessorMessageData, InputPreprocessorMessageHandler}; diff --git a/editor/src/messages/layout/layout_message.rs b/editor/src/messages/layout/layout_message.rs new file mode 100644 index 0000000000000000000000000000000000000000..b18c0055a5071c87e55a2eb36352d23c55a65c0c --- /dev/null +++ b/editor/src/messages/layout/layout_message.rs @@ -0,0 +1,25 @@ +use crate::messages::layout::utility_types::widget_prelude::*; +use crate::messages::prelude::*; + +#[impl_message(Message, Layout)] +#[derive(PartialEq, Clone, Debug, serde::Serialize, serde::Deserialize)] +pub enum LayoutMessage { + ResendActiveWidget { + layout_target: LayoutTarget, + widget_id: WidgetId, + }, + SendLayout { + layout: Layout, + layout_target: LayoutTarget, + }, + WidgetValueCommit { + layout_target: LayoutTarget, + widget_id: WidgetId, + value: serde_json::Value, + }, + WidgetValueUpdate { + layout_target: LayoutTarget, + widget_id: WidgetId, + value: serde_json::Value, + }, +} diff --git a/editor/src/messages/layout/layout_message_handler.rs b/editor/src/messages/layout/layout_message_handler.rs new file mode 100644 index 0000000000000000000000000000000000000000..ee8e506ca87713177203f73711e5829c443a246a --- /dev/null +++ b/editor/src/messages/layout/layout_message_handler.rs @@ -0,0 +1,446 @@ +use crate::messages::input_mapper::utility_types::input_keyboard::KeysGroup; +use crate::messages::layout::utility_types::widget_prelude::*; +use crate::messages::prelude::*; +use graphene_std::raster::color::Color; +use graphene_std::text::Font; +use graphene_std::vector::style::{FillChoice, GradientStops}; +use serde_json::Value; + +#[derive(Debug, Clone, Default)] +pub struct LayoutMessageHandler { + layouts: [Layout; LayoutTarget::LayoutTargetLength as usize], +} + +enum WidgetValueAction { + Commit, + Update, +} + +impl LayoutMessageHandler { + /// Get the widget path for the widget with the specified id + fn get_widget_path(widget_layout: &WidgetLayout, widget_id: WidgetId) -> Option<(&WidgetHolder, Vec)> { + let mut stack = widget_layout.layout.iter().enumerate().map(|(index, val)| (vec![index], val)).collect::>(); + while let Some((mut widget_path, group)) = stack.pop() { + match group { + // Check if any of the widgets in the current column or row have the correct id + LayoutGroup::Column { widgets } | LayoutGroup::Row { widgets } => { + for (index, widget) in widgets.iter().enumerate() { + // Return if this is the correct ID + if widget.widget_id == widget_id { + widget_path.push(index); + return Some((widget, widget_path)); + } + + if let Widget::PopoverButton(popover) = &widget.widget { + stack.extend(popover.popover_layout.iter().enumerate().map(|(child, val)| ([widget_path.as_slice(), &[index, child]].concat(), val))); + } + } + } + // A section contains more LayoutGroups which we add to the stack. + LayoutGroup::Section { layout, .. } => { + stack.extend(layout.iter().enumerate().map(|(index, val)| ([widget_path.as_slice(), &[index]].concat(), val))); + } + + LayoutGroup::Table { rows } => { + for (row_index, cell) in rows.iter().enumerate() { + for (cell_index, entry) in cell.iter().enumerate() { + // Return if this is the correct ID + if entry.widget_id == widget_id { + widget_path.push(row_index); + widget_path.push(cell_index); + return Some((entry, widget_path)); + } + + if let Widget::PopoverButton(popover) = &entry.widget { + stack.extend( + popover + .popover_layout + .iter() + .enumerate() + .map(|(child, val)| ([widget_path.as_slice(), &[row_index, cell_index, child]].concat(), val)), + ); + } + } + } + } + } + } + None + } + + fn handle_widget_callback(&mut self, layout_target: LayoutTarget, widget_id: WidgetId, value: Value, action: WidgetValueAction, responses: &mut std::collections::VecDeque) { + let Some(layout) = self.layouts.get_mut(layout_target as usize) else { + warn!("handle_widget_callback was called referencing an invalid layout. `widget_id: {widget_id}`, `layout_target: {layout_target:?}`",); + return; + }; + + let Some(widget_holder) = layout.iter_mut().find(|widget| widget.widget_id == widget_id) else { + warn!("handle_widget_callback was called referencing an invalid widget ID, although the layout target was valid. `widget_id: {widget_id}`, `layout_target: {layout_target:?}`",); + return; + }; + + match &mut widget_holder.widget { + Widget::BreadcrumbTrailButtons(breadcrumb_trail_buttons) => { + let callback_message = match action { + WidgetValueAction::Commit => (breadcrumb_trail_buttons.on_commit.callback)(&()), + WidgetValueAction::Update => { + let update_value = value.as_u64().expect("BreadcrumbTrailButtons update was not of type: u64"); + (breadcrumb_trail_buttons.on_update.callback)(&update_value) + } + }; + responses.add(callback_message); + } + Widget::CheckboxInput(checkbox_input) => { + let callback_message = match action { + WidgetValueAction::Commit => (checkbox_input.on_commit.callback)(&()), + WidgetValueAction::Update => { + let update_value = value.as_bool().expect("CheckboxInput update was not of type: bool"); + checkbox_input.checked = update_value; + (checkbox_input.on_update.callback)(checkbox_input) + } + }; + responses.add(callback_message); + } + Widget::ColorInput(color_button) => { + let callback_message = match action { + WidgetValueAction::Commit => (color_button.on_commit.callback)(&()), + WidgetValueAction::Update => { + // Decodes the colors in gamma, not linear + let decode_color = |color: &serde_json::map::Map| -> Option { + let red = color.get("red").and_then(|x| x.as_f64()).map(|x| x as f32); + let green = color.get("green").and_then(|x| x.as_f64()).map(|x| x as f32); + let blue = color.get("blue").and_then(|x| x.as_f64()).map(|x| x as f32); + let alpha = color.get("alpha").and_then(|x| x.as_f64()).map(|x| x as f32); + + if let (Some(red), Some(green), Some(blue), Some(alpha)) = (red, green, blue, alpha) { + if let Some(color) = Color::from_rgbaf32(red, green, blue, alpha) { + return Some(color); + } + } + None + }; + + (|| { + let Some(update_value) = value.as_object() else { + warn!("ColorInput update was not of type: object"); + return Message::NoOp; + }; + + // None + let is_none = update_value.get("none").and_then(|x| x.as_bool()); + if is_none == Some(true) { + color_button.value = FillChoice::None; + return (color_button.on_update.callback)(color_button); + } + + // Solid + if let Some(color) = decode_color(update_value) { + color_button.value = FillChoice::Solid(color); + return (color_button.on_update.callback)(color_button); + } + + // Gradient + let gradient = update_value.get("stops").and_then(|x| x.as_array()); + if let Some(stops) = gradient { + let gradient_stops = stops + .iter() + .filter_map(|stop| { + stop.as_object().and_then(|stop| { + let position = stop.get("position").and_then(|x| x.as_f64()); + let color = stop.get("color").and_then(|x| x.as_object()).and_then(decode_color); + if let (Some(position), Some(color)) = (position, color) { Some((position, color)) } else { None } + }) + }) + .collect::>(); + + color_button.value = FillChoice::Gradient(GradientStops::new(gradient_stops)); + return (color_button.on_update.callback)(color_button); + } + + warn!("ColorInput update was not able to be parsed with color data: {color_button:?}"); + Message::NoOp + })() + } + }; + + responses.add(callback_message); + } + Widget::CurveInput(curve_input) => { + let callback_message = match action { + WidgetValueAction::Commit => (curve_input.on_commit.callback)(&()), + WidgetValueAction::Update => { + let curve = serde_json::from_value(value).expect("CurveInput event data could not be deserialized"); + curve_input.value = curve; + (curve_input.on_update.callback)(curve_input) + } + }; + + responses.add(callback_message); + } + Widget::DropdownInput(dropdown_input) => { + let callback_message = match action { + WidgetValueAction::Commit => { + let update_value = value.as_u64().unwrap_or_else(|| panic!("DropdownInput commit was not of type `u64`, found {value:?}")); + (dropdown_input.entries.iter().flatten().nth(update_value as usize).unwrap().on_commit.callback)(&()) + } + WidgetValueAction::Update => { + let update_value = value.as_u64().unwrap_or_else(|| panic!("DropdownInput update was not of type `u64`, found {value:?}")); + dropdown_input.selected_index = Some(update_value as u32); + (dropdown_input.entries.iter().flatten().nth(update_value as usize).unwrap().on_update.callback)(&()) + } + }; + + responses.add(callback_message); + } + Widget::FontInput(font_input) => { + let callback_message = match action { + WidgetValueAction::Commit => (font_input.on_commit.callback)(&()), + WidgetValueAction::Update => { + let update_value = value.as_object().expect("FontInput update was not of type: object"); + let font_family_value = update_value.get("fontFamily").expect("FontInput update does not have a fontFamily"); + let font_style_value = update_value.get("fontStyle").expect("FontInput update does not have a fontStyle"); + + let font_family = font_family_value.as_str().expect("FontInput update fontFamily was not of type: string"); + let font_style = font_style_value.as_str().expect("FontInput update fontStyle was not of type: string"); + + font_input.font_family = font_family.into(); + font_input.font_style = font_style.into(); + + responses.add(PortfolioMessage::LoadFont { + font: Font::new(font_family.into(), font_style.into()), + }); + (font_input.on_update.callback)(font_input) + } + }; + + responses.add(callback_message); + } + Widget::IconButton(icon_button) => { + let callback_message = match action { + WidgetValueAction::Commit => (icon_button.on_commit.callback)(&()), + WidgetValueAction::Update => (icon_button.on_update.callback)(icon_button), + }; + + responses.add(callback_message); + } + Widget::ImageButton(image_label) => { + let callback_message = match action { + WidgetValueAction::Commit => (image_label.on_commit.callback)(&()), + WidgetValueAction::Update => (image_label.on_update.callback)(&()), + }; + + responses.add(callback_message); + } + Widget::IconLabel(_) => {} + Widget::InvisibleStandinInput(invisible) => { + let callback_message = match action { + WidgetValueAction::Commit => (invisible.on_commit.callback)(&()), + WidgetValueAction::Update => (invisible.on_update.callback)(&()), + }; + + responses.add(callback_message); + } + Widget::NodeCatalog(node_type_input) => match action { + WidgetValueAction::Commit => { + let callback_message = (node_type_input.on_commit.callback)(&()); + responses.add(callback_message); + } + WidgetValueAction::Update => { + let value = value.as_str().expect("NodeCatalog update was not of type String").to_string(); + let callback_message = (node_type_input.on_update.callback)(&value); + responses.add(callback_message); + } + }, + Widget::NumberInput(number_input) => match action { + WidgetValueAction::Commit => { + let callback_message = (number_input.on_commit.callback)(&()); + responses.add(callback_message); + } + WidgetValueAction::Update => match value { + Value::Number(num) => { + let update_value = num.as_f64().unwrap(); + number_input.value = Some(update_value); + let callback_message = (number_input.on_update.callback)(number_input); + responses.add(callback_message); + } + // TODO: This crashes when the cursor is in a text box, such as in the Text node, and the transform node is clicked (https://github.com/GraphiteEditor/Graphite/issues/1761) + Value::String(str) => match str.as_str() { + "Increment" => responses.add((number_input.increment_callback_increase.callback)(number_input)), + "Decrement" => responses.add((number_input.increment_callback_decrease.callback)(number_input)), + _ => panic!("Invalid string found when updating `NumberInput`"), + }, + _ => {} + }, + }, + Widget::ParameterExposeButton(parameter_expose_button) => { + let callback_message = match action { + WidgetValueAction::Commit => (parameter_expose_button.on_commit.callback)(&()), + WidgetValueAction::Update => (parameter_expose_button.on_update.callback)(parameter_expose_button), + }; + + responses.add(callback_message); + } + Widget::ReferencePointInput(reference_point_input) => { + let callback_message = match action { + WidgetValueAction::Commit => (reference_point_input.on_commit.callback)(&()), + WidgetValueAction::Update => { + let update_value = value.as_str().expect("ReferencePointInput update was not of type: u64"); + reference_point_input.value = update_value.into(); + (reference_point_input.on_update.callback)(reference_point_input) + } + }; + + responses.add(callback_message); + } + Widget::PopoverButton(_) => {} + Widget::RadioInput(radio_input) => { + let update_value = value.as_u64().expect("RadioInput update was not of type: u64"); + radio_input.selected_index = Some(update_value as u32); + let callback_message = match action { + WidgetValueAction::Commit => (radio_input.entries[update_value as usize].on_commit.callback)(&()), + WidgetValueAction::Update => (radio_input.entries[update_value as usize].on_update.callback)(&()), + }; + + responses.add(callback_message); + } + Widget::Separator(_) => {} + Widget::TextAreaInput(text_area_input) => { + let callback_message = match action { + WidgetValueAction::Commit => (text_area_input.on_commit.callback)(&()), + WidgetValueAction::Update => { + let update_value = value.as_str().expect("TextAreaInput update was not of type: string"); + text_area_input.value = update_value.into(); + (text_area_input.on_update.callback)(text_area_input) + } + }; + + responses.add(callback_message); + } + Widget::TextButton(text_button) => { + let callback_message = match action { + WidgetValueAction::Commit => (text_button.on_commit.callback)(&()), + WidgetValueAction::Update => (text_button.on_update.callback)(text_button), + }; + + responses.add(callback_message); + } + Widget::TextInput(text_input) => { + let callback_message = match action { + WidgetValueAction::Commit => (text_input.on_commit.callback)(&()), + WidgetValueAction::Update => { + let update_value = value.as_str().expect("TextInput update was not of type: string"); + text_input.value = update_value.into(); + (text_input.on_update.callback)(text_input) + } + }; + + responses.add(callback_message); + } + Widget::TextLabel(_) => {} + Widget::WorkingColorsInput(_) => {} + }; + } +} + +impl Option> MessageHandler for LayoutMessageHandler { + fn process_message(&mut self, message: LayoutMessage, responses: &mut std::collections::VecDeque, action_input_mapping: F) { + match message { + LayoutMessage::ResendActiveWidget { layout_target, widget_id } => { + // Find the updated diff based on the specified layout target + let Some(diff) = (match &self.layouts[layout_target as usize] { + Layout::MenuLayout(_) => return, + Layout::WidgetLayout(layout) => Self::get_widget_path(layout, widget_id).map(|(widget, widget_path)| { + // Create a widget update diff for the relevant id + let new_value = DiffUpdate::Widget(widget.clone()); + WidgetDiff { widget_path, new_value } + }), + }) else { + return; + }; + // Resend that diff + self.send_diff(vec![diff], layout_target, responses, &action_input_mapping); + } + LayoutMessage::SendLayout { layout, layout_target } => { + self.diff_and_send_layout_to_frontend(layout_target, layout, responses, &action_input_mapping); + } + LayoutMessage::WidgetValueCommit { layout_target, widget_id, value } => { + self.handle_widget_callback(layout_target, widget_id, value, WidgetValueAction::Commit, responses); + } + LayoutMessage::WidgetValueUpdate { layout_target, widget_id, value } => { + self.handle_widget_callback(layout_target, widget_id, value, WidgetValueAction::Update, responses); + responses.add(LayoutMessage::ResendActiveWidget { layout_target, widget_id }); + } + } + } + + fn actions(&self) -> ActionList { + actions!(LayoutMessageDiscriminant;) + } +} + +impl LayoutMessageHandler { + /// Diff the update and send to the frontend where necessary + fn diff_and_send_layout_to_frontend( + &mut self, + layout_target: LayoutTarget, + new_layout: Layout, + responses: &mut VecDeque, + action_input_mapping: &impl Fn(&MessageDiscriminant) -> Option, + ) { + match new_layout { + Layout::WidgetLayout(_) => { + let mut widget_diffs = Vec::new(); + self.layouts[layout_target as usize].diff(new_layout, &mut Vec::new(), &mut widget_diffs); + + // Skip sending if no diff. + if widget_diffs.is_empty() { + return; + } + + self.send_diff(widget_diffs, layout_target, responses, action_input_mapping); + } + // We don't diff the menu bar layout yet. + Layout::MenuLayout(_) => { + // Skip update if the same + if self.layouts[layout_target as usize] == new_layout { + return; + } + + // Update the backend storage + self.layouts[layout_target as usize] = new_layout; + + // Update the UI + responses.add(FrontendMessage::UpdateMenuBarLayout { + layout_target, + layout: self.layouts[layout_target as usize].clone().unwrap_menu_layout(action_input_mapping).layout, + }); + } + } + } + + /// Send a diff to the frontend based on the layout target. + fn send_diff(&self, mut diff: Vec, layout_target: LayoutTarget, responses: &mut VecDeque, action_input_mapping: &impl Fn(&MessageDiscriminant) -> Option) { + diff.iter_mut().for_each(|diff| diff.new_value.apply_keyboard_shortcut(action_input_mapping)); + + let message = match layout_target { + LayoutTarget::DialogButtons => FrontendMessage::UpdateDialogButtons { layout_target, diff }, + LayoutTarget::DialogColumn1 => FrontendMessage::UpdateDialogColumn1 { layout_target, diff }, + LayoutTarget::DialogColumn2 => FrontendMessage::UpdateDialogColumn2 { layout_target, diff }, + LayoutTarget::DocumentBar => FrontendMessage::UpdateDocumentBarLayout { layout_target, diff }, + LayoutTarget::DocumentMode => FrontendMessage::UpdateDocumentModeLayout { layout_target, diff }, + LayoutTarget::LayersPanelControlLeftBar => FrontendMessage::UpdateLayersPanelControlBarLeftLayout { layout_target, diff }, + LayoutTarget::LayersPanelControlRightBar => FrontendMessage::UpdateLayersPanelControlBarRightLayout { layout_target, diff }, + LayoutTarget::LayersPanelBottomBar => FrontendMessage::UpdateLayersPanelBottomBarLayout { layout_target, diff }, + LayoutTarget::MenuBar => unreachable!("Menu bar is not diffed"), + LayoutTarget::NodeGraphControlBar => FrontendMessage::UpdateNodeGraphControlBarLayout { layout_target, diff }, + LayoutTarget::PropertiesSections => FrontendMessage::UpdatePropertyPanelSectionsLayout { layout_target, diff }, + LayoutTarget::Spreadsheet => FrontendMessage::UpdateSpreadsheetLayout { layout_target, diff }, + LayoutTarget::ToolOptions => FrontendMessage::UpdateToolOptionsLayout { layout_target, diff }, + LayoutTarget::ToolShelf => FrontendMessage::UpdateToolShelfLayout { layout_target, diff }, + LayoutTarget::WorkingColors => FrontendMessage::UpdateWorkingColorsLayout { layout_target, diff }, + + LayoutTarget::LayoutTargetLength => panic!("`LayoutTargetLength` is not a valid Layout Target and is used for array indexing"), + }; + responses.add(message); + } +} diff --git a/editor/src/messages/layout/mod.rs b/editor/src/messages/layout/mod.rs new file mode 100644 index 0000000000000000000000000000000000000000..bd148eb7651e82d5832deb066f65ccba8769d3e8 --- /dev/null +++ b/editor/src/messages/layout/mod.rs @@ -0,0 +1,9 @@ +mod layout_message; +mod layout_message_handler; + +pub mod utility_types; + +#[doc(inline)] +pub use layout_message::{LayoutMessage, LayoutMessageDiscriminant}; +#[doc(inline)] +pub use layout_message_handler::LayoutMessageHandler; diff --git a/editor/src/messages/layout/utility_types/layout_widget.rs b/editor/src/messages/layout/utility_types/layout_widget.rs new file mode 100644 index 0000000000000000000000000000000000000000..8802915e46f2355f6a1710b45213cfa4e1f998ef --- /dev/null +++ b/editor/src/messages/layout/utility_types/layout_widget.rs @@ -0,0 +1,661 @@ +use super::widgets::button_widgets::*; +use super::widgets::input_widgets::*; +use super::widgets::label_widgets::*; +use super::widgets::menu_widgets::MenuLayout; +use crate::application::generate_uuid; +use crate::messages::input_mapper::utility_types::input_keyboard::KeysGroup; +use crate::messages::input_mapper::utility_types::misc::ActionKeys; +use crate::messages::prelude::*; +use std::sync::Arc; + +#[repr(transparent)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, serde::Serialize, serde::Deserialize, specta::Type)] +pub struct WidgetId(pub u64); + +impl core::fmt::Display for WidgetId { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + write!(f, "{}", self.0) + } +} + +#[derive(PartialEq, Clone, Debug, Hash, Eq, Copy, serde::Serialize, serde::Deserialize, specta::Type)] +#[repr(u8)] +pub enum LayoutTarget { + /// Contains the action buttons at the bottom of the dialog. Must be shown with the `FrontendMessage::DisplayDialog` message. + DialogButtons, + /// Contains the contents of the dialog's primary column. Must be shown with the `FrontendMessage::DisplayDialog` message. + DialogColumn1, + /// Contains the contents of the dialog's secondary column (often blank). Must be shown with the `FrontendMessage::DisplayDialog` message. + DialogColumn2, + /// Contains the widgets located directly above the canvas to the right, for example the zoom in and out buttons. + DocumentBar, + /// Contains the dropdown for design / select / guide mode found on the top left of the canvas. + DocumentMode, + /// Blending options at the top of the Layers panel. + LayersPanelControlLeftBar, + /// Selected layer status (locked/hidden) at the top of the Layers panel. + LayersPanelControlRightBar, + /// Controls for adding, grouping, and deleting layers at the bottom of the Layers panel. + LayersPanelBottomBar, + /// The dropdown menu at the very top of the application: File, Edit, etc. + MenuBar, + /// Bar at the top of the node graph containing the location and the "Preview" and "Hide" buttons. + NodeGraphControlBar, + /// The body of the Properties panel containing many collapsable sections. + PropertiesSections, + /// The spredsheet panel allows for the visualisation of data in the graph. + Spreadsheet, + /// The bar directly above the canvas, left-aligned and to the right of the document mode dropdown. + ToolOptions, + /// The vertical buttons for all of the tools on the left of the canvas. + ToolShelf, + /// The color swatch for the working colors and a flip and reset button found at the bottom of the tool shelf. + WorkingColors, + + // KEEP THIS ENUM LAST + // This is a marker that is used to define an array that is used to hold widgets + LayoutTargetLength, +} + +/// For use by structs that define a UI widget layout by implementing the layout() function belonging to this trait. +/// The send_layout() function can then be called by other code which is a part of the same struct so as to send the layout to the frontend. +pub trait LayoutHolder { + fn layout(&self) -> Layout; + + fn send_layout(&self, responses: &mut VecDeque, layout_target: LayoutTarget) { + responses.add(LayoutMessage::SendLayout { layout: self.layout(), layout_target }); + } +} + +/// Structs implementing this hold the layout (like [`LayoutHolder`]) for dialog content, but it also requires defining the dialog's title, icon, and action buttons. +pub trait DialogLayoutHolder: LayoutHolder { + const ICON: &'static str; + const TITLE: &'static str; + + fn layout_buttons(&self) -> Layout; + fn send_layout_buttons(&self, responses: &mut VecDeque, layout_target: LayoutTarget) { + responses.add(LayoutMessage::SendLayout { + layout: self.layout_buttons(), + layout_target, + }); + } + + fn layout_column_2(&self) -> Layout { + Layout::default() + } + fn send_layout_column_2(&self, responses: &mut VecDeque, layout_target: LayoutTarget) { + responses.add(LayoutMessage::SendLayout { + layout: self.layout_column_2(), + layout_target, + }); + } + + fn send_dialog_to_frontend(&self, responses: &mut VecDeque) { + self.send_layout(responses, LayoutTarget::DialogColumn1); + self.send_layout_column_2(responses, LayoutTarget::DialogColumn2); + self.send_layout_buttons(responses, LayoutTarget::DialogButtons); + responses.add(FrontendMessage::DisplayDialog { + icon: Self::ICON.into(), + title: Self::TITLE.into(), + }); + } +} + +/// Wraps a choice of layout type. The chosen layout contains an arrangement of widgets mounted somewhere specific in the frontend. +#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize, specta::Type)] +pub enum Layout { + WidgetLayout(WidgetLayout), + MenuLayout(MenuLayout), +} + +impl Layout { + pub fn unwrap_menu_layout(self, action_input_mapping: &impl Fn(&MessageDiscriminant) -> Option) -> MenuLayout { + if let Self::MenuLayout(mut menu) = self { + menu.layout + .iter_mut() + .for_each(|menu_column| menu_column.children.fill_in_shortcut_actions_with_keys(action_input_mapping)); + menu + } else { + panic!("Called unwrap_menu_layout on a widget layout"); + } + } + + pub fn iter(&self) -> Box + '_> { + match self { + Layout::MenuLayout(menu_layout) => Box::new(menu_layout.iter()), + Layout::WidgetLayout(widget_layout) => Box::new(widget_layout.iter()), + } + } + + pub fn iter_mut(&mut self) -> Box + '_> { + match self { + Layout::MenuLayout(menu_layout) => Box::new(menu_layout.iter_mut()), + Layout::WidgetLayout(widget_layout) => Box::new(widget_layout.iter_mut()), + } + } + + /// Diffing updates self (where self is old) based on new, updating the list of modifications as it does so. + pub fn diff(&mut self, new: Self, widget_path: &mut Vec, widget_diffs: &mut Vec) { + match (self, new) { + // Simply diff the internal layout + (Self::WidgetLayout(current), Self::WidgetLayout(new)) => current.diff(new, widget_path, widget_diffs), + (current, Self::WidgetLayout(widget_layout)) => { + // Update current to the new value + *current = Self::WidgetLayout(widget_layout.clone()); + + // Push an update sublayout value + let new_value = DiffUpdate::SubLayout(widget_layout.layout); + let widget_path = widget_path.to_vec(); + widget_diffs.push(WidgetDiff { widget_path, new_value }); + } + (_, Self::MenuLayout(_)) => panic!("Cannot diff menu layout"), + } + } +} + +impl Default for Layout { + fn default() -> Self { + Self::WidgetLayout(WidgetLayout::default()) + } +} + +#[derive(Debug, Default, Clone, serde::Serialize, serde::Deserialize, PartialEq, specta::Type)] +pub struct WidgetLayout { + pub layout: SubLayout, +} + +impl WidgetLayout { + pub fn new(layout: SubLayout) -> Self { + Self { layout } + } + + pub fn iter(&self) -> WidgetIter<'_> { + WidgetIter { + stack: self.layout.iter().collect(), + ..Default::default() + } + } + + pub fn iter_mut(&mut self) -> WidgetIterMut<'_> { + WidgetIterMut { + stack: self.layout.iter_mut().collect(), + ..Default::default() + } + } + + /// Diffing updates self (where self is old) based on new, updating the list of modifications as it does so. + pub fn diff(&mut self, new: Self, widget_path: &mut Vec, widget_diffs: &mut Vec) { + // Check if the length of items is different + // TODO: Diff insersion and deletion of items + if self.layout.len() != new.layout.len() { + // Update the layout to the new layout + self.layout.clone_from(&new.layout); + + // Push an update sublayout to the diff + let new = DiffUpdate::SubLayout(new.layout); + widget_diffs.push(WidgetDiff { + widget_path: widget_path.to_vec(), + new_value: new, + }); + return; + } + // Diff all of the children + for (index, (current_child, new_child)) in self.layout.iter_mut().zip(new.layout).enumerate() { + widget_path.push(index); + current_child.diff(new_child, widget_path, widget_diffs); + widget_path.pop(); + } + } +} + +#[derive(Debug, Default)] +pub struct WidgetIter<'a> { + pub stack: Vec<&'a LayoutGroup>, + pub table: Vec<&'a WidgetHolder>, + pub current_slice: Option<&'a [WidgetHolder]>, +} + +impl<'a> Iterator for WidgetIter<'a> { + type Item = &'a WidgetHolder; + + fn next(&mut self) -> Option { + let widget = self.table.pop().or_else(|| { + let (first, rest) = self.current_slice.take()?.split_first()?; + self.current_slice = Some(rest); + Some(first) + }); + + if let Some(item) = widget { + if let WidgetHolder { widget: Widget::PopoverButton(p), .. } = item { + self.stack.extend(p.popover_layout.iter()); + return self.next(); + } + + return Some(item); + } + + match self.stack.pop() { + Some(LayoutGroup::Column { widgets }) => { + self.current_slice = Some(widgets); + self.next() + } + Some(LayoutGroup::Row { widgets }) => { + self.current_slice = Some(widgets); + self.next() + } + Some(LayoutGroup::Table { rows }) => { + self.table.extend(rows.iter().flatten().rev()); + self.next() + } + Some(LayoutGroup::Section { layout, .. }) => { + for layout_row in layout { + self.stack.push(layout_row); + } + self.next() + } + None => None, + } + } +} + +#[derive(Debug, Default)] +pub struct WidgetIterMut<'a> { + pub stack: Vec<&'a mut LayoutGroup>, + pub table: Vec<&'a mut WidgetHolder>, + pub current_slice: Option<&'a mut [WidgetHolder]>, +} + +impl<'a> Iterator for WidgetIterMut<'a> { + type Item = &'a mut WidgetHolder; + + fn next(&mut self) -> Option { + let widget = self.table.pop().or_else(|| { + let (first, rest) = self.current_slice.take()?.split_first_mut()?; + self.current_slice = Some(rest); + Some(first) + }); + + if let Some(widget) = widget { + if let WidgetHolder { widget: Widget::PopoverButton(p), .. } = widget { + self.stack.extend(p.popover_layout.iter_mut()); + return self.next(); + } + + return Some(widget); + } + + match self.stack.pop() { + Some(LayoutGroup::Column { widgets }) => { + self.current_slice = Some(widgets); + self.next() + } + Some(LayoutGroup::Row { widgets }) => { + self.current_slice = Some(widgets); + self.next() + } + Some(LayoutGroup::Table { rows }) => { + self.table.extend(rows.iter_mut().flatten().rev()); + self.next() + } + Some(LayoutGroup::Section { layout, .. }) => { + for layout_row in layout { + self.stack.push(layout_row); + } + self.next() + } + None => None, + } + } +} + +pub type SubLayout = Vec; + +#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize, specta::Type)] +pub enum LayoutGroup { + #[serde(rename = "column")] + Column { + #[serde(rename = "columnWidgets")] + widgets: Vec, + }, + #[serde(rename = "row")] + Row { + #[serde(rename = "rowWidgets")] + widgets: Vec, + }, + #[serde(rename = "table")] + Table { + #[serde(rename = "tableWidgets")] + rows: Vec>, + }, + // TODO: Move this from being a child of `enum LayoutGroup` to being a child of `enum Layout` + #[serde(rename = "section")] + Section { + name: String, + description: String, + visible: bool, + pinned: bool, + id: u64, + layout: SubLayout, + }, +} + +impl Default for LayoutGroup { + fn default() -> Self { + Self::Row { widgets: Vec::new() } + } +} +impl From> for LayoutGroup { + fn from(widgets: Vec) -> LayoutGroup { + LayoutGroup::Row { widgets } + } +} + +impl LayoutGroup { + /// Applies a tooltip to all widgets in this row or column without a tooltip. + pub fn with_tooltip(self, tooltip: impl Into) -> Self { + let (is_col, mut widgets) = match self { + LayoutGroup::Column { widgets } => (true, widgets), + LayoutGroup::Row { widgets } => (false, widgets), + _ => unimplemented!(), + }; + let tooltip = tooltip.into(); + for widget in &mut widgets { + let val = match &mut widget.widget { + Widget::CheckboxInput(x) => &mut x.tooltip, + Widget::ColorInput(x) => &mut x.tooltip, + Widget::CurveInput(x) => &mut x.tooltip, + Widget::DropdownInput(x) => &mut x.tooltip, + Widget::FontInput(x) => &mut x.tooltip, + Widget::IconButton(x) => &mut x.tooltip, + Widget::IconLabel(x) => &mut x.tooltip, + Widget::ImageButton(x) => &mut x.tooltip, + Widget::NumberInput(x) => &mut x.tooltip, + Widget::ParameterExposeButton(x) => &mut x.tooltip, + Widget::PopoverButton(x) => &mut x.tooltip, + Widget::TextAreaInput(x) => &mut x.tooltip, + Widget::TextButton(x) => &mut x.tooltip, + Widget::TextInput(x) => &mut x.tooltip, + Widget::TextLabel(x) => &mut x.tooltip, + Widget::BreadcrumbTrailButtons(x) => &mut x.tooltip, + Widget::InvisibleStandinInput(_) | Widget::ReferencePointInput(_) | Widget::RadioInput(_) | Widget::Separator(_) | Widget::WorkingColorsInput(_) | Widget::NodeCatalog(_) => continue, + }; + if val.is_empty() { + val.clone_from(&tooltip); + } + } + if is_col { Self::Column { widgets } } else { Self::Row { widgets } } + } + + /// Diffing updates self (where self is old) based on new, updating the list of modifications as it does so. + pub fn diff(&mut self, new: Self, widget_path: &mut Vec, widget_diffs: &mut Vec) { + let is_column = matches!(new, Self::Column { .. }); + match (self, new) { + (Self::Column { widgets: current_widgets }, Self::Column { widgets: new_widgets }) | (Self::Row { widgets: current_widgets }, Self::Row { widgets: new_widgets }) => { + // If the lengths are different then resend the entire panel + // TODO: Diff insersion and deletion of items + if current_widgets.len() != new_widgets.len() { + // Update to the new value + current_widgets.clone_from(&new_widgets); + + // Push back a LayoutGroup update to the diff + let new_value = DiffUpdate::LayoutGroup(if is_column { Self::Column { widgets: new_widgets } } else { Self::Row { widgets: new_widgets } }); + let widget_path = widget_path.to_vec(); + widget_diffs.push(WidgetDiff { widget_path, new_value }); + return; + } + // Diff all of the children + for (index, (current_child, new_child)) in current_widgets.iter_mut().zip(new_widgets).enumerate() { + widget_path.push(index); + current_child.diff(new_child, widget_path, widget_diffs); + widget_path.pop(); + } + } + ( + Self::Section { + name: current_name, + description: current_description, + visible: current_visible, + pinned: current_pinned, + id: current_id, + layout: current_layout, + }, + Self::Section { + name: new_name, + description: new_description, + visible: new_visible, + pinned: new_pinned, + id: new_id, + layout: new_layout, + }, + ) => { + // Resend the entire panel if the lengths, names, visibility, or node IDs are different + // TODO: Diff insersion and deletion of items + if current_layout.len() != new_layout.len() + || *current_name != new_name + || *current_description != new_description + || *current_visible != new_visible + || *current_pinned != new_pinned + || *current_id != new_id + { + // Update self to reflect new changes + current_name.clone_from(&new_name); + current_description.clone_from(&new_description); + *current_visible = new_visible; + *current_pinned = new_pinned; + *current_id = new_id; + current_layout.clone_from(&new_layout); + + // Push an update layout group to the diff + let new_value = DiffUpdate::LayoutGroup(Self::Section { + name: new_name, + description: new_description, + visible: new_visible, + pinned: new_pinned, + id: new_id, + layout: new_layout, + }); + let widget_path = widget_path.to_vec(); + widget_diffs.push(WidgetDiff { widget_path, new_value }); + } + // Diff all of the children + else { + for (index, (current_child, new_child)) in current_layout.iter_mut().zip(new_layout).enumerate() { + widget_path.push(index); + current_child.diff(new_child, widget_path, widget_diffs); + widget_path.pop(); + } + } + } + (current, new) => { + *current = new.clone(); + let new_value = DiffUpdate::LayoutGroup(new); + let widget_path = widget_path.to_vec(); + widget_diffs.push(WidgetDiff { widget_path, new_value }); + } + } + } + + pub fn iter_mut(&mut self) -> WidgetIterMut<'_> { + WidgetIterMut { + stack: vec![self], + ..Default::default() + } + } +} + +#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize, specta::Type)] +pub struct WidgetHolder { + #[serde(rename = "widgetId")] + pub widget_id: WidgetId, + pub widget: Widget, +} + +impl WidgetHolder { + #[deprecated(since = "0.0.0", note = "Please use the builder pattern, e.g. TextLabel::new(\"hello\").widget_holder()")] + pub fn new(widget: Widget) -> Self { + Self { + widget_id: WidgetId(generate_uuid()), + widget, + } + } + + /// Diffing updates self (where self is old) based on new, updating the list of modifications as it does so. + pub fn diff(&mut self, new: Self, widget_path: &mut [usize], widget_diffs: &mut Vec) { + // If there have been changes to the actual widget (not just the id) + if self.widget != new.widget { + // We should update to the new widget value as well as a new widget id + *self = new.clone(); + + // Push a widget update to the diff + let new_value = DiffUpdate::Widget(new); + let widget_path = widget_path.to_vec(); + widget_diffs.push(WidgetDiff { widget_path, new_value }); + } else { + // Required to update the callback function, which the PartialEq check above skips + self.widget = new.widget; + } + } +} + +#[derive(Clone, specta::Type)] +pub struct WidgetCallback { + #[specta(skip)] + pub callback: Arc Message + 'static + Send + Sync>, +} + +impl WidgetCallback { + pub fn new(callback: impl Fn(&T) -> Message + 'static + Send + Sync) -> Self { + Self { callback: Arc::new(callback) } + } +} + +impl Default for WidgetCallback { + fn default() -> Self { + Self::new(|_| Message::NoOp) + } +} + +#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize, specta::Type)] +pub enum Widget { + BreadcrumbTrailButtons(BreadcrumbTrailButtons), + CheckboxInput(CheckboxInput), + ColorInput(ColorInput), + CurveInput(CurveInput), + DropdownInput(DropdownInput), + FontInput(FontInput), + IconButton(IconButton), + IconLabel(IconLabel), + ImageButton(ImageButton), + InvisibleStandinInput(InvisibleStandinInput), + NodeCatalog(NodeCatalog), + NumberInput(NumberInput), + ParameterExposeButton(ParameterExposeButton), + ReferencePointInput(ReferencePointInput), + PopoverButton(PopoverButton), + RadioInput(RadioInput), + Separator(Separator), + TextAreaInput(TextAreaInput), + TextButton(TextButton), + TextInput(TextInput), + TextLabel(TextLabel), + WorkingColorsInput(WorkingColorsInput), +} + +/// A single change to part of the UI, containing the location of the change and the new value. +#[derive(PartialEq, Clone, Debug, serde::Serialize, serde::Deserialize, specta::Type)] +pub struct WidgetDiff { + /// A path to the change + /// e.g. [0, 1, 2] in the properties panel is the first section, second row and third widget. + /// An empty path [] shows that the entire panel has changed and is sent when the UI is first created. + #[serde(rename = "widgetPath")] + pub widget_path: Vec, + /// What the specified part of the UI has changed to. + #[serde(rename = "newValue")] + pub new_value: DiffUpdate, +} + +/// The new value of the UI, sent as part of a diff. +/// +/// An update can represent a single widget or an entire SubLayout, or just a single layout group. +#[derive(PartialEq, Clone, Debug, serde::Serialize, serde::Deserialize, specta::Type)] +pub enum DiffUpdate { + #[serde(rename = "subLayout")] + SubLayout(SubLayout), + #[serde(rename = "layoutGroup")] + LayoutGroup(LayoutGroup), + #[serde(rename = "widget")] + Widget(WidgetHolder), +} + +impl DiffUpdate { + /// Append the keyboard shortcut to the tooltip where applicable + pub fn apply_keyboard_shortcut(&mut self, action_input_mapping: &impl Fn(&MessageDiscriminant) -> Option) { + // Function used multiple times later in this code block to convert `ActionKeys::Action` to `ActionKeys::Keys` and append its shortcut to the tooltip + let apply_shortcut_to_tooltip = |tooltip_shortcut: &mut ActionKeys, tooltip: &mut String| { + let shortcut_text = tooltip_shortcut.to_keys(action_input_mapping); + + if let ActionKeys::Keys(_keys) = tooltip_shortcut { + if !shortcut_text.is_empty() { + if !tooltip.is_empty() { + tooltip.push(' '); + } + tooltip.push('('); + tooltip.push_str(&shortcut_text); + tooltip.push(')'); + } + } + }; + + // Go through each widget to convert `ActionKeys::Action` to `ActionKeys::Keys` and append the key combination to the widget tooltip + let convert_tooltip = |widget_holder: &mut WidgetHolder| { + // Handle all the widgets that have tooltips + let mut tooltip_shortcut = match &mut widget_holder.widget { + Widget::BreadcrumbTrailButtons(widget) => Some((&mut widget.tooltip, &mut widget.tooltip_shortcut)), + Widget::CheckboxInput(widget) => Some((&mut widget.tooltip, &mut widget.tooltip_shortcut)), + Widget::ColorInput(widget) => Some((&mut widget.tooltip, &mut widget.tooltip_shortcut)), + Widget::DropdownInput(widget) => Some((&mut widget.tooltip, &mut widget.tooltip_shortcut)), + Widget::FontInput(widget) => Some((&mut widget.tooltip, &mut widget.tooltip_shortcut)), + Widget::IconButton(widget) => Some((&mut widget.tooltip, &mut widget.tooltip_shortcut)), + Widget::NumberInput(widget) => Some((&mut widget.tooltip, &mut widget.tooltip_shortcut)), + Widget::ParameterExposeButton(widget) => Some((&mut widget.tooltip, &mut widget.tooltip_shortcut)), + Widget::PopoverButton(widget) => Some((&mut widget.tooltip, &mut widget.tooltip_shortcut)), + Widget::TextButton(widget) => Some((&mut widget.tooltip, &mut widget.tooltip_shortcut)), + Widget::ImageButton(widget) => Some((&mut widget.tooltip, &mut widget.tooltip_shortcut)), + Widget::IconLabel(_) + | Widget::CurveInput(_) + | Widget::InvisibleStandinInput(_) + | Widget::NodeCatalog(_) + | Widget::ReferencePointInput(_) + | Widget::RadioInput(_) + | Widget::Separator(_) + | Widget::TextAreaInput(_) + | Widget::TextInput(_) + | Widget::TextLabel(_) + | Widget::WorkingColorsInput(_) => None, + }; + if let Some((tooltip, Some(tooltip_shortcut))) = &mut tooltip_shortcut { + apply_shortcut_to_tooltip(tooltip_shortcut, tooltip); + } + + // Handle RadioInput separately because its tooltips are children of the widget + if let Widget::RadioInput(radio_input) = &mut widget_holder.widget { + for radio_entry_data in &mut radio_input.entries { + if let RadioEntryData { + tooltip, + tooltip_shortcut: Some(tooltip_shortcut), + .. + } = radio_entry_data + { + apply_shortcut_to_tooltip(tooltip_shortcut, tooltip); + } + } + } + }; + + match self { + Self::SubLayout(sub_layout) => sub_layout.iter_mut().flat_map(|group| group.iter_mut()).for_each(convert_tooltip), + Self::LayoutGroup(layout_group) => layout_group.iter_mut().for_each(convert_tooltip), + Self::Widget(widget_holder) => convert_tooltip(widget_holder), + } + } +} diff --git a/editor/src/messages/layout/utility_types/mod.rs b/editor/src/messages/layout/utility_types/mod.rs new file mode 100644 index 0000000000000000000000000000000000000000..8408d0b1b814bdd71e1e6cb44fd347fe7a77d52e --- /dev/null +++ b/editor/src/messages/layout/utility_types/mod.rs @@ -0,0 +1,10 @@ +pub mod layout_widget; +pub mod widgets; + +pub mod widget_prelude { + pub use super::layout_widget::*; + pub use super::widgets::button_widgets::*; + pub use super::widgets::input_widgets::*; + pub use super::widgets::label_widgets::*; + pub use super::widgets::menu_widgets::*; +} diff --git a/editor/src/messages/layout/utility_types/widgets/button_widgets.rs b/editor/src/messages/layout/utility_types/widgets/button_widgets.rs new file mode 100644 index 0000000000000000000000000000000000000000..54fbc92056f48595f84790efb2c6bc5246bd5127 --- /dev/null +++ b/editor/src/messages/layout/utility_types/widgets/button_widgets.rs @@ -0,0 +1,221 @@ +use crate::messages::input_mapper::utility_types::misc::ActionKeys; +use crate::messages::layout::utility_types::widget_prelude::*; +use crate::messages::portfolio::document::node_graph::utility_types::FrontendGraphDataType; +use crate::messages::tool::tool_messages::tool_prelude::WidgetCallback; +use derivative::*; +use graphene_std::vector::style::FillChoice; +use graphite_proc_macros::WidgetBuilder; + +#[derive(Clone, Default, Derivative, serde::Serialize, serde::Deserialize, WidgetBuilder, specta::Type)] +#[derivative(Debug, PartialEq)] +pub struct IconButton { + #[widget_builder(constructor)] + pub icon: String, + + #[serde(rename = "hoverIcon")] + pub hover_icon: Option, + + #[widget_builder(constructor)] + pub size: u32, // TODO: Convert to an `IconSize` enum + + pub disabled: bool, + + pub active: bool, + + pub tooltip: String, + + #[serde(skip)] + pub tooltip_shortcut: Option, + + // Callbacks + #[serde(skip)] + #[derivative(Debug = "ignore", PartialEq = "ignore")] + pub on_update: WidgetCallback, + + #[serde(skip)] + #[derivative(Debug = "ignore", PartialEq = "ignore")] + pub on_commit: WidgetCallback<()>, +} + +#[derive(Clone, serde::Serialize, serde::Deserialize, Derivative, WidgetBuilder, specta::Type)] +#[derivative(Debug, PartialEq, Default)] +pub struct PopoverButton { + pub style: Option, + + #[serde(rename = "menuDirection")] + pub menu_direction: Option, + + pub icon: Option, + + pub disabled: bool, + + pub tooltip: String, + + #[serde(skip)] + pub tooltip_shortcut: Option, + + #[serde(rename = "popoverLayout")] + pub popover_layout: SubLayout, + + #[serde(rename = "popoverMinWidth")] + pub popover_min_width: Option, +} + +#[derive(Clone, Default, Debug, PartialEq, serde::Serialize, serde::Deserialize, specta::Type)] +pub enum MenuDirection { + Top, + #[default] + Bottom, + Left, + Right, + TopLeft, + TopRight, + BottomLeft, + BottomRight, + Center, +} + +#[derive(Clone, serde::Serialize, serde::Deserialize, Derivative, Default, WidgetBuilder, specta::Type)] +#[derivative(Debug, PartialEq)] +pub struct ParameterExposeButton { + pub exposed: bool, + + #[serde(rename = "dataType")] + pub data_type: FrontendGraphDataType, + + pub tooltip: String, + + #[serde(skip)] + pub tooltip_shortcut: Option, + + // Callbacks + #[serde(skip)] + #[derivative(Debug = "ignore", PartialEq = "ignore")] + pub on_update: WidgetCallback, + + #[serde(skip)] + #[derivative(Debug = "ignore", PartialEq = "ignore")] + pub on_commit: WidgetCallback<()>, +} + +#[derive(Clone, serde::Serialize, serde::Deserialize, Derivative, Default, WidgetBuilder, specta::Type)] +#[derivative(Debug, PartialEq)] +pub struct TextButton { + #[widget_builder(constructor)] + pub label: String, + + pub icon: Option, + + #[serde(rename = "hoverIcon")] + pub hover_icon: Option, + + pub flush: bool, + + pub emphasized: bool, + + #[serde(rename = "minWidth")] + pub min_width: u32, + + pub disabled: bool, + + pub tooltip: String, + + #[serde(skip)] + pub tooltip_shortcut: Option, + + #[serde(rename = "menuListChildren")] + pub menu_list_children: MenuListEntrySections, + + // Callbacks + #[serde(skip)] + #[derivative(Debug = "ignore", PartialEq = "ignore")] + pub on_update: WidgetCallback, + + #[serde(skip)] + #[derivative(Debug = "ignore", PartialEq = "ignore")] + pub on_commit: WidgetCallback<()>, +} + +#[derive(Clone, serde::Serialize, serde::Deserialize, Derivative, Default, WidgetBuilder, specta::Type)] +#[derivative(Debug, PartialEq)] +pub struct ImageButton { + #[widget_builder(constructor)] + pub image: String, + + pub width: Option, + + pub height: Option, + + pub tooltip: String, + + #[serde(skip)] + pub tooltip_shortcut: Option, + + // Callbacks + #[serde(skip)] + #[derivative(Debug = "ignore", PartialEq = "ignore")] + pub on_update: WidgetCallback<()>, + + #[serde(skip)] + #[derivative(Debug = "ignore", PartialEq = "ignore")] + pub on_commit: WidgetCallback<()>, +} + +#[derive(Clone, Derivative, serde::Serialize, serde::Deserialize, WidgetBuilder, specta::Type)] +#[derivative(Debug, PartialEq, Default)] +pub struct ColorInput { + /// WARNING: The colors are gamma, not linear! + #[widget_builder(constructor)] + pub value: FillChoice, + + pub disabled: bool, + + // TODO: Implement + // #[serde(rename = "allowTransparency")] + // #[derivative(Default(value = "false"))] + // pub allow_transparency: bool, + // + #[serde(rename = "allowNone")] + #[derivative(Default(value = "true"))] + pub allow_none: bool, + + // TODO: Implement + // pub disabled: bool, + // + pub tooltip: String, + + #[serde(skip)] + pub tooltip_shortcut: Option, + + // Callbacks + #[serde(skip)] + #[derivative(Debug = "ignore", PartialEq = "ignore")] + pub on_update: WidgetCallback, + + #[serde(skip)] + #[derivative(Debug = "ignore", PartialEq = "ignore")] + pub on_commit: WidgetCallback<()>, +} + +#[derive(Clone, serde::Serialize, serde::Deserialize, Derivative, Default, WidgetBuilder, specta::Type)] +#[derivative(Debug, PartialEq)] +pub struct BreadcrumbTrailButtons { + #[widget_builder(constructor)] + pub labels: Vec, + + pub disabled: bool, + + pub tooltip: String, + + #[serde(skip)] + pub tooltip_shortcut: Option, + + // Callbacks + #[serde(skip)] + #[derivative(Debug = "ignore", PartialEq = "ignore")] + pub on_update: WidgetCallback, + + #[serde(skip)] + #[derivative(Debug = "ignore", PartialEq = "ignore")] + pub on_commit: WidgetCallback<()>, +} diff --git a/editor/src/messages/layout/utility_types/widgets/input_widgets.rs b/editor/src/messages/layout/utility_types/widgets/input_widgets.rs new file mode 100644 index 0000000000000000000000000000000000000000..b76f23a067c8fa0f007050c824cc16c1584df66e --- /dev/null +++ b/editor/src/messages/layout/utility_types/widgets/input_widgets.rs @@ -0,0 +1,482 @@ +use crate::messages::input_mapper::utility_types::misc::ActionKeys; +use crate::messages::layout::utility_types::widget_prelude::*; +use derivative::*; +use graphene_std::Color; +use graphene_std::raster::curve::Curve; +use graphene_std::transform::ReferencePoint; +use graphite_proc_macros::WidgetBuilder; +use once_cell::sync::OnceCell; +use std::sync::Arc; + +#[derive(Clone, Derivative, serde::Serialize, serde::Deserialize, WidgetBuilder, specta::Type)] +#[derivative(Debug, PartialEq)] +pub struct CheckboxInput { + #[widget_builder(constructor)] + pub checked: bool, + + pub disabled: bool, + + pub icon: String, + + pub tooltip: String, + + #[serde(rename = "forLabel", skip_serializing_if = "checkbox_id_is_empty")] + pub for_label: CheckboxId, + + #[serde(skip)] + pub tooltip_shortcut: Option, + + // Callbacks + #[serde(skip)] + #[derivative(Debug = "ignore", PartialEq = "ignore")] + pub on_update: WidgetCallback, + + #[serde(skip)] + #[derivative(Debug = "ignore", PartialEq = "ignore")] + pub on_commit: WidgetCallback<()>, +} + +impl Default for CheckboxInput { + fn default() -> Self { + Self { + checked: false, + disabled: false, + icon: "Checkmark".into(), + tooltip: Default::default(), + tooltip_shortcut: Default::default(), + for_label: CheckboxId::default(), + on_update: Default::default(), + on_commit: Default::default(), + } + } +} + +#[derive(Clone, Default, Debug, Eq, PartialEq)] +pub struct CheckboxId(Arc>); + +impl CheckboxId { + pub fn fill(&mut self) { + let _ = self.0.set(graphene_std::uuid::generate_uuid()); + } +} +impl specta::Type for CheckboxId { + fn inline(_type_map: &mut specta::TypeCollection, _generics: specta::Generics) -> specta::datatype::DataType { + // TODO: This might not be right, but it works for now. We just need the type `bigint | undefined`. + specta::datatype::DataType::Primitive(specta::datatype::PrimitiveType::u64) + } +} +impl serde::Serialize for CheckboxId { + fn serialize(&self, serializer: S) -> Result + where + S: serde::Serializer, + { + self.0.get().copied().serialize(serializer) + } +} +impl<'a> serde::Deserialize<'a> for CheckboxId { + fn deserialize(deserializer: D) -> Result + where + D: serde::Deserializer<'a>, + { + let id = u64::deserialize(deserializer)?; + let checkbox_id = CheckboxId(OnceCell::new().into()); + checkbox_id.0.set(id).map_err(serde::de::Error::custom)?; + Ok(checkbox_id) + } +} + +fn checkbox_id_is_empty(id: &CheckboxId) -> bool { + id.0.get().is_none() +} + +#[derive(Clone, serde::Serialize, serde::Deserialize, Derivative, WidgetBuilder, specta::Type)] +#[derivative(Debug, PartialEq, Default)] +pub struct DropdownInput { + #[widget_builder(constructor)] + pub entries: MenuListEntrySections, + + // This uses `u32` instead of `usize` since it will be serialized as a normal JS number (replace this with `usize` after switching to a Rust-based GUI) + #[serde(rename = "selectedIndex")] + pub selected_index: Option, + + #[serde(rename = "drawIcon")] + pub draw_icon: bool, + + #[derivative(Default(value = "true"))] + pub interactive: bool, + + pub disabled: bool, + + pub tooltip: String, + + #[serde(skip)] + pub tooltip_shortcut: Option, + + // Styling + #[serde(rename = "minWidth")] + pub min_width: u32, + + #[serde(rename = "maxWidth")] + pub max_width: u32, + // + // Callbacks + // `on_update` exists on the `MenuListEntry`, not this parent `DropdownInput` +} + +pub type MenuListEntrySections = Vec>; + +#[derive(Clone, serde::Serialize, serde::Deserialize, Derivative, Default, WidgetBuilder, specta::Type)] +#[derivative(Debug, PartialEq)] +#[widget_builder(not_widget_holder)] +pub struct MenuListEntry { + #[widget_builder(constructor)] + pub value: String, + + pub label: String, + + pub icon: String, + + pub shortcut: Vec, + + #[serde(rename = "shortcutRequiresLock")] + pub shortcut_requires_lock: bool, + + pub disabled: bool, + + pub children: MenuListEntrySections, + + // Callbacks + #[serde(skip)] + #[derivative(Debug = "ignore", PartialEq = "ignore")] + pub on_update: WidgetCallback<()>, + + #[serde(skip)] + #[derivative(Debug = "ignore", PartialEq = "ignore")] + pub on_commit: WidgetCallback<()>, +} + +#[derive(Clone, serde::Serialize, serde::Deserialize, Derivative, WidgetBuilder, specta::Type)] +#[derivative(Debug, PartialEq, Default)] +pub struct FontInput { + #[serde(rename = "fontFamily")] + #[widget_builder(constructor)] + pub font_family: String, + + #[serde(rename = "fontStyle")] + #[widget_builder(constructor)] + pub font_style: String, + + #[serde(rename = "isStyle")] + pub is_style_picker: bool, + + pub disabled: bool, + + pub tooltip: String, + + #[serde(skip)] + pub tooltip_shortcut: Option, + + // Callbacks + #[serde(skip)] + #[derivative(Debug = "ignore", PartialEq = "ignore")] + pub on_update: WidgetCallback, + + #[serde(skip)] + #[derivative(Debug = "ignore", PartialEq = "ignore")] + pub on_commit: WidgetCallback<()>, +} + +/// This widget allows for the flexible use of the layout system. +/// In a custom layout, one can define a widget that is just used to trigger code on the backend. +/// This is used in MenuLayout to pipe the triggering of messages from the frontend to backend. +#[derive(Clone, serde::Serialize, serde::Deserialize, Derivative, Default, WidgetBuilder, specta::Type)] +#[derivative(Debug, PartialEq)] +pub struct InvisibleStandinInput { + #[serde(skip)] + #[derivative(Debug = "ignore", PartialEq = "ignore")] + pub on_update: WidgetCallback<()>, + + #[serde(skip)] + #[derivative(Debug = "ignore", PartialEq = "ignore")] + pub on_commit: WidgetCallback<()>, +} + +#[derive(Clone, serde::Serialize, serde::Deserialize, Derivative, WidgetBuilder, specta::Type)] +#[derivative(Debug, PartialEq, Default)] +pub struct NumberInput { + // Label + pub label: String, + + pub tooltip: String, + + #[serde(skip)] + pub tooltip_shortcut: Option, + + // Disabled + pub disabled: bool, + + // Value + #[widget_builder(constructor)] + pub value: Option, + + #[widget_builder(skip)] + pub min: Option, + + #[widget_builder(skip)] + pub max: Option, + + #[serde(rename = "isInteger")] + pub is_integer: bool, + + // Number presentation + #[serde(rename = "displayDecimalPlaces")] + #[derivative(Default(value = "2"))] + pub display_decimal_places: u32, + + pub unit: String, + + #[serde(rename = "unitIsHiddenWhenEditing")] + #[derivative(Default(value = "true"))] + pub unit_is_hidden_when_editing: bool, + + // Mode behavior + pub mode: NumberInputMode, + + #[serde(rename = "incrementBehavior")] + pub increment_behavior: NumberInputIncrementBehavior, + + #[derivative(Default(value = "1."))] + pub step: f64, + + // TODO: Make this (and range_max) apply to both Range and Increment modes when dragging with the mouse + #[serde(rename = "rangeMin")] + pub range_min: Option, + + #[serde(rename = "rangeMax")] + pub range_max: Option, + + // Styling + #[serde(rename = "minWidth")] + pub min_width: u32, + + #[serde(rename = "maxWidth")] + pub max_width: u32, + + // Callbacks + #[serde(skip)] + #[derivative(Debug = "ignore", PartialEq = "ignore")] + pub increment_callback_increase: WidgetCallback, + + #[serde(skip)] + #[derivative(Debug = "ignore", PartialEq = "ignore")] + pub increment_callback_decrease: WidgetCallback, + + #[serde(skip)] + #[derivative(Debug = "ignore", PartialEq = "ignore")] + pub on_update: WidgetCallback, + + #[serde(skip)] + #[derivative(Debug = "ignore", PartialEq = "ignore")] + pub on_commit: WidgetCallback<()>, +} + +impl NumberInput { + pub fn int(mut self) -> Self { + self.is_integer = true; + self + } + pub fn min(mut self, val: f64) -> Self { + self.min = Some(val); + self.range_min = Some(val); + self + } + pub fn max(mut self, val: f64) -> Self { + self.max = Some(val); + self.range_max = Some(val); + self + } + pub fn mode_range(mut self) -> Self { + self.mode = NumberInputMode::Range; + self + } + pub fn mode_increment(mut self) -> Self { + self.mode = NumberInputMode::Increment; + self + } + pub fn increment_step(mut self, step: f64) -> Self { + self.step = step; + self + } + pub fn percentage(self) -> Self { + self.min(0.).max(100.).mode_range().unit("%").display_decimal_places(2) + } +} + +#[derive(Clone, serde::Serialize, serde::Deserialize, Debug, Default, PartialEq, Eq, specta::Type)] +pub enum NumberInputIncrementBehavior { + #[default] + Add, + Multiply, + Callback, +} + +#[derive(Clone, serde::Serialize, serde::Deserialize, Debug, Default, PartialEq, Eq, specta::Type)] +pub enum NumberInputMode { + #[default] + Increment, + Range, +} + +#[derive(Clone, serde::Serialize, serde::Deserialize, Derivative, WidgetBuilder, specta::Type)] +#[derivative(Debug, PartialEq, Default)] +pub struct NodeCatalog { + pub disabled: bool, + + // Callbacks + #[serde(skip)] + #[derivative(Debug = "ignore", PartialEq = "ignore")] + pub on_update: WidgetCallback, + + #[serde(skip)] + #[derivative(Debug = "ignore", PartialEq = "ignore")] + pub on_commit: WidgetCallback<()>, +} + +#[derive(Clone, Default, Derivative, serde::Serialize, serde::Deserialize, WidgetBuilder, specta::Type)] +#[derivative(Debug, PartialEq)] +pub struct RadioInput { + #[widget_builder(constructor)] + pub entries: Vec, + + pub disabled: bool, + + // This uses `u32` instead of `usize` since it will be serialized as a normal JS number (replace this with `usize` after switching to a Rust-based GUI) + #[serde(rename = "selectedIndex")] + pub selected_index: Option, + + #[serde(rename = "minWidth")] + pub min_width: u32, +} + +#[derive(Clone, Default, Derivative, serde::Serialize, serde::Deserialize, WidgetBuilder, specta::Type)] +#[derivative(Debug, PartialEq)] +#[widget_builder(not_widget_holder)] +pub struct RadioEntryData { + #[widget_builder(constructor)] + pub value: String, + + pub label: String, + + pub icon: String, + + pub tooltip: String, + + #[serde(skip)] + pub tooltip_shortcut: Option, + + // Callbacks + #[serde(skip)] + #[derivative(Debug = "ignore", PartialEq = "ignore")] + pub on_update: WidgetCallback<()>, + + #[serde(skip)] + #[derivative(Debug = "ignore", PartialEq = "ignore")] + pub on_commit: WidgetCallback<()>, +} + +#[derive(Clone, serde::Serialize, serde::Deserialize, Derivative, WidgetBuilder, specta::Type)] +#[derivative(Debug, PartialEq, Default)] +pub struct WorkingColorsInput { + #[widget_builder(constructor)] + pub primary: Color, + + #[widget_builder(constructor)] + pub secondary: Color, +} + +#[derive(Clone, serde::Serialize, serde::Deserialize, Derivative, WidgetBuilder, specta::Type)] +#[derivative(Debug, PartialEq, Default)] +pub struct TextAreaInput { + #[widget_builder(constructor)] + pub value: String, + + pub label: Option, + + pub disabled: bool, + + pub tooltip: String, + + // Callbacks + #[serde(skip)] + #[derivative(Debug = "ignore", PartialEq = "ignore")] + pub on_update: WidgetCallback, + + #[serde(skip)] + #[derivative(Debug = "ignore", PartialEq = "ignore")] + pub on_commit: WidgetCallback<()>, +} + +#[derive(Clone, serde::Serialize, serde::Deserialize, Derivative, WidgetBuilder, specta::Type)] +#[derivative(Debug, PartialEq, Default)] +pub struct TextInput { + #[widget_builder(constructor)] + pub value: String, + + pub label: Option, + + pub disabled: bool, + + pub tooltip: String, + + pub centered: bool, + + #[serde(rename = "minWidth")] + pub min_width: u32, + + // Callbacks + #[serde(skip)] + #[derivative(Debug = "ignore", PartialEq = "ignore")] + pub on_update: WidgetCallback, + + #[serde(skip)] + #[derivative(Debug = "ignore", PartialEq = "ignore")] + pub on_commit: WidgetCallback<()>, +} + +#[derive(Clone, serde::Serialize, serde::Deserialize, Derivative, WidgetBuilder, specta::Type)] +#[derivative(Debug, PartialEq, Default)] +pub struct CurveInput { + #[widget_builder(constructor)] + pub value: Curve, + + pub disabled: bool, + + pub tooltip: String, + + // Callbacks + #[serde(skip)] + #[derivative(Debug = "ignore", PartialEq = "ignore")] + pub on_update: WidgetCallback, + + #[serde(skip)] + #[derivative(Debug = "ignore", PartialEq = "ignore")] + pub on_commit: WidgetCallback<()>, +} + +#[derive(Clone, Default, Derivative, serde::Serialize, serde::Deserialize, WidgetBuilder, specta::Type)] +#[derivative(Debug, PartialEq)] +pub struct ReferencePointInput { + #[widget_builder(constructor)] + pub value: ReferencePoint, + + pub disabled: bool, + + // Callbacks + #[serde(skip)] + #[derivative(Debug = "ignore", PartialEq = "ignore")] + pub on_update: WidgetCallback, + + #[serde(skip)] + #[derivative(Debug = "ignore", PartialEq = "ignore")] + pub on_commit: WidgetCallback<()>, +} diff --git a/editor/src/messages/layout/utility_types/widgets/label_widgets.rs b/editor/src/messages/layout/utility_types/widgets/label_widgets.rs new file mode 100644 index 0000000000000000000000000000000000000000..caeca5a4e10454876cd652dc89b1d0cf22c9fdf0 --- /dev/null +++ b/editor/src/messages/layout/utility_types/widgets/label_widgets.rs @@ -0,0 +1,77 @@ +use super::input_widgets::CheckboxId; +use derivative::*; +use graphite_proc_macros::WidgetBuilder; + +#[derive(Clone, serde::Serialize, serde::Deserialize, Derivative, Debug, Default, PartialEq, Eq, WidgetBuilder, specta::Type)] +pub struct IconLabel { + #[widget_builder(constructor)] + pub icon: String, + + pub disabled: bool, + + pub tooltip: String, +} + +#[derive(Debug, Clone, Default, PartialEq, Eq, serde::Serialize, serde::Deserialize, WidgetBuilder, specta::Type)] +pub struct Separator { + pub direction: SeparatorDirection, + + #[serde(rename = "type")] + #[widget_builder(constructor)] + pub separator_type: SeparatorType, +} + +#[derive(Debug, Clone, Default, PartialEq, Eq, serde::Serialize, serde::Deserialize, specta::Type)] +pub enum SeparatorDirection { + #[default] + Horizontal, + Vertical, +} + +#[derive(Debug, Clone, Default, PartialEq, Eq, serde::Serialize, serde::Deserialize, specta::Type)] +pub enum SeparatorType { + Related, + #[default] + Unrelated, + Section, +} + +#[derive(Clone, serde::Serialize, serde::Deserialize, Derivative, Debug, PartialEq, Eq, Default, WidgetBuilder, specta::Type)] +pub struct TextLabel { + pub disabled: bool, + + pub bold: bool, + + pub italic: bool, + + #[serde(rename = "centerAlign")] + pub center_align: bool, + + #[serde(rename = "tableAlign")] + pub table_align: bool, + + pub multiline: bool, + + #[serde(rename = "minWidth")] + pub min_width: u32, + + pub tooltip: String, + + #[serde(rename = "checkboxId")] + #[widget_builder(skip)] + pub checkbox_id: CheckboxId, + + // Body + #[widget_builder(constructor)] + pub value: String, +} + +impl TextLabel { + pub fn for_checkbox(mut self, id: &mut CheckboxId) -> Self { + id.fill(); + self.checkbox_id = id.clone(); + self + } +} + +// TODO: Add UserInputLabel diff --git a/editor/src/messages/layout/utility_types/widgets/menu_widgets.rs b/editor/src/messages/layout/utility_types/widgets/menu_widgets.rs new file mode 100644 index 0000000000000000000000000000000000000000..e96009d067ac2b3ee80c6ad8abaf8912ea1c68ed --- /dev/null +++ b/editor/src/messages/layout/utility_types/widgets/menu_widgets.rs @@ -0,0 +1,131 @@ +use super::input_widgets::InvisibleStandinInput; +use crate::messages::input_mapper::utility_types::input_keyboard::KeysGroup; +use crate::messages::input_mapper::utility_types::misc::ActionKeys; +use crate::messages::layout::utility_types::widget_prelude::*; +use crate::messages::prelude::*; + +#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, PartialEq, Default, specta::Type)] +pub struct MenuBarEntryChildren(pub Vec>); + +impl MenuBarEntryChildren { + pub fn empty() -> Self { + Self(Vec::new()) + } + + pub fn fill_in_shortcut_actions_with_keys(&mut self, action_input_mapping: &impl Fn(&MessageDiscriminant) -> Option) { + let entries = self.0.iter_mut().flatten(); + + for entry in entries { + if let Some(action_keys) = &mut entry.shortcut { + action_keys.to_keys(action_input_mapping); + } + + // Recursively do this for the children also + entry.children.fill_in_shortcut_actions_with_keys(action_input_mapping); + } + } +} + +#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, PartialEq, specta::Type)] +pub struct MenuBarEntry { + pub label: String, + pub icon: Option, + pub shortcut: Option, + pub action: WidgetHolder, + pub children: MenuBarEntryChildren, + pub disabled: bool, +} + +impl MenuBarEntry { + pub fn new_root(label: String, disabled: bool, children: MenuBarEntryChildren) -> Self { + Self { + label, + disabled, + children, + ..Default::default() + } + } + + pub fn create_action(callback: impl Fn(&()) -> Message + 'static + Send + Sync) -> WidgetHolder { + InvisibleStandinInput::new().on_update(callback).widget_holder() + } + + pub fn no_action() -> WidgetHolder { + MenuBarEntry::create_action(|_| Message::NoOp) + } +} + +impl Default for MenuBarEntry { + fn default() -> Self { + Self { + label: "".into(), + icon: None, + shortcut: None, + action: MenuBarEntry::no_action(), + children: MenuBarEntryChildren::empty(), + disabled: false, + } + } +} + +#[derive(Debug, Default, Clone, PartialEq, serde::Serialize, serde::Deserialize, specta::Type)] +pub struct MenuLayout { + pub layout: Vec, +} + +impl MenuLayout { + pub fn new(layout: Vec) -> Self { + Self { layout } + } + + pub fn iter(&self) -> impl Iterator + '_ { + MenuLayoutIter { stack: self.layout.iter().collect() } + } + + pub fn iter_mut(&mut self) -> impl Iterator + '_ { + MenuLayoutIterMut { + stack: self.layout.iter_mut().collect(), + } + } +} + +#[derive(Debug, Default)] +pub struct MenuLayoutIter<'a> { + pub stack: Vec<&'a MenuBarEntry>, +} + +impl<'a> Iterator for MenuLayoutIter<'a> { + type Item = &'a WidgetHolder; + + fn next(&mut self) -> Option { + match self.stack.pop() { + Some(menu_entry) => { + let more_entries = menu_entry.children.0.iter().flat_map(|entry| entry.iter()); + self.stack.extend(more_entries); + + Some(&menu_entry.action) + } + None => None, + } + } +} + +pub struct MenuLayoutIterMut<'a> { + pub stack: Vec<&'a mut MenuBarEntry>, +} + +impl<'a> Iterator for MenuLayoutIterMut<'a> { + type Item = &'a mut WidgetHolder; + + fn next(&mut self) -> Option { + match self.stack.pop() { + Some(menu_entry) => { + let more_entries = menu_entry.children.0.iter_mut().flat_map(|entry| entry.iter_mut()); + self.stack.extend(more_entries); + + Some(&mut menu_entry.action) + } + None => None, + } + } +} diff --git a/editor/src/messages/layout/utility_types/widgets/mod.rs b/editor/src/messages/layout/utility_types/widgets/mod.rs new file mode 100644 index 0000000000000000000000000000000000000000..922029633c9e90fde9ab86153830116c66065054 --- /dev/null +++ b/editor/src/messages/layout/utility_types/widgets/mod.rs @@ -0,0 +1,4 @@ +pub mod button_widgets; +pub mod input_widgets; +pub mod label_widgets; +pub mod menu_widgets; diff --git a/editor/src/messages/message.rs b/editor/src/messages/message.rs new file mode 100644 index 0000000000000000000000000000000000000000..80323d9309a68c17e409b62c37442327133e21c1 --- /dev/null +++ b/editor/src/messages/message.rs @@ -0,0 +1,47 @@ +use crate::messages::prelude::*; +use graphite_proc_macros::*; + +#[impl_message] +#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize)] +pub enum Message { + NoOp, + Init, + Batched(Box<[Message]>), + StartBuffer, + EndBuffer(graphene_std::renderer::RenderMetadata), + + #[child] + Animation(AnimationMessage), + #[child] + Broadcast(BroadcastMessage), + #[child] + Debug(DebugMessage), + #[child] + Dialog(DialogMessage), + #[child] + Frontend(FrontendMessage), + #[child] + Globals(GlobalsMessage), + #[child] + InputPreprocessor(InputPreprocessorMessage), + #[child] + KeyMapping(KeyMappingMessage), + #[child] + Layout(LayoutMessage), + #[child] + Portfolio(PortfolioMessage), + #[child] + Preferences(PreferencesMessage), + #[child] + Tool(ToolMessage), + #[child] + Workspace(WorkspaceMessage), +} + +/// Provides an impl of `specta::Type` for `MessageDiscriminant`, the struct created by `impl_message`. +/// Specta isn't integrated with `impl_message`, so a remote impl must be provided using this struct. +impl specta::Type for MessageDiscriminant { + fn inline(_type_map: &mut specta::TypeCollection, _generics: specta::Generics) -> specta::DataType { + specta::DataType::Any + } +} diff --git a/editor/src/messages/mod.rs b/editor/src/messages/mod.rs new file mode 100644 index 0000000000000000000000000000000000000000..7b43a4010813a0f407933a3e108193b632c83850 --- /dev/null +++ b/editor/src/messages/mod.rs @@ -0,0 +1,17 @@ +//! The root-level messages forming the first layer of the message system architecture. + +pub mod animation; +pub mod broadcast; +pub mod debug; +pub mod dialog; +pub mod frontend; +pub mod globals; +pub mod input_mapper; +pub mod input_preprocessor; +pub mod layout; +pub mod message; +pub mod portfolio; +pub mod preferences; +pub mod prelude; +pub mod tool; +pub mod workspace; diff --git a/editor/src/messages/portfolio/document/document_message.rs b/editor/src/messages/portfolio/document/document_message.rs new file mode 100644 index 0000000000000000000000000000000000000000..18ede64be85a2eef1240943fa7d35a8632696aa2 --- /dev/null +++ b/editor/src/messages/portfolio/document/document_message.rs @@ -0,0 +1,206 @@ +use super::utility_types::misc::{GroupFolderType, SnappingState}; +use crate::messages::input_mapper::utility_types::input_keyboard::Key; +use crate::messages::portfolio::document::overlays::utility_types::OverlayContext; +use crate::messages::portfolio::document::overlays::utility_types::OverlaysType; +use crate::messages::portfolio::document::utility_types::document_metadata::LayerNodeIdentifier; +use crate::messages::portfolio::document::utility_types::misc::{AlignAggregate, AlignAxis, FlipAxis, GridSnapping}; +use crate::messages::portfolio::utility_types::PanelType; +use crate::messages::prelude::*; +use glam::DAffine2; +use graph_craft::document::NodeId; +use graphene_std::Color; +use graphene_std::raster::BlendMode; +use graphene_std::raster::Image; +use graphene_std::transform::Footprint; +use graphene_std::vector::click_target::ClickTarget; +use graphene_std::vector::style::ViewMode; + +#[impl_message(Message, PortfolioMessage, Document)] +#[derive(derivative::Derivative, Clone, serde::Serialize, serde::Deserialize)] +#[derivative(Debug, PartialEq)] +pub enum DocumentMessage { + Noop, + // Sub-messages + #[child] + GraphOperation(GraphOperationMessage), + #[child] + Navigation(NavigationMessage), + #[child] + NodeGraph(NodeGraphMessage), + #[child] + Overlays(OverlaysMessage), + #[child] + PropertiesPanel(PropertiesPanelMessage), + + // Messages + AlignSelectedLayers { + axis: AlignAxis, + aggregate: AlignAggregate, + }, + RemoveArtboards, + ClearLayersPanel, + CreateEmptyFolder, + DeleteNode { + node_id: NodeId, + }, + DeleteSelectedLayers, + DeselectAllLayers, + DocumentHistoryBackward, + DocumentHistoryForward, + DocumentStructureChanged, + DrawArtboardOverlays(OverlayContext), + DuplicateSelectedLayers, + EnterNestedNetwork { + node_id: NodeId, + }, + Escape, + ExitNestedNetwork { + steps_back: usize, + }, + FlipSelectedLayers { + flip_axis: FlipAxis, + }, + RotateSelectedLayers { + degrees: f64, + }, + GraphViewOverlay { + open: bool, + }, + GraphViewOverlayToggle, + GridOptions(GridSnapping), + GridOverlays(OverlayContext), + GridVisibility(bool), + GroupSelectedLayers { + group_folder_type: GroupFolderType, + }, + MoveSelectedLayersTo { + parent: LayerNodeIdentifier, + insert_index: usize, + }, + MoveSelectedLayersToGroup { + parent: LayerNodeIdentifier, + }, + NudgeSelectedLayers { + delta_x: f64, + delta_y: f64, + resize: Key, + resize_opposite_corner: Key, + }, + PasteImage { + name: Option, + image: Image, + mouse: Option<(f64, f64)>, + parent_and_insert_index: Option<(LayerNodeIdentifier, usize)>, + }, + PasteSvg { + name: Option, + svg: String, + mouse: Option<(f64, f64)>, + parent_and_insert_index: Option<(LayerNodeIdentifier, usize)>, + }, + Redo, + RenameDocument { + new_name: String, + }, + RenderRulers, + RenderScrollbars, + SaveDocument, + SelectParentLayer, + SelectAllLayers, + SelectedLayersLower, + SelectedLayersLowerToBack, + SelectedLayersRaise, + SelectedLayersRaiseToFront, + SelectedLayersReverse, + SelectedLayersReorder { + relative_index_offset: isize, + }, + ClipLayer { + id: NodeId, + }, + SelectLayer { + id: NodeId, + ctrl: bool, + shift: bool, + }, + SetActivePanel { + active_panel: PanelType, + }, + SetBlendModeForSelectedLayers { + blend_mode: BlendMode, + }, + SetGraphFadeArtwork { + percentage: f64, + }, + SetNodePinned { + node_id: NodeId, + pinned: bool, + }, + SetOpacityForSelectedLayers { + opacity: f64, + }, + SetFillForSelectedLayers { + fill: f64, + }, + SetOverlaysVisibility { + visible: bool, + overlays_type: Option, + }, + SetRangeSelectionLayer { + new_layer: Option, + }, + SetSnapping { + #[serde(skip)] + #[derivative(Debug = "ignore", PartialEq = "ignore")] + closure: Option fn(&'a mut SnappingState) -> &'a mut bool>, + snapping_state: bool, + }, + SetToNodeOrLayer { + node_id: NodeId, + is_layer: bool, + }, + SetViewMode { + view_mode: ViewMode, + }, + AddTransaction, + StartTransaction, + EndTransaction, + CommitTransaction, + AbortTransaction, + RepeatedAbortTransaction { + undo_count: usize, + }, + ToggleLayerExpansion { + id: NodeId, + recursive: bool, + }, + ToggleSelectedVisibility, + ToggleSelectedLocked, + ToggleGridVisibility, + ToggleOverlaysVisibility, + ToggleSnapping, + UpdateUpstreamTransforms { + upstream_footprints: HashMap, + local_transforms: HashMap, + }, + UpdateClickTargets { + click_targets: HashMap>, + }, + UpdateClipTargets { + clip_targets: HashSet, + }, + Undo, + UngroupSelectedLayers, + UngroupLayer { + layer: LayerNodeIdentifier, + }, + PTZUpdate, + SelectionStepBack, + SelectionStepForward, + WrapContentInArtboard { + place_artboard_at_origin: bool, + }, + ZoomCanvasTo100Percent, + ZoomCanvasTo200Percent, + ZoomCanvasToFitAll, +} diff --git a/editor/src/messages/portfolio/document/document_message_handler.rs b/editor/src/messages/portfolio/document/document_message_handler.rs new file mode 100644 index 0000000000000000000000000000000000000000..81f631dfe05ad3b7e90faf61599c1dc799ab9b4b --- /dev/null +++ b/editor/src/messages/portfolio/document/document_message_handler.rs @@ -0,0 +1,3371 @@ +use super::node_graph::document_node_definitions; +use super::node_graph::utility_types::Transform; +use super::overlays::utility_types::Pivot; +use super::utility_types::error::EditorError; +use super::utility_types::misc::{GroupFolderType, SNAP_FUNCTIONS_FOR_BOUNDING_BOXES, SNAP_FUNCTIONS_FOR_PATHS, SnappingOptions, SnappingState}; +use super::utility_types::network_interface::{self, NodeNetworkInterface, TransactionStatus}; +use super::utility_types::nodes::{CollapsedLayers, SelectedNodes}; +use crate::application::{GRAPHITE_GIT_COMMIT_HASH, generate_uuid}; +use crate::consts::{ASYMPTOTIC_EFFECT, COLOR_OVERLAY_GRAY, DEFAULT_DOCUMENT_NAME, FILE_SAVE_SUFFIX, SCALE_EFFECT, SCROLLBAR_SPACING, VIEWPORT_ROTATE_SNAP_INTERVAL}; +use crate::messages::input_mapper::utility_types::macros::action_keys; +use crate::messages::layout::utility_types::widget_prelude::*; +use crate::messages::portfolio::document::graph_operation::utility_types::TransformIn; +use crate::messages::portfolio::document::node_graph::NodeGraphHandlerData; +use crate::messages::portfolio::document::overlays::grid_overlays::{grid_overlay, overlay_options}; +use crate::messages::portfolio::document::overlays::utility_types::{OverlaysType, OverlaysVisibilitySettings}; +use crate::messages::portfolio::document::properties_panel::utility_types::PropertiesPanelMessageHandlerData; +use crate::messages::portfolio::document::utility_types::document_metadata::{DocumentMetadata, LayerNodeIdentifier}; +use crate::messages::portfolio::document::utility_types::misc::{AlignAggregate, AlignAxis, DocumentMode, FlipAxis, PTZ}; +use crate::messages::portfolio::document::utility_types::network_interface::{FlowType, InputConnector, NodeTemplate}; +use crate::messages::portfolio::document::utility_types::nodes::RawBuffer; +use crate::messages::portfolio::utility_types::PersistentData; +use crate::messages::prelude::*; +use crate::messages::tool::common_functionality::graph_modification_utils::{self, get_blend_mode, get_fill, get_opacity}; +use crate::messages::tool::tool_messages::select_tool::SelectToolPointerKeys; +use crate::messages::tool::tool_messages::tool_prelude::Key; +use crate::messages::tool::utility_types::ToolType; +use crate::node_graph_executor::NodeGraphExecutor; +use bezier_rs::Subpath; +use glam::{DAffine2, DVec2, IVec2}; +use graph_craft::document::value::TaggedValue; +use graph_craft::document::{NodeId, NodeInput, NodeNetwork, OldNodeNetwork}; +use graphene_std::math::quad::Quad; +use graphene_std::path_bool::{boolean_intersect, path_bool_lib}; +use graphene_std::raster::BlendMode; +use graphene_std::raster_types::{Raster, RasterDataTable}; +use graphene_std::vector::PointId; +use graphene_std::vector::click_target::{ClickTarget, ClickTargetType}; +use graphene_std::vector::style::ViewMode; +use std::time::Duration; + +pub struct DocumentMessageData<'a> { + pub document_id: DocumentId, + pub ipp: &'a InputPreprocessorMessageHandler, + pub persistent_data: &'a PersistentData, + pub executor: &'a mut NodeGraphExecutor, + pub current_tool: &'a ToolType, + pub preferences: &'a PreferencesMessageHandler, + pub device_pixel_ratio: f64, +} + +#[derive(Clone, Debug, serde::Serialize, serde::Deserialize)] +#[serde(default)] +pub struct DocumentMessageHandler { + // ====================== + // Child message handlers + // ====================== + // + #[serde(skip)] + pub navigation_handler: NavigationMessageHandler, + #[serde(skip)] + pub node_graph_handler: NodeGraphMessageHandler, + #[serde(skip)] + overlays_message_handler: OverlaysMessageHandler, + #[serde(skip)] + properties_panel_message_handler: PropertiesPanelMessageHandler, + + // ============================================ + // Fields that are saved in the document format + // ============================================ + // + // Contains the NodeNetwork and acts an an interface to manipulate the NodeNetwork with custom setters in order to keep NetworkMetadata in sync + pub network_interface: NodeNetworkInterface, + /// List of the [`LayerNodeIdentifier`]s that are currently collapsed by the user in the Layers panel. + /// Collapsed means that the expansion arrow isn't set to show the children of these layers. + pub collapsed: CollapsedLayers, + /// The name of the document, which is displayed in the tab and title bar of the editor. + pub name: String, + /// The full Git commit hash of the Graphite repository that was used to build the editor. + /// We save this to provide a hint about which version of the editor was used to create the document. + pub commit_hash: String, + /// The current pan, tilt, and zoom state of the viewport's view of the document canvas. + pub document_ptz: PTZ, + /// The current mode that the document is in, which starts out as Design Mode. This choice affects the editing behavior of the tools. + pub document_mode: DocumentMode, + /// The current view mode that the user has set for rendering the document within the viewport. + /// This is usually "Normal" but can be set to "Outline" or "Pixels" to see the canvas differently. + pub view_mode: ViewMode, + /// Sets whether or not all the viewport overlays should be drawn on top of the artwork. + /// This includes tool interaction visualizations (like the transform cage and path anchors/handles), the grid, and more. + pub overlays_visibility_settings: OverlaysVisibilitySettings, + /// Sets whether or not the rulers should be drawn along the top and left edges of the viewport area. + pub rulers_visible: bool, + /// The current user choices for snapping behavior, including whether snapping is enabled at all. + pub snapping_state: SnappingState, + /// Sets whether or not the node graph is drawn (as an overlay) on top of the viewport area, or otherwise if it's hidden. + pub graph_view_overlay_open: bool, + /// The current opacity of the faded node graph background that covers up the artwork. + pub graph_fade_artwork_percentage: f64, + + // ============================================= + // Fields omitted from the saved document format + // ============================================= + // + /// Path to network currently viewed in the node graph overlay. This will eventually be stored in each panel, so that multiple panels can refer to different networks + #[serde(skip)] + breadcrumb_network_path: Vec, + /// Path to network that is currently selected. Updated based on the most recently clicked panel. + #[serde(skip)] + selection_network_path: Vec, + /// Stack of document network snapshots for previous history states. + #[serde(skip)] + document_undo_history: VecDeque, + /// Stack of document network snapshots for future history states. + #[serde(skip)] + document_redo_history: VecDeque, + /// Hash of the document snapshot that was most recently saved to disk by the user. + #[serde(skip)] + saved_hash: Option, + /// Hash of the document snapshot that was most recently auto-saved to the IndexedDB storage that will reopen when the editor is reloaded. + #[serde(skip)] + auto_saved_hash: Option, + /// The ID of the layer at the start of a range selection in the Layers panel. + /// If the user clicks or Ctrl-clicks one layer, it becomes the start of the range selection and then Shift-clicking another layer selects all layers between the start and end. + #[serde(skip)] + layer_range_selection_reference: Option, + /// Whether or not the editor has executed the network to render the document yet. If this is opened as an inactive tab, it won't be loaded initially because the active tab is prioritized. + #[serde(skip)] + pub is_loaded: bool, +} + +impl Default for DocumentMessageHandler { + fn default() -> Self { + Self { + // ====================== + // Child message handlers + // ====================== + navigation_handler: NavigationMessageHandler::default(), + node_graph_handler: NodeGraphMessageHandler::default(), + overlays_message_handler: OverlaysMessageHandler::default(), + properties_panel_message_handler: PropertiesPanelMessageHandler::default(), + // ============================================ + // Fields that are saved in the document format + // ============================================ + network_interface: default_document_network_interface(), + collapsed: CollapsedLayers::default(), + name: DEFAULT_DOCUMENT_NAME.to_string(), + commit_hash: GRAPHITE_GIT_COMMIT_HASH.to_string(), + document_ptz: PTZ::default(), + document_mode: DocumentMode::DesignMode, + view_mode: ViewMode::default(), + overlays_visibility_settings: OverlaysVisibilitySettings::default(), + rulers_visible: true, + graph_view_overlay_open: false, + snapping_state: SnappingState::default(), + graph_fade_artwork_percentage: 80., + // ============================================= + // Fields omitted from the saved document format + // ============================================= + breadcrumb_network_path: Vec::new(), + selection_network_path: Vec::new(), + document_undo_history: VecDeque::new(), + document_redo_history: VecDeque::new(), + saved_hash: None, + auto_saved_hash: None, + layer_range_selection_reference: None, + is_loaded: false, + } + } +} + +impl MessageHandler> for DocumentMessageHandler { + fn process_message(&mut self, message: DocumentMessage, responses: &mut VecDeque, data: DocumentMessageData) { + let DocumentMessageData { + document_id, + ipp, + persistent_data, + executor, + current_tool, + preferences, + device_pixel_ratio, + } = data; + + let selected_nodes_bounding_box_viewport = self.network_interface.selected_nodes_bounding_box_viewport(&self.breadcrumb_network_path); + let selected_visible_layers_bounding_box_viewport = self.selected_visible_layers_bounding_box_viewport(); + match message { + // Sub-messages + DocumentMessage::Navigation(message) => { + let data = NavigationMessageData { + network_interface: &mut self.network_interface, + breadcrumb_network_path: &self.breadcrumb_network_path, + ipp, + selection_bounds: if self.graph_view_overlay_open { + selected_nodes_bounding_box_viewport + } else { + selected_visible_layers_bounding_box_viewport + }, + document_ptz: &mut self.document_ptz, + graph_view_overlay_open: self.graph_view_overlay_open, + preferences, + }; + + self.navigation_handler.process_message(message, responses, data); + } + DocumentMessage::Overlays(message) => { + let visibility_settings = self.overlays_visibility_settings; + + // Send the overlays message to the overlays message handler + self.overlays_message_handler.process_message( + message, + responses, + OverlaysMessageData { + visibility_settings, + ipp, + device_pixel_ratio, + }, + ); + } + DocumentMessage::PropertiesPanel(message) => { + let properties_panel_message_handler_data = PropertiesPanelMessageHandlerData { + network_interface: &mut self.network_interface, + selection_network_path: &self.selection_network_path, + document_name: self.name.as_str(), + executor, + }; + self.properties_panel_message_handler + .process_message(message, responses, (persistent_data, properties_panel_message_handler_data)); + } + DocumentMessage::NodeGraph(message) => { + self.node_graph_handler.process_message( + message, + responses, + NodeGraphHandlerData { + network_interface: &mut self.network_interface, + selection_network_path: &self.selection_network_path, + breadcrumb_network_path: &self.breadcrumb_network_path, + document_id, + collapsed: &mut self.collapsed, + ipp, + graph_view_overlay_open: self.graph_view_overlay_open, + graph_fade_artwork_percentage: self.graph_fade_artwork_percentage, + navigation_handler: &self.navigation_handler, + preferences, + }, + ); + } + DocumentMessage::GraphOperation(message) => { + let data = GraphOperationMessageData { + network_interface: &mut self.network_interface, + collapsed: &mut self.collapsed, + node_graph: &mut self.node_graph_handler, + }; + let mut graph_operation_message_handler = GraphOperationMessageHandler {}; + graph_operation_message_handler.process_message(message, responses, data); + } + DocumentMessage::AlignSelectedLayers { axis, aggregate } => { + let axis = match axis { + AlignAxis::X => DVec2::X, + AlignAxis::Y => DVec2::Y, + }; + let Some(combined_box) = self.selected_visible_layers_bounding_box_viewport() else { + return; + }; + + let aggregated = match aggregate { + AlignAggregate::Min => combined_box[0], + AlignAggregate::Max => combined_box[1], + AlignAggregate::Center => (combined_box[0] + combined_box[1]) / 2., + }; + + let mut added_transaction = false; + for layer in self.network_interface.selected_nodes().selected_unlocked_layers(&self.network_interface) { + let Some(bbox) = self.metadata().bounding_box_viewport(layer) else { + continue; + }; + let center = match aggregate { + AlignAggregate::Min => bbox[0], + AlignAggregate::Max => bbox[1], + _ => (bbox[0] + bbox[1]) / 2., + }; + let translation = (aggregated - center) * axis; + if !added_transaction { + responses.add(DocumentMessage::AddTransaction); + added_transaction = true; + } + responses.add(GraphOperationMessage::TransformChange { + layer, + transform: DAffine2::from_translation(translation), + transform_in: TransformIn::Viewport, + skip_rerender: false, + }); + } + } + DocumentMessage::RemoveArtboards => { + responses.add(GraphOperationMessage::RemoveArtboards); + } + DocumentMessage::ClearLayersPanel => { + // Send an empty layer list + let data_buffer: RawBuffer = Self::default().serialize_root(); + responses.add(FrontendMessage::UpdateDocumentLayerStructure { data_buffer }); + + // Clear the control bar + responses.add(LayoutMessage::SendLayout { + layout: Layout::WidgetLayout(Default::default()), + layout_target: LayoutTarget::LayersPanelControlLeftBar, + }); + responses.add(LayoutMessage::SendLayout { + layout: Layout::WidgetLayout(Default::default()), + layout_target: LayoutTarget::LayersPanelControlRightBar, + }); + + // Clear the bottom bar + responses.add(LayoutMessage::SendLayout { + layout: Layout::WidgetLayout(Default::default()), + layout_target: LayoutTarget::LayersPanelBottomBar, + }); + } + DocumentMessage::CreateEmptyFolder => { + let selected_nodes = self.network_interface.selected_nodes(); + let id = NodeId::new(); + + let parent = self + .network_interface + .deepest_common_ancestor(&selected_nodes, &self.selection_network_path, true) + .unwrap_or(LayerNodeIdentifier::ROOT_PARENT); + + let insert_index = DocumentMessageHandler::get_calculated_insert_index(self.metadata(), &self.network_interface.selected_nodes(), parent); + responses.add(DocumentMessage::AddTransaction); + responses.add(GraphOperationMessage::NewCustomLayer { + id, + nodes: Vec::new(), + parent, + insert_index, + }); + responses.add(NodeGraphMessage::SelectedNodesSet { nodes: vec![id] }); + } + DocumentMessage::DeleteNode { node_id } => { + responses.add(DocumentMessage::StartTransaction); + + responses.add(NodeGraphMessage::DeleteNodes { + node_ids: vec![node_id], + delete_children: true, + }); + responses.add(NodeGraphMessage::RunDocumentGraph); + responses.add(NodeGraphMessage::SelectedNodesUpdated); + responses.add(NodeGraphMessage::SendGraph); + responses.add(DocumentMessage::EndTransaction); + } + DocumentMessage::DeleteSelectedLayers => { + responses.add(NodeGraphMessage::DeleteSelectedNodes { delete_children: true }); + } + DocumentMessage::DeselectAllLayers => { + responses.add(NodeGraphMessage::SelectedNodesSet { nodes: vec![] }); + self.layer_range_selection_reference = None; + } + DocumentMessage::DocumentHistoryBackward => self.undo_with_history(ipp, responses), + DocumentMessage::DocumentHistoryForward => self.redo_with_history(ipp, responses), + DocumentMessage::DocumentStructureChanged => { + self.update_layers_panel_control_bar_widgets(responses); + self.update_layers_panel_bottom_bar_widgets(responses); + + self.network_interface.load_structure(); + let data_buffer: RawBuffer = self.serialize_root(); + responses.add(FrontendMessage::UpdateDocumentLayerStructure { data_buffer }); + } + DocumentMessage::DrawArtboardOverlays(overlay_context) => { + if !overlay_context.visibility_settings.artboard_name() { + return; + } + + for layer in self.metadata().all_layers() { + if !self.network_interface.is_artboard(&layer.to_node(), &[]) { + continue; + } + let Some(bounds) = self.metadata().bounding_box_document(layer) else { continue }; + let min = bounds[0].min(bounds[1]); + let max = bounds[0].max(bounds[1]); + + let name = self.network_interface.display_name(&layer.to_node(), &[]); + + // Calculate position of the text + let corner_pos = if !self.document_ptz.flip { + // Use the top-left corner + min + } else { + // Use the top-right corner, which appears to be the top-left due to being flipped + DVec2::new(max.x, min.y) + }; + + // When the canvas is flipped, mirror the text so it appears correctly + let scale = if !self.document_ptz.flip { DVec2::ONE } else { DVec2::new(-1., 1.) }; + + // Create a transform that puts the text at the true top-left regardless of flip + let transform = self.metadata().document_to_viewport + * DAffine2::from_translation(corner_pos) + * DAffine2::from_scale(DVec2::splat(self.document_ptz.zoom().recip())) + * DAffine2::from_translation(-DVec2::Y * 4.) + * DAffine2::from_scale(scale); + + overlay_context.text(&name, COLOR_OVERLAY_GRAY, None, transform, 0., [Pivot::Start, Pivot::End]); + } + } + DocumentMessage::DuplicateSelectedLayers => { + responses.add(DocumentMessage::AddTransaction); + + let mut new_dragging = Vec::new(); + let mut layers = self.network_interface.shallowest_unique_layers(&[]).collect::>(); + + layers.sort_by_key(|layer| { + let Some(parent) = layer.parent(self.metadata()) else { return usize::MAX }; + DocumentMessageHandler::get_calculated_insert_index(self.metadata(), &SelectedNodes(vec![layer.to_node()]), parent) + }); + + for layer in layers.into_iter().rev() { + let Some(parent) = layer.parent(self.metadata()) else { continue }; + + // Copy the layer + let mut copy_ids = HashMap::new(); + let node_id = layer.to_node(); + copy_ids.insert(node_id, NodeId(0)); + + self.network_interface + .upstream_flow_back_from_nodes(vec![layer.to_node()], &[], FlowType::LayerChildrenUpstreamFlow) + .enumerate() + .for_each(|(index, node_id)| { + copy_ids.insert(node_id, NodeId((index + 1) as u64)); + }); + + let nodes = self.network_interface.copy_nodes(©_ids, &[]).collect::>(); + + let insert_index = DocumentMessageHandler::get_calculated_insert_index(self.metadata(), &SelectedNodes(vec![layer.to_node()]), parent); + + let new_ids: HashMap<_, _> = nodes.iter().map(|(id, _)| (*id, NodeId::new())).collect(); + + let layer_id = *new_ids.get(&NodeId(0)).expect("Node Id 0 should be a layer"); + let layer = LayerNodeIdentifier::new_unchecked(layer_id); + new_dragging.push(layer); + responses.add(NodeGraphMessage::AddNodes { nodes, new_ids }); + responses.add(NodeGraphMessage::MoveLayerToStack { layer, parent, insert_index }); + } + let nodes = new_dragging.iter().map(|layer| layer.to_node()).collect(); + responses.add(NodeGraphMessage::SelectedNodesSet { nodes }); + responses.add(NodeGraphMessage::RunDocumentGraph); + } + DocumentMessage::EnterNestedNetwork { node_id } => { + self.breadcrumb_network_path.push(node_id); + self.selection_network_path.clone_from(&self.breadcrumb_network_path); + responses.add(NodeGraphMessage::UnloadWires); + responses.add(NodeGraphMessage::SendGraph); + responses.add(DocumentMessage::ZoomCanvasToFitAll); + responses.add(NodeGraphMessage::SetGridAlignedEdges); + } + DocumentMessage::Escape => { + if self.node_graph_handler.drag_start.is_some() { + responses.add(DocumentMessage::AbortTransaction); + self.node_graph_handler.drag_start = None; + } else if self + .node_graph_handler + .context_menu + .as_ref() + .is_some_and(|context_menu| matches!(context_menu.context_menu_data, super::node_graph::utility_types::ContextMenuData::CreateNode { compatible_type: None })) + { + // Close the context menu + self.node_graph_handler.context_menu = None; + responses.add(FrontendMessage::UpdateContextMenuInformation { context_menu_information: None }); + self.node_graph_handler.wire_in_progress_from_connector = None; + self.node_graph_handler.wire_in_progress_to_connector = None; + responses.add(FrontendMessage::UpdateWirePathInProgress { wire_path: None }); + } else { + responses.add(DocumentMessage::GraphViewOverlay { open: false }); + } + } + DocumentMessage::ExitNestedNetwork { steps_back } => { + for _ in 0..steps_back { + self.breadcrumb_network_path.pop(); + self.selection_network_path.clone_from(&self.breadcrumb_network_path); + } + responses.add(NodeGraphMessage::UnloadWires); + responses.add(NodeGraphMessage::SendGraph); + responses.add(DocumentMessage::PTZUpdate); + responses.add(NodeGraphMessage::SetGridAlignedEdges); + } + DocumentMessage::FlipSelectedLayers { flip_axis } => { + let scale = match flip_axis { + FlipAxis::X => DVec2::new(-1., 1.), + FlipAxis::Y => DVec2::new(1., -1.), + }; + if let Some([min, max]) = self.selected_visible_and_unlock_layers_bounding_box_viewport() { + let center = (max + min) / 2.; + let bbox_trans = DAffine2::from_translation(-center); + let mut added_transaction = false; + for layer in self.network_interface.selected_nodes().selected_unlocked_layers(&self.network_interface) { + if !added_transaction { + responses.add(DocumentMessage::AddTransaction); + added_transaction = true; + } + responses.add(GraphOperationMessage::TransformChange { + layer, + transform: DAffine2::from_scale(scale), + transform_in: TransformIn::Scope { scope: bbox_trans }, + skip_rerender: false, + }); + } + } + } + DocumentMessage::RotateSelectedLayers { degrees } => { + // Get the bounding box of selected layers in viewport space + if let Some([min, max]) = self.selected_visible_and_unlock_layers_bounding_box_viewport() { + // Calculate the center of the bounding box to use as rotation pivot + let center = (max + min) / 2.; + // Transform that moves pivot point to origin + let bbox_trans = DAffine2::from_translation(-center); + + let mut added_transaction = false; + for layer in self.network_interface.selected_nodes().selected_unlocked_layers(&self.network_interface) { + if !added_transaction { + responses.add(DocumentMessage::AddTransaction); + added_transaction = true; + } + + responses.add(GraphOperationMessage::TransformChange { + layer, + transform: DAffine2::from_angle(degrees.to_radians()), + transform_in: TransformIn::Scope { scope: bbox_trans }, + skip_rerender: false, + }); + } + } + } + DocumentMessage::GraphViewOverlay { open } => { + let opened = !self.graph_view_overlay_open && open; + self.graph_view_overlay_open = open; + + responses.add(FrontendMessage::UpdateGraphViewOverlay { open }); + responses.add(FrontendMessage::UpdateGraphFadeArtwork { + percentage: self.graph_fade_artwork_percentage, + }); + + // Update the tilt menu bar buttons to be disabled when the graph is open + responses.add(MenuBarMessage::SendLayout); + + responses.add(DocumentMessage::RenderRulers); + responses.add(DocumentMessage::RenderScrollbars); + if opened { + responses.add(NodeGraphMessage::UnloadWires); + } + if open { + responses.add(ToolMessage::DeactivateTools); + responses.add(OverlaysMessage::Draw); // Clear the overlays + responses.add(NavigationMessage::CanvasTiltSet { angle_radians: 0. }); + responses.add(NodeGraphMessage::SetGridAlignedEdges); + responses.add(NodeGraphMessage::UpdateGraphBarRight); + responses.add(NodeGraphMessage::SendGraph); + responses.add(NodeGraphMessage::UpdateHints); + } else { + responses.add(ToolMessage::ActivateTool { tool_type: *current_tool }); + } + } + DocumentMessage::GraphViewOverlayToggle => { + responses.add(DocumentMessage::GraphViewOverlay { open: !self.graph_view_overlay_open }); + } + DocumentMessage::GridOptions(grid) => { + self.snapping_state.grid = grid; + self.snapping_state.grid_snapping = true; + responses.add(OverlaysMessage::Draw); + responses.add(PortfolioMessage::UpdateDocumentWidgets); + } + DocumentMessage::GridOverlays(mut overlay_context) => { + if self.snapping_state.grid_snapping { + grid_overlay(self, &mut overlay_context) + } + } + DocumentMessage::GridVisibility(enabled) => { + self.snapping_state.grid_snapping = enabled; + responses.add(OverlaysMessage::Draw); + } + DocumentMessage::GroupSelectedLayers { group_folder_type } => { + responses.add(DocumentMessage::AddTransaction); + + let mut parent_per_selected_nodes: HashMap> = HashMap::new(); + let artboards = LayerNodeIdentifier::ROOT_PARENT + .children(self.metadata()) + .filter(|x| self.network_interface.is_artboard(&x.to_node(), &self.selection_network_path)) + .collect::>(); + let selected_nodes = self.network_interface.selected_nodes(); + + // Non-artboard (infinite canvas) workflow + if artboards.is_empty() { + let Some(parent) = self.network_interface.deepest_common_ancestor(&selected_nodes, &self.selection_network_path, false) else { + return; + }; + let Some(selected_nodes) = &self.network_interface.selected_nodes_in_nested_network(&self.selection_network_path) else { + return; + }; + let insert_index = DocumentMessageHandler::get_calculated_insert_index(self.metadata(), selected_nodes, parent); + + DocumentMessageHandler::group_layers(responses, insert_index, parent, group_folder_type, &mut self.network_interface); + } + // Artboard workflow + else { + for artboard in artboards { + let selected_descendants = artboard.descendants(self.metadata()).filter(|x| selected_nodes.selected_layers_contains(*x, self.metadata())); + for selected_descendant in selected_descendants { + parent_per_selected_nodes.entry(artboard).or_default().push(selected_descendant.to_node()); + } + } + + let mut new_folders: Vec = Vec::new(); + + for children in parent_per_selected_nodes.into_values() { + let child_selected_nodes = SelectedNodes(children); + let Some(parent) = self.network_interface.deepest_common_ancestor(&child_selected_nodes, &self.selection_network_path, false) else { + continue; + }; + let insert_index = DocumentMessageHandler::get_calculated_insert_index(self.metadata(), &child_selected_nodes, parent); + + responses.add(NodeGraphMessage::SelectedNodesSet { nodes: child_selected_nodes.0 }); + + new_folders.push(DocumentMessageHandler::group_layers(responses, insert_index, parent, group_folder_type, &mut self.network_interface)); + } + + responses.add(NodeGraphMessage::SelectedNodesSet { nodes: new_folders }); + } + } + DocumentMessage::MoveSelectedLayersTo { parent, insert_index } => { + if !self.selection_network_path.is_empty() { + log::error!("Moving selected layers is only supported for the Document Network"); + return; + } + + // Disallow trying to insert into self. + if self + .network_interface + .selected_nodes() + .selected_layers(self.metadata()) + .any(|layer| parent.ancestors(self.metadata()).any(|ancestor| ancestor == layer)) + { + return; + } + // Artboards can only have `ROOT_PARENT` as the parent. + let any_artboards = self + .network_interface + .selected_nodes() + .selected_layers(self.metadata()) + .any(|layer| self.network_interface.is_artboard(&layer.to_node(), &self.selection_network_path)); + if any_artboards && parent != LayerNodeIdentifier::ROOT_PARENT { + return; + } + + // Non-artboards cannot be put at the top level if artboards also exist there + let selected_any_non_artboards = self + .network_interface + .selected_nodes() + .selected_layers(self.metadata()) + .any(|layer| !self.network_interface.is_artboard(&layer.to_node(), &self.selection_network_path)); + + let top_level_artboards = LayerNodeIdentifier::ROOT_PARENT + .children(self.metadata()) + .any(|layer| self.network_interface.is_artboard(&layer.to_node(), &self.selection_network_path)); + + if selected_any_non_artboards && parent == LayerNodeIdentifier::ROOT_PARENT && top_level_artboards { + return; + } + + let layers_to_move = self.network_interface.shallowest_unique_layers_sorted(&self.selection_network_path); + // Offset the index for layers to move that are below another layer to move. For example when moving 1 and 2 between 3 and 4, 2 should be inserted at the same index as 1 since 1 is moved first. + let layers_to_move_with_insert_offset = layers_to_move + .iter() + .map(|layer| { + if layer.parent(self.metadata()) != Some(parent) { + return (*layer, 0); + } + + let upstream_selected_siblings = layer + .downstream_siblings(self.network_interface.document_metadata()) + .filter(|sibling| { + sibling != layer + && layers_to_move.iter().any(|layer| { + layer == sibling + && layer + .parent(self.metadata()) + .is_some_and(|parent| parent.children(self.metadata()).position(|child| child == *layer) < Some(insert_index)) + }) + }) + .count(); + (*layer, upstream_selected_siblings) + }) + .collect::>(); + + responses.add(DocumentMessage::AddTransaction); + + for (layer_index, (layer_to_move, insert_offset)) in layers_to_move_with_insert_offset.into_iter().enumerate() { + responses.add(NodeGraphMessage::MoveLayerToStack { + layer: layer_to_move, + parent, + insert_index: insert_index + layer_index - insert_offset, + }); + + if layer_to_move.parent(self.metadata()) != Some(parent) { + // TODO: Fix this so it works when dragging a layer into a group parent which has a Transform node, which used to work before #2689 caused this regression by removing the empty VectorData table row. + // TODO: See #2688 for this issue. + let layer_local_transform = self.network_interface.document_metadata().transform_to_viewport(layer_to_move); + let undo_transform = self.network_interface.document_metadata().transform_to_viewport(parent).inverse(); + let transform = undo_transform * layer_local_transform; + + responses.add(GraphOperationMessage::TransformSet { + layer: layer_to_move, + transform, + transform_in: TransformIn::Local, + skip_rerender: false, + }); + } + } + + responses.add(NodeGraphMessage::RunDocumentGraph); + responses.add(NodeGraphMessage::SendGraph); + } + DocumentMessage::MoveSelectedLayersToGroup { parent } => { + // Group all shallowest unique selected layers in order + let all_layers_to_group_sorted = self.network_interface.shallowest_unique_layers_sorted(&self.selection_network_path); + + for layer_to_group in all_layers_to_group_sorted.into_iter().rev() { + responses.add(NodeGraphMessage::MoveLayerToStack { + layer: layer_to_group, + parent, + insert_index: 0, + }); + } + + responses.add(NodeGraphMessage::SelectedNodesSet { nodes: vec![parent.to_node()] }); + responses.add(NodeGraphMessage::RunDocumentGraph); + responses.add(DocumentMessage::DocumentStructureChanged); + responses.add(NodeGraphMessage::SendGraph); + } + DocumentMessage::NudgeSelectedLayers { + delta_x, + delta_y, + resize, + resize_opposite_corner, + } => { + responses.add(DocumentMessage::AddTransaction); + + let resize = ipp.keyboard.key(resize); + let resize_opposite_corner = ipp.keyboard.key(resize_opposite_corner); + + let can_move = |layer| { + let selected = self.network_interface.selected_nodes(); + selected.layer_visible(layer, &self.network_interface) && !selected.layer_locked(layer, &self.network_interface) + }; + + // Nudge translation without resizing + if !resize { + let transform = DAffine2::from_translation(DVec2::from_angle(-self.document_ptz.tilt()).rotate(DVec2::new(delta_x, delta_y))); + + for layer in self.network_interface.shallowest_unique_layers(&[]).filter(|layer| can_move(*layer)) { + responses.add(GraphOperationMessage::TransformChange { + layer, + transform, + transform_in: TransformIn::Local, + skip_rerender: false, + }); + } + + return; + } + + let selected_bounding_box = self.network_interface.selected_bounds_document_space(false, &[]); + let Some([existing_top_left, existing_bottom_right]) = selected_bounding_box else { return }; + + // Swap and negate coordinates as needed to match the resize direction that's closest to the current tilt angle + let tilt = (self.document_ptz.tilt() + std::f64::consts::TAU) % std::f64::consts::TAU; + let (delta_x, delta_y, opposite_x, opposite_y) = match ((tilt + std::f64::consts::FRAC_PI_4) / std::f64::consts::FRAC_PI_2).floor() as i32 % 4 { + 0 => (delta_x, delta_y, false, false), + 1 => (delta_y, -delta_x, false, true), + 2 => (-delta_x, -delta_y, true, true), + 3 => (-delta_y, delta_x, true, false), + _ => unreachable!(), + }; + + let size = existing_bottom_right - existing_top_left; + // TODO: This is a hacky band-aid. It still results in the shape becoming zero-sized. Properly fix this using the correct math. + // If size is zero we clamp it to minimun value to avoid dividing by zero vector to calculate enlargement. + let size = size.max(DVec2::ONE); + let enlargement = DVec2::new( + if resize_opposite_corner != opposite_x { -delta_x } else { delta_x }, + if resize_opposite_corner != opposite_y { -delta_y } else { delta_y }, + ); + let enlargement_factor = (enlargement + size) / size; + + let position = DVec2::new( + existing_top_left.x + if resize_opposite_corner != opposite_x { delta_x } else { 0. }, + existing_top_left.y + if resize_opposite_corner != opposite_y { delta_y } else { 0. }, + ); + let mut pivot = (existing_top_left * enlargement_factor - position) / (enlargement_factor - DVec2::ONE); + if !pivot.x.is_finite() { + pivot.x = 0.; + } + if !pivot.y.is_finite() { + pivot.y = 0.; + } + let scale = DAffine2::from_scale(enlargement_factor); + let pivot = DAffine2::from_translation(pivot); + let transformation = pivot * scale * pivot.inverse(); + let document_to_viewport = self.navigation_handler.calculate_offset_transform(ipp.viewport_bounds.center(), &self.document_ptz); + + for layer in self.network_interface.shallowest_unique_layers(&[]).filter(|layer| can_move(*layer)) { + let to = document_to_viewport.inverse() * self.metadata().downstream_transform_to_viewport(layer); + let original_transform = self.metadata().upstream_transform(layer.to_node()); + let new = to.inverse() * transformation * to * original_transform; + responses.add(GraphOperationMessage::TransformSet { + layer, + transform: new, + transform_in: TransformIn::Local, + skip_rerender: false, + }); + } + } + DocumentMessage::PasteImage { + name, + image, + mouse, + parent_and_insert_index, + } => { + // All the image's pixels have been converted to 0..=1, linear, and premultiplied by `Color::from_rgba8_srgb` + + let image_size = DVec2::new(image.width as f64, image.height as f64); + + // Align the layer with the mouse or center of viewport + let viewport_location = mouse.map_or(ipp.viewport_bounds.center() + ipp.viewport_bounds.top_left, |pos| pos.into()); + + let document_to_viewport = self.navigation_handler.calculate_offset_transform(ipp.viewport_bounds.center(), &self.document_ptz); + let center_in_viewport = DAffine2::from_translation(document_to_viewport.inverse().transform_point2(viewport_location - ipp.viewport_bounds.top_left)); + let center_in_viewport_layerspace = center_in_viewport; + + // Make layer the size of the image + let fit_image_size = DAffine2::from_scale_angle_translation(image_size, 0., image_size / -2.); + + let transform = center_in_viewport_layerspace * fit_image_size; + + let layer_node_id = NodeId::new(); + let layer_id = LayerNodeIdentifier::new_unchecked(layer_node_id); + + responses.add(DocumentMessage::AddTransaction); + + let layer = graph_modification_utils::new_image_layer(RasterDataTable::new(Raster::new_cpu(image)), layer_node_id, self.new_layer_parent(true), responses); + + if let Some(name) = name { + responses.add(NodeGraphMessage::SetDisplayName { + node_id: layer.to_node(), + alias: name, + skip_adding_history_step: false, + }); + } + if let Some((parent, insert_index)) = parent_and_insert_index { + responses.add(NodeGraphMessage::MoveLayerToStack { + layer: layer_id, + parent, + insert_index, + }); + } + + // `layer` cannot be `ROOT_PARENT` since it is the newly created layer + responses.add(NodeGraphMessage::SelectedNodesSet { nodes: vec![layer.to_node()] }); + + responses.add(GraphOperationMessage::TransformSet { + layer, + transform, + transform_in: TransformIn::Local, + skip_rerender: false, + }); + + // Force chosen tool to be Select Tool after importing image. + responses.add(ToolMessage::ActivateTool { tool_type: ToolType::Select }); + } + DocumentMessage::PasteSvg { + name, + svg, + mouse, + parent_and_insert_index, + } => { + let document_to_viewport = self.navigation_handler.calculate_offset_transform(ipp.viewport_bounds.center(), &self.document_ptz); + let viewport_location = mouse.map_or(ipp.viewport_bounds.center() + ipp.viewport_bounds.top_left, |pos| pos.into()); + let center_in_viewport = DAffine2::from_translation(document_to_viewport.inverse().transform_point2(viewport_location - ipp.viewport_bounds.top_left)); + + let layer_node_id = NodeId::new(); + let layer_id = LayerNodeIdentifier::new_unchecked(layer_node_id); + + responses.add(DocumentMessage::AddTransaction); + + let layer = graph_modification_utils::new_svg_layer(svg, center_in_viewport, layer_node_id, self.new_layer_parent(true), responses); + + if let Some(name) = name { + responses.add(NodeGraphMessage::SetDisplayName { + node_id: layer.to_node(), + alias: name, + skip_adding_history_step: false, + }); + } + if let Some((parent, insert_index)) = parent_and_insert_index { + responses.add(NodeGraphMessage::MoveLayerToStack { + layer: layer_id, + parent, + insert_index, + }); + } + + responses.add(NodeGraphMessage::SelectedNodesSet { nodes: vec![layer.to_node()] }); + responses.add(ToolMessage::ActivateTool { tool_type: ToolType::Select }); + } + DocumentMessage::Redo => { + if self.network_interface.transaction_status() != TransactionStatus::Finished { + return; + } + responses.add(SelectToolMessage::Abort); + responses.add(DocumentMessage::DocumentHistoryForward); + responses.add(ToolMessage::Redo); + responses.add(OverlaysMessage::Draw); + } + DocumentMessage::RenameDocument { new_name } => { + self.name = new_name; + responses.add(PortfolioMessage::UpdateOpenDocumentsList); + responses.add(NodeGraphMessage::UpdateNewNodeGraph); + } + DocumentMessage::RenderRulers => { + let current_ptz = if self.graph_view_overlay_open { + let Some(network_metadata) = self.network_interface.network_metadata(&self.breadcrumb_network_path) else { + return; + }; + &network_metadata.persistent_metadata.navigation_metadata.node_graph_ptz + } else { + &self.document_ptz + }; + let document_to_viewport = self.navigation_handler.calculate_offset_transform(ipp.viewport_bounds.center(), current_ptz); + + let ruler_scale = if !self.graph_view_overlay_open { + self.navigation_handler.snapped_zoom(current_ptz.zoom()) + } else { + self.navigation_handler.snapped_zoom(current_ptz.zoom() * (crate::consts::GRID_SIZE as f64)) + }; + + let ruler_origin = document_to_viewport.transform_point2(DVec2::ZERO); + let log = ruler_scale.log2(); + let mut ruler_interval: f64 = if log < 0. { 100. * 2_f64.powf(-log.ceil()) } else { 100. / 2_f64.powf(log.ceil()) }; + + // When the interval becomes too small, force it to be a whole number, then to powers of 10. + // The progression of intervals is: + // ..., 100, 50, 25, 12.5, 6 (6.25), 4 (3.125), 2 (1.5625), 1, 0.1, 0.01, ... + if ruler_interval < 1. { + ruler_interval = 10_f64.powf(ruler_interval.log10().ceil()); + } else if ruler_interval < 12.5 { + // Round to nearest even number + ruler_interval = 2. * (ruler_interval / 2.).round(); + } + + if self.graph_view_overlay_open { + ruler_interval = ruler_interval.max(1.); + } + + let ruler_spacing = ruler_interval * ruler_scale; + + responses.add(FrontendMessage::UpdateDocumentRulers { + origin: ruler_origin.into(), + spacing: ruler_spacing, + interval: ruler_interval, + visible: self.rulers_visible, + }); + } + DocumentMessage::RenderScrollbars => { + let document_transform_scale = self.navigation_handler.snapped_zoom(self.document_ptz.zoom()); + + let scale = 0.5 + ASYMPTOTIC_EFFECT + document_transform_scale * SCALE_EFFECT; + + let viewport_size = ipp.viewport_bounds.size(); + let viewport_mid = ipp.viewport_bounds.center(); + let [bounds1, bounds2] = if !self.graph_view_overlay_open { + self.metadata().document_bounds_viewport_space().unwrap_or([viewport_mid; 2]) + } else { + self.network_interface.graph_bounds_viewport_space(&self.breadcrumb_network_path).unwrap_or([viewport_mid; 2]) + }; + let bounds1 = bounds1.min(viewport_mid) - viewport_size * scale; + let bounds2 = bounds2.max(viewport_mid) + viewport_size * scale; + let bounds_length = (bounds2 - bounds1) * (1. + SCROLLBAR_SPACING); + let scrollbar_position = DVec2::splat(0.5) - (bounds1.lerp(bounds2, 0.5) - viewport_mid) / (bounds_length - viewport_size); + let scrollbar_multiplier = bounds_length - viewport_size; + let scrollbar_size = viewport_size / bounds_length; + + responses.add(FrontendMessage::UpdateDocumentScrollbars { + position: scrollbar_position.into(), + size: scrollbar_size.into(), + multiplier: scrollbar_multiplier.into(), + }); + } + DocumentMessage::SaveDocument => { + self.set_save_state(true); + responses.add(PortfolioMessage::AutoSaveActiveDocument); + // Update the save status of the just saved document + responses.add(PortfolioMessage::UpdateOpenDocumentsList); + + let name = match self.name.ends_with(FILE_SAVE_SUFFIX) { + true => self.name.clone(), + false => self.name.clone() + FILE_SAVE_SUFFIX, + }; + responses.add(FrontendMessage::TriggerDownloadTextFile { + document: self.serialize_document(), + name, + }) + } + DocumentMessage::SelectParentLayer => { + let selected_nodes = self.network_interface.selected_nodes(); + let selected_layers = selected_nodes.selected_layers(self.metadata()); + + let mut parent_layers = HashSet::new(); + + // Find the parent of each selected layer + for layer in selected_layers { + // Get this layer's parent + let Some(parent) = layer.parent(self.metadata()) else { continue }; + + // Either use the parent, or keep the same layer if it's already at the top level + let to_insert = if parent == LayerNodeIdentifier::ROOT_PARENT { layer } else { parent }; + + // Add the layer to the set of those which will become selected + parent_layers.insert(to_insert.to_node()); + } + + // Select each parent layer + if !parent_layers.is_empty() { + let nodes = parent_layers.into_iter().collect(); + responses.add(NodeGraphMessage::SelectedNodesSet { nodes }); + responses.add(BroadcastEvent::SelectionChanged); + } + } + DocumentMessage::SelectAllLayers => { + if !self.overlays_visibility_settings.selection_outline() { + return; + } + + let metadata = self.metadata(); + let all_layers_except_artboards_invisible_and_locked = metadata.all_layers().filter(|&layer| !self.network_interface.is_artboard(&layer.to_node(), &[])).filter(|&layer| { + self.network_interface.selected_nodes().layer_visible(layer, &self.network_interface) && !self.network_interface.selected_nodes().layer_locked(layer, &self.network_interface) + }); + let nodes = all_layers_except_artboards_invisible_and_locked.map(|layer| layer.to_node()).collect(); + responses.add(NodeGraphMessage::SelectedNodesSet { nodes }); + } + DocumentMessage::SelectedLayersLower => { + responses.add(DocumentMessage::SelectedLayersReorder { relative_index_offset: 1 }); + } + DocumentMessage::SelectedLayersLowerToBack => { + responses.add(DocumentMessage::SelectedLayersReorder { relative_index_offset: isize::MAX }); + } + DocumentMessage::SelectedLayersRaise => { + responses.add(DocumentMessage::SelectedLayersReorder { relative_index_offset: -1 }); + } + DocumentMessage::SelectedLayersRaiseToFront => { + responses.add(DocumentMessage::SelectedLayersReorder { relative_index_offset: isize::MIN }); + } + DocumentMessage::SelectedLayersReverse => { + self.selected_layers_reverse(responses); + } + DocumentMessage::SelectedLayersReorder { relative_index_offset } => { + self.selected_layers_reorder(relative_index_offset, responses); + } + DocumentMessage::ClipLayer { id } => { + let layer = LayerNodeIdentifier::new(id, &self.network_interface, &[]); + + responses.add(DocumentMessage::AddTransaction); + responses.add(GraphOperationMessage::ClipModeToggle { layer }); + } + DocumentMessage::SelectLayer { id, ctrl, shift } => { + let layer = LayerNodeIdentifier::new(id, &self.network_interface, &[]); + + let mut nodes = vec![]; + + // If we have shift pressed and a layer already selected then fill the range + if let Some(last_selected) = self.layer_range_selection_reference.filter(|_| shift) { + if last_selected == LayerNodeIdentifier::ROOT_PARENT { + log::error!("ROOT_PARENT cannot be selected in SelectLayer"); + return; + } + + nodes.push(last_selected.to_node()); + nodes.push(id); + + // Fill the selection range + self.metadata() + .all_layers() + .skip_while(|&node| node != layer && node != last_selected) + .skip(1) + .take_while(|&node| node != layer && node != last_selected) + .for_each(|node| { + if node == LayerNodeIdentifier::ROOT_PARENT { + log::error!("ROOT_PARENT should not exist in all_layers") + } else { + nodes.push(node.to_node()) + } + }); + } else { + if ctrl { + // Toggle selection when holding ctrl + if self.network_interface.selected_nodes().selected_layers_contains(layer, self.metadata()) { + responses.add_front(NodeGraphMessage::SelectedNodesRemove { nodes: vec![id] }); + } else { + responses.add_front(NodeGraphMessage::SelectedNodesAdd { nodes: vec![id] }); + } + responses.add(BroadcastEvent::SelectionChanged); + } else { + nodes.push(id); + } + + // Set our last selection reference + self.layer_range_selection_reference = Some(layer); + } + + // Don't create messages for empty operations + if !nodes.is_empty() { + // Add or set our selected layers + if ctrl { + responses.add_front(NodeGraphMessage::SelectedNodesAdd { nodes }); + } else { + responses.add_front(NodeGraphMessage::SelectedNodesSet { nodes }); + } + } + } + DocumentMessage::SetActivePanel { active_panel: panel } => { + use crate::messages::portfolio::utility_types::PanelType; + match panel { + PanelType::Document => { + if self.graph_view_overlay_open { + self.selection_network_path.clone_from(&self.breadcrumb_network_path); + } else { + self.selection_network_path = vec![] + } + } + PanelType::Layers => self.selection_network_path = vec![], + _ => {} + } + responses.add(PropertiesPanelMessage::Refresh); + responses.add(NodeGraphMessage::UpdateLayerPanel); + responses.add(NodeGraphMessage::UpdateInSelectedNetwork); + } + DocumentMessage::SetBlendModeForSelectedLayers { blend_mode } => { + for layer in self.network_interface.selected_nodes().selected_layers_except_artboards(&self.network_interface) { + responses.add(GraphOperationMessage::BlendModeSet { layer, blend_mode }); + } + } + DocumentMessage::SetGraphFadeArtwork { percentage } => { + self.graph_fade_artwork_percentage = percentage; + responses.add(FrontendMessage::UpdateGraphFadeArtwork { percentage }); + } + DocumentMessage::SetNodePinned { node_id, pinned } => { + responses.add(DocumentMessage::AddTransaction); + responses.add(NodeGraphMessage::SetPinned { node_id, pinned }); + responses.add(NodeGraphMessage::RunDocumentGraph); + responses.add(NodeGraphMessage::SelectedNodesUpdated); + responses.add(NodeGraphMessage::SendGraph); + } + DocumentMessage::SetOpacityForSelectedLayers { opacity } => { + let opacity = opacity.clamp(0., 1.); + for layer in self.network_interface.selected_nodes().selected_layers_except_artboards(&self.network_interface) { + responses.add(GraphOperationMessage::OpacitySet { layer, opacity }); + } + } + DocumentMessage::SetFillForSelectedLayers { fill } => { + let fill = fill.clamp(0., 1.); + for layer in self.network_interface.selected_nodes().selected_layers_except_artboards(&self.network_interface) { + responses.add(GraphOperationMessage::BlendingFillSet { layer, fill }); + } + } + DocumentMessage::SetOverlaysVisibility { visible, overlays_type } => { + let visibility_settings = &mut self.overlays_visibility_settings; + let overlays_type = match overlays_type { + Some(overlays_type) => overlays_type, + None => { + visibility_settings.all = visible; + responses.add(BroadcastEvent::ToolAbort); + responses.add(OverlaysMessage::Draw); + return; + } + }; + match overlays_type { + OverlaysType::ArtboardName => visibility_settings.artboard_name = visible, + OverlaysType::CompassRose => visibility_settings.compass_rose = visible, + OverlaysType::QuickMeasurement => visibility_settings.quick_measurement = visible, + OverlaysType::TransformMeasurement => visibility_settings.transform_measurement = visible, + OverlaysType::TransformCage => visibility_settings.transform_cage = visible, + OverlaysType::HoverOutline => visibility_settings.hover_outline = visible, + OverlaysType::SelectionOutline => visibility_settings.selection_outline = visible, + OverlaysType::Pivot => visibility_settings.pivot = visible, + OverlaysType::Path => visibility_settings.path = visible, + OverlaysType::Anchors => { + visibility_settings.anchors = visible; + responses.add(PortfolioMessage::UpdateDocumentWidgets); + } + OverlaysType::Handles => visibility_settings.handles = visible, + } + + responses.add(BroadcastEvent::ToolAbort); + responses.add(OverlaysMessage::Draw); + } + DocumentMessage::SetRangeSelectionLayer { new_layer } => { + self.layer_range_selection_reference = new_layer; + } + DocumentMessage::SetSnapping { closure, snapping_state } => { + if let Some(closure) = closure { + *closure(&mut self.snapping_state) = snapping_state; + } + } + DocumentMessage::SetToNodeOrLayer { node_id, is_layer } => { + responses.add(DocumentMessage::StartTransaction); + responses.add(NodeGraphMessage::SetToNodeOrLayer { node_id, is_layer }); + responses.add(DocumentMessage::EndTransaction); + } + DocumentMessage::SetViewMode { view_mode } => { + self.view_mode = view_mode; + responses.add_front(NodeGraphMessage::RunDocumentGraph); + } + DocumentMessage::AddTransaction => { + // Reverse order since they are added to the front + responses.add_front(DocumentMessage::CommitTransaction); + responses.add_front(DocumentMessage::StartTransaction); + } + // Note: A transaction should never be started in a scope that mutates the network interface, since it will only be run after that scope ends. + DocumentMessage::StartTransaction => { + self.network_interface.start_transaction(); + let network_interface_clone = self.network_interface.clone(); + self.document_undo_history.push_back(network_interface_clone); + if self.document_undo_history.len() > crate::consts::MAX_UNDO_HISTORY_LEN { + self.document_undo_history.pop_front(); + } + // Push the UpdateOpenDocumentsList message to the bus in order to update the save status of the open documents + responses.add(PortfolioMessage::UpdateOpenDocumentsList); + } + // Commits the transaction if the network was mutated since the transaction started, otherwise it aborts the transaction + DocumentMessage::EndTransaction => match self.network_interface.transaction_status() { + TransactionStatus::Started => { + responses.add_front(DocumentMessage::AbortTransaction); + } + TransactionStatus::Modified => { + responses.add_front(DocumentMessage::CommitTransaction); + } + TransactionStatus::Finished => {} + }, + DocumentMessage::CommitTransaction => { + if self.network_interface.transaction_status() == TransactionStatus::Finished { + return; + } + self.network_interface.finish_transaction(); + self.document_redo_history.clear(); + } + DocumentMessage::AbortTransaction => { + responses.add(DocumentMessage::RepeatedAbortTransaction { undo_count: 1 }); + } + DocumentMessage::RepeatedAbortTransaction { undo_count } => { + if self.network_interface.transaction_status() == TransactionStatus::Finished { + return; + } + + for _ in 0..undo_count { + self.undo(ipp, responses); + } + + self.network_interface.finish_transaction(); + responses.add(OverlaysMessage::Draw); + } + DocumentMessage::ToggleLayerExpansion { id, recursive } => { + let layer = LayerNodeIdentifier::new(id, &self.network_interface, &[]); + let metadata = self.metadata(); + + let is_collapsed = self.collapsed.0.contains(&layer); + + if is_collapsed { + if recursive { + let children: HashSet<_> = layer.descendants(metadata).collect(); + self.collapsed.0.retain(|collapsed_layer| !children.contains(collapsed_layer) && collapsed_layer != &layer); + } else { + self.collapsed.0.retain(|collapsed_layer| collapsed_layer != &layer); + } + } else { + if recursive { + let children_to_add: Vec<_> = layer.descendants(metadata).filter(|child| !self.collapsed.0.contains(child)).collect(); + self.collapsed.0.extend(children_to_add); + } + self.collapsed.0.push(layer); + } + + responses.add(NodeGraphMessage::SendGraph); + } + DocumentMessage::ToggleSelectedLocked => responses.add(NodeGraphMessage::ToggleSelectedLocked), + DocumentMessage::ToggleSelectedVisibility => { + responses.add(NodeGraphMessage::ToggleSelectedVisibility); + } + DocumentMessage::ToggleGridVisibility => { + self.snapping_state.grid_snapping = !self.snapping_state.grid_snapping; + responses.add(OverlaysMessage::Draw); + responses.add(PortfolioMessage::UpdateDocumentWidgets); + } + DocumentMessage::ToggleOverlaysVisibility => { + self.overlays_visibility_settings.all = !self.overlays_visibility_settings.all(); + responses.add(OverlaysMessage::Draw); + responses.add(PortfolioMessage::UpdateDocumentWidgets); + } + DocumentMessage::ToggleSnapping => { + self.snapping_state.snapping_enabled = !self.snapping_state.snapping_enabled; + responses.add(PortfolioMessage::UpdateDocumentWidgets); + } + DocumentMessage::UpdateUpstreamTransforms { + upstream_footprints, + local_transforms, + } => { + self.network_interface.update_transforms(upstream_footprints, local_transforms); + } + DocumentMessage::UpdateClickTargets { click_targets } => { + // TODO: Allow non layer nodes to have click targets + let layer_click_targets = click_targets + .into_iter() + .filter(|(node_id, _)| + // Ensure that the layer is in the document network to prevent logging an error + self.network_interface.document_network().nodes.contains_key(node_id)) + .filter_map(|(node_id, click_targets)| { + self.network_interface.is_layer(&node_id, &[]).then(|| { + let layer = LayerNodeIdentifier::new(node_id, &self.network_interface, &[]); + (layer, click_targets) + }) + }) + .collect(); + self.network_interface.update_click_targets(layer_click_targets); + } + DocumentMessage::UpdateClipTargets { clip_targets } => { + self.network_interface.update_clip_targets(clip_targets); + } + DocumentMessage::Undo => { + if self.network_interface.transaction_status() != TransactionStatus::Finished { + return; + } + responses.add(ToolMessage::PreUndo); + responses.add(DocumentMessage::DocumentHistoryBackward); + responses.add(OverlaysMessage::Draw); + responses.add(ToolMessage::Undo); + } + DocumentMessage::UngroupSelectedLayers => { + if !self.selection_network_path.is_empty() { + log::error!("Ungrouping selected layers is only supported for the Document Network"); + return; + } + responses.add(DocumentMessage::AddTransaction); + + let folder_paths = self.network_interface.folders_sorted_by_most_nested(&self.selection_network_path); + for folder in folder_paths { + if folder == LayerNodeIdentifier::ROOT_PARENT { + log::error!("ROOT_PARENT cannot be selected when ungrouping selected layers"); + continue; + } + + // Cannot ungroup artboard + if self.network_interface.is_artboard(&folder.to_node(), &self.selection_network_path) { + return; + } + + responses.add(DocumentMessage::UngroupLayer { layer: folder }); + } + + responses.add(NodeGraphMessage::RunDocumentGraph); + responses.add(DocumentMessage::DocumentStructureChanged); + responses.add(NodeGraphMessage::SendGraph); + } + DocumentMessage::UngroupLayer { layer } => { + let parent = layer.parent(self.metadata()).expect("Ungrouped folder must have a parent"); + let folder_index = parent.children(self.metadata()).position(|child| child == layer).unwrap_or(0); + + // Move all children of the folder above the folder in reverse order since each children is moved above the previous one + for child in layer.children(self.metadata()).collect::>().into_iter().rev() { + responses.add(NodeGraphMessage::MoveLayerToStack { + layer: child, + parent, + insert_index: folder_index, + }); + + let metadata = self.network_interface.document_metadata(); + let layer_local_transform = metadata.transform_to_viewport(child); + let undo_parent_transform = if parent == LayerNodeIdentifier::ROOT_PARENT { + // This is functionally the same as transform_to_viewport for the root, however to_node cannot run on the root in debug mode. + metadata.document_to_viewport.inverse() + } else { + metadata.transform_to_viewport(parent).inverse() + }; + let transform = undo_parent_transform * layer_local_transform; + responses.add(GraphOperationMessage::TransformSet { + layer: child, + transform, + transform_in: TransformIn::Local, + skip_rerender: false, + }); + } + + // Delete empty group folder + responses.add(NodeGraphMessage::DeleteNodes { + node_ids: vec![layer.to_node()], + delete_children: true, + }); + responses.add(NodeGraphMessage::RunDocumentGraph); + responses.add(NodeGraphMessage::SelectedNodesUpdated); + responses.add(NodeGraphMessage::SendGraph); + } + DocumentMessage::PTZUpdate => { + if !self.graph_view_overlay_open { + let transform = self.navigation_handler.calculate_offset_transform(ipp.viewport_bounds.center(), &self.document_ptz); + self.network_interface.set_document_to_viewport_transform(transform); + // Ensure selection box is kept in sync with the pointer when the PTZ changes + responses.add(SelectToolMessage::PointerMove(SelectToolPointerKeys { + axis_align: Key::Shift, + snap_angle: Key::Shift, + center: Key::Alt, + duplicate: Key::Alt, + })); + responses.add(NodeGraphMessage::RunDocumentGraph); + } else { + let Some(network_metadata) = self.network_interface.network_metadata(&self.breadcrumb_network_path) else { + return; + }; + + let transform = self + .navigation_handler + .calculate_offset_transform(ipp.viewport_bounds.center(), &network_metadata.persistent_metadata.navigation_metadata.node_graph_ptz); + self.network_interface.set_transform(transform, &self.breadcrumb_network_path); + + responses.add(DocumentMessage::RenderRulers); + responses.add(DocumentMessage::RenderScrollbars); + responses.add(NodeGraphMessage::UpdateEdges); + responses.add(NodeGraphMessage::UpdateBoxSelection); + responses.add(NodeGraphMessage::UpdateImportsExports); + + responses.add(FrontendMessage::UpdateNodeGraphTransform { + transform: Transform { + scale: transform.matrix2.x_axis.x, + x: transform.translation.x, + y: transform.translation.y, + }, + }) + } + } + DocumentMessage::SelectionStepBack => { + self.network_interface.selection_step_back(&self.selection_network_path); + responses.add(BroadcastEvent::SelectionChanged); + } + DocumentMessage::SelectionStepForward => { + self.network_interface.selection_step_forward(&self.selection_network_path); + responses.add(BroadcastEvent::SelectionChanged); + } + DocumentMessage::WrapContentInArtboard { place_artboard_at_origin } => { + // Get bounding box of all layers + let bounds = self.network_interface.document_bounds_document_space(false); + let Some(bounds) = bounds else { return }; + let bounds_rounded_dimensions = (bounds[1] - bounds[0]).round(); + + // Create an artboard and set its dimensions to the bounding box size and location + let node_id = NodeId::new(); + let node_layer_id = LayerNodeIdentifier::new_unchecked(node_id); + let new_artboard_node = document_node_definitions::resolve_document_node_type("Artboard") + .expect("Failed to create artboard node") + .default_node_template(); + responses.add(NodeGraphMessage::InsertNode { + node_id, + node_template: new_artboard_node, + }); + responses.add(NodeGraphMessage::ShiftNodePosition { node_id, x: 15, y: -3 }); + responses.add(GraphOperationMessage::ResizeArtboard { + layer: LayerNodeIdentifier::new_unchecked(node_id), + location: if place_artboard_at_origin { IVec2::ZERO } else { bounds[0].round().as_ivec2() }, + dimensions: bounds_rounded_dimensions.as_ivec2(), + }); + + // Connect the current output data to the artboard's input data, and the artboard's output to the document output + responses.add(NodeGraphMessage::InsertNodeBetween { + node_id, + input_connector: network_interface::InputConnector::Export(0), + insert_node_input_index: 1, + }); + + // Shift the content by half its width and height so it gets centered in the artboard + responses.add(GraphOperationMessage::TransformChange { + layer: node_layer_id, + transform: DAffine2::from_translation(bounds_rounded_dimensions / 2.), + transform_in: TransformIn::Local, + skip_rerender: false, + }); + } + DocumentMessage::ZoomCanvasTo100Percent => { + responses.add_front(NavigationMessage::CanvasZoomSet { zoom_factor: 1. }); + } + DocumentMessage::ZoomCanvasTo200Percent => { + responses.add_front(NavigationMessage::CanvasZoomSet { zoom_factor: 2. }); + } + DocumentMessage::ZoomCanvasToFitAll => { + let bounds = if self.graph_view_overlay_open { + self.network_interface.all_nodes_bounding_box(&self.breadcrumb_network_path).cloned() + } else { + self.network_interface.document_bounds_document_space(true) + }; + if let Some(bounds) = bounds { + if self.document_ptz.flip { + responses.add(NavigationMessage::CanvasFlip); + } + responses.add(NavigationMessage::CanvasTiltSet { angle_radians: 0. }); + responses.add(NavigationMessage::FitViewportToBounds { bounds, prevent_zoom_past_100: true }); + } else { + warn!("Cannot zoom due to no bounds") + } + } + DocumentMessage::Noop => (), + } + } + + fn actions(&self) -> ActionList { + let mut common = actions!(DocumentMessageDiscriminant; + CreateEmptyFolder, + DeselectAllLayers, + GraphViewOverlayToggle, + Noop, + Redo, + SaveDocument, + SelectAllLayers, + SetSnapping, + ToggleGridVisibility, + ToggleOverlaysVisibility, + ToggleSnapping, + Undo, + SelectParentLayer, + SelectionStepForward, + SelectionStepBack, + ZoomCanvasTo100Percent, + ZoomCanvasTo200Percent, + ZoomCanvasToFitAll, + ); + + // Additional actions if there are any selected layers + if self.network_interface.selected_nodes().selected_layers(self.metadata()).next().is_some() { + let mut select = actions!(DocumentMessageDiscriminant; + DeleteSelectedLayers, + DuplicateSelectedLayers, + GroupSelectedLayers, + SelectedLayersLower, + SelectedLayersLowerToBack, + SelectedLayersRaise, + SelectedLayersRaiseToFront, + UngroupSelectedLayers, + ToggleSelectedLocked + ); + if !self.graph_view_overlay_open { + select.extend(actions!(DocumentMessageDiscriminant; + NudgeSelectedLayers, + ToggleSelectedVisibility, + )); + } + common.extend(select); + } + + // Additional actions if the node graph is open + if self.graph_view_overlay_open { + common.extend(actions!(DocumentMessageDiscriminant; + Escape + )); + common.extend(self.node_graph_handler.actions_additional_if_node_graph_is_open()); + } + // More additional actions + common.extend(self.navigation_handler.actions()); + common.extend(self.node_graph_handler.actions()); + common + } +} + +impl DocumentMessageHandler { + /// Runs an intersection test with all layers and a viewport space quad + pub fn intersect_quad<'a>(&'a self, viewport_quad: graphene_std::renderer::Quad, ipp: &InputPreprocessorMessageHandler) -> impl Iterator + use<'a> { + let document_to_viewport = self.navigation_handler.calculate_offset_transform(ipp.viewport_bounds.center(), &self.document_ptz); + let document_quad = document_to_viewport.inverse() * viewport_quad; + + ClickXRayIter::new(&self.network_interface, XRayTarget::Quad(document_quad)) + } + + /// Runs an intersection test with all layers and a viewport space quad; ignoring artboards + pub fn intersect_quad_no_artboards<'a>(&'a self, viewport_quad: graphene_std::renderer::Quad, ipp: &InputPreprocessorMessageHandler) -> impl Iterator + use<'a> { + self.intersect_quad(viewport_quad, ipp).filter(|layer| !self.network_interface.is_artboard(&layer.to_node(), &[])) + } + + /// Runs an intersection test with all layers and a viewport space subpath + pub fn intersect_polygon<'a>(&'a self, mut viewport_polygon: Subpath, ipp: &InputPreprocessorMessageHandler) -> impl Iterator + use<'a> { + let document_to_viewport = self.navigation_handler.calculate_offset_transform(ipp.viewport_bounds.center(), &self.document_ptz); + viewport_polygon.apply_transform(document_to_viewport.inverse()); + + ClickXRayIter::new(&self.network_interface, XRayTarget::Polygon(viewport_polygon)) + } + + /// Runs an intersection test with all layers and a viewport space subpath; ignoring artboards + pub fn intersect_polygon_no_artboards<'a>(&'a self, viewport_polygon: Subpath, ipp: &InputPreprocessorMessageHandler) -> impl Iterator + use<'a> { + self.intersect_polygon(viewport_polygon, ipp).filter(|layer| !self.network_interface.is_artboard(&layer.to_node(), &[])) + } + + pub fn is_layer_fully_inside(&self, layer: &LayerNodeIdentifier, quad: graphene_std::renderer::Quad) -> bool { + // Get the bounding box of the layer in document space + let Some(bounding_box) = self.metadata().bounding_box_viewport(*layer) else { return false }; + + // Check if the bounding box is fully within the selection quad + let [top_left, bottom_right] = bounding_box; + + let quad_bbox = quad.bounding_box(); + + let quad_left = quad_bbox[0].x; + let quad_right = quad_bbox[1].x; + let quad_top = quad_bbox[0].y.max(quad_bbox[1].y); // Correct top + let quad_bottom = quad_bbox[0].y.min(quad_bbox[1].y); // Correct bottom + + // Extract layer's bounding box coordinates + let layer_left = top_left.x; + let layer_right = bottom_right.x; + let layer_top = bottom_right.y; + let layer_bottom = top_left.y; + + layer_left >= quad_left && layer_right <= quad_right && layer_top <= quad_top && layer_bottom >= quad_bottom + } + + pub fn is_layer_fully_inside_polygon(&self, layer: &LayerNodeIdentifier, ipp: &InputPreprocessorMessageHandler, mut viewport_polygon: Subpath) -> bool { + let document_to_viewport = self.navigation_handler.calculate_offset_transform(ipp.viewport_bounds.center(), &self.document_ptz); + viewport_polygon.apply_transform(document_to_viewport.inverse()); + + let layer_click_targets = self.network_interface.document_metadata().click_targets(*layer); + let layer_transform = self.network_interface.document_metadata().transform_to_document(*layer); + + layer_click_targets.is_some_and(|targets| { + targets.iter().all(|target| match target.target_type() { + ClickTargetType::Subpath(subpath) => { + let mut subpath = subpath.clone(); + subpath.apply_transform(layer_transform); + subpath.is_inside_subpath(&viewport_polygon, None, None) + } + ClickTargetType::FreePoint(point) => { + let mut point = *point; + point.apply_transform(layer_transform); + viewport_polygon.contains_point(point.position) + } + }) + }) + } + + /// Find all of the layers that were clicked on from a viewport space location + pub fn click_xray(&self, ipp: &InputPreprocessorMessageHandler) -> impl Iterator + use<'_> { + let document_to_viewport = self.navigation_handler.calculate_offset_transform(ipp.viewport_bounds.center(), &self.document_ptz); + let point = document_to_viewport.inverse().transform_point2(ipp.mouse.position); + ClickXRayIter::new(&self.network_interface, XRayTarget::Point(point)) + } + + /// Find the deepest layer given in the sorted array (by returning the one which is not a folder from the list of layers under the click location). + pub fn find_deepest(&self, node_list: &[LayerNodeIdentifier]) -> Option { + node_list + .iter() + .find(|&&layer| { + if layer != LayerNodeIdentifier::ROOT_PARENT { + !layer.has_children(self.network_interface.document_metadata()) + } else { + log::error!("ROOT_PARENT should not exist in find_deepest"); + false + } + }) + .copied() + } + + /// Find layers under the location in viewport space that was clicked, listed by their depth in the layer tree hierarchy. + pub fn click_list<'a>(&'a self, ipp: &InputPreprocessorMessageHandler) -> impl Iterator + use<'a> { + self.click_xray(ipp) + .filter(move |&layer| !self.network_interface.is_artboard(&layer.to_node(), &[])) + .skip_while(|&layer| layer == LayerNodeIdentifier::ROOT_PARENT) + .scan(true, |last_had_children, layer| { + if *last_had_children { + *last_had_children = layer.has_children(self.network_interface.document_metadata()); + Some(layer) + } else { + None + } + }) + } + + /// Find the deepest layer that has been clicked on from a location in viewport space. + pub fn click(&self, ipp: &InputPreprocessorMessageHandler) -> Option { + self.click_list(ipp).last() + } + + pub fn click_based_on_position(&self, mouse_snapped_positon: DVec2) -> Option { + ClickXRayIter::new(&self.network_interface, XRayTarget::Point(mouse_snapped_positon)) + .filter(move |&layer| !self.network_interface.is_artboard(&layer.to_node(), &[])) + .skip_while(|&layer| layer == LayerNodeIdentifier::ROOT_PARENT) + .scan(true, |last_had_children, layer| { + if *last_had_children { + *last_had_children = layer.has_children(self.network_interface.document_metadata()); + Some(layer) + } else { + None + } + }) + .last() + } + + /// Get the combined bounding box of the click targets of the selected visible layers in viewport space + pub fn selected_visible_layers_bounding_box_viewport(&self) -> Option<[DVec2; 2]> { + self.network_interface + .selected_nodes() + .selected_visible_layers(&self.network_interface) + .filter_map(|layer| self.metadata().bounding_box_viewport(layer)) + .reduce(graphene_std::renderer::Quad::combine_bounds) + } + + pub fn selected_visible_and_unlock_layers_bounding_box_viewport(&self) -> Option<[DVec2; 2]> { + self.network_interface + .selected_nodes() + .selected_visible_and_unlocked_layers(&self.network_interface) + .filter_map(|layer| self.metadata().bounding_box_viewport(layer)) + .reduce(graphene_std::renderer::Quad::combine_bounds) + } + + pub fn document_network(&self) -> &NodeNetwork { + self.network_interface.document_network() + } + + pub fn metadata(&self) -> &DocumentMetadata { + self.network_interface.document_metadata() + } + + pub fn serialize_document(&self) -> String { + let val = serde_json::to_string(self); + // We fully expect the serialization to succeed + val.unwrap() + } + + pub fn deserialize_document(serialized_content: &str) -> Result { + let document_message_handler = serde_json::from_str::(serialized_content) + .or_else(|_| { + // TODO: Eventually remove this document upgrade code + #[derive(Debug, serde::Serialize, serde::Deserialize)] + pub struct OldDocumentMessageHandler { + // ============================================ + // Fields that are saved in the document format + // ============================================ + // + /// The node graph that generates this document's artwork. + /// It recursively stores its sub-graphs, so this root graph is the whole snapshot of the document content. + pub network: OldNodeNetwork, + /// List of the [`NodeId`]s that are currently selected by the user. + pub selected_nodes: SelectedNodes, + /// List of the [`LayerNodeIdentifier`]s that are currently collapsed by the user in the Layers panel. + /// Collapsed means that the expansion arrow isn't set to show the children of these layers. + pub collapsed: CollapsedLayers, + /// The name of the document, which is displayed in the tab and title bar of the editor. + pub name: String, + /// The full Git commit hash of the Graphite repository that was used to build the editor. + /// We save this to provide a hint about which version of the editor was used to create the document. + pub commit_hash: String, + /// The current pan, tilt, and zoom state of the viewport's view of the document canvas. + pub document_ptz: PTZ, + /// The current mode that the document is in, which starts out as Design Mode. This choice affects the editing behavior of the tools. + pub document_mode: DocumentMode, + /// The current view mode that the user has set for rendering the document within the viewport. + /// This is usually "Normal" but can be set to "Outline" or "Pixels" to see the canvas differently. + pub view_mode: ViewMode, + /// Sets whether or not all the viewport overlays should be drawn on top of the artwork. + /// This includes tool interaction visualizations (like the transform cage and path anchors/handles), the grid, and more. + pub overlays_visibility_settings: OverlaysVisibilitySettings, + /// Sets whether or not the rulers should be drawn along the top and left edges of the viewport area. + pub rulers_visible: bool, + /// Sets whether or not the node graph is drawn (as an overlay) on top of the viewport area, or otherwise if it's hidden. + pub graph_view_overlay_open: bool, + /// The current user choices for snapping behavior, including whether snapping is enabled at all. + pub snapping_state: SnappingState, + } + + serde_json::from_str::(serialized_content).map(|old_message_handler| DocumentMessageHandler { + network_interface: NodeNetworkInterface::from_old_network(old_message_handler.network), + collapsed: old_message_handler.collapsed, + commit_hash: old_message_handler.commit_hash, + document_ptz: old_message_handler.document_ptz, + document_mode: old_message_handler.document_mode, + view_mode: old_message_handler.view_mode, + overlays_visibility_settings: old_message_handler.overlays_visibility_settings, + rulers_visible: old_message_handler.rulers_visible, + graph_view_overlay_open: old_message_handler.graph_view_overlay_open, + snapping_state: old_message_handler.snapping_state, + ..Default::default() + }) + }) + .map_err(|e| EditorError::DocumentDeserialization(e.to_string()))?; + Ok(document_message_handler) + } + + /// Called recursively by the entry function [`serialize_root`]. + fn serialize_structure(&self, folder: LayerNodeIdentifier, structure_section: &mut Vec, data_section: &mut Vec, path: &mut Vec) { + let mut space = 0; + for layer_node in folder.children(self.metadata()) { + data_section.push(layer_node.to_node().0); + space += 1; + if layer_node.has_children(self.metadata()) && !self.collapsed.0.contains(&layer_node) { + path.push(layer_node); + + // TODO: Skip if folder is not expanded. + structure_section.push(space); + self.serialize_structure(layer_node, structure_section, data_section, path); + space = 0; + + path.pop(); + } + } + structure_section.push(space | (1 << 63)); + } + + /// Serializes the layer structure into a condensed 1D structure. + /// + /// # Format + /// It is a string of numbers broken into three sections: + /// + /// | Data | Description | Length | + /// |------------------------------------------------------------------------------------------------------------------------------ |---------------------------------------------------------------|------------------| + /// | `4,` `2, 1, -2, -0,` `16533113728871998040,3427872634365736244,18115028555707261608,15878401910454357952,449479075714955186` | Encoded example data | | + /// | _____________________________________________________________________________________________________________________________ | _____________________________________________________________ | ________________ | + /// | **Length** section: `4` | Length of the **Structure** section (`L` = `structure.len()`) | First value | + /// | **Structure** section: `2, 1, -2, -0` | The **Structure** section | Next `L` values | + /// | **Data** section: `16533113728871998040, 3427872634365736244, 18115028555707261608, 15878401910454357952, 449479075714955186` | The **Data** section (layer IDs) | Remaining values | + /// + /// The data section lists the layer IDs for all folders/layers in the tree as read from top to bottom. + /// The structure section lists signed numbers. The sign indicates a folder indentation change (`+` is down a level, `-` is up a level). + /// The numbers in the structure block encode the indentation. For example: + /// - `2` means read two elements from the data section, then place a `[`. + /// - `-x` means read `x` elements from the data section and then insert a `]`. + /// + /// ```text + /// 2 V 1 V -2 A -0 A + /// 16533113728871998040,3427872634365736244, 18115028555707261608, 15878401910454357952,449479075714955186 + /// 16533113728871998040,3427872634365736244,[ 18115028555707261608,[15878401910454357952,449479075714955186] ] + /// ``` + /// + /// Resulting layer panel: + /// ```text + /// 16533113728871998040 + /// 3427872634365736244 + /// [3427872634365736244,18115028555707261608] + /// [3427872634365736244,18115028555707261608,15878401910454357952] + /// [3427872634365736244,18115028555707261608,449479075714955186] + /// ``` + pub fn serialize_root(&self) -> RawBuffer { + let mut structure_section = vec![NodeId(0).0]; + let mut data_section = Vec::new(); + self.serialize_structure(LayerNodeIdentifier::ROOT_PARENT, &mut structure_section, &mut data_section, &mut vec![]); + + // Remove the ROOT element. Prepend `L`, the length (excluding the ROOT) of the structure section (which happens to be where the ROOT element was). + structure_section[0] = structure_section.len() as u64 - 1; + // Append the data section to the end. + structure_section.extend(data_section); + + structure_section.as_slice().into() + } + + pub fn undo_with_history(&mut self, ipp: &InputPreprocessorMessageHandler, responses: &mut VecDeque) { + let Some(previous_network) = self.undo(ipp, responses) else { return }; + + self.document_redo_history.push_back(previous_network); + if self.document_redo_history.len() > crate::consts::MAX_UNDO_HISTORY_LEN { + self.document_redo_history.pop_front(); + } + } + + pub fn undo(&mut self, ipp: &InputPreprocessorMessageHandler, responses: &mut VecDeque) -> Option { + // If there is no history return and don't broadcast SelectionChanged + let mut network_interface = self.document_undo_history.pop_back()?; + + // Set the previous network navigation metadata to the current navigation metadata + network_interface.copy_all_navigation_metadata(&self.network_interface); + std::mem::swap(&mut network_interface.resolved_types, &mut self.network_interface.resolved_types); + + //Update the metadata transform based on document PTZ + let transform = self.navigation_handler.calculate_offset_transform(ipp.viewport_bounds.center(), &self.document_ptz); + network_interface.set_document_to_viewport_transform(transform); + + // Ensure document structure is loaded so that updating the selected nodes has the correct metadata + network_interface.load_structure(); + + let previous_network = std::mem::replace(&mut self.network_interface, network_interface); + + // Push the UpdateOpenDocumentsList message to the bus in order to update the save status of the open documents + responses.add(PortfolioMessage::UpdateOpenDocumentsList); + responses.add(NodeGraphMessage::SelectedNodesUpdated); + responses.add(NodeGraphMessage::ForceRunDocumentGraph); + // TODO: Remove once the footprint is used to load the imports/export distances from the edge + responses.add(NodeGraphMessage::UnloadWires); + responses.add(NodeGraphMessage::SetGridAlignedEdges); + responses.add(Message::StartBuffer); + Some(previous_network) + } + pub fn redo_with_history(&mut self, ipp: &InputPreprocessorMessageHandler, responses: &mut VecDeque) { + // Push the UpdateOpenDocumentsList message to the queue in order to update the save status of the open documents + let Some(previous_network) = self.redo(ipp, responses) else { return }; + + self.document_undo_history.push_back(previous_network); + if self.document_undo_history.len() > crate::consts::MAX_UNDO_HISTORY_LEN { + self.document_undo_history.pop_front(); + } + } + + pub fn redo(&mut self, ipp: &InputPreprocessorMessageHandler, responses: &mut VecDeque) -> Option { + // If there is no history return and don't broadcast SelectionChanged + let mut network_interface = self.document_redo_history.pop_back()?; + + // Set the previous network navigation metadata to the current navigation metadata + network_interface.copy_all_navigation_metadata(&self.network_interface); + std::mem::swap(&mut network_interface.resolved_types, &mut self.network_interface.resolved_types); + + //Update the metadata transform based on document PTZ + let transform = self.navigation_handler.calculate_offset_transform(ipp.viewport_bounds.center(), &self.document_ptz); + network_interface.set_document_to_viewport_transform(transform); + + let previous_network = std::mem::replace(&mut self.network_interface, network_interface); + // Push the UpdateOpenDocumentsList message to the bus in order to update the save status of the open documents + responses.add(PortfolioMessage::UpdateOpenDocumentsList); + responses.add(NodeGraphMessage::SelectedNodesUpdated); + responses.add(NodeGraphMessage::ForceRunDocumentGraph); + responses.add(NodeGraphMessage::UnloadWires); + responses.add(NodeGraphMessage::SendWires); + Some(previous_network) + } + + pub fn current_hash(&self) -> Option { + self.document_undo_history.iter().last().map(|network| network.document_network().current_hash()) + } + + pub fn is_auto_saved(&self) -> bool { + self.current_hash() == self.auto_saved_hash + } + + pub fn is_saved(&self) -> bool { + self.current_hash() == self.saved_hash + } + + pub fn is_graph_overlay_open(&self) -> bool { + self.graph_view_overlay_open + } + + pub fn set_auto_save_state(&mut self, is_saved: bool) { + if is_saved { + self.auto_saved_hash = self.current_hash(); + } else { + self.auto_saved_hash = None; + } + } + + pub fn set_save_state(&mut self, is_saved: bool) { + if is_saved { + self.saved_hash = self.current_hash(); + } else { + self.saved_hash = None; + } + } + + /// Finds the artboard that bounds the point in viewport space and be the container of any newly added layers. + pub fn new_layer_bounding_artboard(&self, ipp: &InputPreprocessorMessageHandler) -> LayerNodeIdentifier { + let container_based_on_selection = self.new_layer_parent(true); + + let container_based_on_clicked_artboard = self + .click_xray(ipp) + .find(|layer| self.network_interface.is_artboard(&layer.to_node(), &[])) + .unwrap_or(LayerNodeIdentifier::ROOT_PARENT); + + if container_based_on_selection.ancestors(self.metadata()).any(|ancestor| ancestor == container_based_on_clicked_artboard) { + container_based_on_selection + } else { + container_based_on_clicked_artboard + } + } + + /// Finds the parent folder which, based on the current selections, should be the container of any newly added layers. + pub fn new_layer_parent(&self, include_self: bool) -> LayerNodeIdentifier { + let Some(selected_nodes) = self.network_interface.selected_nodes_in_nested_network(&self.selection_network_path) else { + warn!("No selected nodes found in new_layer_parent. Defaulting to ROOT_PARENT."); + return LayerNodeIdentifier::ROOT_PARENT; + }; + + self.network_interface + .deepest_common_ancestor(&selected_nodes, &self.selection_network_path, include_self) + .unwrap_or_else(|| self.network_interface.all_artboards().iter().next().copied().unwrap_or(LayerNodeIdentifier::ROOT_PARENT)) + } + + pub fn get_calculated_insert_index(metadata: &DocumentMetadata, selected_nodes: &SelectedNodes, parent: LayerNodeIdentifier) -> usize { + parent + .children(metadata) + .enumerate() + .find_map(|(index, direct_child)| { + if selected_nodes.selected_layers(metadata).any(|selected| selected == direct_child) { + return Some(index); + } + + for descendant in direct_child.descendants(metadata) { + if selected_nodes.selected_layers(metadata).any(|selected| selected == descendant) { + return Some(index); + } + } + + None + }) + .unwrap_or(0) + } + + pub fn group_layers( + responses: &mut VecDeque, + insert_index: usize, + parent: LayerNodeIdentifier, + group_folder_type: GroupFolderType, + network_interface: &mut NodeNetworkInterface, + ) -> NodeId { + let folder_id = NodeId(generate_uuid()); + + match group_folder_type { + GroupFolderType::Layer => responses.add(GraphOperationMessage::NewCustomLayer { + id: folder_id, + nodes: Vec::new(), + parent, + insert_index, + }), + GroupFolderType::BooleanOperation(operation) => { + // Get the ID of the one selected layer, if exactly one is selected + let only_selected_layer = { + let selected_nodes = network_interface.selected_nodes(); + let mut layers = selected_nodes.selected_layers(network_interface.document_metadata()); + + match (layers.next(), layers.next()) { + (Some(id), None) => Some(id), + _ => None, + } + }; + + // If there is a single selected layer, check if there is a boolean operation upstream from it + let upstream_boolean_op = only_selected_layer.and_then(|selected_id| { + network_interface.upstream_flow_back_from_nodes(vec![selected_id.to_node()], &[], FlowType::HorizontalFlow).find(|id| { + network_interface + .reference(id, &[]) + .map(|name| name.as_deref().unwrap_or_default() == "Boolean Operation") + .unwrap_or_default() + }) + }); + + // If there's already a boolean operation on the selected layer, update it with the new operation + if let (Some(upstream_boolean_op), Some(only_selected_layer)) = (upstream_boolean_op, only_selected_layer) { + network_interface.set_input(&InputConnector::node(upstream_boolean_op, 1), NodeInput::value(TaggedValue::BooleanOperation(operation), false), &[]); + + responses.add(NodeGraphMessage::RunDocumentGraph); + + return only_selected_layer.to_node(); + } + // Otherwise, create a new boolean operation node group + else { + responses.add(GraphOperationMessage::NewBooleanOperationLayer { + id: folder_id, + operation, + parent, + insert_index, + }); + } + } + } + + let new_group_folder = LayerNodeIdentifier::new_unchecked(folder_id); + // Move the new folder to the correct position + responses.add(NodeGraphMessage::MoveLayerToStack { + layer: new_group_folder, + parent, + insert_index, + }); + responses.add(DocumentMessage::MoveSelectedLayersToGroup { parent: new_group_folder }); + + folder_id + } + + /// Loads all of the fonts in the document. + pub fn load_layer_resources(&self, responses: &mut VecDeque) { + let mut fonts = HashSet::new(); + for (_node_id, node, _) in self.document_network().recursive_nodes() { + for input in &node.inputs { + if let Some(TaggedValue::Font(font)) = input.as_value() { + fonts.insert(font.clone()); + } + } + } + for font in fonts { + responses.add_front(FrontendMessage::TriggerFontLoad { font }); + } + } + + pub fn update_document_widgets(&self, responses: &mut VecDeque, animation_is_playing: bool, time: Duration) { + // Document mode (dropdown menu at the left of the bar above the viewport, before the tool options) + + let document_mode_layout = WidgetLayout::new(vec![LayoutGroup::Row { + widgets: vec![ + // DropdownInput::new( + // vec![vec![ + // MenuListEntry::new(format!("{:?}", DocumentMode::DesignMode)) + // .label(DocumentMode::DesignMode.to_string()) + // .icon(DocumentMode::DesignMode.icon_name()), + // MenuListEntry::new(format!("{:?}", DocumentMode::SelectMode)) + // .label(DocumentMode::SelectMode.to_string()) + // .icon(DocumentMode::SelectMode.icon_name()) + // .on_commit(|_| DialogMessage::RequestComingSoonDialog { issue: Some(330) }.into()), + // MenuListEntry::new(format!("{:?}", DocumentMode::GuideMode)) + // .label(DocumentMode::GuideMode.to_string()) + // .icon(DocumentMode::GuideMode.icon_name()) + // .on_commit(|_| DialogMessage::RequestComingSoonDialog { issue: Some(331) }.into()), + // ]]) + // .selected_index(Some(self.document_mode as u32)) + // .draw_icon(true) + // .interactive(false) // TODO: set to true when dialogs are not spawned + // .widget_holder(), + // Separator::new(SeparatorType::Section).widget_holder(), + ], + }]); + + responses.add(LayoutMessage::SendLayout { + layout: Layout::WidgetLayout(document_mode_layout), + layout_target: LayoutTarget::DocumentMode, + }); + + // Document bar (right portion of the bar above the viewport) + + let mut snapping_state = self.snapping_state.clone(); + let mut snapping_state2 = self.snapping_state.clone(); + + let mut widgets = vec![ + IconButton::new("PlaybackToStart", 24) + .tooltip("Restart Animation") + .tooltip_shortcut(action_keys!(AnimationMessageDiscriminant::RestartAnimation)) + .on_update(|_| AnimationMessage::RestartAnimation.into()) + .disabled(time == Duration::ZERO) + .widget_holder(), + IconButton::new(if animation_is_playing { "PlaybackPause" } else { "PlaybackPlay" }, 24) + .tooltip(if animation_is_playing { "Pause Animation" } else { "Play Animation" }) + .tooltip_shortcut(action_keys!(AnimationMessageDiscriminant::ToggleLivePreview)) + .on_update(|_| AnimationMessage::ToggleLivePreview.into()) + .widget_holder(), + Separator::new(SeparatorType::Unrelated).widget_holder(), + CheckboxInput::new(self.overlays_visibility_settings.all) + .icon("Overlays") + .tooltip("Overlays") + .tooltip_shortcut(action_keys!(DocumentMessageDiscriminant::ToggleOverlaysVisibility)) + .on_update(|optional_input: &CheckboxInput| { + DocumentMessage::SetOverlaysVisibility { + visible: optional_input.checked, + overlays_type: None, + } + .into() + }) + .widget_holder(), + PopoverButton::new() + .popover_layout(vec![ + LayoutGroup::Row { + widgets: vec![TextLabel::new("Overlays").bold(true).widget_holder()], + }, + LayoutGroup::Row { + widgets: vec![TextLabel::new("General").widget_holder()], + }, + LayoutGroup::Row { + widgets: { + let mut checkbox_id = CheckboxId::default(); + vec![ + CheckboxInput::new(self.overlays_visibility_settings.artboard_name) + .on_update(|optional_input: &CheckboxInput| { + DocumentMessage::SetOverlaysVisibility { + visible: optional_input.checked, + overlays_type: Some(OverlaysType::ArtboardName), + } + .into() + }) + .for_label(checkbox_id.clone()) + .widget_holder(), + TextLabel::new("Artboard Name".to_string()).for_checkbox(&mut checkbox_id).widget_holder(), + ] + }, + }, + LayoutGroup::Row { + widgets: { + let mut checkbox_id = CheckboxId::default(); + vec![ + CheckboxInput::new(self.overlays_visibility_settings.transform_measurement) + .on_update(|optional_input: &CheckboxInput| { + DocumentMessage::SetOverlaysVisibility { + visible: optional_input.checked, + overlays_type: Some(OverlaysType::TransformMeasurement), + } + .into() + }) + .for_label(checkbox_id.clone()) + .widget_holder(), + TextLabel::new("G/R/S Measurement".to_string()).for_checkbox(&mut checkbox_id).widget_holder(), + ] + }, + }, + LayoutGroup::Row { + widgets: vec![TextLabel::new("Select Tool").widget_holder()], + }, + LayoutGroup::Row { + widgets: { + let mut checkbox_id = CheckboxId::default(); + vec![ + CheckboxInput::new(self.overlays_visibility_settings.quick_measurement) + .on_update(|optional_input: &CheckboxInput| { + DocumentMessage::SetOverlaysVisibility { + visible: optional_input.checked, + overlays_type: Some(OverlaysType::QuickMeasurement), + } + .into() + }) + .for_label(checkbox_id.clone()) + .widget_holder(), + TextLabel::new("Quick Measurement".to_string()).for_checkbox(&mut checkbox_id).widget_holder(), + ] + }, + }, + LayoutGroup::Row { + widgets: { + let mut checkbox_id = CheckboxId::default(); + vec![ + CheckboxInput::new(self.overlays_visibility_settings.transform_cage) + .on_update(|optional_input: &CheckboxInput| { + DocumentMessage::SetOverlaysVisibility { + visible: optional_input.checked, + overlays_type: Some(OverlaysType::TransformCage), + } + .into() + }) + .for_label(checkbox_id.clone()) + .widget_holder(), + TextLabel::new("Transform Cage".to_string()).for_checkbox(&mut checkbox_id).widget_holder(), + ] + }, + }, + LayoutGroup::Row { + widgets: { + let mut checkbox_id = CheckboxId::default(); + vec![ + CheckboxInput::new(self.overlays_visibility_settings.compass_rose) + .on_update(|optional_input: &CheckboxInput| { + DocumentMessage::SetOverlaysVisibility { + visible: optional_input.checked, + overlays_type: Some(OverlaysType::CompassRose), + } + .into() + }) + .for_label(checkbox_id.clone()) + .widget_holder(), + TextLabel::new("Transform Dial".to_string()).for_checkbox(&mut checkbox_id).widget_holder(), + ] + }, + }, + LayoutGroup::Row { + widgets: { + let mut checkbox_id = CheckboxId::default(); + vec![ + CheckboxInput::new(self.overlays_visibility_settings.pivot) + .on_update(|optional_input: &CheckboxInput| { + DocumentMessage::SetOverlaysVisibility { + visible: optional_input.checked, + overlays_type: Some(OverlaysType::Pivot), + } + .into() + }) + .for_label(checkbox_id.clone()) + .widget_holder(), + TextLabel::new("Transform Pivot".to_string()).for_checkbox(&mut checkbox_id).widget_holder(), + ] + }, + }, + LayoutGroup::Row { + widgets: { + let mut checkbox_id = CheckboxId::default(); + vec![ + CheckboxInput::new(self.overlays_visibility_settings.hover_outline) + .on_update(|optional_input: &CheckboxInput| { + DocumentMessage::SetOverlaysVisibility { + visible: optional_input.checked, + overlays_type: Some(OverlaysType::HoverOutline), + } + .into() + }) + .for_label(checkbox_id.clone()) + .widget_holder(), + TextLabel::new("Hover Outline".to_string()).for_checkbox(&mut checkbox_id).widget_holder(), + ] + }, + }, + LayoutGroup::Row { + widgets: { + let mut checkbox_id = CheckboxId::default(); + vec![ + CheckboxInput::new(self.overlays_visibility_settings.selection_outline) + .on_update(|optional_input: &CheckboxInput| { + DocumentMessage::SetOverlaysVisibility { + visible: optional_input.checked, + overlays_type: Some(OverlaysType::SelectionOutline), + } + .into() + }) + .for_label(checkbox_id.clone()) + .widget_holder(), + TextLabel::new("Selection Outline".to_string()).for_checkbox(&mut checkbox_id).widget_holder(), + ] + }, + }, + LayoutGroup::Row { + widgets: vec![TextLabel::new("Pen & Path Tools").widget_holder()], + }, + LayoutGroup::Row { + widgets: { + let mut checkbox_id = CheckboxId::default(); + vec![ + CheckboxInput::new(self.overlays_visibility_settings.path) + .on_update(|optional_input: &CheckboxInput| { + DocumentMessage::SetOverlaysVisibility { + visible: optional_input.checked, + overlays_type: Some(OverlaysType::Path), + } + .into() + }) + .for_label(checkbox_id.clone()) + .widget_holder(), + TextLabel::new("Path".to_string()).for_checkbox(&mut checkbox_id).widget_holder(), + ] + }, + }, + LayoutGroup::Row { + widgets: { + let mut checkbox_id = CheckboxId::default(); + vec![ + CheckboxInput::new(self.overlays_visibility_settings.anchors) + .on_update(|optional_input: &CheckboxInput| { + DocumentMessage::SetOverlaysVisibility { + visible: optional_input.checked, + overlays_type: Some(OverlaysType::Anchors), + } + .into() + }) + .for_label(checkbox_id.clone()) + .widget_holder(), + TextLabel::new("Anchors".to_string()).for_checkbox(&mut checkbox_id).widget_holder(), + ] + }, + }, + LayoutGroup::Row { + widgets: { + let mut checkbox_id = CheckboxId::default(); + vec![ + CheckboxInput::new(self.overlays_visibility_settings.handles) + .disabled(!self.overlays_visibility_settings.anchors) + .on_update(|optional_input: &CheckboxInput| { + DocumentMessage::SetOverlaysVisibility { + visible: optional_input.checked, + overlays_type: Some(OverlaysType::Handles), + } + .into() + }) + .for_label(checkbox_id.clone()) + .widget_holder(), + TextLabel::new("Handles".to_string()) + .disabled(!self.overlays_visibility_settings.anchors) + .for_checkbox(&mut checkbox_id) + .widget_holder(), + ] + }, + }, + ]) + .widget_holder(), + Separator::new(SeparatorType::Related).widget_holder(), + CheckboxInput::new(snapping_state.snapping_enabled) + .icon("Snapping") + .tooltip("Snapping") + .tooltip_shortcut(action_keys!(DocumentMessageDiscriminant::ToggleSnapping)) + .on_update(move |optional_input: &CheckboxInput| { + DocumentMessage::SetSnapping { + closure: Some(|snapping_state| &mut snapping_state.snapping_enabled), + snapping_state: optional_input.checked, + } + .into() + }) + .widget_holder(), + PopoverButton::new() + .popover_layout( + [ + LayoutGroup::Row { + widgets: vec![TextLabel::new("Snapping").bold(true).widget_holder()], + }, + LayoutGroup::Row { + widgets: vec![TextLabel::new(SnappingOptions::BoundingBoxes.to_string()).widget_holder()], + }, + ] + .into_iter() + .chain(SNAP_FUNCTIONS_FOR_BOUNDING_BOXES.into_iter().map(|(name, closure, tooltip)| LayoutGroup::Row { + widgets: { + let mut checkbox_id = CheckboxId::default(); + vec![ + CheckboxInput::new(*closure(&mut snapping_state)) + .on_update(move |input: &CheckboxInput| { + DocumentMessage::SetSnapping { + closure: Some(closure), + snapping_state: input.checked, + } + .into() + }) + .tooltip(tooltip) + .for_label(checkbox_id.clone()) + .widget_holder(), + TextLabel::new(name).tooltip(tooltip).for_checkbox(&mut checkbox_id).widget_holder(), + ] + }, + })) + .chain([LayoutGroup::Row { + widgets: vec![TextLabel::new(SnappingOptions::Paths.to_string()).widget_holder()], + }]) + .chain(SNAP_FUNCTIONS_FOR_PATHS.into_iter().map(|(name, closure, tooltip)| LayoutGroup::Row { + widgets: { + let mut checkbox_id = CheckboxId::default(); + vec![ + CheckboxInput::new(*closure(&mut snapping_state2)) + .on_update(move |input: &CheckboxInput| { + DocumentMessage::SetSnapping { + closure: Some(closure), + snapping_state: input.checked, + } + .into() + }) + .tooltip(tooltip) + .for_label(checkbox_id.clone()) + .widget_holder(), + TextLabel::new(name).tooltip(tooltip).for_checkbox(&mut checkbox_id).widget_holder(), + ] + }, + })) + .collect(), + ) + .widget_holder(), + Separator::new(SeparatorType::Related).widget_holder(), + CheckboxInput::new(self.snapping_state.grid_snapping) + .icon("Grid") + .tooltip("Grid") + .tooltip_shortcut(action_keys!(DocumentMessageDiscriminant::ToggleGridVisibility)) + .on_update(|optional_input: &CheckboxInput| DocumentMessage::GridVisibility(optional_input.checked).into()) + .widget_holder(), + PopoverButton::new() + .popover_layout(overlay_options(&self.snapping_state.grid)) + .popover_min_width(Some(320)) + .widget_holder(), + Separator::new(SeparatorType::Unrelated).widget_holder(), + RadioInput::new(vec![ + RadioEntryData::new("normal") + .icon("ViewModeNormal") + .tooltip("View Mode: Normal") + .on_update(|_| DocumentMessage::SetViewMode { view_mode: ViewMode::Normal }.into()), + RadioEntryData::new("outline") + .icon("ViewModeOutline") + .tooltip("View Mode: Outline") + .on_update(|_| DocumentMessage::SetViewMode { view_mode: ViewMode::Outline }.into()), + RadioEntryData::new("pixels") + .icon("ViewModePixels") + .tooltip("View Mode: Pixels") + .on_update(|_| DialogMessage::RequestComingSoonDialog { issue: Some(320) }.into()), + ]) + .selected_index(match self.view_mode { + ViewMode::Normal => Some(0), + _ => Some(1), + }) + .widget_holder(), + // PopoverButton::new() + // .popover_layout(vec![ + // LayoutGroup::Row { + // widgets: vec![TextLabel::new("View Mode").bold(true).widget_holder()], + // }, + // LayoutGroup::Row { + // widgets: vec![TextLabel::new("Coming soon").widget_holder()], + // }, + // ]) + // .widget_holder(), + Separator::new(SeparatorType::Unrelated).widget_holder(), + ]; + + widgets.extend(navigation_controls(&self.document_ptz, &self.navigation_handler, false)); + + let tilt_value = self.navigation_handler.snapped_tilt(self.document_ptz.tilt()) / (std::f64::consts::PI / 180.); + if tilt_value.abs() > 0.00001 { + widgets.extend([ + Separator::new(SeparatorType::Related).widget_holder(), + NumberInput::new(Some(tilt_value)) + .unit("°") + .increment_behavior(NumberInputIncrementBehavior::Callback) + .increment_callback_increase(|number_input: &NumberInput| { + let one = 1. + f64::EPSILON * 100.; + NavigationMessage::CanvasTiltSet { + angle_radians: ((number_input.value.unwrap() / VIEWPORT_ROTATE_SNAP_INTERVAL + one).floor() * VIEWPORT_ROTATE_SNAP_INTERVAL).to_radians(), + } + .into() + }) + .increment_callback_decrease(|number_input: &NumberInput| { + let one = 1. + f64::EPSILON * 100.; + NavigationMessage::CanvasTiltSet { + angle_radians: ((number_input.value.unwrap() / VIEWPORT_ROTATE_SNAP_INTERVAL - one).ceil() * VIEWPORT_ROTATE_SNAP_INTERVAL).to_radians(), + } + .into() + }) + .tooltip("Canvas Tilt") + .on_update(|number_input: &NumberInput| { + NavigationMessage::CanvasTiltSet { + angle_radians: number_input.value.unwrap().to_radians(), + } + .into() + }) + .widget_holder(), + ]); + } + + widgets.extend([ + Separator::new(SeparatorType::Unrelated).widget_holder(), + TextButton::new("Node Graph") + .icon(Some((if self.graph_view_overlay_open { "GraphViewOpen" } else { "GraphViewClosed" }).into())) + .hover_icon(Some((if self.graph_view_overlay_open { "GraphViewClosed" } else { "GraphViewOpen" }).into())) + .tooltip(if self.graph_view_overlay_open { "Hide Node Graph" } else { "Show Node Graph" }) + .tooltip_shortcut(action_keys!(DocumentMessageDiscriminant::GraphViewOverlayToggle)) + .on_update(move |_| DocumentMessage::GraphViewOverlayToggle.into()) + .widget_holder(), + ]); + + let document_bar_layout = WidgetLayout::new(vec![LayoutGroup::Row { widgets }]); + + responses.add(LayoutMessage::SendLayout { + layout: Layout::WidgetLayout(document_bar_layout), + layout_target: LayoutTarget::DocumentBar, + }); + responses.add(NodeGraphMessage::ForceRunDocumentGraph); + } + + pub fn update_layers_panel_control_bar_widgets(&self, responses: &mut VecDeque) { + // Get an iterator over the selected layers (excluding artboards which don't have an opacity or blend mode). + let selected_nodes = self.network_interface.selected_nodes(); + let selected_layers_except_artboards = selected_nodes.selected_layers_except_artboards(&self.network_interface); + + // Look up the current opacity and blend mode of the selected layers (if any), and split the iterator into the first tuple and the rest. + let mut blending_options = selected_layers_except_artboards.map(|layer| { + ( + get_opacity(layer, &self.network_interface).unwrap_or(100.), + get_fill(layer, &self.network_interface).unwrap_or(100.), + get_blend_mode(layer, &self.network_interface).unwrap_or_default(), + ) + }); + let first_blending_options = blending_options.next(); + let result_blending_options = blending_options; + + // If there are no selected layers, disable the opacity and blend mode widgets. + let disabled = first_blending_options.is_none(); + + // Amongst the selected layers, check if the opacities and blend modes are identical across all layers. + // The result is setting `option` and `blend_mode` to Some value if all their values are identical, or None if they are not. + // If identical, we display the value in the widget. If not, we display a dash indicating dissimilarity. + let (opacity, fill, blend_mode) = first_blending_options + .map(|(first_opacity, first_fill, first_blend_mode)| { + let mut opacity_identical = true; + let mut fill_identical = true; + let mut blend_mode_identical = true; + + for (opacity, fill, blend_mode) in result_blending_options { + if (opacity - first_opacity).abs() > (f64::EPSILON * 100.) { + opacity_identical = false; + } + if (fill - first_fill).abs() > (f64::EPSILON * 100.) { + fill_identical = false; + } + if blend_mode != first_blend_mode { + blend_mode_identical = false; + } + } + + ( + opacity_identical.then_some(first_opacity), + fill_identical.then_some(first_fill), + blend_mode_identical.then_some(first_blend_mode), + ) + }) + .unwrap_or((None, None, None)); + + let blend_mode_menu_entries = BlendMode::list_svg_subset() + .iter() + .map(|modes| { + modes + .iter() + .map(|&blend_mode| { + MenuListEntry::new(format!("{blend_mode:?}")) + .label(blend_mode.to_string()) + .on_update(move |_| DocumentMessage::SetBlendModeForSelectedLayers { blend_mode }.into()) + .on_commit(|_| DocumentMessage::AddTransaction.into()) + }) + .collect() + }) + .collect(); + + let has_selection = self.network_interface.selected_nodes().selected_layers(self.metadata()).next().is_some(); + let selection_all_visible = self + .network_interface + .selected_nodes() + .selected_layers(self.metadata()) + .all(|layer| self.network_interface.is_visible(&layer.to_node(), &[])); + let selection_all_locked = self + .network_interface + .selected_nodes() + .selected_layers(self.metadata()) + .all(|layer| self.network_interface.is_locked(&layer.to_node(), &[])); + + let widgets = vec![ + DropdownInput::new(blend_mode_menu_entries) + .selected_index(blend_mode.and_then(|blend_mode| blend_mode.index_in_list_svg_subset()).map(|index| index as u32)) + .disabled(disabled) + .draw_icon(false) + .max_width(100) + .tooltip("Blend Mode") + .widget_holder(), + Separator::new(SeparatorType::Related).widget_holder(), + NumberInput::new(opacity) + .label("Opacity") + .unit("%") + .display_decimal_places(0) + .disabled(disabled) + .min(0.) + .max(100.) + .range_min(Some(0.)) + .range_max(Some(100.)) + .mode_range() + .on_update(|number_input: &NumberInput| { + if let Some(value) = number_input.value { + DocumentMessage::SetOpacityForSelectedLayers { opacity: value / 100. }.into() + } else { + Message::NoOp + } + }) + .on_commit(|_| DocumentMessage::AddTransaction.into()) + .max_width(100) + .tooltip("Opacity") + .widget_holder(), + Separator::new(SeparatorType::Related).widget_holder(), + NumberInput::new(fill) + .label("Fill") + .unit("%") + .display_decimal_places(0) + .disabled(disabled) + .min(0.) + .max(100.) + .range_min(Some(0.)) + .range_max(Some(100.)) + .mode_range() + .on_update(|number_input: &NumberInput| { + if let Some(value) = number_input.value { + DocumentMessage::SetFillForSelectedLayers { fill: value / 100. }.into() + } else { + Message::NoOp + } + }) + .on_commit(|_| DocumentMessage::AddTransaction.into()) + .max_width(100) + .tooltip("Fill") + .widget_holder(), + ]; + let layers_panel_control_bar_left = WidgetLayout::new(vec![LayoutGroup::Row { widgets }]); + + let widgets = vec![ + IconButton::new(if selection_all_locked { "PadlockLocked" } else { "PadlockUnlocked" }, 24) + .hover_icon(Some((if selection_all_locked { "PadlockUnlocked" } else { "PadlockLocked" }).into())) + .tooltip(if selection_all_locked { "Unlock Selected" } else { "Lock Selected" }) + .tooltip_shortcut(action_keys!(DocumentMessageDiscriminant::ToggleSelectedLocked)) + .on_update(|_| NodeGraphMessage::ToggleSelectedLocked.into()) + .disabled(!has_selection) + .widget_holder(), + IconButton::new(if selection_all_visible { "EyeVisible" } else { "EyeHidden" }, 24) + .hover_icon(Some((if selection_all_visible { "EyeHide" } else { "EyeShow" }).into())) + .tooltip(if selection_all_visible { "Hide Selected" } else { "Show Selected" }) + .tooltip_shortcut(action_keys!(DocumentMessageDiscriminant::ToggleSelectedVisibility)) + .on_update(|_| DocumentMessage::ToggleSelectedVisibility.into()) + .disabled(!has_selection) + .widget_holder(), + ]; + let layers_panel_control_bar_right = WidgetLayout::new(vec![LayoutGroup::Row { widgets }]); + + responses.add(LayoutMessage::SendLayout { + layout: Layout::WidgetLayout(layers_panel_control_bar_left), + layout_target: LayoutTarget::LayersPanelControlLeftBar, + }); + responses.add(LayoutMessage::SendLayout { + layout: Layout::WidgetLayout(layers_panel_control_bar_right), + layout_target: LayoutTarget::LayersPanelControlRightBar, + }); + } + + pub fn update_layers_panel_bottom_bar_widgets(&self, responses: &mut VecDeque) { + let selected_nodes = self.network_interface.selected_nodes(); + let mut selected_layers = selected_nodes.selected_layers(self.metadata()); + let selected_layer = selected_layers.next(); + let has_selection = selected_layer.is_some(); + let has_multiple_selection = selected_layers.next().is_some(); + + let widgets = vec![ + PopoverButton::new() + .icon(Some("Node".to_string())) + .menu_direction(Some(MenuDirection::Top)) + .tooltip("Add an operation to the end of this layer's chain of nodes") + .disabled(!has_selection || has_multiple_selection) + .popover_layout({ + let node_chooser = NodeCatalog::new() + .on_update(move |node_type| { + if let Some(layer) = selected_layer { + NodeGraphMessage::CreateNodeInLayerWithTransaction { + node_type: node_type.clone(), + layer: LayerNodeIdentifier::new_unchecked(layer.to_node()), + } + .into() + } else { + Message::NoOp + } + }) + .widget_holder(); + vec![LayoutGroup::Row { widgets: vec![node_chooser] }] + }) + .widget_holder(), + Separator::new(SeparatorType::Unrelated).widget_holder(), + IconButton::new("Folder", 24) + .tooltip("Group Selected") + .tooltip_shortcut(action_keys!(DocumentMessageDiscriminant::GroupSelectedLayers)) + .on_update(|_| { + let group_folder_type = GroupFolderType::Layer; + DocumentMessage::GroupSelectedLayers { group_folder_type }.into() + }) + .disabled(!has_selection) + .widget_holder(), + IconButton::new("NewLayer", 24) + .tooltip("New Layer") + .tooltip_shortcut(action_keys!(DocumentMessageDiscriminant::CreateEmptyFolder)) + .on_update(|_| DocumentMessage::CreateEmptyFolder.into()) + .widget_holder(), + IconButton::new("Trash", 24) + .tooltip("Delete Selected") + .tooltip_shortcut(action_keys!(DocumentMessageDiscriminant::DeleteSelectedLayers)) + .on_update(|_| DocumentMessage::DeleteSelectedLayers.into()) + .disabled(!has_selection) + .widget_holder(), + ]; + let layers_panel_bottom_bar = WidgetLayout::new(vec![LayoutGroup::Row { widgets }]); + + responses.add(LayoutMessage::SendLayout { + layout: Layout::WidgetLayout(layers_panel_bottom_bar), + layout_target: LayoutTarget::LayersPanelBottomBar, + }); + } + + pub fn selected_layers_reverse(&mut self, responses: &mut VecDeque) { + let selected_layers = self.network_interface.selected_nodes(); + let metadata = self.metadata(); + let selected_layer_set = selected_layers.selected_layers(metadata).collect::>(); + + // Ignore those with selected ancestors + let mut top_level_layers = Vec::new(); + for &layer in &selected_layer_set { + let mut is_top_level = true; + let mut current_layer = layer; + + while let Some(parent) = current_layer.parent(metadata) { + if selected_layer_set.contains(&parent) { + is_top_level = false; + break; + } + current_layer = parent; + } + + if is_top_level { + top_level_layers.push(layer); + } + } + + // Group selected layers by their parent + let mut grouped_layers: HashMap> = HashMap::new(); + for &layer in &top_level_layers { + if let Some(parent) = layer.parent(metadata) { + let index = parent.children(metadata).position(|child| child == layer).unwrap_or(usize::MAX); + + grouped_layers.entry(parent).or_default().push((index, layer)); + } + } + + let mut modified = false; + + // Process each group separately + for (parent, mut layers) in grouped_layers { + // Retrieve all children under the parent + let all_children = parent.children(metadata).collect::>(); + + // Separate unselected layers with their original indices + let unselected_layers = all_children + .iter() + .enumerate() + .filter_map(|(index, &layer)| if !selected_layer_set.contains(&layer) { Some((index, layer)) } else { None }) + .collect::>(); + + layers.sort_by_key(|(index, _)| *index); + + let reversed_layers = layers.iter().rev().map(|(_, layer)| *layer).collect::>(); + let selected_positions = layers.iter().map(|(index, _)| *index).collect::>(); + let selected_iter = reversed_layers.into_iter(); + let mut merged_layers = vec![None; all_children.len()]; + + for (&original_index, new_layer) in selected_positions.iter().zip(selected_iter) { + merged_layers[original_index] = Some(new_layer); + } + + // Place unselected layers at their original positions + for (index, layer) in unselected_layers { + if merged_layers[index].is_none() { + merged_layers[index] = Some(layer); + } + } + + let final_layers = merged_layers.into_iter().flatten().collect::>(); + if final_layers.is_empty() { + continue; + } + + if !modified { + responses.add(DocumentMessage::AddTransaction); + } + + for (index, layer) in final_layers.iter().enumerate() { + responses.add(NodeGraphMessage::MoveLayerToStack { + layer: *layer, + parent, + insert_index: index, + }); + } + + modified = true; + } + + if modified { + responses.add(NodeGraphMessage::RunDocumentGraph); + responses.add(NodeGraphMessage::SendGraph); + } + } + + pub fn selected_layers_reorder(&mut self, relative_index_offset: isize, responses: &mut VecDeque) { + let selected_nodes = self.network_interface.selected_nodes(); + let mut selected_layers = selected_nodes.selected_layers(self.metadata()); + + let first_or_last_selected_layer = match relative_index_offset.signum() { + -1 => selected_layers.next(), + 1 => selected_layers.last(), + _ => panic!("selected_layers_reorder() must be given a non-zero value"), + }; + + let Some(pivot_layer) = first_or_last_selected_layer else { + return; + }; + let parent = pivot_layer.parent(self.metadata()).unwrap_or(LayerNodeIdentifier::ROOT_PARENT); + + let sibling_layer_paths: Vec<_> = parent.children(self.metadata()).collect(); + let Some(pivot_index) = sibling_layer_paths.iter().position(|path| *path == pivot_layer) else { + return; + }; + + let max = sibling_layer_paths.len() as i64 - 1; + let insert_index = (pivot_index as i64 + relative_index_offset as i64).clamp(0, max) as usize; + + let Some(&neighbor) = sibling_layer_paths.get(insert_index) else { + return; + }; + let Some(neighbor_index) = sibling_layer_paths.iter().position(|path| *path == neighbor) else { + return; + }; + + // If moving down, insert below this layer. If moving up, insert above this layer. + let insert_index = if relative_index_offset < 0 { neighbor_index } else { neighbor_index + 1 }; + responses.add(DocumentMessage::MoveSelectedLayersTo { parent, insert_index }); + } + + pub fn graph_view_overlay_open(&self) -> bool { + self.graph_view_overlay_open + } +} + +/// Create a network interface with a single export +fn default_document_network_interface() -> NodeNetworkInterface { + let mut network_interface = NodeNetworkInterface::default(); + network_interface.add_export(TaggedValue::ArtboardGroup(graphene_std::ArtboardGroupTable::default()), -1, "", &[]); + network_interface +} + +/// Targets for the [`ClickXRayIter`]. In order to reduce computation, we prefer just a point/path test where possible. +#[derive(Clone)] +enum XRayTarget { + Point(DVec2), + Quad(Quad), + Path(Vec), + Polygon(Subpath), +} + +/// The result for the [`ClickXRayIter`] on the layer +struct XRayResult { + clicked: bool, + use_children: bool, +} + +/// An iterator for finding layers within an [`XRayTarget`]. Constructed by [`DocumentMessageHandler::intersect_quad`] and [`DocumentMessageHandler::click_xray`]. +#[derive(Clone)] +pub struct ClickXRayIter<'a> { + next_layer: Option, + network_interface: &'a NodeNetworkInterface, + parent_targets: Vec<(LayerNodeIdentifier, XRayTarget)>, +} + +fn quad_to_path_lib_segments(quad: Quad) -> Vec { + quad.all_edges().into_iter().map(|[start, end]| path_bool_lib::PathSegment::Line(start, end)).collect() +} + +fn click_targets_to_path_lib_segments<'a>(click_targets: impl Iterator, transform: DAffine2) -> Vec { + let segment = |bezier: bezier_rs::Bezier| match bezier.handles { + bezier_rs::BezierHandles::Linear => path_bool_lib::PathSegment::Line(bezier.start, bezier.end), + bezier_rs::BezierHandles::Quadratic { handle } => path_bool_lib::PathSegment::Quadratic(bezier.start, handle, bezier.end), + bezier_rs::BezierHandles::Cubic { handle_start, handle_end } => path_bool_lib::PathSegment::Cubic(bezier.start, handle_start, handle_end, bezier.end), + }; + click_targets + .filter_map(|target| { + if let ClickTargetType::Subpath(subpath) = target.target_type() { + Some(subpath.iter()) + } else { + None + } + }) + .flatten() + .map(|bezier| segment(bezier.apply_transformation(|x| transform.transform_point2(x)))) + .collect() +} + +impl<'a> ClickXRayIter<'a> { + fn new(network_interface: &'a NodeNetworkInterface, target: XRayTarget) -> Self { + if let Some(first_layer) = LayerNodeIdentifier::ROOT_PARENT.first_child(network_interface.document_metadata()) { + Self { + network_interface, + next_layer: Some(first_layer), + parent_targets: vec![(LayerNodeIdentifier::ROOT_PARENT, target)], + } + } else { + Self { + network_interface, + next_layer: Default::default(), + parent_targets: Default::default(), + } + } + } + + /// Handles the checking of the layer where the target is a rect or path + fn check_layer_area_target(&mut self, click_targets: Option<&Vec>, clip: bool, layer: LayerNodeIdentifier, path: Vec, transform: DAffine2) -> XRayResult { + // Convert back to Bezier-rs types for intersections + let segment = |bezier: &path_bool_lib::PathSegment| match *bezier { + path_bool_lib::PathSegment::Line(start, end) => bezier_rs::Bezier::from_linear_dvec2(start, end), + path_bool_lib::PathSegment::Cubic(start, h1, h2, end) => bezier_rs::Bezier::from_cubic_dvec2(start, h1, h2, end), + path_bool_lib::PathSegment::Quadratic(start, h1, end) => bezier_rs::Bezier::from_quadratic_dvec2(start, h1, end), + path_bool_lib::PathSegment::Arc(_, _, _, _, _, _, _) => unimplemented!(), + }; + let get_clip = || path.iter().map(segment); + + let intersects = click_targets.is_some_and(|targets| targets.iter().any(|target| target.intersect_path(get_clip, transform))); + let clicked = intersects; + let mut use_children = !clip || intersects; + + // In the case of a clip path where the area partially intersects, it is necessary to do a boolean operation. + // We do this on this using the target area to reduce computation (as the target area is usually very simple). + if clip && intersects { + let clip_path = click_targets_to_path_lib_segments(click_targets.iter().flat_map(|x| x.iter()), transform); + let subtracted = boolean_intersect(path, clip_path).into_iter().flatten().collect::>(); + if subtracted.is_empty() { + use_children = false; + } else { + // All child layers will use the new clipped target area + self.parent_targets.push((layer, XRayTarget::Path(subtracted))); + } + } + XRayResult { clicked, use_children } + } + + /// Handles the checking of the layer to find if it has been clicked + fn check_layer(&mut self, layer: LayerNodeIdentifier) -> XRayResult { + let selected_layers = self.network_interface.selected_nodes(); + // Discard invisible and locked layers + if !selected_layers.layer_visible(layer, self.network_interface) || selected_layers.layer_locked(layer, self.network_interface) { + return XRayResult { clicked: false, use_children: false }; + } + + let click_targets = self.network_interface.document_metadata().click_targets(layer); + let transform = self.network_interface.document_metadata().transform_to_document(layer); + let target = &self.parent_targets.last().expect("In `check_layer()`: there should be a `target`").1; + let clip = self.network_interface.document_metadata().is_clip(layer.to_node()); + + match target { + // Single points are much cheaper than paths so have their own special case + XRayTarget::Point(point) => { + let intersects = click_targets.is_some_and(|targets| targets.iter().any(|target| target.intersect_point(*point, transform))); + XRayResult { + clicked: intersects, + use_children: !clip || intersects, + } + } + XRayTarget::Quad(quad) => self.check_layer_area_target(click_targets, clip, layer, quad_to_path_lib_segments(*quad), transform), + XRayTarget::Path(path) => self.check_layer_area_target(click_targets, clip, layer, path.clone(), transform), + XRayTarget::Polygon(polygon) => { + let polygon = polygon.iter_closed().map(|line| path_bool_lib::PathSegment::Line(line.start, line.end)).collect(); + self.check_layer_area_target(click_targets, clip, layer, polygon, transform) + } + } + } +} + +pub fn navigation_controls(ptz: &PTZ, navigation_handler: &NavigationMessageHandler, node_graph: bool) -> Vec { + let mut list = vec![ + IconButton::new("ZoomIn", 24) + .tooltip("Zoom In") + .tooltip_shortcut(action_keys!(NavigationMessageDiscriminant::CanvasZoomIncrease)) + .on_update(|_| NavigationMessage::CanvasZoomIncrease { center_on_mouse: false }.into()) + .widget_holder(), + IconButton::new("ZoomOut", 24) + .tooltip("Zoom Out") + .tooltip_shortcut(action_keys!(NavigationMessageDiscriminant::CanvasZoomDecrease)) + .on_update(|_| NavigationMessage::CanvasZoomDecrease { center_on_mouse: false }.into()) + .widget_holder(), + IconButton::new("ZoomReset", 24) + .tooltip("Reset Tilt and Zoom to 100%") + .tooltip_shortcut(action_keys!(NavigationMessageDiscriminant::CanvasTiltResetAndZoomTo100Percent)) + .on_update(|_| NavigationMessage::CanvasTiltResetAndZoomTo100Percent.into()) + .disabled(ptz.tilt().abs() < 1e-4 && (ptz.zoom() - 1.).abs() < 1e-4) + .widget_holder(), + ]; + if ptz.flip && !node_graph { + list.push( + IconButton::new("Reverse", 24) + .tooltip("Flip the canvas back to its standard orientation") + .tooltip_shortcut(action_keys!(NavigationMessageDiscriminant::CanvasFlip)) + .on_update(|_| NavigationMessage::CanvasFlip.into()) + .widget_holder(), + ); + } + list.extend([ + Separator::new(SeparatorType::Related).widget_holder(), + NumberInput::new(Some(navigation_handler.snapped_zoom(ptz.zoom()) * 100.)) + .unit("%") + .min(0.000001) + .max(1000000.) + .tooltip(if node_graph { "Node Graph Zoom" } else { "Canvas Zoom" }) + .on_update(|number_input: &NumberInput| { + NavigationMessage::CanvasZoomSet { + zoom_factor: number_input.value.unwrap() / 100., + } + .into() + }) + .increment_behavior(NumberInputIncrementBehavior::Callback) + .increment_callback_decrease(|_| NavigationMessage::CanvasZoomDecrease { center_on_mouse: false }.into()) + .increment_callback_increase(|_| NavigationMessage::CanvasZoomIncrease { center_on_mouse: false }.into()) + .widget_holder(), + ]); + list +} + +impl Iterator for ClickXRayIter<'_> { + type Item = LayerNodeIdentifier; + + fn next(&mut self) -> Option { + // While there are still layers in the layer tree + while let Some(layer) = self.next_layer.take() { + let XRayResult { clicked, use_children } = self.check_layer(layer); + let metadata = self.network_interface.document_metadata(); + // If we should use the children and also there is a child, that child is the next layer. + self.next_layer = use_children.then(|| layer.first_child(metadata)).flatten(); + + // If we aren't using children, iterate up the ancestors until there is a layer with a sibling + for ancestor in layer.ancestors(metadata) { + if self.next_layer.is_some() { + break; + } + // If there is a clipped area for this ancestor (that we are now exiting), discard it. + if self.parent_targets.last().is_some_and(|(id, _)| *id == ancestor) { + self.parent_targets.pop(); + } + self.next_layer = ancestor.next_sibling(metadata) + } + + if clicked { + return Some(layer); + } + } + assert!(self.parent_targets.is_empty(), "The parent targets should always be empty (since we have left all layers)"); + None + } +} + +#[cfg(test)] +mod document_message_handler_tests { + use super::*; + use crate::test_utils::test_prelude::*; + + #[tokio::test] + async fn test_layer_selection_with_shift_and_ctrl() { + let mut editor = EditorTestUtils::create(); + editor.new_document().await; + // Three rectangle layers + editor.drag_tool(ToolType::Rectangle, 0., 0., 100., 100., ModifierKeys::empty()).await; + editor.drag_tool(ToolType::Rectangle, 50., 50., 150., 150., ModifierKeys::empty()).await; + editor.drag_tool(ToolType::Rectangle, 100., 100., 200., 200., ModifierKeys::empty()).await; + + let layers: Vec<_> = editor.active_document().metadata().all_layers().collect(); + + // Case 1: Basic selection (no modifier) + editor + .handle_message(DocumentMessage::SelectLayer { + id: layers[0].to_node(), + ctrl: false, + shift: false, + }) + .await; + // Fresh document reference for verification + let document = editor.active_document(); + let selected_nodes = document.network_interface.selected_nodes(); + assert_eq!(selected_nodes.selected_nodes_ref().len(), 1); + assert!(selected_nodes.selected_layers_contains(layers[0], document.metadata())); + + // Case 2: Ctrl + click to add another layer + editor + .handle_message(DocumentMessage::SelectLayer { + id: layers[2].to_node(), + ctrl: true, + shift: false, + }) + .await; + let document = editor.active_document(); + let selected_nodes = document.network_interface.selected_nodes(); + assert_eq!(selected_nodes.selected_nodes_ref().len(), 2); + assert!(selected_nodes.selected_layers_contains(layers[0], document.metadata())); + assert!(selected_nodes.selected_layers_contains(layers[2], document.metadata())); + + // Case 3: Shift + click to select a range + editor + .handle_message(DocumentMessage::SelectLayer { + id: layers[1].to_node(), + ctrl: false, + shift: true, + }) + .await; + let document = editor.active_document(); + let selected_nodes = document.network_interface.selected_nodes(); + // We expect 2 layers to be selected (layers 1 and 2) - not 3 + assert_eq!(selected_nodes.selected_nodes_ref().len(), 2); + assert!(!selected_nodes.selected_layers_contains(layers[0], document.metadata())); + assert!(selected_nodes.selected_layers_contains(layers[1], document.metadata())); + assert!(selected_nodes.selected_layers_contains(layers[2], document.metadata())); + + // Case 4: Ctrl + click to toggle selection (deselect) + editor + .handle_message(DocumentMessage::SelectLayer { + id: layers[1].to_node(), + ctrl: true, + shift: false, + }) + .await; + + // Final fresh document reference + let document = editor.active_document(); + let selected_nodes = document.network_interface.selected_nodes(); + assert_eq!(selected_nodes.selected_nodes_ref().len(), 1); + assert!(!selected_nodes.selected_layers_contains(layers[0], document.metadata())); + assert!(!selected_nodes.selected_layers_contains(layers[1], document.metadata())); + assert!(selected_nodes.selected_layers_contains(layers[2], document.metadata())); + } + + #[tokio::test] + async fn test_layer_rearrangement() { + let mut editor = EditorTestUtils::create(); + editor.new_document().await; + // Create three rectangle layers + editor.drag_tool(ToolType::Rectangle, 0., 0., 100., 100., ModifierKeys::empty()).await; + editor.drag_tool(ToolType::Rectangle, 50., 50., 150., 150., ModifierKeys::empty()).await; + editor.drag_tool(ToolType::Rectangle, 100., 100., 200., 200., ModifierKeys::empty()).await; + + // Helper function to identify layers by bounds + async fn get_layer_by_bounds(editor: &mut EditorTestUtils, min_x: f64, min_y: f64) -> Option { + let document = editor.active_document(); + for layer in document.metadata().all_layers() { + if let Some(bbox) = document.metadata().bounding_box_viewport(layer) { + if (bbox[0].x - min_x).abs() < 1. && (bbox[0].y - min_y).abs() < 1. { + return Some(layer); + } + } + } + None + } + + async fn get_layer_index(editor: &mut EditorTestUtils, layer: LayerNodeIdentifier) -> Option { + let document = editor.active_document(); + let parent = layer.parent(document.metadata())?; + parent.children(document.metadata()).position(|child| child == layer) + } + + let layer_middle = get_layer_by_bounds(&mut editor, 50., 50.).await.unwrap(); + let layer_top = get_layer_by_bounds(&mut editor, 100., 100.).await.unwrap(); + + let initial_index_top = get_layer_index(&mut editor, layer_top).await.unwrap(); + let initial_index_middle = get_layer_index(&mut editor, layer_middle).await.unwrap(); + + // Test 1: Lower the top layer + editor.handle_message(NodeGraphMessage::SelectedNodesSet { nodes: vec![layer_top.to_node()] }).await; + editor.handle_message(DocumentMessage::SelectedLayersLower).await; + let new_index_top = get_layer_index(&mut editor, layer_top).await.unwrap(); + assert!(new_index_top > initial_index_top, "Top layer should have moved down"); + + // Test 2: Raise the middle layer + editor.handle_message(NodeGraphMessage::SelectedNodesSet { nodes: vec![layer_middle.to_node()] }).await; + editor.handle_message(DocumentMessage::SelectedLayersRaise).await; + let new_index_middle = get_layer_index(&mut editor, layer_middle).await.unwrap(); + assert!(new_index_middle < initial_index_middle, "Middle layer should have moved up"); + } + + #[tokio::test] + async fn test_move_folder_into_itself_doesnt_crash() { + let mut editor = EditorTestUtils::create(); + editor.new_document().await; + + // Creating a parent folder + editor.handle_message(DocumentMessage::CreateEmptyFolder).await; + let parent_folder = editor.active_document().metadata().all_layers().next().unwrap(); + + // Creating a child folder inside the parent folder + editor.handle_message(NodeGraphMessage::SelectedNodesSet { nodes: vec![parent_folder.to_node()] }).await; + editor.handle_message(DocumentMessage::CreateEmptyFolder).await; + let child_folder = editor.active_document().metadata().all_layers().next().unwrap(); + + // Attempt to move parent folder into child folder + editor.handle_message(NodeGraphMessage::SelectedNodesSet { nodes: vec![parent_folder.to_node()] }).await; + editor + .handle_message(DocumentMessage::MoveSelectedLayersTo { + parent: child_folder, + insert_index: 0, + }) + .await; + + // The operation completed without crashing + // Verifying application still functions by performing another operation + editor.handle_message(DocumentMessage::CreateEmptyFolder).await; + assert!(true, "Application didn't crash after folder move operation"); + } + #[tokio::test] + async fn test_moving_folder_with_children() { + let mut editor = EditorTestUtils::create(); + editor.new_document().await; + + // Creating two folders at root level + editor.handle_message(DocumentMessage::CreateEmptyFolder).await; + editor.handle_message(DocumentMessage::CreateEmptyFolder).await; + + let folder1 = editor.active_document().metadata().all_layers().next().unwrap(); + let folder2 = editor.active_document().metadata().all_layers().nth(1).unwrap(); + + editor.drag_tool(ToolType::Rectangle, 0., 0., 100., 100., ModifierKeys::empty()).await; + let rect_layer = editor.active_document().metadata().all_layers().next().unwrap(); + + // First move rectangle into folder1 + editor.handle_message(NodeGraphMessage::SelectedNodesSet { nodes: vec![rect_layer.to_node()] }).await; + editor.handle_message(DocumentMessage::MoveSelectedLayersTo { parent: folder1, insert_index: 0 }).await; + + // Verifying rectagle is now in folder1 + let rect_parent = rect_layer.parent(editor.active_document().metadata()).unwrap(); + assert_eq!(rect_parent, folder1, "Rectangle should be inside folder1"); + + // Moving folder1 into folder2 + editor.handle_message(NodeGraphMessage::SelectedNodesSet { nodes: vec![folder1.to_node()] }).await; + editor.handle_message(DocumentMessage::MoveSelectedLayersTo { parent: folder2, insert_index: 0 }).await; + + // Verifing hirarchy: folder2 > folder1 > rectangle + let document = editor.active_document(); + let folder1_parent = folder1.parent(document.metadata()).unwrap(); + assert_eq!(folder1_parent, folder2, "Folder1 should be inside folder2"); + + // Verifing rectangle moved with its parent + let rect_parent = rect_layer.parent(document.metadata()).unwrap(); + assert_eq!(rect_parent, folder1, "Rectangle should still be inside folder1"); + + let rect_grandparent = rect_parent.parent(document.metadata()).unwrap(); + assert_eq!(rect_grandparent, folder2, "Rectangle's grandparent should be folder2"); + } + + // TODO: Fix https://github.com/GraphiteEditor/Graphite/issues/2688 and reenable this as part of that fix. + #[ignore] + #[tokio::test] + async fn test_moving_layers_retains_transforms() { + let mut editor = EditorTestUtils::create(); + editor.new_document().await; + + editor.handle_message(DocumentMessage::CreateEmptyFolder).await; + editor.handle_message(DocumentMessage::CreateEmptyFolder).await; + + let folder2 = editor.active_document().metadata().all_layers().next().unwrap(); + let folder1 = editor.active_document().metadata().all_layers().nth(1).unwrap(); + + // Applying transform to folder1 (translation) + editor.handle_message(NodeGraphMessage::SelectedNodesSet { nodes: vec![folder1.to_node()] }).await; + editor.handle_message(TransformLayerMessage::BeginGrab).await; + editor.move_mouse(100., 50., ModifierKeys::empty(), MouseKeys::NONE).await; + editor + .handle_message(TransformLayerMessage::PointerMove { + slow_key: Key::Shift, + increments_key: Key::Control, + }) + .await; + editor.handle_message(TransformLayerMessage::ApplyTransformOperation { final_transform: true }).await; + + // Applying different transform to folder2 (translation) + editor.handle_message(NodeGraphMessage::SelectedNodesSet { nodes: vec![folder2.to_node()] }).await; + editor.handle_message(TransformLayerMessage::BeginGrab).await; + editor.move_mouse(200., 100., ModifierKeys::empty(), MouseKeys::NONE).await; + editor + .handle_message(TransformLayerMessage::PointerMove { + slow_key: Key::Shift, + increments_key: Key::Control, + }) + .await; + editor.handle_message(TransformLayerMessage::ApplyTransformOperation { final_transform: true }).await; + + // Creating rectangle in folder1 + editor.handle_message(NodeGraphMessage::SelectedNodesSet { nodes: vec![folder1.to_node()] }).await; + editor.drag_tool(ToolType::Rectangle, 0., 0., 100., 100., ModifierKeys::empty()).await; + let rect_layer = editor.active_document().metadata().all_layers().next().unwrap(); + + // Moving the rectangle to folder1 to ensure it's inside + editor.handle_message(NodeGraphMessage::SelectedNodesSet { nodes: vec![rect_layer.to_node()] }).await; + editor.handle_message(DocumentMessage::MoveSelectedLayersTo { parent: folder1, insert_index: 0 }).await; + + editor.handle_message(TransformLayerMessage::BeginGrab).await; + editor.move_mouse(50., 25., ModifierKeys::empty(), MouseKeys::NONE).await; + editor + .handle_message(TransformLayerMessage::PointerMove { + slow_key: Key::Shift, + increments_key: Key::Control, + }) + .await; + editor.handle_message(TransformLayerMessage::ApplyTransformOperation { final_transform: true }).await; + + // Rectangle's viewport position before moving + let document = editor.active_document(); + let rect_bbox_before = document.metadata().bounding_box_viewport(rect_layer).unwrap(); + + // Moving rectangle from folder1 to folder2 + editor.handle_message(DocumentMessage::MoveSelectedLayersTo { parent: folder2, insert_index: 0 }).await; + + // Rectangle's viewport position after moving + let document = editor.active_document(); + let rect_bbox_after = document.metadata().bounding_box_viewport(rect_layer).unwrap(); + + // Verifing the rectangle maintains approximately the same position in viewport space + let before_center = (rect_bbox_before[0] + rect_bbox_before[1]) / 2.; // TODO: Should be: DVec2(0., -25.), regression (#2688) causes it to be: DVec2(100., 25.) + let after_center = (rect_bbox_after[0] + rect_bbox_after[1]) / 2.; // TODO: Should be: DVec2(0., -25.), regression (#2688) causes it to be: DVec2(200., 75.) + let distance = before_center.distance(after_center); // TODO: Should be: 0., regression (#2688) causes it to be: 111.80339887498948 + + assert!( + distance < 1., + "Rectangle should maintain its viewport position after moving between transformed groups.\n\ + Before: {before_center:?}\n\ + After: {after_center:?}\n\ + Dist: {distance} (should be < 1)" + ); + } +} diff --git a/editor/src/messages/portfolio/document/graph_operation/graph_operation_message.rs b/editor/src/messages/portfolio/document/graph_operation/graph_operation_message.rs new file mode 100644 index 0000000000000000000000000000000000000000..abb1aa85945cb175903158e25c57183adea80bee --- /dev/null +++ b/editor/src/messages/portfolio/document/graph_operation/graph_operation_message.rs @@ -0,0 +1,119 @@ +use super::utility_types::TransformIn; +use crate::messages::portfolio::document::utility_types::document_metadata::LayerNodeIdentifier; +use crate::messages::portfolio::document::utility_types::network_interface::NodeTemplate; +use crate::messages::prelude::*; +use bezier_rs::Subpath; +use glam::{DAffine2, DVec2, IVec2}; +use graph_craft::document::NodeId; +use graphene_std::Artboard; +use graphene_std::brush::brush_stroke::BrushStroke; +use graphene_std::raster::BlendMode; +use graphene_std::raster_types::{CPU, RasterDataTable}; +use graphene_std::text::{Font, TypesettingConfig}; +use graphene_std::vector::PointId; +use graphene_std::vector::VectorModificationType; +use graphene_std::vector::style::{Fill, Stroke}; + +#[impl_message(Message, DocumentMessage, GraphOperation)] +#[derive(PartialEq, Clone, Debug, serde::Serialize, serde::Deserialize)] +pub enum GraphOperationMessage { + FillSet { + layer: LayerNodeIdentifier, + fill: Fill, + }, + BlendingFillSet { + layer: LayerNodeIdentifier, + fill: f64, + }, + OpacitySet { + layer: LayerNodeIdentifier, + opacity: f64, + }, + BlendModeSet { + layer: LayerNodeIdentifier, + blend_mode: BlendMode, + }, + ClipModeToggle { + layer: LayerNodeIdentifier, + }, + StrokeSet { + layer: LayerNodeIdentifier, + stroke: Stroke, + }, + TransformChange { + layer: LayerNodeIdentifier, + transform: DAffine2, + transform_in: TransformIn, + skip_rerender: bool, + }, + TransformSet { + layer: LayerNodeIdentifier, + transform: DAffine2, + transform_in: TransformIn, + skip_rerender: bool, + }, + TransformSetPivot { + layer: LayerNodeIdentifier, + pivot: DVec2, + }, + Vector { + layer: LayerNodeIdentifier, + modification_type: VectorModificationType, + }, + Brush { + layer: LayerNodeIdentifier, + strokes: Vec, + }, + SetUpstreamToChain { + layer: LayerNodeIdentifier, + }, + NewArtboard { + id: NodeId, + artboard: Artboard, + }, + NewBitmapLayer { + id: NodeId, + image_frame: RasterDataTable, + parent: LayerNodeIdentifier, + insert_index: usize, + }, + NewBooleanOperationLayer { + id: NodeId, + operation: graphene_std::path_bool::BooleanOperation, + parent: LayerNodeIdentifier, + insert_index: usize, + }, + NewCustomLayer { + id: NodeId, + nodes: Vec<(NodeId, NodeTemplate)>, + parent: LayerNodeIdentifier, + insert_index: usize, + }, + NewVectorLayer { + id: NodeId, + subpaths: Vec>, + parent: LayerNodeIdentifier, + insert_index: usize, + }, + NewTextLayer { + id: NodeId, + text: String, + font: Font, + typesetting: TypesettingConfig, + parent: LayerNodeIdentifier, + insert_index: usize, + }, + ResizeArtboard { + layer: LayerNodeIdentifier, + location: IVec2, + dimensions: IVec2, + }, + RemoveArtboards, + NewSvg { + id: NodeId, + svg: String, + transform: DAffine2, + parent: LayerNodeIdentifier, + insert_index: usize, + }, +} diff --git a/editor/src/messages/portfolio/document/graph_operation/graph_operation_message_handler.rs b/editor/src/messages/portfolio/document/graph_operation/graph_operation_message_handler.rs new file mode 100644 index 0000000000000000000000000000000000000000..375ae5ef0fc61d7e00c98e24354c9105f2819314 --- /dev/null +++ b/editor/src/messages/portfolio/document/graph_operation/graph_operation_message_handler.rs @@ -0,0 +1,473 @@ +use super::transform_utils; +use super::utility_types::ModifyInputsContext; +use crate::messages::portfolio::document::graph_operation::utility_types::TransformIn; +use crate::messages::portfolio::document::utility_types::document_metadata::LayerNodeIdentifier; +use crate::messages::portfolio::document::utility_types::network_interface::{InputConnector, NodeNetworkInterface, OutputConnector}; +use crate::messages::portfolio::document::utility_types::nodes::CollapsedLayers; +use crate::messages::prelude::*; +use crate::messages::tool::common_functionality::graph_modification_utils::get_clip_mode; +use glam::{DAffine2, DVec2, IVec2}; +use graph_craft::document::{NodeId, NodeInput}; +use graphene_std::Color; +use graphene_std::renderer::Quad; +use graphene_std::renderer::convert_usvg_path::convert_usvg_path; +use graphene_std::text::{Font, TypesettingConfig}; +use graphene_std::vector::style::{Fill, Gradient, GradientStops, GradientType, PaintOrder, Stroke, StrokeAlign, StrokeCap, StrokeJoin}; + +#[derive(Debug, Clone)] +struct ArtboardInfo { + input_node: NodeInput, + output_nodes: Vec, + merge_node: NodeId, +} + +pub struct GraphOperationMessageData<'a> { + pub network_interface: &'a mut NodeNetworkInterface, + pub collapsed: &'a mut CollapsedLayers, + pub node_graph: &'a mut NodeGraphMessageHandler, +} + +#[derive(Debug, Clone, PartialEq, Default, serde::Serialize, serde::Deserialize)] +pub struct GraphOperationMessageHandler {} + +// GraphOperationMessageHandler always modified the document network. This is so changes to the layers panel will only affect the document network. +// For changes to the selected network, use NodeGraphMessageHandler. No NodeGraphMessage's should be added here, since they will affect the selected nested network. +impl MessageHandler> for GraphOperationMessageHandler { + fn process_message(&mut self, message: GraphOperationMessage, responses: &mut VecDeque, data: GraphOperationMessageData) { + let network_interface = data.network_interface; + + match message { + GraphOperationMessage::FillSet { layer, fill } => { + if let Some(mut modify_inputs) = ModifyInputsContext::new_with_layer(layer, network_interface, responses) { + modify_inputs.fill_set(fill); + } + } + GraphOperationMessage::BlendingFillSet { layer, fill } => { + if let Some(mut modify_inputs) = ModifyInputsContext::new_with_layer(layer, network_interface, responses) { + modify_inputs.blending_fill_set(fill); + } + } + GraphOperationMessage::OpacitySet { layer, opacity } => { + if let Some(mut modify_inputs) = ModifyInputsContext::new_with_layer(layer, network_interface, responses) { + modify_inputs.opacity_set(opacity); + } + } + GraphOperationMessage::BlendModeSet { layer, blend_mode } => { + if let Some(mut modify_inputs) = ModifyInputsContext::new_with_layer(layer, network_interface, responses) { + modify_inputs.blend_mode_set(blend_mode); + } + } + GraphOperationMessage::ClipModeToggle { layer } => { + let clip_mode = get_clip_mode(layer, network_interface); + if let Some(mut modify_inputs) = ModifyInputsContext::new_with_layer(layer, network_interface, responses) { + modify_inputs.clip_mode_toggle(clip_mode); + } + } + GraphOperationMessage::StrokeSet { layer, stroke } => { + if let Some(mut modify_inputs) = ModifyInputsContext::new_with_layer(layer, network_interface, responses) { + modify_inputs.stroke_set(stroke); + } + } + GraphOperationMessage::TransformChange { + layer, + transform, + transform_in, + skip_rerender, + } => { + let parent_transform = network_interface.document_metadata().downstream_transform_to_viewport(layer); + if let Some(mut modify_inputs) = ModifyInputsContext::new_with_layer(layer, network_interface, responses) { + modify_inputs.transform_change_with_parent(transform, transform_in, parent_transform, skip_rerender); + } + } + GraphOperationMessage::TransformSet { + layer, + transform, + transform_in, + skip_rerender, + } => { + if let Some(mut modify_inputs) = ModifyInputsContext::new_with_layer(layer, network_interface, responses) { + modify_inputs.transform_set(transform, transform_in, skip_rerender); + } + } + GraphOperationMessage::TransformSetPivot { layer, pivot } => { + if layer == LayerNodeIdentifier::ROOT_PARENT { + log::error!("Cannot run TransformSetPivot on ROOT_PARENT"); + return; + } + if let Some(mut modify_inputs) = ModifyInputsContext::new_with_layer(layer, network_interface, responses) { + modify_inputs.pivot_set(pivot); + } + } + GraphOperationMessage::Vector { layer, modification_type } => { + if layer == LayerNodeIdentifier::ROOT_PARENT { + log::error!("Cannot run Vector on ROOT_PARENT"); + return; + } + if let Some(mut modify_inputs) = ModifyInputsContext::new_with_layer(layer, network_interface, responses) { + modify_inputs.vector_modify(modification_type); + } + } + GraphOperationMessage::Brush { layer, strokes } => { + if let Some(mut modify_inputs) = ModifyInputsContext::new_with_layer(layer, network_interface, responses) { + modify_inputs.brush_modify(strokes); + } + } + GraphOperationMessage::SetUpstreamToChain { layer } => { + let Some(OutputConnector::Node { node_id: first_chain_node, .. }) = network_interface.upstream_output_connector(&InputConnector::node(layer.to_node(), 1), &[]) else { + return; + }; + + network_interface.force_set_upstream_to_chain(&first_chain_node, &[]); + } + GraphOperationMessage::NewArtboard { id, artboard } => { + let mut modify_inputs = ModifyInputsContext::new(network_interface, responses); + + let artboard_layer = modify_inputs.create_artboard(id, artboard); + network_interface.move_layer_to_stack(artboard_layer, LayerNodeIdentifier::ROOT_PARENT, 0, &[]); + + // If there is a non artboard feeding into the primary input of the artboard, move it to the secondary input + let Some(artboard) = network_interface.document_network().nodes.get(&id) else { + log::error!("Artboard not created"); + return; + }; + let primary_input = artboard.inputs.first().expect("Artboard should have a primary input").clone(); + if let NodeInput::Node { node_id, .. } = &primary_input { + if network_interface.is_layer(node_id, &[]) && !network_interface.is_artboard(node_id, &[]) { + network_interface.move_layer_to_stack(LayerNodeIdentifier::new(*node_id, network_interface, &[]), artboard_layer, 0, &[]); + } else { + network_interface.disconnect_input(&InputConnector::node(artboard_layer.to_node(), 0), &[]); + network_interface.set_input(&InputConnector::node(id, 0), primary_input, &[]); + } + } + responses.add_front(NodeGraphMessage::SelectedNodesSet { nodes: vec![id] }); + responses.add(NodeGraphMessage::RunDocumentGraph); + } + GraphOperationMessage::NewBitmapLayer { + id, + image_frame, + parent, + insert_index, + } => { + let mut modify_inputs = ModifyInputsContext::new(network_interface, responses); + let layer = modify_inputs.create_layer(id); + modify_inputs.insert_image_data(image_frame, layer); + network_interface.move_layer_to_stack(layer, parent, insert_index, &[]); + responses.add(NodeGraphMessage::RunDocumentGraph); + } + GraphOperationMessage::NewBooleanOperationLayer { id, operation, parent, insert_index } => { + let mut modify_inputs = ModifyInputsContext::new(network_interface, responses); + let layer = modify_inputs.create_layer(id); + modify_inputs.insert_boolean_data(operation, layer); + network_interface.move_layer_to_stack(layer, parent, insert_index, &[]); + responses.add(NodeGraphMessage::SetDisplayNameImpl { + node_id: id, + alias: "Boolean Operation".to_string(), + }); + responses.add(NodeGraphMessage::RunDocumentGraph); + } + GraphOperationMessage::NewCustomLayer { id, nodes, parent, insert_index } => { + let mut modify_inputs = ModifyInputsContext::new(network_interface, responses); + let layer = modify_inputs.create_layer(id); + + if !nodes.is_empty() { + // Add the nodes to the network + let new_ids: HashMap<_, _> = nodes.iter().map(|(id, _)| (*id, NodeId::new())).collect(); + // Since all the new nodes are already connected, just connect the input of the layer to first new node + let first_new_node_id = new_ids[&NodeId(0)]; + responses.add(NodeGraphMessage::AddNodes { nodes, new_ids }); + + responses.add(NodeGraphMessage::SetInput { + input_connector: InputConnector::node(layer.to_node(), 1), + input: NodeInput::node(first_new_node_id, 0), + }); + } + // Move the layer and all nodes to the correct position in the network + responses.add(NodeGraphMessage::MoveLayerToStack { layer, parent, insert_index }); + responses.add(NodeGraphMessage::RunDocumentGraph); + } + GraphOperationMessage::NewVectorLayer { id, subpaths, parent, insert_index } => { + let mut modify_inputs = ModifyInputsContext::new(network_interface, responses); + let layer = modify_inputs.create_layer(id); + modify_inputs.insert_vector_data(subpaths, layer, true, true, true); + network_interface.move_layer_to_stack(layer, parent, insert_index, &[]); + responses.add(NodeGraphMessage::RunDocumentGraph); + } + GraphOperationMessage::NewTextLayer { + id, + text, + font, + typesetting, + parent, + insert_index, + } => { + let mut modify_inputs = ModifyInputsContext::new(network_interface, responses); + let layer = modify_inputs.create_layer(id); + modify_inputs.insert_text(text, font, typesetting, layer); + network_interface.move_layer_to_stack(layer, parent, insert_index, &[]); + responses.add(GraphOperationMessage::StrokeSet { layer, stroke: Stroke::default() }); + responses.add(NodeGraphMessage::RunDocumentGraph); + } + GraphOperationMessage::ResizeArtboard { layer, location, dimensions } => { + if let Some(mut modify_inputs) = ModifyInputsContext::new_with_layer(layer, network_interface, responses) { + modify_inputs.resize_artboard(location, dimensions); + } + } + GraphOperationMessage::RemoveArtboards => { + if network_interface.all_artboards().is_empty() { + return; + } + + responses.add(DocumentMessage::AddTransaction); + responses.add(NodeGraphMessage::DeleteNodes { + node_ids: network_interface.all_artboards().iter().map(|layer_node| layer_node.to_node()).collect(), + delete_children: false, + }); + + let mut artboard_data: HashMap = HashMap::new(); + + // Go through all artboards and create merge nodes + for artboard in network_interface.all_artboards() { + let node_id = NodeId::new(); + let Some(document_node) = network_interface.document_network().nodes.get(&artboard.to_node()) else { + log::error!("Artboard not created"); + responses.add(DocumentMessage::AbortTransaction); + return; + }; + + artboard_data.insert( + artboard.to_node(), + ArtboardInfo { + input_node: NodeInput::node(document_node.inputs[1].as_node().unwrap_or_default(), 0), + output_nodes: network_interface + .outward_wires(&[]) + .and_then(|outward_wires| outward_wires.get(&OutputConnector::node(artboard.to_node(), 0))) + .cloned() + .unwrap_or_default(), + merge_node: node_id, + }, + ); + + let mut modify_inputs = ModifyInputsContext::new(network_interface, responses); + modify_inputs.create_layer(node_id); + + responses.add(NodeGraphMessage::SetDisplayName { + node_id, + alias: network_interface.display_name(&artboard.to_node(), &[]), + skip_adding_history_step: true, + }); + + // Shift node positions in the graph + let (x, y) = network_interface.position(&artboard.to_node(), &[]).unwrap_or_default().into(); + responses.add(NodeGraphMessage::ShiftNodePosition { node_id, x, y }); + } + + // Go through all artboards and connect them to the merge nodes + for artboard in &artboard_data { + // Modify downstream connections + responses.add(NodeGraphMessage::SetInput { + input_connector: InputConnector::node(artboard.1.merge_node, 1), + input: NodeInput::node(artboard.1.input_node.as_node().unwrap_or_default(), 0), + }); + + // Modify upstream connections + for outward_wire in &artboard.1.output_nodes { + let input = NodeInput::node(artboard_data[artboard.0].merge_node, 0); + let input_connector = match artboard_data.get(&outward_wire.node_id().unwrap_or_default()) { + Some(artboard_info) => InputConnector::node(artboard_info.merge_node, outward_wire.input_index()), + _ => *outward_wire, + }; + responses.add(NodeGraphMessage::SetInput { input_connector, input }); + } + + // Apply a transformation to the newly created layers to match the original artboard position + let offset = network_interface + .document_metadata() + .bounding_box_document(LayerNodeIdentifier::new_unchecked(*artboard.0)) + .map(|p| p[0]) + .unwrap_or_default(); + responses.add(GraphOperationMessage::TransformChange { + layer: LayerNodeIdentifier::new_unchecked(artboard.1.merge_node), + transform: DAffine2::from_translation(offset), + transform_in: TransformIn::Local, + skip_rerender: false, + }); + } + + responses.add(NodeGraphMessage::RunDocumentGraph); + responses.add(NodeGraphMessage::SelectedNodesUpdated); + responses.add(NodeGraphMessage::SendGraph); + } + GraphOperationMessage::NewSvg { + id, + svg, + transform, + parent, + insert_index, + } => { + let tree = match usvg::Tree::from_str(&svg, &usvg::Options::default()) { + Ok(t) => t, + Err(e) => { + responses.add(DialogMessage::DisplayDialogError { + title: "SVG parsing failed".to_string(), + description: e.to_string(), + }); + return; + } + }; + let mut modify_inputs = ModifyInputsContext::new(network_interface, responses); + + let size = tree.size(); + let offset_to_center = DVec2::new(size.width() as f64, size.height() as f64) / -2.; + let transform = transform * DAffine2::from_translation(offset_to_center); + + import_usvg_node(&mut modify_inputs, &usvg::Node::Group(Box::new(tree.root().clone())), transform, id, parent, insert_index); + } + } + } + + fn actions(&self) -> ActionList { + actions!(GraphOperationMessage;) + } +} + +fn usvg_color(c: usvg::Color, a: f32) -> Color { + Color::from_rgbaf32_unchecked(c.red as f32 / 255., c.green as f32 / 255., c.blue as f32 / 255., a) +} + +fn usvg_transform(c: usvg::Transform) -> DAffine2 { + DAffine2::from_cols_array(&[c.sx as f64, c.ky as f64, c.kx as f64, c.sy as f64, c.tx as f64, c.ty as f64]) +} + +fn import_usvg_node(modify_inputs: &mut ModifyInputsContext, node: &usvg::Node, transform: DAffine2, id: NodeId, parent: LayerNodeIdentifier, insert_index: usize) { + let layer = modify_inputs.create_layer(id); + modify_inputs.network_interface.move_layer_to_stack(layer, parent, insert_index, &[]); + modify_inputs.layer_node = Some(layer); + if let Some(upstream_layer) = layer.next_sibling(modify_inputs.network_interface.document_metadata()) { + modify_inputs.network_interface.shift_node(&upstream_layer.to_node(), IVec2::new(0, 3), &[]); + } + match node { + usvg::Node::Group(group) => { + for child in group.children() { + import_usvg_node(modify_inputs, child, transform, NodeId::new(), layer, 0); + } + modify_inputs.layer_node = Some(layer); + } + usvg::Node::Path(path) => { + let subpaths = convert_usvg_path(path); + let bounds = subpaths.iter().filter_map(|subpath| subpath.bounding_box()).reduce(Quad::combine_bounds).unwrap_or_default(); + + modify_inputs.insert_vector_data(subpaths, layer, true, path.fill().is_some(), path.stroke().is_some()); + + if let Some(transform_node_id) = modify_inputs.existing_node_id("Transform", true) { + transform_utils::update_transform(modify_inputs.network_interface, &transform_node_id, transform * usvg_transform(node.abs_transform())); + } + + if let Some(fill) = path.fill() { + let bounds_transform = DAffine2::from_scale_angle_translation(bounds[1] - bounds[0], 0., bounds[0]); + apply_usvg_fill(fill, modify_inputs, transform * usvg_transform(node.abs_transform()), bounds_transform); + } + if let Some(stroke) = path.stroke() { + apply_usvg_stroke(stroke, modify_inputs, transform * usvg_transform(node.abs_transform())); + } + } + usvg::Node::Image(_image) => { + warn!("Skip image") + } + usvg::Node::Text(text) => { + let font = Font::new(graphene_std::consts::DEFAULT_FONT_FAMILY.to_string(), graphene_std::consts::DEFAULT_FONT_STYLE.to_string()); + modify_inputs.insert_text(text.chunks().iter().map(|chunk| chunk.text()).collect(), font, TypesettingConfig::default(), layer); + modify_inputs.fill_set(Fill::Solid(Color::BLACK)); + } + } +} + +fn apply_usvg_stroke(stroke: &usvg::Stroke, modify_inputs: &mut ModifyInputsContext, transform: DAffine2) { + if let usvg::Paint::Color(color) = &stroke.paint() { + modify_inputs.stroke_set(Stroke { + color: Some(usvg_color(*color, stroke.opacity().get())), + weight: stroke.width().get() as f64, + dash_lengths: stroke.dasharray().as_ref().map(|lengths| lengths.iter().map(|&length| length as f64).collect()).unwrap_or_default(), + dash_offset: stroke.dashoffset() as f64, + cap: match stroke.linecap() { + usvg::LineCap::Butt => StrokeCap::Butt, + usvg::LineCap::Round => StrokeCap::Round, + usvg::LineCap::Square => StrokeCap::Square, + }, + join: match stroke.linejoin() { + usvg::LineJoin::Miter => StrokeJoin::Miter, + usvg::LineJoin::MiterClip => StrokeJoin::Miter, + usvg::LineJoin::Round => StrokeJoin::Round, + usvg::LineJoin::Bevel => StrokeJoin::Bevel, + }, + join_miter_limit: stroke.miterlimit().get() as f64, + align: StrokeAlign::Center, + paint_order: PaintOrder::StrokeAbove, + transform, + non_scaling: false, + }) + } +} + +fn apply_usvg_fill(fill: &usvg::Fill, modify_inputs: &mut ModifyInputsContext, transform: DAffine2, bounds_transform: DAffine2) { + modify_inputs.fill_set(match &fill.paint() { + usvg::Paint::Color(color) => Fill::solid(usvg_color(*color, fill.opacity().get())), + usvg::Paint::LinearGradient(linear) => { + let local = [DVec2::new(linear.x1() as f64, linear.y1() as f64), DVec2::new(linear.x2() as f64, linear.y2() as f64)]; + + // TODO: fix this + // let to_doc_transform = if linear.base.units() == usvg::Units::UserSpaceOnUse { + // transform + // } else { + // transformed_bound_transform + // }; + let to_doc_transform = transform; + let to_doc = to_doc_transform * usvg_transform(linear.transform()); + + let document = [to_doc.transform_point2(local[0]), to_doc.transform_point2(local[1])]; + let layer = [transform.inverse().transform_point2(document[0]), transform.inverse().transform_point2(document[1])]; + + let [start, end] = [bounds_transform.inverse().transform_point2(layer[0]), bounds_transform.inverse().transform_point2(layer[1])]; + let stops = linear.stops().iter().map(|stop| (stop.offset().get() as f64, usvg_color(stop.color(), stop.opacity().get()))).collect(); + let stops = GradientStops::new(stops); + + Fill::Gradient(Gradient { + start, + end, + transform: DAffine2::IDENTITY, + gradient_type: GradientType::Linear, + stops, + }) + } + usvg::Paint::RadialGradient(radial) => { + let local = [DVec2::new(radial.cx() as f64, radial.cy() as f64), DVec2::new(radial.fx() as f64, radial.fy() as f64)]; + + // TODO: fix this + // let to_doc_transform = if radial.base.units == usvg::Units::UserSpaceOnUse { + // transform + // } else { + // transformed_bound_transform + // }; + let to_doc_transform = transform; + let to_doc = to_doc_transform * usvg_transform(radial.transform()); + + let document = [to_doc.transform_point2(local[0]), to_doc.transform_point2(local[1])]; + let layer = [transform.inverse().transform_point2(document[0]), transform.inverse().transform_point2(document[1])]; + + let [start, end] = [bounds_transform.inverse().transform_point2(layer[0]), bounds_transform.inverse().transform_point2(layer[1])]; + let stops = radial.stops().iter().map(|stop| (stop.offset().get() as f64, usvg_color(stop.color(), stop.opacity().get()))).collect(); + let stops = GradientStops::new(stops); + + Fill::Gradient(Gradient { + start, + end, + transform: DAffine2::IDENTITY, + gradient_type: GradientType::Radial, + stops, + }) + } + usvg::Paint::Pattern(_) => { + warn!("Skip pattern"); + return; + } + }); +} diff --git a/editor/src/messages/portfolio/document/graph_operation/mod.rs b/editor/src/messages/portfolio/document/graph_operation/mod.rs new file mode 100644 index 0000000000000000000000000000000000000000..c85d45010b156483f097c11797de1d52a86af327 --- /dev/null +++ b/editor/src/messages/portfolio/document/graph_operation/mod.rs @@ -0,0 +1,9 @@ +mod graph_operation_message; +pub mod graph_operation_message_handler; +pub mod transform_utils; +pub mod utility_types; + +#[doc(inline)] +pub use graph_operation_message::*; +#[doc(inline)] +pub use graph_operation_message_handler::*; diff --git a/editor/src/messages/portfolio/document/graph_operation/transform_utils.rs b/editor/src/messages/portfolio/document/graph_operation/transform_utils.rs new file mode 100644 index 0000000000000000000000000000000000000000..2b3639516ddffd3069b9a0ead70d80b090c7a0e3 --- /dev/null +++ b/editor/src/messages/portfolio/document/graph_operation/transform_utils.rs @@ -0,0 +1,166 @@ +use crate::messages::portfolio::document::utility_types::network_interface::{InputConnector, NodeNetworkInterface}; +use bezier_rs::Subpath; +use glam::{DAffine2, DVec2}; +use graph_craft::document::value::TaggedValue; +use graph_craft::document::{NodeId, NodeInput}; +use graphene_std::vector::PointId; + +/// Convert an affine transform into the tuple `(scale, angle, translation, shear)` assuming `shear.y = 0`. +pub fn compute_scale_angle_translation_shear(transform: DAffine2) -> (DVec2, f64, DVec2, DVec2) { + let x_axis = transform.matrix2.x_axis; + let y_axis = transform.matrix2.y_axis; + + // Assuming there is no vertical shear + let angle = x_axis.y.atan2(x_axis.x); + let (sin, cos) = angle.sin_cos(); + let scale_x = if cos.abs() > 1e-10 { x_axis.x / cos } else { x_axis.y / sin }; + + let mut shear_x = (sin * y_axis.y + cos * y_axis.x) / (sin * sin * scale_x + cos * cos * scale_x); + if !shear_x.is_finite() { + shear_x = 0.; + } + let scale_y = if cos.abs() > 1e-10 { + (y_axis.y - scale_x * sin * shear_x) / cos + } else { + (scale_x * cos * shear_x - y_axis.x) / sin + }; + let translation = transform.translation; + let scale = DVec2::new(scale_x, scale_y); + let shear = DVec2::new(shear_x, 0.); + (scale, angle, translation, shear) +} + +/// Update the inputs of the transform node to match a new transform +pub fn update_transform(network_interface: &mut NodeNetworkInterface, node_id: &NodeId, transform: DAffine2) { + let (scale, angle, translation, shear) = compute_scale_angle_translation_shear(transform); + + network_interface.set_input(&InputConnector::node(*node_id, 1), NodeInput::value(TaggedValue::DVec2(translation), false), &[]); + network_interface.set_input(&InputConnector::node(*node_id, 2), NodeInput::value(TaggedValue::F64(angle), false), &[]); + network_interface.set_input(&InputConnector::node(*node_id, 3), NodeInput::value(TaggedValue::DVec2(scale), false), &[]); + network_interface.set_input(&InputConnector::node(*node_id, 4), NodeInput::value(TaggedValue::DVec2(shear), false), &[]); +} + +// TODO: This should be extracted from the graph at the location of the transform node. +pub struct LayerBounds { + pub bounds: [DVec2; 2], + pub bounds_transform: DAffine2, + pub layer_transform: DAffine2, +} + +impl LayerBounds { + /// Extract the layer bounds and their transform for a layer. + pub fn new( + metadata: &crate::messages::portfolio::document::utility_types::document_metadata::DocumentMetadata, + layer: crate::messages::portfolio::document::utility_types::document_metadata::LayerNodeIdentifier, + ) -> Self { + Self { + bounds: metadata.nonzero_bounding_box(layer), + bounds_transform: DAffine2::IDENTITY, + layer_transform: metadata.transform_to_document(layer), + } + } + + pub fn layerspace_pivot(&self, normalized_pivot: DVec2) -> DVec2 { + self.bounds[0] + (self.bounds[1] - self.bounds[0]) * normalized_pivot + } + + pub fn local_pivot(&self, normalized_pivot: DVec2) -> DVec2 { + self.bounds_transform.transform_point2(self.layerspace_pivot(normalized_pivot)) + } +} + +/// Get the current affine transform from the transform node's inputs +pub fn get_current_transform(inputs: &[NodeInput]) -> DAffine2 { + let translation = if let Some(&TaggedValue::DVec2(translation)) = inputs[1].as_value() { + translation + } else { + DVec2::ZERO + }; + + let angle = if let Some(&TaggedValue::F64(angle)) = inputs[2].as_value() { angle } else { 0. }; + + let scale = if let Some(&TaggedValue::DVec2(scale)) = inputs[3].as_value() { scale } else { DVec2::ONE }; + + let shear = if let Some(&TaggedValue::DVec2(shear)) = inputs[4].as_value() { shear } else { DVec2::ZERO }; + + DAffine2::from_scale_angle_translation(scale, angle, translation) * DAffine2::from_cols_array(&[1., shear.y, shear.x, 1., 0., 0.]) +} + +/// Extract the current normalized pivot from the layer +pub fn get_current_normalized_pivot(inputs: &[NodeInput]) -> DVec2 { + if let Some(&TaggedValue::DVec2(pivot)) = inputs[5].as_value() { pivot } else { DVec2::splat(0.5) } +} + +#[cfg(test)] +mod tests { + use super::*; + /// ![](https://files.keavon.com/-/OptimisticSpotlessTinamou/capture.png) + /// + /// Source: + /// ```tex + /// \begin{bmatrix} + /// S_{x}\cos(\theta)-S_{y}\sin(\theta)H_{y} & S_{x}\cos(\theta)H_{x}-S_{y}\sin(\theta) & T_{x}\\ + /// S_{x}\sin(\theta)+S_{y}\cos(\theta)H_{y} & S_{x}\sin(\theta)H_{x}+S_{y}\cos(\theta) & T_{y}\\ + /// 0 & 0 & 1 + /// \end{bmatrix} + /// ``` + #[test] + fn derive_transform() { + for shear_x in -10..=10 { + let shear_x = (shear_x as f64) / 2.; + for angle in (0..=360).step_by(15) { + let angle = (angle as f64).to_radians(); + for scale_x in 1..10 { + let scale_x = (scale_x as f64) / 5.; + for scale_y in 1..10 { + let scale_y = (scale_y as f64) / 5.; + + let shear = DVec2::new(shear_x, 0.); + let scale = DVec2::new(scale_x, scale_y); + let translate = DVec2::new(5666., 644.); + + let original_transform = DAffine2::from_cols( + DVec2::new(scale.x * angle.cos() - scale.y * angle.sin() * shear.y, scale.x * angle.sin() + scale.y * angle.cos() * shear.y), + DVec2::new(scale.x * angle.cos() * shear.x - scale.y * angle.sin(), scale.x * angle.sin() * shear.x + scale.y * angle.cos()), + translate, + ); + + let (new_scale, new_angle, new_translation, new_shear) = compute_scale_angle_translation_shear(original_transform); + let new_transform = DAffine2::from_scale_angle_translation(new_scale, new_angle, new_translation) * DAffine2::from_cols_array(&[1., new_shear.y, new_shear.x, 1., 0., 0.]); + + assert!( + new_transform.abs_diff_eq(original_transform, 1e-10), + "original_transform {original_transform} new_transform {new_transform} / scale {scale} new_scale {new_scale} / angle {angle} new_angle {new_angle} / shear {shear} / new_shear {new_shear}", + ); + } + } + } + } + } +} + +/// Expand a bounds to avoid div zero errors +fn clamp_bounds(bounds_min: DVec2, mut bounds_max: DVec2) -> [DVec2; 2] { + let bounds_size = bounds_max - bounds_min; + if bounds_size.x < 1e-10 { + bounds_max.x = bounds_min.x + 1.; + } + if bounds_size.y < 1e-10 { + bounds_max.y = bounds_min.y + 1.; + } + [bounds_min, bounds_max] +} +/// Returns corners of all subpaths +fn subpath_bounds(subpaths: &[Subpath]) -> [DVec2; 2] { + subpaths + .iter() + .filter_map(|subpath| subpath.bounding_box()) + .reduce(|b1, b2| [b1[0].min(b2[0]), b1[1].max(b2[1])]) + .unwrap_or_default() +} + +/// Returns corners of all subpaths (but expanded to avoid division-by-zero errors) +pub fn nonzero_subpath_bounds(subpaths: &[Subpath]) -> [DVec2; 2] { + let [bounds_min, bounds_max] = subpath_bounds(subpaths); + clamp_bounds(bounds_min, bounds_max) +} diff --git a/editor/src/messages/portfolio/document/graph_operation/utility_types.rs b/editor/src/messages/portfolio/document/graph_operation/utility_types.rs new file mode 100644 index 0000000000000000000000000000000000000000..311e22aaa9a3c6663f183a4bfefe855ee012053a --- /dev/null +++ b/editor/src/messages/portfolio/document/graph_operation/utility_types.rs @@ -0,0 +1,500 @@ +use super::transform_utils; +use crate::messages::portfolio::document::node_graph::document_node_definitions::resolve_document_node_type; +use crate::messages::portfolio::document::utility_types::document_metadata::LayerNodeIdentifier; +use crate::messages::portfolio::document::utility_types::network_interface::{self, InputConnector, NodeNetworkInterface, OutputConnector}; +use crate::messages::prelude::*; +use bezier_rs::Subpath; +use glam::{DAffine2, DVec2, IVec2}; +use graph_craft::concrete; +use graph_craft::document::value::TaggedValue; +use graph_craft::document::{NodeId, NodeInput}; +use graphene_std::Artboard; +use graphene_std::brush::brush_stroke::BrushStroke; +use graphene_std::raster::BlendMode; +use graphene_std::raster_types::{CPU, RasterDataTable}; +use graphene_std::text::{Font, TypesettingConfig}; +use graphene_std::vector::style::{Fill, Stroke}; +use graphene_std::vector::{PointId, VectorModificationType}; +use graphene_std::vector::{VectorData, VectorDataTable}; +use graphene_std::{GraphicGroupTable, NodeInputDecleration}; + +#[derive(PartialEq, Clone, Copy, Debug, serde::Serialize, serde::Deserialize)] +pub enum TransformIn { + Local, + Scope { scope: DAffine2 }, + Viewport, +} + +// This struct is helpful to prevent passing the same arguments to multiple functions +// Should only be used by GraphOperationMessage, since it only affects the document network. +pub struct ModifyInputsContext<'a> { + pub network_interface: &'a mut NodeNetworkInterface, + pub responses: &'a mut VecDeque, + // Cannot be LayerNodeIdentifier::ROOT_PARENT + pub layer_node: Option, +} + +impl<'a> ModifyInputsContext<'a> { + /// Get the node network from the document + pub fn new(network_interface: &'a mut NodeNetworkInterface, responses: &'a mut VecDeque) -> Self { + Self { + network_interface, + responses, + layer_node: None, + } + } + + pub fn new_with_layer(layer: LayerNodeIdentifier, network_interface: &'a mut NodeNetworkInterface, responses: &'a mut VecDeque) -> Option { + if layer == LayerNodeIdentifier::ROOT_PARENT { + log::error!("LayerNodeIdentifier::ROOT_PARENT should not be used in ModifyInputsContext::new_with_layer"); + return None; + } + let mut document = Self::new(network_interface, responses); + document.layer_node = Some(layer); + Some(document) + } + + /// Starts at any folder, or the output, and skips layer nodes based on insert_index. Non layer nodes are always skipped. Returns the post node InputConnector and pre node OutputConnector + /// Non layer nodes directly upstream of a layer are treated as part of that layer. See insert_index == 2 in the diagram + /// -----> Post node + /// | if insert_index == 0, return (Post node, Some(Layer1)) + /// -> Layer1 + /// ↑ if insert_index == 1, return (Layer1, Some(Layer2)) + /// -> Layer2 + /// ↑ + /// -> NonLayerNode + /// ↑ if insert_index == 2, return (NonLayerNode, Some(Layer3)) + /// -> Layer3 + /// if insert_index == 3, return (Layer3, None) + pub fn get_post_node_with_index(network_interface: &NodeNetworkInterface, parent: LayerNodeIdentifier, insert_index: usize) -> InputConnector { + let mut post_node_input_connector = if parent == LayerNodeIdentifier::ROOT_PARENT { + InputConnector::Export(0) + } else { + InputConnector::node(parent.to_node(), 1) + }; + // Skip layers based on skip_layer_nodes, which inserts the new layer at a certain index of the layer stack. + let mut current_index = 0; + + // Set the post node to the layer node at insert_index + loop { + if current_index == insert_index { + break; + } + let next_node_in_stack_id = network_interface + .input_from_connector(&post_node_input_connector, &[]) + .and_then(|input_from_connector| if let NodeInput::Node { node_id, .. } = input_from_connector { Some(node_id) } else { None }); + + if let Some(next_node_in_stack_id) = next_node_in_stack_id { + // Only increment index for layer nodes + if network_interface.is_layer(next_node_in_stack_id, &[]) { + current_index += 1; + } + // Input as a sibling to the Layer node above + post_node_input_connector = InputConnector::node(*next_node_in_stack_id, 0); + } else { + log::error!("Error getting post node: insert_index out of bounds"); + break; + }; + } + + // Sink post_node down to the end of the non layer chain that feeds into post_node, such that pre_node is the layer node at insert_index + 1, or None if insert_index is the last layer + loop { + let pre_node_output_connector = network_interface.upstream_output_connector(&post_node_input_connector, &[]); + + match pre_node_output_connector { + Some(OutputConnector::Node { node_id: pre_node_id, .. }) if !network_interface.is_layer(&pre_node_id, &[]) => { + // Update post_node_input_connector for the next iteration + post_node_input_connector = InputConnector::node(pre_node_id, 0); + } + _ => break, // Break if pre_node_output_connector is None or if pre_node_id is a layer + } + } + + post_node_input_connector + } + + /// Creates a new layer and adds it to the document network. network_interface.move_layer_to_stack should be called after + pub fn create_layer(&mut self, new_id: NodeId) -> LayerNodeIdentifier { + let new_merge_node = resolve_document_node_type("Merge").expect("Merge node").default_node_template(); + self.network_interface.insert_node(new_id, new_merge_node, &[]); + LayerNodeIdentifier::new(new_id, self.network_interface, &[]) + } + + /// Creates an artboard as the primary export for the document network + pub fn create_artboard(&mut self, new_id: NodeId, artboard: Artboard) -> LayerNodeIdentifier { + let artboard_node_template = resolve_document_node_type("Artboard").expect("Node").node_template_input_override([ + Some(NodeInput::value(TaggedValue::ArtboardGroup(graphene_std::ArtboardGroupTable::default()), true)), + Some(NodeInput::value(TaggedValue::GraphicGroup(graphene_std::GraphicGroupTable::default()), true)), + Some(NodeInput::value(TaggedValue::IVec2(artboard.location), false)), + Some(NodeInput::value(TaggedValue::IVec2(artboard.dimensions), false)), + Some(NodeInput::value(TaggedValue::Color(artboard.background), false)), + Some(NodeInput::value(TaggedValue::Bool(artboard.clip), false)), + ]); + self.network_interface.insert_node(new_id, artboard_node_template, &[]); + LayerNodeIdentifier::new(new_id, self.network_interface, &[]) + } + + pub fn insert_boolean_data(&mut self, operation: graphene_std::path_bool::BooleanOperation, layer: LayerNodeIdentifier) { + let boolean = resolve_document_node_type("Boolean Operation").expect("Boolean node does not exist").node_template_input_override([ + Some(NodeInput::value(TaggedValue::GraphicGroup(graphene_std::GraphicGroupTable::default()), true)), + Some(NodeInput::value(TaggedValue::BooleanOperation(operation), false)), + ]); + + let boolean_id = NodeId::new(); + self.network_interface.insert_node(boolean_id, boolean, &[]); + self.network_interface.move_node_to_chain_start(&boolean_id, layer, &[]); + } + + pub fn insert_vector_data(&mut self, subpaths: Vec>, layer: LayerNodeIdentifier, include_transform: bool, include_fill: bool, include_stroke: bool) { + let vector_data = VectorDataTable::new(VectorData::from_subpaths(subpaths, true)); + + let shape = resolve_document_node_type("Path") + .expect("Path node does not exist") + .node_template_input_override([Some(NodeInput::value(TaggedValue::VectorData(vector_data), false))]); + let shape_id = NodeId::new(); + self.network_interface.insert_node(shape_id, shape, &[]); + self.network_interface.move_node_to_chain_start(&shape_id, layer, &[]); + + if include_transform { + let transform = resolve_document_node_type("Transform").expect("Transform node does not exist").default_node_template(); + let transform_id = NodeId::new(); + self.network_interface.insert_node(transform_id, transform, &[]); + self.network_interface.move_node_to_chain_start(&transform_id, layer, &[]); + } + + if include_fill { + let fill = resolve_document_node_type("Fill").expect("Fill node does not exist").default_node_template(); + let fill_id = NodeId::new(); + self.network_interface.insert_node(fill_id, fill, &[]); + self.network_interface.move_node_to_chain_start(&fill_id, layer, &[]); + } + + if include_stroke { + let stroke = resolve_document_node_type("Stroke").expect("Stroke node does not exist").default_node_template(); + let stroke_id = NodeId::new(); + self.network_interface.insert_node(stroke_id, stroke, &[]); + self.network_interface.move_node_to_chain_start(&stroke_id, layer, &[]); + } + } + + pub fn insert_text(&mut self, text: String, font: Font, typesetting: TypesettingConfig, layer: LayerNodeIdentifier) { + let stroke = resolve_document_node_type("Stroke").expect("Stroke node does not exist").default_node_template(); + let fill = resolve_document_node_type("Fill").expect("Fill node does not exist").default_node_template(); + let transform = resolve_document_node_type("Transform").expect("Transform node does not exist").default_node_template(); + let text = resolve_document_node_type("Text").expect("Text node does not exist").node_template_input_override([ + Some(NodeInput::scope("editor-api")), + Some(NodeInput::value(TaggedValue::String(text), false)), + Some(NodeInput::value(TaggedValue::Font(font), false)), + Some(NodeInput::value(TaggedValue::F64(typesetting.font_size), false)), + Some(NodeInput::value(TaggedValue::F64(typesetting.line_height_ratio), false)), + Some(NodeInput::value(TaggedValue::F64(typesetting.character_spacing), false)), + Some(NodeInput::value(TaggedValue::OptionalF64(typesetting.max_width), false)), + Some(NodeInput::value(TaggedValue::OptionalF64(typesetting.max_height), false)), + Some(NodeInput::value(TaggedValue::F64(typesetting.tilt), false)), + ]); + + let text_id = NodeId::new(); + self.network_interface.insert_node(text_id, text, &[]); + self.network_interface.move_node_to_chain_start(&text_id, layer, &[]); + + let transform_id = NodeId::new(); + self.network_interface.insert_node(transform_id, transform, &[]); + self.network_interface.move_node_to_chain_start(&transform_id, layer, &[]); + + let fill_id = NodeId::new(); + self.network_interface.insert_node(fill_id, fill, &[]); + self.network_interface.move_node_to_chain_start(&fill_id, layer, &[]); + + let stroke_id = NodeId::new(); + self.network_interface.insert_node(stroke_id, stroke, &[]); + self.network_interface.move_node_to_chain_start(&stroke_id, layer, &[]); + } + + pub fn insert_image_data(&mut self, image_frame: RasterDataTable, layer: LayerNodeIdentifier) { + let transform = resolve_document_node_type("Transform").expect("Transform node does not exist").default_node_template(); + let image = resolve_document_node_type("Image Value") + .expect("ImageValue node does not exist") + .node_template_input_override([Some(NodeInput::value(TaggedValue::None, false)), Some(NodeInput::value(TaggedValue::RasterData(image_frame), false))]); + + let image_id = NodeId::new(); + self.network_interface.insert_node(image_id, image, &[]); + self.network_interface.move_node_to_chain_start(&image_id, layer, &[]); + + let transform_id = NodeId::new(); + self.network_interface.insert_node(transform_id, transform, &[]); + self.network_interface.move_node_to_chain_start(&transform_id, layer, &[]); + } + + fn get_output_layer(&self) -> Option { + self.layer_node.or_else(|| { + let export_node = self.network_interface.document_network().exports.first().and_then(|export| export.as_node())?; + if self.network_interface.is_layer(&export_node, &[]) { + Some(LayerNodeIdentifier::new(export_node, self.network_interface, &[])) + } else { + None + } + }) + } + + /// Gets the node id of a node with a specific reference that is upstream from the layer node, and optionally creates it if it does not exist. + /// The returned node is based on the selection dots in the layer. The right most dot will always insert/access the path that flows directly into the layer. + /// Each dot after that represents an existing path node. If there is an existing upstream node, then it will always be returned first. + pub fn existing_node_id(&mut self, reference_name: &'static str, create_if_nonexistent: bool) -> Option { + // Start from the layer node or export + let output_layer = self.get_output_layer()?; + + let existing_node_id = Self::locate_node_in_layer_chain(reference_name, output_layer, self.network_interface); + + // Create a new node if the node does not exist and update its inputs + if create_if_nonexistent { + return existing_node_id.or_else(|| self.create_node(reference_name)); + } + + existing_node_id + } + + /// Gets the node id of a node with a specific reference (name) that is upstream (leftward) from the layer node, but before reaching another upstream layer stack. + /// For example, if given a group layer, this would find a requested "Transform" or "Boolean Operation" node in its chain, between the group layer and its layer stack child contents. + /// It would also travel up an entire layer that's not fed by a stack until reaching the generator node, such as a "Rectangle" or "Path" layer. + pub fn locate_node_in_layer_chain(reference_name: &str, left_of_layer: LayerNodeIdentifier, network_interface: &NodeNetworkInterface) -> Option { + let upstream = network_interface.upstream_flow_back_from_nodes(vec![left_of_layer.to_node()], &[], network_interface::FlowType::HorizontalFlow); + + // Look at all of the upstream nodes + for upstream_node in upstream { + // Check if this is the node we have been searching for. + if network_interface + .reference(&upstream_node, &[]) + .is_some_and(|node_reference| *node_reference == Some(reference_name.to_string())) + { + if !network_interface.is_visible(&upstream_node, &[]) { + continue; + } + + return Some(upstream_node); + } + + // Take until another layer node is found (but not the first layer node) + let is_traversal_start = |node_id: NodeId| left_of_layer.to_node() == node_id || network_interface.document_network().exports.iter().any(|export| export.as_node() == Some(node_id)); + if !is_traversal_start(upstream_node) && (network_interface.is_layer(&upstream_node, &[])) { + return None; + } + } + + None + } + + /// Create a new node inside the layer + pub fn create_node(&mut self, reference: &str) -> Option { + let output_layer = self.get_output_layer()?; + let Some(node_definition) = resolve_document_node_type(reference) else { + log::error!("Node type {} does not exist in ModifyInputsContext::existing_node_id", reference); + return None; + }; + // If inserting a path node, insert a Flatten Path if the type is a graphic group. + // TODO: Allow the path node to operate on Graphic Group data by utilizing the reference for each vector data in a group. + if node_definition.identifier == "Path" { + let layer_input_type = self.network_interface.input_type(&InputConnector::node(output_layer.to_node(), 1), &[]).0.nested_type().clone(); + if layer_input_type == concrete!(GraphicGroupTable) { + let Some(flatten_path_definition) = resolve_document_node_type("Flatten Path") else { + log::error!("Flatten Path does not exist in ModifyInputsContext::existing_node_id"); + return None; + }; + let node_id = NodeId::new(); + self.network_interface.insert_node(node_id, flatten_path_definition.default_node_template(), &[]); + self.network_interface.move_node_to_chain_start(&node_id, output_layer, &[]); + } + } + let node_id = NodeId::new(); + self.network_interface.insert_node(node_id, node_definition.default_node_template(), &[]); + self.network_interface.move_node_to_chain_start(&node_id, output_layer, &[]); + Some(node_id) + } + + pub fn fill_set(&mut self, fill: Fill) { + let fill_index = 1; + let backup_color_index = 2; + let backup_gradient_index = 3; + + let Some(fill_node_id) = self.existing_node_id("Fill", true) else { return }; + match &fill { + Fill::None => { + let input_connector = InputConnector::node(fill_node_id, backup_color_index); + self.set_input_with_refresh(input_connector, NodeInput::value(TaggedValue::OptionalColor(None), false), true); + } + Fill::Solid(color) => { + let input_connector = InputConnector::node(fill_node_id, backup_color_index); + self.set_input_with_refresh(input_connector, NodeInput::value(TaggedValue::OptionalColor(Some(*color)), false), true); + } + Fill::Gradient(gradient) => { + let input_connector = InputConnector::node(fill_node_id, backup_gradient_index); + self.set_input_with_refresh(input_connector, NodeInput::value(TaggedValue::Gradient(gradient.clone()), false), true); + } + } + let input_connector = InputConnector::node(fill_node_id, fill_index); + self.set_input_with_refresh(input_connector, NodeInput::value(TaggedValue::Fill(fill), false), false); + } + + pub fn blend_mode_set(&mut self, blend_mode: BlendMode) { + let Some(blend_node_id) = self.existing_node_id("Blending", true) else { return }; + let input_connector = InputConnector::node(blend_node_id, 1); + self.set_input_with_refresh(input_connector, NodeInput::value(TaggedValue::BlendMode(blend_mode), false), false); + } + + pub fn opacity_set(&mut self, opacity: f64) { + let Some(blend_node_id) = self.existing_node_id("Blending", true) else { return }; + let input_connector = InputConnector::node(blend_node_id, 2); + self.set_input_with_refresh(input_connector, NodeInput::value(TaggedValue::F64(opacity * 100.), false), false); + } + + pub fn blending_fill_set(&mut self, fill: f64) { + let Some(blend_node_id) = self.existing_node_id("Blending", true) else { return }; + let input_connector = InputConnector::node(blend_node_id, 3); + self.set_input_with_refresh(input_connector, NodeInput::value(TaggedValue::F64(fill * 100.), false), false); + } + + pub fn clip_mode_toggle(&mut self, clip_mode: Option) { + let clip = !clip_mode.unwrap_or(false); + let Some(clip_node_id) = self.existing_node_id("Blending", true) else { return }; + let input_connector = InputConnector::node(clip_node_id, 4); + self.set_input_with_refresh(input_connector, NodeInput::value(TaggedValue::Bool(clip), false), false); + } + + pub fn stroke_set(&mut self, stroke: Stroke) { + let Some(stroke_node_id) = self.existing_node_id("Stroke", true) else { return }; + + let input_connector = InputConnector::node(stroke_node_id, graphene_std::vector::stroke::ColorInput::>::INDEX); + self.set_input_with_refresh(input_connector, NodeInput::value(TaggedValue::OptionalColor(stroke.color), false), true); + let input_connector = InputConnector::node(stroke_node_id, graphene_std::vector::stroke::WeightInput::INDEX); + self.set_input_with_refresh(input_connector, NodeInput::value(TaggedValue::F64(stroke.weight), false), true); + let input_connector = InputConnector::node(stroke_node_id, graphene_std::vector::stroke::AlignInput::INDEX); + self.set_input_with_refresh(input_connector, NodeInput::value(TaggedValue::StrokeAlign(stroke.align), false), false); + let input_connector = InputConnector::node(stroke_node_id, graphene_std::vector::stroke::CapInput::INDEX); + self.set_input_with_refresh(input_connector, NodeInput::value(TaggedValue::StrokeCap(stroke.cap), false), true); + let input_connector = InputConnector::node(stroke_node_id, graphene_std::vector::stroke::JoinInput::INDEX); + self.set_input_with_refresh(input_connector, NodeInput::value(TaggedValue::StrokeJoin(stroke.join), false), true); + let input_connector = InputConnector::node(stroke_node_id, graphene_std::vector::stroke::MiterLimitInput::INDEX); + self.set_input_with_refresh(input_connector, NodeInput::value(TaggedValue::F64(stroke.join_miter_limit), false), false); + let input_connector = InputConnector::node(stroke_node_id, graphene_std::vector::stroke::PaintOrderInput::INDEX); + self.set_input_with_refresh(input_connector, NodeInput::value(TaggedValue::PaintOrder(stroke.paint_order), false), false); + let input_connector = InputConnector::node(stroke_node_id, graphene_std::vector::stroke::DashLengthsInput::INDEX); + self.set_input_with_refresh(input_connector, NodeInput::value(TaggedValue::VecF64(stroke.dash_lengths), false), true); + let input_connector = InputConnector::node(stroke_node_id, graphene_std::vector::stroke::DashOffsetInput::INDEX); + self.set_input_with_refresh(input_connector, NodeInput::value(TaggedValue::F64(stroke.dash_offset), false), true); + } + + /// Update the transform value of the upstream Transform node based a change to its existing value and the given parent transform. + /// A new Transform node is created if one does not exist, unless it would be given the identity transform. + pub fn transform_change_with_parent(&mut self, transform: DAffine2, transform_in: TransformIn, parent_transform: DAffine2, skip_rerender: bool) { + // Get the existing upstream Transform node and its transform, if present, otherwise use the identity transform + let (layer_transform, transform_node_id) = self + .existing_node_id("Transform", false) + .and_then(|transform_node_id| { + let document_node = self.network_interface.document_network().nodes.get(&transform_node_id)?; + Some((transform_utils::get_current_transform(&document_node.inputs), transform_node_id)) + }) + .unzip(); + let layer_transform = layer_transform.unwrap_or_default(); + + // Get a transform appropriate for the requested space + let to_transform = match transform_in { + TransformIn::Local => DAffine2::IDENTITY, + TransformIn::Scope { scope } => scope * parent_transform, + TransformIn::Viewport => parent_transform, + }; + + // Set the transform value to the Transform node + let final_transform = to_transform.inverse() * transform * to_transform * layer_transform; + self.transform_set_direct(final_transform, skip_rerender, transform_node_id); + } + + /// Set the transform value to the upstream Transform node, replacing the existing value. + /// A new Transform node is created if one does not exist, unless it would be given the identity transform. + pub fn transform_set(&mut self, transform: DAffine2, transform_in: TransformIn, skip_rerender: bool) { + // Get the existing upstream Transform node, if present + let transform_node_id = self.existing_node_id("Transform", false); + + // Get a transform appropriate for the requested space + let to_transform = match transform_in { + TransformIn::Local => DAffine2::IDENTITY, + TransformIn::Scope { scope } => scope, + TransformIn::Viewport => self.network_interface.document_metadata().downstream_transform_to_viewport(self.layer_node.unwrap()).inverse(), + }; + + // Set the transform value to the Transform node + let final_transform = to_transform * transform; + self.transform_set_direct(final_transform, skip_rerender, transform_node_id); + } + + /// Write the given transform value to the upstream Transform node, if one is supplied. If one doesn't exist, it will be created unless the given transform is the identity. + pub fn transform_set_direct(&mut self, transform: DAffine2, skip_rerender: bool, transform_node_id: Option) { + // If the Transform node didn't exist yet, create it now + let Some(transform_node_id) = transform_node_id.or_else(|| { + // Check if the transform is the identity transform (within an epsilon) and if so, don't create a new Transform node + if transform.abs_diff_eq(DAffine2::IDENTITY, 1e-6) { + // We don't want to pollute the graph with an unnecessary Transform node, so we avoid creating and setting it by returning None + return None; + } + + // Create the Transform node + self.existing_node_id("Transform", true) + }) else { + return; + }; + + // Update the transform value of the Transform node + transform_utils::update_transform(self.network_interface, &transform_node_id, transform); + + // Refresh the render and editor UI + self.responses.add(PropertiesPanelMessage::Refresh); + if !skip_rerender { + self.responses.add(NodeGraphMessage::RunDocumentGraph); + } + } + + pub fn pivot_set(&mut self, new_pivot: DVec2) { + let Some(transform_node_id) = self.existing_node_id("Transform", true) else { return }; + + self.set_input_with_refresh(InputConnector::node(transform_node_id, 5), NodeInput::value(TaggedValue::DVec2(new_pivot), false), false); + } + + pub fn vector_modify(&mut self, modification_type: VectorModificationType) { + let Some(path_node_id) = self.existing_node_id("Path", true) else { return }; + self.network_interface.vector_modify(&path_node_id, modification_type); + self.responses.add(PropertiesPanelMessage::Refresh); + self.responses.add(NodeGraphMessage::RunDocumentGraph); + } + + pub fn brush_modify(&mut self, strokes: Vec) { + let Some(brush_node_id) = self.existing_node_id("Brush", true) else { return }; + self.set_input_with_refresh(InputConnector::node(brush_node_id, 1), NodeInput::value(TaggedValue::BrushStrokes(strokes), false), false); + } + + pub fn resize_artboard(&mut self, location: IVec2, dimensions: IVec2) { + let Some(artboard_node_id) = self.existing_node_id("Artboard", true) else { + return; + }; + + let mut dimensions = dimensions; + let mut location = location; + + if dimensions.x < 0 { + dimensions.x *= -1; + location.x -= dimensions.x; + } + if dimensions.y < 0 { + dimensions.y *= -1; + location.y -= dimensions.y; + } + self.set_input_with_refresh(InputConnector::node(artboard_node_id, 2), NodeInput::value(TaggedValue::IVec2(location), false), false); + self.set_input_with_refresh(InputConnector::node(artboard_node_id, 3), NodeInput::value(TaggedValue::IVec2(dimensions), false), false); + } + + /// Set the input, refresh the properties panel, and run the document graph if skip_rerender is false + pub fn set_input_with_refresh(&mut self, input_connector: InputConnector, input: NodeInput, skip_rerender: bool) { + self.network_interface.set_input(&input_connector, input, &[]); + self.responses.add(PropertiesPanelMessage::Refresh); + if !skip_rerender { + self.responses.add(NodeGraphMessage::RunDocumentGraph); + } + } +} diff --git a/editor/src/messages/portfolio/document/mod.rs b/editor/src/messages/portfolio/document/mod.rs new file mode 100644 index 0000000000000000000000000000000000000000..b9b7172e5a7eaf2948238a825f15d41f6d06eb50 --- /dev/null +++ b/editor/src/messages/portfolio/document/mod.rs @@ -0,0 +1,14 @@ +mod document_message; +mod document_message_handler; + +pub mod graph_operation; +pub mod navigation; +pub mod node_graph; +pub mod overlays; +pub mod properties_panel; +pub mod utility_types; + +#[doc(inline)] +pub use document_message::{DocumentMessage, DocumentMessageDiscriminant}; +#[doc(inline)] +pub use document_message_handler::{DocumentMessageData, DocumentMessageHandler}; diff --git a/editor/src/messages/portfolio/document/navigation/mod.rs b/editor/src/messages/portfolio/document/navigation/mod.rs new file mode 100644 index 0000000000000000000000000000000000000000..0ee1512eda1f18941ece6f4fa83c1aed64c2ffbc --- /dev/null +++ b/editor/src/messages/portfolio/document/navigation/mod.rs @@ -0,0 +1,8 @@ +mod navigation_message; +mod navigation_message_handler; +pub mod utility_types; + +#[doc(inline)] +pub use navigation_message::{NavigationMessage, NavigationMessageDiscriminant}; +#[doc(inline)] +pub use navigation_message_handler::{NavigationMessageData, NavigationMessageHandler}; diff --git a/editor/src/messages/portfolio/document/navigation/navigation_message.rs b/editor/src/messages/portfolio/document/navigation/navigation_message.rs new file mode 100644 index 0000000000000000000000000000000000000000..a55f8dbef42861a51d92f5baed059afb774d7621 --- /dev/null +++ b/editor/src/messages/portfolio/document/navigation/navigation_message.rs @@ -0,0 +1,29 @@ +use crate::messages::input_mapper::utility_types::input_keyboard::Key; +use crate::messages::prelude::*; +use glam::DVec2; + +#[impl_message(Message, DocumentMessage, Navigation)] +#[derive(PartialEq, Clone, Debug, serde::Serialize, serde::Deserialize)] +pub enum NavigationMessage { + // Messages + BeginCanvasPan, + BeginCanvasTilt { was_dispatched_from_menu: bool }, + BeginCanvasZoom, + CanvasPan { delta: DVec2 }, + CanvasPanAbortPrepare { x_not_y_axis: bool }, + CanvasPanAbort { x_not_y_axis: bool }, + CanvasPanByViewportFraction { delta: DVec2 }, + CanvasPanMouseWheel { use_y_as_x: bool }, + CanvasTiltResetAndZoomTo100Percent, + CanvasTiltSet { angle_radians: f64 }, + CanvasZoomDecrease { center_on_mouse: bool }, + CanvasZoomIncrease { center_on_mouse: bool }, + CanvasZoomMouseWheel, + CanvasZoomSet { zoom_factor: f64 }, + CanvasFlip, + EndCanvasPTZ { abort_transform: bool }, + EndCanvasPTZWithClick { commit_key: Key }, + FitViewportToBounds { bounds: [DVec2; 2], prevent_zoom_past_100: bool }, + FitViewportToSelection, + PointerMove { snap: Key }, +} diff --git a/editor/src/messages/portfolio/document/navigation/navigation_message_handler.rs b/editor/src/messages/portfolio/document/navigation/navigation_message_handler.rs new file mode 100644 index 0000000000000000000000000000000000000000..929c8501604ae1ba5c5c24fd4ed8fd87415e9310 --- /dev/null +++ b/editor/src/messages/portfolio/document/navigation/navigation_message_handler.rs @@ -0,0 +1,577 @@ +use crate::consts::{ + VIEWPORT_ROTATE_SNAP_INTERVAL, VIEWPORT_SCROLL_RATE, VIEWPORT_ZOOM_LEVELS, VIEWPORT_ZOOM_MIN_FRACTION_COVER, VIEWPORT_ZOOM_MOUSE_RATE, VIEWPORT_ZOOM_SCALE_MAX, VIEWPORT_ZOOM_SCALE_MIN, + VIEWPORT_ZOOM_TO_FIT_PADDING_SCALE_FACTOR, +}; +use crate::messages::frontend::utility_types::MouseCursorIcon; +use crate::messages::input_mapper::utility_types::input_keyboard::{Key, MouseMotion}; +use crate::messages::input_mapper::utility_types::input_mouse::ViewportPosition; +use crate::messages::portfolio::document::navigation::utility_types::NavigationOperation; +use crate::messages::portfolio::document::utility_types::misc::PTZ; +use crate::messages::portfolio::document::utility_types::network_interface::NodeNetworkInterface; +use crate::messages::prelude::*; +use crate::messages::tool::utility_types::{HintData, HintGroup, HintInfo}; +use glam::{DAffine2, DVec2}; +use graph_craft::document::NodeId; + +pub struct NavigationMessageData<'a> { + pub network_interface: &'a mut NodeNetworkInterface, + pub breadcrumb_network_path: &'a [NodeId], + pub ipp: &'a InputPreprocessorMessageHandler, + pub selection_bounds: Option<[DVec2; 2]>, + pub document_ptz: &'a mut PTZ, + pub graph_view_overlay_open: bool, + pub preferences: &'a PreferencesMessageHandler, +} + +#[derive(Debug, Clone, PartialEq, Default)] +pub struct NavigationMessageHandler { + navigation_operation: NavigationOperation, + mouse_position: ViewportPosition, + finish_operation_with_click: bool, + abortable_pan_start: Option, +} + +impl MessageHandler> for NavigationMessageHandler { + fn process_message(&mut self, message: NavigationMessage, responses: &mut VecDeque, data: NavigationMessageData) { + let NavigationMessageData { + network_interface, + breadcrumb_network_path, + ipp, + selection_bounds, + document_ptz, + graph_view_overlay_open, + preferences, + } = data; + + fn get_ptz<'a>(document_ptz: &'a PTZ, network_interface: &'a NodeNetworkInterface, graph_view_overlay_open: bool, breadcrumb_network_path: &[NodeId]) -> Option<&'a PTZ> { + if !graph_view_overlay_open { + Some(document_ptz) + } else { + let network_metadata = network_interface.network_metadata(breadcrumb_network_path)?; + Some(&network_metadata.persistent_metadata.navigation_metadata.node_graph_ptz) + } + } + + fn get_ptz_mut<'a>(document_ptz: &'a mut PTZ, network_interface: &'a mut NodeNetworkInterface, graph_view_overlay_open: bool, breadcrumb_network_path: &[NodeId]) -> Option<&'a mut PTZ> { + if !graph_view_overlay_open { + Some(document_ptz) + } else { + let Some(node_graph_ptz) = network_interface.node_graph_ptz_mut(breadcrumb_network_path) else { + log::error!("Could not get node graph PTZ in NavigationMessageHandler process_message"); + return None; + }; + Some(node_graph_ptz) + } + } + + let Some(ptz) = get_ptz(document_ptz, network_interface, graph_view_overlay_open, breadcrumb_network_path) else { + log::error!("Could not get PTZ in NavigationMessageHandler process_message"); + return; + }; + let old_zoom = ptz.zoom(); + + match message { + NavigationMessage::BeginCanvasPan => { + responses.add(FrontendMessage::UpdateMouseCursor { cursor: MouseCursorIcon::Grabbing }); + + responses.add(FrontendMessage::UpdateInputHints { + hint_data: HintData(vec![HintGroup(vec![HintInfo::mouse(MouseMotion::Rmb, ""), HintInfo::keys([Key::Escape], "Cancel").prepend_slash()])]), + }); + + self.mouse_position = ipp.mouse.position; + let Some(ptz) = get_ptz(document_ptz, network_interface, graph_view_overlay_open, breadcrumb_network_path) else { + return; + }; + self.navigation_operation = NavigationOperation::Pan { pan_original_for_abort: ptz.pan }; + } + NavigationMessage::BeginCanvasTilt { was_dispatched_from_menu } => { + let Some(ptz) = get_ptz(document_ptz, network_interface, graph_view_overlay_open, breadcrumb_network_path) else { + return; + }; + // If the node graph is open, prevent tilt and instead start panning + if graph_view_overlay_open { + responses.add(NavigationMessage::BeginCanvasPan); + } else { + responses.add(FrontendMessage::UpdateMouseCursor { cursor: MouseCursorIcon::Default }); + responses.add(FrontendMessage::UpdateInputHints { + hint_data: HintData(vec![ + HintGroup(vec![HintInfo::mouse(MouseMotion::Rmb, ""), HintInfo::keys([Key::Escape], "Cancel").prepend_slash()]), + HintGroup(vec![HintInfo::keys([Key::Shift], "15° Increments")]), + ]), + }); + + self.navigation_operation = NavigationOperation::Tilt { + tilt_original_for_abort: ptz.tilt(), + tilt_raw_not_snapped: ptz.tilt(), + snap: false, + }; + + self.mouse_position = ipp.mouse.position; + self.finish_operation_with_click = was_dispatched_from_menu; + } + } + NavigationMessage::BeginCanvasZoom => { + let Some(ptz) = get_ptz(document_ptz, network_interface, graph_view_overlay_open, breadcrumb_network_path) else { + return; + }; + + responses.add(FrontendMessage::UpdateMouseCursor { cursor: MouseCursorIcon::ZoomIn }); + responses.add(FrontendMessage::UpdateInputHints { + hint_data: HintData(vec![ + HintGroup(vec![HintInfo::mouse(MouseMotion::Rmb, ""), HintInfo::keys([Key::Escape], "Cancel").prepend_slash()]), + HintGroup(vec![HintInfo::keys([Key::Shift], "Increments")]), + ]), + }); + + self.navigation_operation = NavigationOperation::Zoom { + zoom_raw_not_snapped: ptz.zoom(), + zoom_original_for_abort: ptz.zoom(), + snap: false, + }; + self.mouse_position = ipp.mouse.position; + } + NavigationMessage::CanvasPan { delta } => { + let Some(ptz) = get_ptz_mut(document_ptz, network_interface, graph_view_overlay_open, breadcrumb_network_path) else { + log::error!("Could not get PTZ in CanvasPan"); + return; + }; + let document_to_viewport = self.calculate_offset_transform(ipp.viewport_bounds.center(), ptz); + let transformed_delta = document_to_viewport.inverse().transform_vector2(delta); + + ptz.pan += transformed_delta; + responses.add(BroadcastEvent::CanvasTransformed); + responses.add(DocumentMessage::PTZUpdate); + } + NavigationMessage::CanvasPanAbortPrepare { x_not_y_axis } => { + let Some(ptz) = get_ptz_mut(document_ptz, network_interface, graph_view_overlay_open, breadcrumb_network_path) else { + log::error!("Could not get PTZ in CanvasPanAbortPrepare"); + return; + }; + self.abortable_pan_start = Some(if x_not_y_axis { ptz.pan.x } else { ptz.pan.y }); + } + NavigationMessage::CanvasPanAbort { x_not_y_axis } => { + let Some(ptz) = get_ptz_mut(document_ptz, network_interface, graph_view_overlay_open, breadcrumb_network_path) else { + log::error!("Could not get PTZ in CanvasPanAbort"); + return; + }; + if let Some(abortable_pan_start) = self.abortable_pan_start { + if x_not_y_axis { + ptz.pan.x = abortable_pan_start; + } else { + ptz.pan.y = abortable_pan_start; + } + } + self.abortable_pan_start = None; + responses.add(DocumentMessage::PTZUpdate); + } + NavigationMessage::CanvasPanByViewportFraction { delta } => { + let Some(ptz) = get_ptz_mut(document_ptz, network_interface, graph_view_overlay_open, breadcrumb_network_path) else { + log::error!("Could not get node graph PTZ in CanvasPanByViewportFraction"); + return; + }; + let document_to_viewport = self.calculate_offset_transform(ipp.viewport_bounds.center(), ptz); + let transformed_delta = document_to_viewport.inverse().transform_vector2(delta * ipp.viewport_bounds.size()); + + ptz.pan += transformed_delta; + responses.add(DocumentMessage::PTZUpdate); + } + NavigationMessage::CanvasPanMouseWheel { use_y_as_x } => { + let delta = if use_y_as_x { (-ipp.mouse.scroll_delta.y, 0.).into() } else { -ipp.mouse.scroll_delta.as_dvec2() } * VIEWPORT_SCROLL_RATE; + responses.add(NavigationMessage::CanvasPan { delta }); + responses.add(NodeGraphMessage::SetGridAlignedEdges); + } + NavigationMessage::CanvasTiltResetAndZoomTo100Percent => { + let Some(ptz) = get_ptz_mut(document_ptz, network_interface, graph_view_overlay_open, breadcrumb_network_path) else { + log::error!("Could not get mutable PTZ in CanvasTiltResetAndZoomTo100Percent"); + return; + }; + ptz.set_tilt(0.); + ptz.set_zoom(1.); + if graph_view_overlay_open { + responses.add(NodeGraphMessage::UpdateGraphBarRight); + } else { + responses.add(PortfolioMessage::UpdateDocumentWidgets); + } + responses.add(DocumentMessage::PTZUpdate); + responses.add(NodeGraphMessage::SetGridAlignedEdges); + } + NavigationMessage::CanvasTiltSet { angle_radians } => { + let Some(ptz) = get_ptz_mut(document_ptz, network_interface, graph_view_overlay_open, breadcrumb_network_path) else { + log::error!("Could not get mutable PTZ in CanvasTiltSet"); + return; + }; + ptz.set_tilt(angle_radians); + responses.add(DocumentMessage::PTZUpdate); + if !graph_view_overlay_open { + responses.add(PortfolioMessage::UpdateDocumentWidgets); + responses.add(MenuBarMessage::SendLayout); + } + } + NavigationMessage::CanvasZoomDecrease { center_on_mouse } => { + let Some(ptz) = get_ptz(document_ptz, network_interface, graph_view_overlay_open, breadcrumb_network_path) else { + return; + }; + + let new_scale = *VIEWPORT_ZOOM_LEVELS.iter().rev().find(|scale| **scale < ptz.zoom()).unwrap_or(&ptz.zoom()); + if center_on_mouse { + responses.add(self.center_zoom(ipp.viewport_bounds.size(), new_scale / ptz.zoom(), ipp.mouse.position)); + } + responses.add(NavigationMessage::CanvasZoomSet { zoom_factor: new_scale }); + } + NavigationMessage::CanvasZoomIncrease { center_on_mouse } => { + let Some(ptz) = get_ptz(document_ptz, network_interface, graph_view_overlay_open, breadcrumb_network_path) else { + return; + }; + + let new_scale = *VIEWPORT_ZOOM_LEVELS.iter().find(|scale| **scale > ptz.zoom()).unwrap_or(&ptz.zoom()); + if center_on_mouse { + responses.add(self.center_zoom(ipp.viewport_bounds.size(), new_scale / ptz.zoom(), ipp.mouse.position)); + } + responses.add(NavigationMessage::CanvasZoomSet { zoom_factor: new_scale }); + } + NavigationMessage::CanvasZoomMouseWheel => { + let scroll = ipp.mouse.scroll_delta.scroll_delta(); + let mut zoom_factor = 1. + scroll.abs() * preferences.viewport_zoom_wheel_rate; + if ipp.mouse.scroll_delta.y > 0. { + zoom_factor = 1. / zoom_factor + } + let document_bounds = if !graph_view_overlay_open { + // TODO: Cache this in node graph coordinates and apply the transform to the rectangle to get viewport coordinates + network_interface.document_metadata().document_bounds_viewport_space() + } else { + network_interface.graph_bounds_viewport_space(breadcrumb_network_path) + }; + let Some(ptz) = get_ptz(document_ptz, network_interface, graph_view_overlay_open, breadcrumb_network_path) else { + return; + }; + + zoom_factor *= Self::clamp_zoom(ptz.zoom() * zoom_factor, document_bounds, old_zoom, ipp); + + responses.add(self.center_zoom(ipp.viewport_bounds.size(), zoom_factor, ipp.mouse.position)); + responses.add(NavigationMessage::CanvasZoomSet { + zoom_factor: ptz.zoom() * zoom_factor, + }); + } + NavigationMessage::CanvasZoomSet { zoom_factor } => { + let document_bounds = if !graph_view_overlay_open { + // TODO: Cache this in node graph coordinates and apply the transform to the rectangle to get viewport coordinates + network_interface.document_metadata().document_bounds_viewport_space() + } else { + network_interface.graph_bounds_viewport_space(breadcrumb_network_path) + }; + let Some(ptz) = get_ptz_mut(document_ptz, network_interface, graph_view_overlay_open, breadcrumb_network_path) else { + log::error!("Could not get mutable PTZ in CanvasZoomSet"); + return; + }; + let zoom = zoom_factor.clamp(VIEWPORT_ZOOM_SCALE_MIN, VIEWPORT_ZOOM_SCALE_MAX); + let zoom = zoom * Self::clamp_zoom(zoom, document_bounds, old_zoom, ipp); + ptz.set_zoom(zoom); + if graph_view_overlay_open { + responses.add(NodeGraphMessage::UpdateGraphBarRight); + } else { + responses.add(PortfolioMessage::UpdateDocumentWidgets); + } + responses.add(DocumentMessage::PTZUpdate); + responses.add(NodeGraphMessage::SetGridAlignedEdges); + } + NavigationMessage::CanvasFlip => { + if graph_view_overlay_open { + return; + } + let Some(ptz) = get_ptz_mut(document_ptz, network_interface, graph_view_overlay_open, breadcrumb_network_path) else { + log::error!("Could not get mutable PTZ in CanvasFlip"); + return; + }; + + ptz.flip = !ptz.flip; + + responses.add(DocumentMessage::PTZUpdate); + responses.add(BroadcastEvent::CanvasTransformed); + responses.add(MenuBarMessage::SendLayout); + responses.add(PortfolioMessage::UpdateDocumentWidgets); + } + NavigationMessage::EndCanvasPTZ { abort_transform } => { + let Some(ptz) = get_ptz_mut(document_ptz, network_interface, graph_view_overlay_open, breadcrumb_network_path) else { + log::error!("Could not get mutable PTZ in EndCanvasPTZ"); + return; + }; + // If an abort was requested, reset the active PTZ value to its original state + if abort_transform && self.navigation_operation != NavigationOperation::None { + match self.navigation_operation { + NavigationOperation::None => {} + NavigationOperation::Tilt { tilt_original_for_abort, .. } => { + ptz.set_tilt(tilt_original_for_abort); + } + NavigationOperation::Pan { pan_original_for_abort, .. } => { + ptz.pan = pan_original_for_abort; + } + NavigationOperation::Zoom { zoom_original_for_abort, .. } => { + ptz.set_zoom(zoom_original_for_abort); + } + } + } + + // Final chance to apply snapping if the key was pressed during this final frame + ptz.set_tilt(self.snapped_tilt(ptz.tilt())); + ptz.set_zoom(self.snapped_zoom(ptz.zoom())); + responses.add(DocumentMessage::PTZUpdate); + if graph_view_overlay_open { + responses.add(NodeGraphMessage::UpdateGraphBarRight); + } else { + responses.add(PortfolioMessage::UpdateDocumentWidgets); + } + responses.add(NodeGraphMessage::SetGridAlignedEdges); + // Reset the navigation operation now that it's done + self.navigation_operation = NavigationOperation::None; + + // Send the final messages to close out the operation + responses.add(BroadcastEvent::CanvasTransformed); + responses.add(ToolMessage::UpdateCursor); + responses.add(ToolMessage::UpdateHints); + responses.add(NavigateToolMessage::End); + } + NavigationMessage::EndCanvasPTZWithClick { commit_key } => { + self.finish_operation_with_click = false; + + let abort_transform = commit_key == Key::MouseRight; + responses.add(NavigationMessage::EndCanvasPTZ { abort_transform }); + } + NavigationMessage::FitViewportToBounds { + bounds: [pos1, pos2], + prevent_zoom_past_100, + } => { + let (pos1, pos2) = (pos1.min(pos2), pos1.max(pos2)); + let diagonal = pos2 - pos1; + + if diagonal.length() < f64::EPSILON * 1000. || ipp.viewport_bounds.size() == DVec2::ZERO { + warn!("Cannot center since the viewport size is 0"); + return; + } + + let Some(ptz) = get_ptz_mut(document_ptz, network_interface, graph_view_overlay_open, breadcrumb_network_path) else { + log::error!("Could not get node graph PTZ in CanvasPanByViewportFraction"); + return; + }; + let document_to_viewport = self.calculate_offset_transform(ipp.viewport_bounds.center(), ptz); + + let v1 = document_to_viewport.inverse().transform_point2(DVec2::ZERO); + let v2 = document_to_viewport.inverse().transform_point2(ipp.viewport_bounds.size()); + + let center = ((v2 + v1) - (pos2 + pos1)) / 2.; + let size = (v2 - v1) / diagonal; + let new_scale = size.min_element(); + + let viewport_change = document_to_viewport.transform_vector2(center); + + // Only change the pan if the change will be visible in the viewport + if viewport_change.x.abs() > 0.5 || viewport_change.y.abs() > 0.5 { + ptz.pan += center; + } + + ptz.set_zoom(ptz.zoom() * new_scale * VIEWPORT_ZOOM_TO_FIT_PADDING_SCALE_FACTOR); + + // Keep the canvas filling less than the full available viewport bounds if requested. + // And if the zoom is close to the full viewport bounds, we ignore the padding because 100% is preferrable if it still fits. + if prevent_zoom_past_100 && ptz.zoom() > VIEWPORT_ZOOM_TO_FIT_PADDING_SCALE_FACTOR { + ptz.set_zoom(1.); + } + + if graph_view_overlay_open { + responses.add(NodeGraphMessage::UpdateGraphBarRight); + } else { + responses.add(PortfolioMessage::UpdateDocumentWidgets); + } + responses.add(DocumentMessage::PTZUpdate); + responses.add(NodeGraphMessage::SetGridAlignedEdges); + } + NavigationMessage::FitViewportToSelection => { + if let Some(bounds) = selection_bounds { + let Some(ptz) = get_ptz_mut(document_ptz, network_interface, graph_view_overlay_open, breadcrumb_network_path) else { + log::error!("Could not get node graph PTZ in FitViewportToSelection"); + return; + }; + let document_to_viewport = self.calculate_offset_transform(ipp.viewport_bounds.center(), ptz); + responses.add(NavigationMessage::FitViewportToBounds { + bounds: [document_to_viewport.inverse().transform_point2(bounds[0]), document_to_viewport.inverse().transform_point2(bounds[1])], + prevent_zoom_past_100: false, + }) + } + } + NavigationMessage::PointerMove { snap } => { + match self.navigation_operation { + NavigationOperation::None => {} + NavigationOperation::Pan { .. } => { + let delta = ipp.mouse.position - self.mouse_position; + responses.add(NavigationMessage::CanvasPan { delta }); + } + NavigationOperation::Tilt { + tilt_raw_not_snapped, + tilt_original_for_abort, + .. + } => { + let tilt_raw_not_snapped = { + // Compute the angle in document space to counter for the canvas being flipped + let viewport_to_document = network_interface.document_metadata().document_to_viewport.inverse(); + let half_viewport = ipp.viewport_bounds.size() / 2.; + let start_offset = viewport_to_document.transform_vector2(self.mouse_position - half_viewport); + let end_offset = viewport_to_document.transform_vector2(ipp.mouse.position - half_viewport); + let angle = start_offset.angle_to(end_offset); + + tilt_raw_not_snapped + angle + }; + let Some(ptz) = get_ptz_mut(document_ptz, network_interface, graph_view_overlay_open, breadcrumb_network_path) else { + log::error!("Could not get mutable PTZ in Tilt"); + return; + }; + ptz.set_tilt(self.snapped_tilt(tilt_raw_not_snapped)); + + let snap = ipp.keyboard.get(snap as usize); + + self.navigation_operation = NavigationOperation::Tilt { + tilt_original_for_abort, + tilt_raw_not_snapped, + snap, + }; + + responses.add(NavigationMessage::CanvasTiltSet { angle_radians: ptz.tilt() }); + } + NavigationOperation::Zoom { + zoom_raw_not_snapped, + zoom_original_for_abort, + .. + } => { + let zoom_raw_not_snapped = { + let vertical_delta = self.mouse_position.y - ipp.mouse.position.y; + let amount = vertical_delta * VIEWPORT_ZOOM_MOUSE_RATE; + let updated_zoom = zoom_raw_not_snapped * (1. + amount); + + let document_bounds = if !graph_view_overlay_open { + // TODO: Cache this in node graph coordinates and apply the transform to the rectangle to get viewport coordinates + network_interface.document_metadata().document_bounds_viewport_space() + } else { + network_interface.graph_bounds_viewport_space(breadcrumb_network_path) + }; + + updated_zoom * Self::clamp_zoom(updated_zoom, document_bounds, old_zoom, ipp) + }; + let Some(ptz) = get_ptz_mut(document_ptz, network_interface, graph_view_overlay_open, breadcrumb_network_path) else { + log::error!("Could not get mutable PTZ in Zoom"); + return; + }; + ptz.set_zoom(self.snapped_zoom(zoom_raw_not_snapped)); + + let snap = ipp.keyboard.get(snap as usize); + + self.navigation_operation = NavigationOperation::Zoom { + zoom_raw_not_snapped, + zoom_original_for_abort, + snap, + }; + + responses.add(NavigationMessage::CanvasZoomSet { zoom_factor: ptz.zoom() }); + responses.add(NodeGraphMessage::SetGridAlignedEdges); + } + } + + self.mouse_position = ipp.mouse.position; + } + } + } + + fn actions(&self) -> ActionList { + let mut common = actions!(NavigationMessageDiscriminant; + BeginCanvasPan, + BeginCanvasTilt, + BeginCanvasZoom, + CanvasPan, + CanvasPanByViewportFraction, + CanvasPanMouseWheel, + CanvasTiltSet, + CanvasZoomDecrease, + CanvasZoomIncrease, + CanvasZoomMouseWheel, + CanvasFlip, + FitViewportToSelection, + ); + + if self.navigation_operation != NavigationOperation::None { + let transforming = actions!(NavigationMessageDiscriminant; + EndCanvasPTZ, + PointerMove, + ); + common.extend(transforming); + } + + if self.finish_operation_with_click { + let transforming_from_menu = actions!(NavigationMessageDiscriminant; + EndCanvasPTZWithClick, + ); + + common.extend(transforming_from_menu); + } + + common + } +} + +impl NavigationMessageHandler { + pub fn snapped_tilt(&self, tilt: f64) -> f64 { + let increment_radians: f64 = VIEWPORT_ROTATE_SNAP_INTERVAL.to_radians(); + if matches!(self.navigation_operation, NavigationOperation::Tilt { snap: true, .. }) { + (tilt / increment_radians).round() * increment_radians + } else { + tilt + } + } + + pub fn snapped_zoom(&self, zoom: f64) -> f64 { + snapped_zoom(&self.navigation_operation, zoom) + } + + pub fn calculate_offset_transform(&self, viewport_center: DVec2, ptz: &PTZ) -> DAffine2 { + let pan = ptz.pan; + let tilt = ptz.tilt(); + let zoom = ptz.zoom(); + + let scale = self.snapped_zoom(zoom); + let scale_vec = if ptz.flip { DVec2::new(-scale, scale) } else { DVec2::splat(scale) }; + let scaled_center = viewport_center / scale_vec; + + // Try to avoid fractional coordinates to reduce anti aliasing. + let rounded_pan = ((pan + scaled_center) * scale).round() / scale - scaled_center; + + // TODO: replace with DAffine2::from_scale_angle_translation and fix the errors + let offset_transform = DAffine2::from_translation(scaled_center); + let scale_transform = DAffine2::from_scale(scale_vec); + let angle_transform = DAffine2::from_angle(self.snapped_tilt(tilt)); + let translation_transform = DAffine2::from_translation(rounded_pan); + scale_transform * offset_transform * angle_transform * translation_transform + } + + pub fn center_zoom(&self, viewport_bounds: DVec2, zoom_factor: f64, mouse: DVec2) -> Message { + let new_viewport_bounds = viewport_bounds / zoom_factor; + let delta_size = viewport_bounds - new_viewport_bounds; + let mouse_fraction = mouse / viewport_bounds; + let delta = delta_size * (DVec2::splat(0.5) - mouse_fraction); + NavigationMessage::CanvasPan { delta }.into() + } + + pub fn clamp_zoom(zoom: f64, document_bounds: Option<[DVec2; 2]>, old_zoom: f64, ipp: &InputPreprocessorMessageHandler) -> f64 { + let document_size = (document_bounds.map(|[min, max]| max - min).unwrap_or_default() / old_zoom) * zoom; + let scale_factor = (document_size / ipp.viewport_bounds.size()).max_element(); + + if scale_factor <= f64::EPSILON * 100. || !scale_factor.is_finite() || scale_factor >= VIEWPORT_ZOOM_MIN_FRACTION_COVER { + return 1.; + } + + VIEWPORT_ZOOM_MIN_FRACTION_COVER / scale_factor + } +} + +pub fn snapped_zoom(navigation_operation: &NavigationOperation, zoom: f64) -> f64 { + if matches!(navigation_operation, NavigationOperation::Zoom { snap: true, .. }) { + *VIEWPORT_ZOOM_LEVELS.iter().min_by(|a, b| (**a - zoom).abs().partial_cmp(&(**b - zoom).abs()).unwrap()).unwrap_or(&zoom) + } else { + zoom + } +} diff --git a/editor/src/messages/portfolio/document/navigation/utility_types.rs b/editor/src/messages/portfolio/document/navigation/utility_types.rs new file mode 100644 index 0000000000000000000000000000000000000000..09684b890e51562a4ea1c5c04508cb33164abfcc --- /dev/null +++ b/editor/src/messages/portfolio/document/navigation/utility_types.rs @@ -0,0 +1,20 @@ +use glam::DVec2; + +#[derive(Debug, Default, Clone, PartialEq, serde::Serialize, serde::Deserialize)] +pub enum NavigationOperation { + #[default] + None, + Pan { + pan_original_for_abort: DVec2, + }, + Tilt { + tilt_original_for_abort: f64, + tilt_raw_not_snapped: f64, + snap: bool, + }, + Zoom { + zoom_raw_not_snapped: f64, + zoom_original_for_abort: f64, + snap: bool, + }, +} diff --git a/editor/src/messages/portfolio/document/node_graph/document_node_definitions.rs b/editor/src/messages/portfolio/document/node_graph/document_node_definitions.rs new file mode 100644 index 0000000000000000000000000000000000000000..d6fa996f19fc8399d7fe80eee8ea025a36754ea9 --- /dev/null +++ b/editor/src/messages/portfolio/document/node_graph/document_node_definitions.rs @@ -0,0 +1,2823 @@ +mod document_node_derive; + +use super::node_properties::choice::enum_choice; +use super::node_properties::{self, ParameterWidgetsInfo}; +use super::utility_types::FrontendNodeType; +use crate::messages::layout::utility_types::widget_prelude::*; +use crate::messages::portfolio::document::utility_types::network_interface::{ + DocumentNodeMetadata, DocumentNodePersistentMetadata, InputMetadata, NodeNetworkInterface, NodeNetworkMetadata, NodeNetworkPersistentMetadata, NodeTemplate, NodeTypePersistentMetadata, + NumberInputSettings, Vec2InputSettings, WidgetOverride, +}; +use crate::messages::portfolio::utility_types::PersistentData; +use crate::messages::prelude::Message; +use crate::node_graph_executor::NodeGraphExecutor; +use glam::DVec2; +use graph_craft::ProtoNodeIdentifier; +use graph_craft::concrete; +use graph_craft::document::value::*; +use graph_craft::document::*; +use graphene_std::brush::brush_cache::BrushCache; +use graphene_std::extract_xy::XY; +use graphene_std::raster::{CellularDistanceFunction, CellularReturnType, Color, DomainWarpType, FractalType, NoiseType, RedGreenBlueAlpha}; +use graphene_std::raster_types::{CPU, RasterDataTable}; +use graphene_std::text::{Font, TypesettingConfig}; +use graphene_std::transform::Footprint; +use graphene_std::vector::VectorDataTable; +use graphene_std::*; +use std::collections::{HashMap, HashSet, VecDeque}; + +pub struct NodePropertiesContext<'a> { + pub persistent_data: &'a PersistentData, + pub responses: &'a mut VecDeque, + pub executor: &'a mut NodeGraphExecutor, + pub network_interface: &'a mut NodeNetworkInterface, + pub selection_network_path: &'a [NodeId], + pub document_name: &'a str, +} + +impl NodePropertiesContext<'_> { + pub fn call_widget_override(&mut self, node_id: &NodeId, index: usize) -> Option> { + let input_properties_row = self.network_interface.persistent_input_metadata(node_id, index, self.selection_network_path)?; + if let Some(widget_override) = &input_properties_row.widget_override { + let Some(widget_override_lambda) = INPUT_OVERRIDES.get(widget_override) else { + log::error!("Could not get widget override '{widget_override}' lambda in call_widget_override"); + return None; + }; + widget_override_lambda(*node_id, index, self) + .map_err(|error| log::error!("Error in widget override lambda: {}", error)) + .ok() + } else { + None + } + } +} + +/// Acts as a description for a [DocumentNode] before it gets instantiated as one. +#[derive(Clone)] +pub struct DocumentNodeDefinition { + /// Used by the reference field in [`DocumentNodeMetadata`] to prevent storing a copy of the implementation, if it is unchanged from the definition. + pub identifier: &'static str, + + /// All data required to construct a [`DocumentNode`] and [`DocumentNodeMetadata`] + pub node_template: NodeTemplate, + + /// Definition specific data. In order for the editor to access this data, the reference will be used. + pub category: &'static str, + + /// User-facing description of the node's functionality. + pub description: Cow<'static, str>, + + /// Node level overrides are stored based on the reference, not the instance. If the node is modified such that it becomes a local version + /// (for example an input is added), the reference is no longer to the definition, and the overrides are lost. + /// Most nodes should not use node based properties, since they are less flexible than input level properties. + pub properties: Option<&'static str>, +} + +// We use the once cell for lazy initialization to avoid the overhead of reconstructing the node list every time. +// TODO: make document nodes not require a `'static` lifetime to avoid having to split the construction into const and non-const parts. +static DOCUMENT_NODE_TYPES: once_cell::sync::Lazy> = once_cell::sync::Lazy::new(static_nodes); + +// TODO: Dynamic node library +/// Defines the "signature" or "header file"-like metadata for the document nodes, but not the implementation (which is defined in the node registry). +/// The [`DocumentNode`] is the instance while these [`DocumentNodeDefinition`]s are the "classes" or "blueprints" from which the instances are built. +fn static_nodes() -> Vec { + let custom = vec![ + // TODO: Auto-generate this from its proto node macro + DocumentNodeDefinition { + identifier: "Identity", + category: "General", + node_template: NodeTemplate { + document_node: DocumentNode { + implementation: DocumentNodeImplementation::proto("graphene_core::ops::IdentityNode"), + inputs: vec![NodeInput::value(TaggedValue::None, true)], + ..Default::default() + }, + persistent_node_metadata: DocumentNodePersistentMetadata { + input_metadata: vec![("In", "TODO").into()], + output_names: vec!["Out".to_string()], + ..Default::default() + }, + }, + description: Cow::Borrowed("Passes-through the input value without changing it. This is useful for rerouting wires for organization purposes."), + properties: Some("identity_properties"), + }, + // TODO: Auto-generate this from its proto node macro + DocumentNodeDefinition { + identifier: "Monitor", + category: "Debug", + node_template: NodeTemplate { + document_node: DocumentNode { + implementation: DocumentNodeImplementation::proto("graphene_core::memo::MonitorNode"), + inputs: vec![NodeInput::value(TaggedValue::None, true)], + manual_composition: Some(generic!(T)), + skip_deduplication: true, + ..Default::default() + }, + persistent_node_metadata: DocumentNodePersistentMetadata { + input_metadata: vec![("In", "TODO").into()], + output_names: vec!["Out".to_string()], + ..Default::default() + }, + }, + description: Cow::Borrowed("The Monitor node is used by the editor to access the data flowing through it."), + properties: Some("monitor_properties"), + }, + DocumentNodeDefinition { + identifier: "Default Network", + category: "General", + node_template: NodeTemplate { + document_node: DocumentNode { + implementation: DocumentNodeImplementation::Network(NodeNetwork::default()), + ..Default::default() + }, + persistent_node_metadata: DocumentNodePersistentMetadata { + network_metadata: Some(NodeNetworkMetadata::default()), + ..Default::default() + }, + }, + description: Cow::Borrowed("A default node network you can use to create your own custom nodes."), + properties: None, + }, + DocumentNodeDefinition { + identifier: "Cache", + category: "General", + node_template: NodeTemplate { + document_node: DocumentNode { + implementation: DocumentNodeImplementation::Network(NodeNetwork { + exports: vec![NodeInput::node(NodeId(2), 0)], + nodes: [ + DocumentNode { + inputs: vec![NodeInput::network(generic!(T), 0)], + implementation: DocumentNodeImplementation::ProtoNode(ProtoNodeIdentifier::new("graphene_core::memo::MemoNode")), + manual_composition: Some(generic!(T)), + ..Default::default() + }, + DocumentNode { + inputs: vec![NodeInput::node(NodeId(0), 0)], + implementation: DocumentNodeImplementation::ProtoNode(ProtoNodeIdentifier::new("graphene_core::transform_nodes::FreezeRealTimeNode")), + manual_composition: Some(generic!(T)), + ..Default::default() + }, + DocumentNode { + inputs: vec![NodeInput::node(NodeId(1), 0)], + implementation: DocumentNodeImplementation::ProtoNode(ProtoNodeIdentifier::new("graphene_core::transform_nodes::BoundlessFootprintNode")), + manual_composition: Some(generic!(T)), + ..Default::default() + }, + ] + .into_iter() + .enumerate() + .map(|(id, node)| (NodeId(id as u64), node)) + .collect(), + ..Default::default() + }), + inputs: vec![NodeInput::value(TaggedValue::None, true)], + ..Default::default() + }, + persistent_node_metadata: DocumentNodePersistentMetadata { + network_metadata: Some(NodeNetworkMetadata { + persistent_metadata: NodeNetworkPersistentMetadata { + node_metadata: [ + DocumentNodeMetadata { + persistent_metadata: DocumentNodePersistentMetadata { + display_name: "Memoize".to_string(), + node_type_metadata: NodeTypePersistentMetadata::node(IVec2::new(0, 0)), + ..Default::default() + }, + ..Default::default() + }, + DocumentNodeMetadata { + persistent_metadata: DocumentNodePersistentMetadata { + display_name: "Freeze Real Time".to_string(), + node_type_metadata: NodeTypePersistentMetadata::node(IVec2::new(7, 0)), + ..Default::default() + }, + ..Default::default() + }, + DocumentNodeMetadata { + persistent_metadata: DocumentNodePersistentMetadata { + display_name: "Boundless Footprint".to_string(), + node_type_metadata: NodeTypePersistentMetadata::node(IVec2::new(14, 0)), + ..Default::default() + }, + ..Default::default() + }, + ] + .into_iter() + .enumerate() + .map(|(id, node)| (NodeId(id as u64), node)) + .collect(), + ..Default::default() + }, + ..Default::default() + }), + input_metadata: vec![("Data", "TODO").into()], + output_names: vec!["Data".to_string()], + ..Default::default() + }, + }, + description: Cow::Borrowed("TODO"), + properties: None, + }, + DocumentNodeDefinition { + identifier: "Merge", + category: "General", + node_template: NodeTemplate { + document_node: DocumentNode { + implementation: DocumentNodeImplementation::Network(NodeNetwork { + exports: vec![NodeInput::node(NodeId(3), 0)], + nodes: [ + // Secondary (left) input type coercion + DocumentNode { + inputs: vec![NodeInput::network(generic!(T), 1)], + implementation: DocumentNodeImplementation::proto("graphene_core::graphic_element::ToElementNode"), + manual_composition: Some(concrete!(Context)), + ..Default::default() + }, + // Primary (bottom) input type coercion + DocumentNode { + inputs: vec![NodeInput::network(generic!(T), 0)], + implementation: DocumentNodeImplementation::proto("graphene_core::graphic_element::ToGroupNode"), + manual_composition: Some(concrete!(Context)), + ..Default::default() + }, + // The monitor node is used to display a thumbnail in the UI + DocumentNode { + inputs: vec![NodeInput::node(NodeId(0), 0)], + implementation: DocumentNodeImplementation::proto("graphene_core::memo::MonitorNode"), + manual_composition: Some(concrete!(Context)), + skip_deduplication: true, + ..Default::default() + }, + DocumentNode { + manual_composition: Some(generic!(T)), + inputs: vec![ + NodeInput::node(NodeId(1), 0), + NodeInput::node(NodeId(2), 0), + NodeInput::Reflection(graph_craft::document::DocumentNodeMetadata::DocumentNodePath), + ], + implementation: DocumentNodeImplementation::proto("graphene_core::graphic_element::LayerNode"), + ..Default::default() + }, + ] + .into_iter() + .enumerate() + .map(|(id, node)| (NodeId(id as u64), node)) + .collect(), + ..Default::default() + }), + inputs: vec![ + NodeInput::value(TaggedValue::GraphicGroup(GraphicGroupTable::default()), true), + NodeInput::value(TaggedValue::GraphicGroup(GraphicGroupTable::default()), true), + ], + ..Default::default() + }, + persistent_node_metadata: DocumentNodePersistentMetadata { + input_metadata: vec![("Graphical Data", "TODO").into(), ("Over", "TODO").into()], + output_names: vec!["Out".to_string()], + node_type_metadata: NodeTypePersistentMetadata::layer(IVec2::new(0, 0)), + network_metadata: Some(NodeNetworkMetadata { + persistent_metadata: NodeNetworkPersistentMetadata { + node_metadata: [ + DocumentNodeMetadata { + persistent_metadata: DocumentNodePersistentMetadata { + display_name: "To Element".to_string(), + node_type_metadata: NodeTypePersistentMetadata::node(IVec2::new(-14, -1)), + ..Default::default() + }, + ..Default::default() + }, + DocumentNodeMetadata { + persistent_metadata: DocumentNodePersistentMetadata { + display_name: "To Group".to_string(), + node_type_metadata: NodeTypePersistentMetadata::node(IVec2::new(-14, -3)), + ..Default::default() + }, + ..Default::default() + }, + DocumentNodeMetadata { + persistent_metadata: DocumentNodePersistentMetadata { + display_name: "Monitor".to_string(), + node_type_metadata: NodeTypePersistentMetadata::node(IVec2::new(-7, -1)), + ..Default::default() + }, + ..Default::default() + }, + DocumentNodeMetadata { + persistent_metadata: DocumentNodePersistentMetadata { + display_name: "Layer".to_string(), + node_type_metadata: NodeTypePersistentMetadata::node(IVec2::new(0, -3)), + ..Default::default() + }, + ..Default::default() + }, + ] + .into_iter() + .enumerate() + .map(|(id, node)| (NodeId(id as u64), node)) + .collect(), + ..Default::default() + }, + ..Default::default() + }), + ..Default::default() + }, + }, + description: Cow::Borrowed("Merge attaches a layer to the stack's group."), + properties: None, + }, + DocumentNodeDefinition { + identifier: "Artboard", + category: "General", + node_template: NodeTemplate { + document_node: DocumentNode { + implementation: DocumentNodeImplementation::Network(NodeNetwork { + exports: vec![NodeInput::node(NodeId(2), 0)], + nodes: [ + // Ensure this ID is kept in sync with the ID in set_alias so that the name input is kept in sync with the alias + DocumentNode { + manual_composition: Some(generic!(T)), + implementation: DocumentNodeImplementation::proto("graphene_core::graphic_element::ToArtboardNode"), + inputs: vec![ + NodeInput::network(concrete!(TaggedValue), 1), + NodeInput::value(TaggedValue::String(String::from("Artboard")), false), + NodeInput::network(concrete!(TaggedValue), 2), + NodeInput::network(concrete!(TaggedValue), 3), + NodeInput::network(concrete!(TaggedValue), 4), + NodeInput::network(concrete!(TaggedValue), 5), + ], + ..Default::default() + }, + // The monitor node is used to display a thumbnail in the UI. + // TODO: Check if thumbnail is reversed + DocumentNode { + inputs: vec![NodeInput::node(NodeId(0), 0)], + implementation: DocumentNodeImplementation::proto("graphene_core::memo::MonitorNode"), + manual_composition: Some(generic!(T)), + skip_deduplication: true, + ..Default::default() + }, + DocumentNode { + manual_composition: Some(concrete!(Context)), + inputs: vec![ + NodeInput::network(graphene_std::Type::Fn(Box::new(concrete!(Context)), Box::new(concrete!(ArtboardGroupTable))), 0), + NodeInput::node(NodeId(1), 0), + NodeInput::Reflection(graph_craft::document::DocumentNodeMetadata::DocumentNodePath), + ], + implementation: DocumentNodeImplementation::proto("graphene_core::graphic_element::AppendArtboardNode"), + ..Default::default() + }, + ] + .into_iter() + .enumerate() + .map(|(id, node)| (NodeId(id as u64), node)) + .collect(), + ..Default::default() + }), + inputs: vec![ + NodeInput::value(TaggedValue::ArtboardGroup(ArtboardGroupTable::default()), true), + NodeInput::value(TaggedValue::GraphicGroup(GraphicGroupTable::default()), true), + NodeInput::value(TaggedValue::IVec2(glam::IVec2::ZERO), false), + NodeInput::value(TaggedValue::IVec2(glam::IVec2::new(1920, 1080)), false), + NodeInput::value(TaggedValue::Color(Color::WHITE), false), + NodeInput::value(TaggedValue::Bool(false), false), + ], + ..Default::default() + }, + persistent_node_metadata: DocumentNodePersistentMetadata { + input_metadata: vec![ + ("Artboards", "TODO").into(), + InputMetadata::with_name_description_override("Contents", "TODO", WidgetOverride::Hidden), + InputMetadata::with_name_description_override( + "Location", + "TODO", + WidgetOverride::Vec2(Vec2InputSettings { + x: "X".to_string(), + y: "Y".to_string(), + unit: " px".to_string(), + ..Default::default() + }), + ), + InputMetadata::with_name_description_override( + "Dimensions", + "TODO", + WidgetOverride::Vec2(Vec2InputSettings { + x: "W".to_string(), + y: "H".to_string(), + unit: " px".to_string(), + ..Default::default() + }), + ), + InputMetadata::with_name_description_override("Background", "TODO", WidgetOverride::Custom("artboard_background".to_string())), + ("Clip", "TODO").into(), + ], + output_names: vec!["Out".to_string()], + node_type_metadata: NodeTypePersistentMetadata::layer(IVec2::new(0, 0)), + network_metadata: Some(NodeNetworkMetadata { + persistent_metadata: NodeNetworkPersistentMetadata { + node_metadata: [ + DocumentNodeMetadata { + persistent_metadata: DocumentNodePersistentMetadata { + display_name: "To Artboard".to_string(), + node_type_metadata: NodeTypePersistentMetadata::node(IVec2::new(-14, -3)), + ..Default::default() + }, + ..Default::default() + }, + DocumentNodeMetadata { + persistent_metadata: DocumentNodePersistentMetadata { + display_name: "Monitor".to_string(), + node_type_metadata: NodeTypePersistentMetadata::node(IVec2::new(-7, -3)), + ..Default::default() + }, + ..Default::default() + }, + DocumentNodeMetadata { + persistent_metadata: DocumentNodePersistentMetadata { + display_name: "Append Artboards".to_string(), + node_type_metadata: NodeTypePersistentMetadata::node(IVec2::new(0, -4)), + ..Default::default() + }, + ..Default::default() + }, + ] + .into_iter() + .enumerate() + .map(|(id, node)| (NodeId(id as u64), node)) + .collect(), + ..Default::default() + }, + ..Default::default() + }), + ..Default::default() + }, + }, + description: Cow::Borrowed("Creates a new Artboard which can be used as a working surface."), + properties: None, + }, + DocumentNodeDefinition { + identifier: "Load Image", + category: "Web Request", + node_template: NodeTemplate { + document_node: DocumentNode { + implementation: DocumentNodeImplementation::Network(NodeNetwork { + exports: vec![NodeInput::node(NodeId(1), 0)], + nodes: [ + DocumentNode { + inputs: vec![NodeInput::value(TaggedValue::None, false), NodeInput::scope("editor-api"), NodeInput::network(concrete!(String), 1)], + manual_composition: Some(concrete!(Context)), + implementation: DocumentNodeImplementation::ProtoNode(ProtoNodeIdentifier::new("graphene_std::wasm_application_io::LoadResourceNode")), + ..Default::default() + }, + DocumentNode { + inputs: vec![NodeInput::node(NodeId(0), 0)], + manual_composition: Some(concrete!(Context)), + implementation: DocumentNodeImplementation::ProtoNode(ProtoNodeIdentifier::new("graphene_std::wasm_application_io::DecodeImageNode")), + ..Default::default() + }, + ] + .into_iter() + .enumerate() + .map(|(id, node)| (NodeId(id as u64), node)) + .collect(), + ..Default::default() + }), + inputs: vec![NodeInput::value(TaggedValue::None, false), NodeInput::value(TaggedValue::String("graphite:null".to_string()), false)], + ..Default::default() + }, + persistent_node_metadata: DocumentNodePersistentMetadata { + input_metadata: vec![("Empty", "TODO").into(), ("URL", "TODO").into()], + output_names: vec!["Image".to_string()], + network_metadata: Some(NodeNetworkMetadata { + persistent_metadata: NodeNetworkPersistentMetadata { + node_metadata: [ + DocumentNodeMetadata { + persistent_metadata: DocumentNodePersistentMetadata { + display_name: "Load Resource".to_string(), + node_type_metadata: NodeTypePersistentMetadata::node(IVec2::new(0, 0)), + ..Default::default() + }, + ..Default::default() + }, + DocumentNodeMetadata { + persistent_metadata: DocumentNodePersistentMetadata { + display_name: "Decode Image".to_string(), + node_type_metadata: NodeTypePersistentMetadata::node(IVec2::new(7, 0)), + ..Default::default() + }, + ..Default::default() + }, + ] + .into_iter() + .enumerate() + .map(|(id, node)| (NodeId(id as u64), node)) + .collect(), + ..Default::default() + }, + ..Default::default() + }), + ..Default::default() + }, + }, + description: Cow::Borrowed("Loads an image from a given URL"), + properties: None, + }, + DocumentNodeDefinition { + identifier: "Create Canvas", + category: "Debug: GPU", + node_template: NodeTemplate { + document_node: DocumentNode { + implementation: DocumentNodeImplementation::Network(NodeNetwork { + exports: vec![NodeInput::node(NodeId(1), 0)], + nodes: [ + DocumentNode { + inputs: vec![NodeInput::scope("editor-api")], + implementation: DocumentNodeImplementation::ProtoNode(ProtoNodeIdentifier::new("graphene_std::wasm_application_io::CreateSurfaceNode")), + skip_deduplication: true, + ..Default::default() + }, + DocumentNode { + manual_composition: Some(concrete!(Context)), + inputs: vec![NodeInput::node(NodeId(0), 0)], + implementation: DocumentNodeImplementation::ProtoNode(ProtoNodeIdentifier::new("graphene_core::memo::MemoNode")), + ..Default::default() + }, + ] + .into_iter() + .enumerate() + .map(|(id, node)| (NodeId(id as u64), node)) + .collect(), + ..Default::default() + }), + ..Default::default() + }, + persistent_node_metadata: DocumentNodePersistentMetadata { + output_names: vec!["Image".to_string()], + network_metadata: Some(NodeNetworkMetadata { + persistent_metadata: NodeNetworkPersistentMetadata { + node_metadata: [ + DocumentNodeMetadata { + persistent_metadata: DocumentNodePersistentMetadata { + display_name: "Create Canvas".to_string(), + node_type_metadata: NodeTypePersistentMetadata::node(IVec2::new(0, 0)), + ..Default::default() + }, + ..Default::default() + }, + DocumentNodeMetadata { + persistent_metadata: DocumentNodePersistentMetadata { + display_name: "Cache".to_string(), + node_type_metadata: NodeTypePersistentMetadata::node(IVec2::new(7, 0)), + ..Default::default() + }, + ..Default::default() + }, + ] + .into_iter() + .enumerate() + .map(|(id, node)| (NodeId(id as u64), node)) + .collect(), + ..Default::default() + }, + ..Default::default() + }), + ..Default::default() + }, + }, + description: Cow::Borrowed("Creates a new canvas object."), + properties: None, + }, + DocumentNodeDefinition { + identifier: "Draw Canvas", + category: "Debug: GPU", + node_template: NodeTemplate { + document_node: DocumentNode { + implementation: DocumentNodeImplementation::Network(NodeNetwork { + exports: vec![NodeInput::node(NodeId(3), 0)], + nodes: [ + DocumentNode { + inputs: vec![NodeInput::network(concrete!(RasterDataTable), 0)], + implementation: DocumentNodeImplementation::ProtoNode(ProtoNodeIdentifier::new("graphene_core::ops::IntoNode<_, RasterDataTable>")), + ..Default::default() + }, + DocumentNode { + inputs: vec![NodeInput::scope("editor-api")], + implementation: DocumentNodeImplementation::ProtoNode(ProtoNodeIdentifier::new("graphene_std::wasm_application_io::CreateSurfaceNode")), + skip_deduplication: true, + ..Default::default() + }, + DocumentNode { + manual_composition: Some(concrete!(Context)), + inputs: vec![NodeInput::node(NodeId(1), 0)], + implementation: DocumentNodeImplementation::ProtoNode(ProtoNodeIdentifier::new("graphene_core::memo::MemoNode")), + ..Default::default() + }, + DocumentNode { + inputs: vec![NodeInput::node(NodeId(0), 0), NodeInput::node(NodeId(2), 0)], + implementation: DocumentNodeImplementation::ProtoNode(ProtoNodeIdentifier::new("graphene_std::wasm_application_io::DrawImageFrameNode")), + ..Default::default() + }, + ] + .into_iter() + .enumerate() + .map(|(id, node)| (NodeId(id as u64), node)) + .collect(), + ..Default::default() + }), + inputs: vec![NodeInput::value(TaggedValue::RasterData(RasterDataTable::default()), true)], + ..Default::default() + }, + persistent_node_metadata: DocumentNodePersistentMetadata { + input_metadata: vec![("In", "TODO").into()], + output_names: vec!["Canvas".to_string()], + network_metadata: Some(NodeNetworkMetadata { + persistent_metadata: NodeNetworkPersistentMetadata { + node_metadata: [ + DocumentNodeMetadata { + persistent_metadata: DocumentNodePersistentMetadata { + display_name: "Into".to_string(), + node_type_metadata: NodeTypePersistentMetadata::node(IVec2::new(0, 0)), + ..Default::default() + }, + ..Default::default() + }, + DocumentNodeMetadata { + persistent_metadata: DocumentNodePersistentMetadata { + display_name: "Create Canvas".to_string(), + node_type_metadata: NodeTypePersistentMetadata::node(IVec2::new(0, 2)), + ..Default::default() + }, + ..Default::default() + }, + DocumentNodeMetadata { + persistent_metadata: DocumentNodePersistentMetadata { + display_name: "Cache".to_string(), + node_type_metadata: NodeTypePersistentMetadata::node(IVec2::new(7, 2)), + ..Default::default() + }, + ..Default::default() + }, + DocumentNodeMetadata { + persistent_metadata: DocumentNodePersistentMetadata { + display_name: "Draw Canvas".to_string(), + node_type_metadata: NodeTypePersistentMetadata::node(IVec2::new(14, 0)), + ..Default::default() + }, + ..Default::default() + }, + ] + .into_iter() + .enumerate() + .map(|(id, node)| (NodeId(id as u64), node)) + .collect(), + ..Default::default() + }, + ..Default::default() + }), + ..Default::default() + }, + }, + description: Cow::Borrowed("Draws raster data to a canvas element."), + properties: None, + }, + DocumentNodeDefinition { + identifier: "Rasterize", + category: "Raster", + node_template: NodeTemplate { + document_node: DocumentNode { + implementation: DocumentNodeImplementation::Network(NodeNetwork { + exports: vec![NodeInput::node(NodeId(2), 0)], + nodes: [ + DocumentNode { + inputs: vec![NodeInput::scope("editor-api")], + implementation: DocumentNodeImplementation::ProtoNode(ProtoNodeIdentifier::new("graphene_std::wasm_application_io::CreateSurfaceNode")), + manual_composition: Some(concrete!(Context)), + skip_deduplication: true, + ..Default::default() + }, + DocumentNode { + inputs: vec![NodeInput::node(NodeId(0), 0)], + implementation: DocumentNodeImplementation::ProtoNode(ProtoNodeIdentifier::new("graphene_core::memo::MemoNode")), + manual_composition: Some(concrete!(Context)), + ..Default::default() + }, + DocumentNode { + inputs: vec![NodeInput::network(generic!(T), 0), NodeInput::network(concrete!(Footprint), 1), NodeInput::node(NodeId(1), 0)], + implementation: DocumentNodeImplementation::ProtoNode(ProtoNodeIdentifier::new("graphene_std::wasm_application_io::RasterizeNode")), + manual_composition: Some(concrete!(Context)), + ..Default::default() + }, + ] + .into_iter() + .enumerate() + .map(|(id, node)| (NodeId(id as u64), node)) + .collect(), + ..Default::default() + }), + inputs: vec![ + NodeInput::value(TaggedValue::VectorData(VectorDataTable::default()), true), + NodeInput::value( + TaggedValue::Footprint(Footprint { + transform: DAffine2::from_scale_angle_translation(DVec2::new(100., 100.), 0., DVec2::new(0., 0.)), + resolution: UVec2::new(100, 100), + ..Default::default() + }), + false, + ), + ], + ..Default::default() + }, + persistent_node_metadata: DocumentNodePersistentMetadata { + input_metadata: vec![("Artwork", "TODO").into(), ("Footprint", "TODO").into()], + output_names: vec!["Canvas".to_string()], + network_metadata: Some(NodeNetworkMetadata { + persistent_metadata: NodeNetworkPersistentMetadata { + node_metadata: [ + DocumentNodeMetadata { + persistent_metadata: DocumentNodePersistentMetadata { + display_name: "Create Surface".to_string(), + node_type_metadata: NodeTypePersistentMetadata::node(IVec2::new(0, 2)), + ..Default::default() + }, + ..Default::default() + }, + DocumentNodeMetadata { + persistent_metadata: DocumentNodePersistentMetadata { + display_name: "Cache".to_string(), + node_type_metadata: NodeTypePersistentMetadata::node(IVec2::new(7, 2)), + ..Default::default() + }, + ..Default::default() + }, + DocumentNodeMetadata { + persistent_metadata: DocumentNodePersistentMetadata { + display_name: "Rasterize".to_string(), + node_type_metadata: NodeTypePersistentMetadata::node(IVec2::new(14, 0)), + ..Default::default() + }, + ..Default::default() + }, + ] + .into_iter() + .enumerate() + .map(|(id, node)| (NodeId(id as u64), node)) + .collect(), + ..Default::default() + }, + ..Default::default() + }), + ..Default::default() + }, + }, + description: Cow::Borrowed("Rasterizes the given vector data"), + properties: None, + }, + DocumentNodeDefinition { + identifier: "Noise Pattern", + category: "Raster: Pattern", + node_template: NodeTemplate { + document_node: DocumentNode { + manual_composition: Some(concrete!(Context)), + implementation: DocumentNodeImplementation::ProtoNode(ProtoNodeIdentifier::new("graphene_std::raster::NoisePatternNode")), + inputs: vec![ + NodeInput::value(TaggedValue::None, false), + NodeInput::value(TaggedValue::Bool(true), false), + NodeInput::value(TaggedValue::U32(0), false), + NodeInput::value(TaggedValue::F64(10.), false), + NodeInput::value(TaggedValue::NoiseType(NoiseType::default()), false), + NodeInput::value(TaggedValue::DomainWarpType(DomainWarpType::default()), false), + NodeInput::value(TaggedValue::F64(100.), false), + NodeInput::value(TaggedValue::FractalType(FractalType::default()), false), + NodeInput::value(TaggedValue::U32(3), false), + NodeInput::value(TaggedValue::F64(2.), false), + NodeInput::value(TaggedValue::F64(0.5), false), + NodeInput::value(TaggedValue::F64(0.), false), // 0-1 range + NodeInput::value(TaggedValue::F64(2.), false), + NodeInput::value(TaggedValue::CellularDistanceFunction(CellularDistanceFunction::default()), false), + NodeInput::value(TaggedValue::CellularReturnType(CellularReturnType::default()), false), + NodeInput::value(TaggedValue::F64(1.), false), + ], + ..Default::default() + }, + persistent_node_metadata: DocumentNodePersistentMetadata { + input_metadata: vec![ + ("Spacer", "TODO").into(), + ("Clip", "TODO").into(), + ("Seed", "TODO").into(), + InputMetadata::with_name_description_override("Scale", "TODO", WidgetOverride::Custom("noise_properties_scale".to_string())), + InputMetadata::with_name_description_override("Noise Type", "TODO", WidgetOverride::Custom("noise_properties_noise_type".to_string())), + InputMetadata::with_name_description_override("Domain Warp Type", "TODO", WidgetOverride::Custom("noise_properties_domain_warp_type".to_string())), + InputMetadata::with_name_description_override("Domain Warp Amplitude", "TODO", WidgetOverride::Custom("noise_properties_domain_warp_amplitude".to_string())), + InputMetadata::with_name_description_override("Fractal Type", "TODO", WidgetOverride::Custom("noise_properties_fractal_type".to_string())), + InputMetadata::with_name_description_override("Fractal Octaves", "TODO", WidgetOverride::Custom("noise_properties_fractal_octaves".to_string())), + InputMetadata::with_name_description_override("Fractal Lacunarity", "TODO", WidgetOverride::Custom("noise_properties_fractal_lacunarity".to_string())), + InputMetadata::with_name_description_override("Fractal Gain", "TODO", WidgetOverride::Custom("noise_properties_fractal_gain".to_string())), + InputMetadata::with_name_description_override("Fractal Weighted Strength", "TODO", WidgetOverride::Custom("noise_properties_fractal_weighted_strength".to_string())), + InputMetadata::with_name_description_override("Fractal Ping Pong Strength", "TODO", WidgetOverride::Custom("noise_properties_ping_pong_strength".to_string())), + InputMetadata::with_name_description_override("Cellular Distance Function", "TODO", WidgetOverride::Custom("noise_properties_cellular_distance_function".to_string())), + InputMetadata::with_name_description_override("Cellular Return Type", "TODO", WidgetOverride::Custom("noise_properties_cellular_return_type".to_string())), + InputMetadata::with_name_description_override("Cellular Jitter", "TODO", WidgetOverride::Custom("noise_properties_cellular_jitter".to_string())), + ], + output_names: vec!["Image".to_string()], + ..Default::default() + }, + }, + description: Cow::Borrowed("Generates different noise patterns."), + properties: None, + }, + DocumentNodeDefinition { + identifier: "Split Channels", + category: "Raster: Channels", + node_template: NodeTemplate { + document_node: DocumentNode { + implementation: DocumentNodeImplementation::Network(NodeNetwork { + exports: vec![ + NodeInput::node(NodeId(0), 0), + NodeInput::node(NodeId(1), 0), + NodeInput::node(NodeId(2), 0), + NodeInput::node(NodeId(3), 0), + ], + nodes: [ + DocumentNode { + inputs: vec![ + NodeInput::network(concrete!(RasterDataTable), 0), + NodeInput::value(TaggedValue::RedGreenBlueAlpha(RedGreenBlueAlpha::Red), false), + ], + implementation: DocumentNodeImplementation::ProtoNode(ProtoNodeIdentifier::new("graphene_core::raster::adjustments::ExtractChannelNode")), + manual_composition: Some(generic!(T)), + ..Default::default() + }, + DocumentNode { + inputs: vec![ + NodeInput::network(concrete!(RasterDataTable), 0), + NodeInput::value(TaggedValue::RedGreenBlueAlpha(RedGreenBlueAlpha::Green), false), + ], + implementation: DocumentNodeImplementation::ProtoNode(ProtoNodeIdentifier::new("graphene_core::raster::adjustments::ExtractChannelNode")), + manual_composition: Some(generic!(T)), + ..Default::default() + }, + DocumentNode { + inputs: vec![ + NodeInput::network(concrete!(RasterDataTable), 0), + NodeInput::value(TaggedValue::RedGreenBlueAlpha(RedGreenBlueAlpha::Blue), false), + ], + implementation: DocumentNodeImplementation::ProtoNode(ProtoNodeIdentifier::new("graphene_core::raster::adjustments::ExtractChannelNode")), + manual_composition: Some(generic!(T)), + ..Default::default() + }, + DocumentNode { + inputs: vec![ + NodeInput::network(concrete!(RasterDataTable), 0), + NodeInput::value(TaggedValue::RedGreenBlueAlpha(RedGreenBlueAlpha::Alpha), false), + ], + implementation: DocumentNodeImplementation::ProtoNode(ProtoNodeIdentifier::new("graphene_core::raster::adjustments::ExtractChannelNode")), + manual_composition: Some(generic!(T)), + ..Default::default() + }, + ] + .into_iter() + .enumerate() + .map(|(id, node)| (NodeId(id as u64), node)) + .collect(), + ..Default::default() + }), + inputs: vec![NodeInput::value(TaggedValue::RasterData(RasterDataTable::default()), true)], + ..Default::default() + }, + persistent_node_metadata: DocumentNodePersistentMetadata { + input_metadata: vec![("Image", "TODO").into()], + output_names: vec!["Red".to_string(), "Green".to_string(), "Blue".to_string(), "Alpha".to_string()], + has_primary_output: false, + network_metadata: Some(NodeNetworkMetadata { + persistent_metadata: NodeNetworkPersistentMetadata { + node_metadata: [ + DocumentNodeMetadata { + persistent_metadata: DocumentNodePersistentMetadata { + display_name: "Extract Channel".to_string(), + node_type_metadata: NodeTypePersistentMetadata::node(IVec2::new(0, 0)), + ..Default::default() + }, + ..Default::default() + }, + DocumentNodeMetadata { + persistent_metadata: DocumentNodePersistentMetadata { + display_name: "Extract Channel".to_string(), + node_type_metadata: NodeTypePersistentMetadata::node(IVec2::new(0, 2)), + ..Default::default() + }, + ..Default::default() + }, + DocumentNodeMetadata { + persistent_metadata: DocumentNodePersistentMetadata { + display_name: "Extract Channel".to_string(), + node_type_metadata: NodeTypePersistentMetadata::node(IVec2::new(0, 4)), + ..Default::default() + }, + ..Default::default() + }, + DocumentNodeMetadata { + persistent_metadata: DocumentNodePersistentMetadata { + display_name: "Extract Channel".to_string(), + node_type_metadata: NodeTypePersistentMetadata::node(IVec2::new(0, 6)), + ..Default::default() + }, + ..Default::default() + }, + ] + .into_iter() + .enumerate() + .map(|(id, node)| (NodeId(id as u64), node)) + .collect(), + ..Default::default() + }, + ..Default::default() + }), + ..Default::default() + }, + }, + description: Cow::Borrowed("TODO"), + properties: None, + }, + DocumentNodeDefinition { + identifier: "Split Coordinate", + category: "Math: Vector", + node_template: NodeTemplate { + document_node: DocumentNode { + implementation: DocumentNodeImplementation::Network(NodeNetwork { + exports: vec![NodeInput::node(NodeId(0), 0), NodeInput::node(NodeId(1), 0)], + nodes: [ + DocumentNode { + inputs: vec![NodeInput::network(concrete!(RasterDataTable), 0), NodeInput::value(TaggedValue::XY(XY::X), false)], + implementation: DocumentNodeImplementation::ProtoNode(ProtoNodeIdentifier::new("graphene_core::extract_xy::ExtractXyNode")), + manual_composition: Some(generic!(T)), + ..Default::default() + }, + DocumentNode { + inputs: vec![NodeInput::network(concrete!(RasterDataTable), 0), NodeInput::value(TaggedValue::XY(XY::Y), false)], + implementation: DocumentNodeImplementation::ProtoNode(ProtoNodeIdentifier::new("graphene_core::extract_xy::ExtractXyNode")), + manual_composition: Some(generic!(T)), + ..Default::default() + }, + ] + .into_iter() + .enumerate() + .map(|(id, node)| (NodeId(id as u64), node)) + .collect(), + + ..Default::default() + }), + inputs: vec![NodeInput::value(TaggedValue::RasterData(RasterDataTable::default()), true)], + ..Default::default() + }, + persistent_node_metadata: DocumentNodePersistentMetadata { + input_metadata: vec![("Coordinate", "TODO").into()], + output_names: vec!["X".to_string(), "Y".to_string()], + has_primary_output: false, + network_metadata: Some(NodeNetworkMetadata { + persistent_metadata: NodeNetworkPersistentMetadata { + node_metadata: [ + DocumentNodeMetadata { + persistent_metadata: DocumentNodePersistentMetadata { + display_name: "Extract XY".to_string(), + node_type_metadata: NodeTypePersistentMetadata::node(IVec2::new(0, 0)), + ..Default::default() + }, + ..Default::default() + }, + DocumentNodeMetadata { + persistent_metadata: DocumentNodePersistentMetadata { + display_name: "Extract XY".to_string(), + node_type_metadata: NodeTypePersistentMetadata::node(IVec2::new(0, 2)), + ..Default::default() + }, + ..Default::default() + }, + ] + .into_iter() + .enumerate() + .map(|(id, node)| (NodeId(id as u64), node)) + .collect(), + ..Default::default() + }, + ..Default::default() + }), + ..Default::default() + }, + }, + description: Cow::Borrowed( + "Decomposes the X and Y components of a 2D coordinate.\n\nThe inverse of this node is \"Coordinate Value\", which can have either or both its X and Y exposed as graph inputs.", + ), + properties: None, + }, + // TODO: Remove this and just use the proto node definition directly + DocumentNodeDefinition { + identifier: "Brush", + category: "Raster", + node_template: NodeTemplate { + document_node: DocumentNode { + implementation: DocumentNodeImplementation::Network(NodeNetwork { + exports: vec![NodeInput::node(NodeId(0), 0)], + nodes: vec![DocumentNode { + inputs: vec![ + NodeInput::network(concrete!(RasterDataTable), 0), + NodeInput::network(concrete!(Vec), 1), + NodeInput::network(concrete!(BrushCache), 2), + ], + manual_composition: Some(concrete!(Context)), + implementation: DocumentNodeImplementation::ProtoNode(ProtoNodeIdentifier::new("graphene_std::brush::BrushNode")), + ..Default::default() + }] + .into_iter() + .enumerate() + .map(|(id, node)| (NodeId(id as u64), node)) + .collect(), + ..Default::default() + }), + inputs: vec![ + NodeInput::value(TaggedValue::RasterData(RasterDataTable::default()), true), + NodeInput::value(TaggedValue::BrushStrokes(Vec::new()), false), + NodeInput::value(TaggedValue::BrushCache(BrushCache::new_proto()), false), + ], + ..Default::default() + }, + persistent_node_metadata: DocumentNodePersistentMetadata { + input_metadata: vec![("Background", "TODO").into(), ("Trace", "TODO").into(), ("Cache", "TODO").into()], + output_names: vec!["Image".to_string()], + network_metadata: Some(NodeNetworkMetadata { + persistent_metadata: NodeNetworkPersistentMetadata { + node_metadata: [DocumentNodeMetadata { + persistent_metadata: DocumentNodePersistentMetadata { + display_name: "Brush".to_string(), + node_type_metadata: NodeTypePersistentMetadata::node(IVec2::new(0, 0)), + ..Default::default() + }, + ..Default::default() + }] + .into_iter() + .enumerate() + .map(|(id, node)| (NodeId(id as u64), node)) + .collect(), + ..Default::default() + }, + ..Default::default() + }), + ..Default::default() + }, + }, + description: Cow::Borrowed("TODO"), + properties: None, + }, + DocumentNodeDefinition { + identifier: "Memoize", + category: "Debug", + node_template: NodeTemplate { + document_node: DocumentNode { + implementation: DocumentNodeImplementation::proto("graphene_core::memo::MemoNode"), + inputs: vec![NodeInput::value(TaggedValue::RasterData(RasterDataTable::default()), true)], + manual_composition: Some(concrete!(Context)), + ..Default::default() + }, + persistent_node_metadata: DocumentNodePersistentMetadata { + input_metadata: vec![("Image", "TODO").into()], + output_names: vec!["Image".to_string()], + ..Default::default() + }, + }, + description: Cow::Borrowed("TODO"), + properties: None, + }, + DocumentNodeDefinition { + identifier: "Memoize Impure", + category: "Debug", + node_template: NodeTemplate { + document_node: DocumentNode { + implementation: DocumentNodeImplementation::proto("graphene_core::memo::ImpureMemoNode"), + inputs: vec![NodeInput::value(TaggedValue::RasterData(RasterDataTable::default()), true)], + manual_composition: Some(concrete!(Context)), + ..Default::default() + }, + persistent_node_metadata: DocumentNodePersistentMetadata { + input_metadata: vec![("Image", "TODO").into()], + output_names: vec!["Image".to_string()], + ..Default::default() + }, + }, + description: Cow::Borrowed("TODO"), + properties: None, + }, + DocumentNodeDefinition { + identifier: "Storage", + category: "Debug: GPU", + node_template: NodeTemplate { + document_node: DocumentNode { + implementation: DocumentNodeImplementation::Network(NodeNetwork { + exports: vec![NodeInput::node(NodeId(2), 0)], + nodes: [ + DocumentNode { + inputs: vec![NodeInput::scope("editor-api")], + implementation: DocumentNodeImplementation::ProtoNode(ProtoNodeIdentifier::new("graphene_core::ops::IntoNode")), + ..Default::default() + }, + DocumentNode { + inputs: vec![NodeInput::network(concrete!(Vec), 0), NodeInput::node(NodeId(0), 0)], + implementation: DocumentNodeImplementation::ProtoNode(ProtoNodeIdentifier::new("wgpu_executor::StorageNode")), + ..Default::default() + }, + DocumentNode { + manual_composition: Some(concrete!(Context)), + inputs: vec![NodeInput::node(NodeId(1), 0)], + implementation: DocumentNodeImplementation::ProtoNode(ProtoNodeIdentifier::new("graphene_core::memo::MemoNode")), + ..Default::default() + }, + ] + .into_iter() + .enumerate() + .map(|(id, node)| (NodeId(id as u64), node)) + .collect(), + ..Default::default() + }), + inputs: vec![NodeInput::value(TaggedValue::None, true)], + ..Default::default() + }, + persistent_node_metadata: DocumentNodePersistentMetadata { + input_metadata: vec![("In", "TODO").into()], + output_names: vec!["Storage".to_string()], + network_metadata: Some(NodeNetworkMetadata { + persistent_metadata: NodeNetworkPersistentMetadata { + node_metadata: [ + DocumentNodeMetadata { + persistent_metadata: DocumentNodePersistentMetadata { + display_name: "Extract Executor".to_string(), + node_type_metadata: NodeTypePersistentMetadata::node(IVec2::new(0, 0)), + ..Default::default() + }, + ..Default::default() + }, + DocumentNodeMetadata { + persistent_metadata: DocumentNodePersistentMetadata { + display_name: "Create Storage".to_string(), + node_type_metadata: NodeTypePersistentMetadata::node(IVec2::new(7, 0)), + ..Default::default() + }, + ..Default::default() + }, + DocumentNodeMetadata { + persistent_metadata: DocumentNodePersistentMetadata { + display_name: "Cache".to_string(), + node_type_metadata: NodeTypePersistentMetadata::node(IVec2::new(14, 0)), + ..Default::default() + }, + ..Default::default() + }, + ] + .into_iter() + .enumerate() + .map(|(id, node)| (NodeId(id as u64), node)) + .collect(), + ..Default::default() + }, + ..Default::default() + }), + ..Default::default() + }, + }, + description: Cow::Borrowed("TODO"), + properties: None, + }, + DocumentNodeDefinition { + identifier: "Create Output Buffer", + category: "Debug: GPU", + node_template: NodeTemplate { + document_node: DocumentNode { + implementation: DocumentNodeImplementation::Network(NodeNetwork { + exports: vec![NodeInput::node(NodeId(2), 0)], + nodes: [ + DocumentNode { + inputs: vec![NodeInput::scope("editor-api")], + implementation: DocumentNodeImplementation::ProtoNode(ProtoNodeIdentifier::new("graphene_core::ops::IntoNode")), + ..Default::default() + }, + DocumentNode { + inputs: vec![NodeInput::network(concrete!(usize), 0), NodeInput::node(NodeId(0), 0), NodeInput::network(concrete!(Type), 1)], + implementation: DocumentNodeImplementation::ProtoNode(ProtoNodeIdentifier::new("wgpu_executor::CreateOutputBufferNode")), + ..Default::default() + }, + DocumentNode { + manual_composition: Some(concrete!(Context)), + inputs: vec![NodeInput::node(NodeId(1), 0)], + implementation: DocumentNodeImplementation::ProtoNode(ProtoNodeIdentifier::new("graphene_core::memo::MemoNode")), + ..Default::default() + }, + ] + .into_iter() + .enumerate() + .map(|(id, node)| (NodeId(id as u64), node)) + .collect(), + ..Default::default() + }), + inputs: vec![NodeInput::value(TaggedValue::None, true), NodeInput::value(TaggedValue::None, true)], + ..Default::default() + }, + persistent_node_metadata: DocumentNodePersistentMetadata { + input_metadata: vec![("In", "TODO").into(), ("In", "TODO").into()], + output_names: vec!["Output Buffer".to_string()], + network_metadata: Some(NodeNetworkMetadata { + persistent_metadata: NodeNetworkPersistentMetadata { + node_metadata: [ + DocumentNodeMetadata { + persistent_metadata: DocumentNodePersistentMetadata { + display_name: "Extract Executor".to_string(), + node_type_metadata: NodeTypePersistentMetadata::node(IVec2::new(0, 0)), + ..Default::default() + }, + ..Default::default() + }, + DocumentNodeMetadata { + persistent_metadata: DocumentNodePersistentMetadata { + display_name: "Create Output Buffer".to_string(), + node_type_metadata: NodeTypePersistentMetadata::node(IVec2::new(7, 0)), + ..Default::default() + }, + ..Default::default() + }, + DocumentNodeMetadata { + persistent_metadata: DocumentNodePersistentMetadata { + display_name: "Cache".to_string(), + node_type_metadata: NodeTypePersistentMetadata::node(IVec2::new(14, 0)), + ..Default::default() + }, + ..Default::default() + }, + ] + .into_iter() + .enumerate() + .map(|(id, node)| (NodeId(id as u64), node)) + .collect(), + ..Default::default() + }, + ..Default::default() + }), + ..Default::default() + }, + }, + description: Cow::Borrowed("TODO"), + properties: None, + }, + #[cfg(feature = "gpu")] + DocumentNodeDefinition { + identifier: "Create GPU Surface", + category: "Debug: GPU", + node_template: NodeTemplate { + document_node: DocumentNode { + implementation: DocumentNodeImplementation::Network(NodeNetwork { + exports: vec![NodeInput::node(NodeId(1), 0)], + nodes: [ + DocumentNode { + manual_composition: Some(concrete!(Context)), + inputs: vec![NodeInput::scope("editor-api")], + implementation: DocumentNodeImplementation::ProtoNode(ProtoNodeIdentifier::new("wgpu_executor::CreateGpuSurfaceNode")), + ..Default::default() + }, + DocumentNode { + manual_composition: Some(concrete!(Context)), + inputs: vec![NodeInput::node(NodeId(0), 0)], + implementation: DocumentNodeImplementation::ProtoNode(ProtoNodeIdentifier::new("graphene_core::memo::ImpureMemoNode")), + ..Default::default() + }, + ] + .into_iter() + .enumerate() + .map(|(id, node)| (NodeId(id as u64), node)) + .collect(), + ..Default::default() + }), + ..Default::default() + }, + persistent_node_metadata: DocumentNodePersistentMetadata { + output_names: vec!["GPU Surface".to_string()], + network_metadata: Some(NodeNetworkMetadata { + persistent_metadata: NodeNetworkPersistentMetadata { + node_metadata: [ + DocumentNodeMetadata { + persistent_metadata: DocumentNodePersistentMetadata { + display_name: "Create GPU Surface".to_string(), + node_type_metadata: NodeTypePersistentMetadata::node(IVec2::new(0, 0)), + ..Default::default() + }, + ..Default::default() + }, + DocumentNodeMetadata { + persistent_metadata: DocumentNodePersistentMetadata { + display_name: "Cache".to_string(), + node_type_metadata: NodeTypePersistentMetadata::node(IVec2::new(7, 0)), + ..Default::default() + }, + ..Default::default() + }, + ] + .into_iter() + .enumerate() + .map(|(id, node)| (NodeId(id as u64), node)) + .collect(), + ..Default::default() + }, + ..Default::default() + }), + ..Default::default() + }, + }, + description: Cow::Borrowed("TODO"), + properties: None, + }, + #[cfg(feature = "gpu")] + DocumentNodeDefinition { + identifier: "Upload Texture", + category: "Debug: GPU", + node_template: NodeTemplate { + document_node: DocumentNode { + implementation: DocumentNodeImplementation::Network(NodeNetwork { + exports: vec![NodeInput::node(NodeId(2), 0)], + nodes: [ + DocumentNode { + inputs: vec![NodeInput::scope("editor-api")], + implementation: DocumentNodeImplementation::ProtoNode(ProtoNodeIdentifier::new("graphene_core::ops::IntoNode<&WgpuExecutor>")), + ..Default::default() + }, + DocumentNode { + inputs: vec![NodeInput::network(concrete!(RasterDataTable), 0), NodeInput::node(NodeId(0), 0)], + manual_composition: Some(generic!(T)), + implementation: DocumentNodeImplementation::ProtoNode(ProtoNodeIdentifier::new("wgpu_executor::UploadTextureNode")), + ..Default::default() + }, + DocumentNode { + manual_composition: Some(generic!(T)), + inputs: vec![NodeInput::node(NodeId(1), 0)], + implementation: DocumentNodeImplementation::ProtoNode(ProtoNodeIdentifier::new("graphene_core::memo::ImpureMemoNode")), + ..Default::default() + }, + ] + .into_iter() + .enumerate() + .map(|(id, node)| (NodeId(id as u64), node)) + .collect(), + ..Default::default() + }), + inputs: vec![NodeInput::value(TaggedValue::RasterData(RasterDataTable::default()), true)], + ..Default::default() + }, + persistent_node_metadata: DocumentNodePersistentMetadata { + input_metadata: vec![("In", "TODO").into()], + output_names: vec!["Texture".to_string()], + network_metadata: Some(NodeNetworkMetadata { + persistent_metadata: NodeNetworkPersistentMetadata { + node_metadata: [ + DocumentNodeMetadata { + persistent_metadata: DocumentNodePersistentMetadata { + display_name: "Extract Executor".to_string(), + node_type_metadata: NodeTypePersistentMetadata::node(IVec2::new(0, 0)), + ..Default::default() + }, + ..Default::default() + }, + DocumentNodeMetadata { + persistent_metadata: DocumentNodePersistentMetadata { + display_name: "Upload Texture".to_string(), + node_type_metadata: NodeTypePersistentMetadata::node(IVec2::new(7, 0)), + ..Default::default() + }, + ..Default::default() + }, + DocumentNodeMetadata { + persistent_metadata: DocumentNodePersistentMetadata { + display_name: "Cache".to_string(), + node_type_metadata: NodeTypePersistentMetadata::node(IVec2::new(14, 0)), + ..Default::default() + }, + ..Default::default() + }, + ] + .into_iter() + .enumerate() + .map(|(id, node)| (NodeId(id as u64), node)) + .collect(), + ..Default::default() + }, + ..Default::default() + }), + ..Default::default() + }, + }, + description: Cow::Borrowed("TODO"), + properties: None, + }, + DocumentNodeDefinition { + identifier: "Extract", + category: "Debug", + node_template: NodeTemplate { + document_node: DocumentNode { + implementation: DocumentNodeImplementation::Extract, + inputs: vec![NodeInput::value(TaggedValue::DocumentNode(DocumentNode::default()), true)], + ..Default::default() + }, + persistent_node_metadata: DocumentNodePersistentMetadata { + input_metadata: vec![("Node", "TODO").into()], + output_names: vec!["Document Node".to_string()], + ..Default::default() + }, + }, + description: Cow::Borrowed("TODO"), + properties: None, + }, + // Aims for interoperable compatibility with: + // https://www.adobe.com/devnet-apps/photoshop/fileformatashtml/#:~:text=levl%27%20%3D%20Levels-,%27curv%27%20%3D%20Curves,-%27expA%27%20%3D%20Exposure + // https://www.adobe.com/devnet-apps/photoshop/fileformatashtml/#:~:text=Max%20input%20range-,Curves,-Curves%20settings%20files + // + // Some further analysis available at: + // https://geraldbakker.nl/psnumbers/curves.html + // TODO: Fix this, it's currently broken + // DocumentNodeDefinition { + // identifier: "Curves", + // category: "Raster: Adjustment", + // node_template: NodeTemplate { + // document_node: DocumentNode { + // implementation: DocumentNodeImplementation::proto("graphene_core::raster::CurvesNode"), + // inputs: vec![ + // NodeInput::value(TaggedValue::RasterData(RasterDataTable::default()), true), + // NodeInput::value(TaggedValue::Curve(Default::default()), false), + // ], + // ..Default::default() + // }, + // persistent_node_metadata: DocumentNodePersistentMetadata { + // input_properties: vec![("Image", "TODO").into(), ("Curve", "TODO").into()], + // output_names: vec!["Image".to_string()], + // ..Default::default() + // }, + // }, + // description: Cow::Borrowed("TODO"), + // properties: None, + // }, + DocumentNodeDefinition { + identifier: "Path", + category: "Vector", + node_template: NodeTemplate { + document_node: DocumentNode { + implementation: DocumentNodeImplementation::Network(NodeNetwork { + exports: vec![NodeInput::node(NodeId(1), 0)], + nodes: vec![ + DocumentNode { + inputs: vec![NodeInput::network(concrete!(VectorDataTable), 0)], + implementation: DocumentNodeImplementation::proto("graphene_core::memo::MonitorNode"), + manual_composition: Some(generic!(T)), + skip_deduplication: true, + ..Default::default() + }, + DocumentNode { + inputs: vec![NodeInput::node(NodeId(0), 0), NodeInput::network(concrete!(graphene_std::vector::VectorModification), 1)], + manual_composition: Some(generic!(T)), + implementation: DocumentNodeImplementation::ProtoNode(ProtoNodeIdentifier::new("graphene_core::vector::vector_data::modification::PathModifyNode")), + ..Default::default() + }, + ] + .into_iter() + .enumerate() + .map(|(id, node)| (NodeId(id as u64), node)) + .collect(), + ..Default::default() + }), + inputs: vec![ + NodeInput::value(TaggedValue::VectorData(VectorDataTable::default()), true), + NodeInput::value(TaggedValue::VectorModification(Default::default()), false), + ], + ..Default::default() + }, + persistent_node_metadata: DocumentNodePersistentMetadata { + input_metadata: vec![("Vector Data", "TODO").into(), ("Modification", "TODO").into()], + output_names: vec!["Vector Data".to_string()], + network_metadata: Some(NodeNetworkMetadata { + persistent_metadata: NodeNetworkPersistentMetadata { + node_metadata: [ + DocumentNodeMetadata { + persistent_metadata: DocumentNodePersistentMetadata { + display_name: "Monitor".to_string(), + node_type_metadata: NodeTypePersistentMetadata::node(IVec2::new(0, 0)), + ..Default::default() + }, + ..Default::default() + }, + DocumentNodeMetadata { + persistent_metadata: DocumentNodePersistentMetadata { + display_name: "Path Modify".to_string(), + node_type_metadata: NodeTypePersistentMetadata::node(IVec2::new(7, 0)), + ..Default::default() + }, + ..Default::default() + }, + ] + .into_iter() + .enumerate() + .map(|(id, node)| (NodeId(id as u64), node)) + .collect(), + ..Default::default() + }, + ..Default::default() + }), + ..Default::default() + }, + }, + description: Cow::Borrowed("TODO"), + properties: None, + }, + DocumentNodeDefinition { + identifier: "Text", + category: "Text", + node_template: NodeTemplate { + document_node: DocumentNode { + implementation: DocumentNodeImplementation::proto("graphene_std::text::TextNode"), + manual_composition: Some(concrete!(Context)), + inputs: vec![ + NodeInput::scope("editor-api"), + NodeInput::value(TaggedValue::String("Lorem ipsum".to_string()), false), + NodeInput::value( + TaggedValue::Font(Font::new(graphene_std::consts::DEFAULT_FONT_FAMILY.into(), graphene_std::consts::DEFAULT_FONT_STYLE.into())), + false, + ), + NodeInput::value(TaggedValue::F64(TypesettingConfig::default().font_size), false), + NodeInput::value(TaggedValue::F64(TypesettingConfig::default().line_height_ratio), false), + NodeInput::value(TaggedValue::F64(TypesettingConfig::default().character_spacing), false), + NodeInput::value(TaggedValue::OptionalF64(TypesettingConfig::default().max_width), false), + NodeInput::value(TaggedValue::OptionalF64(TypesettingConfig::default().max_height), false), + NodeInput::value(TaggedValue::F64(TypesettingConfig::default().tilt), false), + ], + ..Default::default() + }, + persistent_node_metadata: DocumentNodePersistentMetadata { + input_metadata: vec![ + ("Editor API", "TODO").into(), + InputMetadata::with_name_description_override("Text", "TODO", WidgetOverride::Custom("text_area".to_string())), + InputMetadata::with_name_description_override("Font", "TODO", WidgetOverride::Custom("text_font".to_string())), + InputMetadata::with_name_description_override( + "Size", + "TODO", + WidgetOverride::Number(NumberInputSettings { + unit: Some(" px".to_string()), + min: Some(1.), + ..Default::default() + }), + ), + InputMetadata::with_name_description_override( + "Line Height", + "TODO", + WidgetOverride::Number(NumberInputSettings { + unit: Some("x".to_string()), + min: Some(0.), + step: Some(0.1), + ..Default::default() + }), + ), + InputMetadata::with_name_description_override( + "Character Spacing", + "TODO", + WidgetOverride::Number(NumberInputSettings { + unit: Some(" px".to_string()), + min: Some(0.), + step: Some(0.1), + ..Default::default() + }), + ), + InputMetadata::with_name_description_override( + "Max Width", + "TODO", + WidgetOverride::Number(NumberInputSettings { + unit: Some(" px".to_string()), + min: Some(1.), + blank_assist: false, + ..Default::default() + }), + ), + InputMetadata::with_name_description_override( + "Max Height", + "TODO", + WidgetOverride::Number(NumberInputSettings { + unit: Some(" px".to_string()), + min: Some(1.), + blank_assist: false, + ..Default::default() + }), + ), + InputMetadata::with_name_description_override( + "Tilt", + "Faux italic", + WidgetOverride::Number(NumberInputSettings { + min: Some(-85.), + max: Some(85.), + unit: Some("°".to_string()), + ..Default::default() + }), + ), + ], + output_names: vec!["Vector".to_string()], + ..Default::default() + }, + }, + description: Cow::Borrowed("TODO"), + properties: None, + }, + DocumentNodeDefinition { + identifier: "Transform", + category: "General", + node_template: NodeTemplate { + document_node: DocumentNode { + inputs: vec![ + NodeInput::value(TaggedValue::VectorData(VectorDataTable::default()), true), + NodeInput::value(TaggedValue::DVec2(DVec2::ZERO), false), + NodeInput::value(TaggedValue::F64(0.), false), + NodeInput::value(TaggedValue::DVec2(DVec2::ONE), false), + NodeInput::value(TaggedValue::DVec2(DVec2::ZERO), false), + NodeInput::value(TaggedValue::DVec2(DVec2::splat(0.5)), false), + ], + implementation: DocumentNodeImplementation::Network(NodeNetwork { + exports: vec![NodeInput::node(NodeId(1), 0)], + nodes: [ + DocumentNode { + inputs: vec![NodeInput::network(concrete!(VectorDataTable), 0)], + implementation: DocumentNodeImplementation::proto("graphene_core::memo::MonitorNode"), + manual_composition: Some(generic!(T)), + skip_deduplication: true, + ..Default::default() + }, + DocumentNode { + inputs: vec![ + NodeInput::node(NodeId(0), 0), + NodeInput::network(concrete!(DVec2), 1), + NodeInput::network(concrete!(f64), 2), + NodeInput::network(concrete!(DVec2), 3), + NodeInput::network(concrete!(DVec2), 4), + NodeInput::network(concrete!(DVec2), 5), + ], + manual_composition: Some(concrete!(Context)), + implementation: DocumentNodeImplementation::ProtoNode(ProtoNodeIdentifier::new("graphene_core::transform_nodes::TransformNode")), + ..Default::default() + }, + ] + .into_iter() + .enumerate() + .map(|(id, node)| (NodeId(id as u64), node)) + .collect(), + ..Default::default() + }), + ..Default::default() + }, + persistent_node_metadata: DocumentNodePersistentMetadata { + network_metadata: Some(NodeNetworkMetadata { + persistent_metadata: NodeNetworkPersistentMetadata { + node_metadata: [ + DocumentNodeMetadata { + persistent_metadata: DocumentNodePersistentMetadata { + display_name: "Monitor".to_string(), + node_type_metadata: NodeTypePersistentMetadata::node(IVec2::new(0, 0)), + ..Default::default() + }, + ..Default::default() + }, + DocumentNodeMetadata { + persistent_metadata: DocumentNodePersistentMetadata { + display_name: "Transform".to_string(), + node_type_metadata: NodeTypePersistentMetadata::node(IVec2::new(7, 0)), + ..Default::default() + }, + ..Default::default() + }, + ] + .into_iter() + .enumerate() + .map(|(id, node)| (NodeId(id as u64), node)) + .collect(), + ..Default::default() + }, + ..Default::default() + }), + input_metadata: vec![ + ("Vector Data", "TODO").into(), + InputMetadata::with_name_description_override( + "Translation", + "TODO", + WidgetOverride::Vec2(Vec2InputSettings { + x: "X".to_string(), + y: "Y".to_string(), + unit: " px".to_string(), + ..Default::default() + }), + ), + InputMetadata::with_name_description_override("Rotation", "TODO", WidgetOverride::Custom("transform_rotation".to_string())), + InputMetadata::with_name_description_override( + "Scale", + "TODO", + WidgetOverride::Vec2(Vec2InputSettings { + x: "W".to_string(), + y: "H".to_string(), + unit: "x".to_string(), + ..Default::default() + }), + ), + InputMetadata::with_name_description_override("Skew", "TODO", WidgetOverride::Custom("transform_skew".to_string())), + InputMetadata::with_name_description_override("Pivot", "TODO", WidgetOverride::Hidden), + ], + output_names: vec!["Data".to_string()], + ..Default::default() + }, + }, + description: Cow::Borrowed("TODO"), + properties: None, + }, + DocumentNodeDefinition { + identifier: "Boolean Operation", + category: "Vector", + node_template: NodeTemplate { + document_node: DocumentNode { + implementation: DocumentNodeImplementation::Network(NodeNetwork { + exports: vec![NodeInput::node(NodeId(3), 0)], + nodes: vec![ + DocumentNode { + inputs: vec![NodeInput::network(concrete!(VectorDataTable), 0), NodeInput::network(concrete!(vector::style::Fill), 1)], + implementation: DocumentNodeImplementation::ProtoNode(ProtoNodeIdentifier::new("graphene_path_bool::BooleanOperationNode")), + manual_composition: Some(generic!(T)), + ..Default::default() + }, + DocumentNode { + inputs: vec![NodeInput::node(NodeId(0), 0)], + implementation: DocumentNodeImplementation::ProtoNode(ProtoNodeIdentifier::new("graphene_core::memo::MemoNode")), + manual_composition: Some(generic!(T)), + ..Default::default() + }, + DocumentNode { + inputs: vec![NodeInput::node(NodeId(1), 0)], + implementation: DocumentNodeImplementation::ProtoNode(ProtoNodeIdentifier::new("graphene_core::transform_nodes::FreezeRealTimeNode")), + manual_composition: Some(generic!(T)), + ..Default::default() + }, + DocumentNode { + inputs: vec![NodeInput::node(NodeId(2), 0)], + implementation: DocumentNodeImplementation::ProtoNode(ProtoNodeIdentifier::new("graphene_core::transform_nodes::BoundlessFootprintNode")), + manual_composition: Some(generic!(T)), + ..Default::default() + }, + ] + .into_iter() + .enumerate() + .map(|(id, node)| (NodeId(id as u64), node)) + .collect(), + ..Default::default() + }), + inputs: vec![ + NodeInput::value(TaggedValue::GraphicGroup(GraphicGroupTable::default()), true), + NodeInput::value(TaggedValue::BooleanOperation(path_bool::BooleanOperation::Union), false), + ], + ..Default::default() + }, + persistent_node_metadata: DocumentNodePersistentMetadata { + network_metadata: Some(NodeNetworkMetadata { + persistent_metadata: NodeNetworkPersistentMetadata { + node_metadata: [ + DocumentNodeMetadata { + persistent_metadata: DocumentNodePersistentMetadata { + display_name: "Boolean Operation".to_string(), + node_type_metadata: NodeTypePersistentMetadata::node(IVec2::new(0, 0)), + ..Default::default() + }, + ..Default::default() + }, + DocumentNodeMetadata { + persistent_metadata: DocumentNodePersistentMetadata { + display_name: "Memoize".to_string(), + node_type_metadata: NodeTypePersistentMetadata::node(IVec2::new(7, 0)), + ..Default::default() + }, + ..Default::default() + }, + DocumentNodeMetadata { + persistent_metadata: DocumentNodePersistentMetadata { + display_name: "Freeze Real Time".to_string(), + node_type_metadata: NodeTypePersistentMetadata::node(IVec2::new(14, 0)), + ..Default::default() + }, + ..Default::default() + }, + DocumentNodeMetadata { + persistent_metadata: DocumentNodePersistentMetadata { + display_name: "Boundless Footprint".to_string(), + node_type_metadata: NodeTypePersistentMetadata::node(IVec2::new(21, 0)), + ..Default::default() + }, + ..Default::default() + }, + ] + .into_iter() + .enumerate() + .map(|(id, node)| (NodeId(id as u64), node)) + .collect(), + ..Default::default() + }, + ..Default::default() + }), + input_metadata: vec![("Group of Paths", "TODO").into(), ("Operation", "TODO").into()], + output_names: vec!["Vector".to_string()], + ..Default::default() + }, + }, + description: Cow::Borrowed("TODO"), + properties: None, + }, + DocumentNodeDefinition { + identifier: "Sample Polyline", + category: "Vector: Modifier", + node_template: NodeTemplate { + document_node: DocumentNode { + implementation: DocumentNodeImplementation::Network(NodeNetwork { + exports: vec![NodeInput::node(NodeId(4), 0)], + nodes: [ + DocumentNode { + inputs: vec![NodeInput::network(concrete!(graphene_std::vector::VectorDataTable), 0)], + implementation: DocumentNodeImplementation::ProtoNode(ProtoNodeIdentifier::new("graphene_core::vector::SubpathSegmentLengthsNode")), + manual_composition: Some(generic!(T)), + ..Default::default() + }, + DocumentNode { + inputs: vec![ + NodeInput::network(concrete!(graphene_std::vector::VectorDataTable), 0), + NodeInput::network(concrete!(vector::misc::PointSpacingType), 1), + NodeInput::network(concrete!(f64), 2), + NodeInput::network(concrete!(u32), 3), + NodeInput::network(concrete!(f64), 4), + NodeInput::network(concrete!(f64), 5), + NodeInput::network(concrete!(bool), 6), + NodeInput::node(NodeId(0), 0), + ], + implementation: DocumentNodeImplementation::ProtoNode(ProtoNodeIdentifier::new("graphene_core::vector::SamplePolylineNode")), + manual_composition: Some(generic!(T)), + ..Default::default() + }, + DocumentNode { + inputs: vec![NodeInput::node(NodeId(1), 0)], + implementation: DocumentNodeImplementation::ProtoNode(ProtoNodeIdentifier::new("graphene_core::memo::MemoNode")), + manual_composition: Some(generic!(T)), + ..Default::default() + }, + DocumentNode { + inputs: vec![NodeInput::node(NodeId(2), 0)], + implementation: DocumentNodeImplementation::ProtoNode(ProtoNodeIdentifier::new("graphene_core::transform_nodes::FreezeRealTimeNode")), + manual_composition: Some(generic!(T)), + ..Default::default() + }, + DocumentNode { + inputs: vec![NodeInput::node(NodeId(3), 0)], + implementation: DocumentNodeImplementation::ProtoNode(ProtoNodeIdentifier::new("graphene_core::transform_nodes::BoundlessFootprintNode")), + manual_composition: Some(generic!(T)), + ..Default::default() + }, + ] + .into_iter() + .enumerate() + .map(|(id, node)| (NodeId(id as u64), node)) + .collect(), + ..Default::default() + }), + inputs: vec![ + NodeInput::value(TaggedValue::VectorData(graphene_std::vector::VectorDataTable::default()), true), + NodeInput::value(TaggedValue::PointSpacingType(Default::default()), false), + NodeInput::value(TaggedValue::F64(100.), false), + NodeInput::value(TaggedValue::U32(100), false), + NodeInput::value(TaggedValue::F64(0.), false), + NodeInput::value(TaggedValue::F64(0.), false), + NodeInput::value(TaggedValue::Bool(false), false), + ], + ..Default::default() + }, + persistent_node_metadata: DocumentNodePersistentMetadata { + network_metadata: Some(NodeNetworkMetadata { + persistent_metadata: NodeNetworkPersistentMetadata { + node_metadata: [ + DocumentNodeMetadata { + persistent_metadata: DocumentNodePersistentMetadata { + display_name: "Subpath Segment Lengths".to_string(), + node_type_metadata: NodeTypePersistentMetadata::node(IVec2::new(0, 7)), + ..Default::default() + }, + ..Default::default() + }, + DocumentNodeMetadata { + persistent_metadata: DocumentNodePersistentMetadata { + display_name: "Sample Polyline".to_string(), + node_type_metadata: NodeTypePersistentMetadata::node(IVec2::new(7, 0)), + ..Default::default() + }, + ..Default::default() + }, + DocumentNodeMetadata { + persistent_metadata: DocumentNodePersistentMetadata { + display_name: "Memoize".to_string(), + node_type_metadata: NodeTypePersistentMetadata::node(IVec2::new(14, 0)), + ..Default::default() + }, + ..Default::default() + }, + DocumentNodeMetadata { + persistent_metadata: DocumentNodePersistentMetadata { + display_name: "Freeze Real Time".to_string(), + node_type_metadata: NodeTypePersistentMetadata::node(IVec2::new(21, 0)), + ..Default::default() + }, + ..Default::default() + }, + DocumentNodeMetadata { + persistent_metadata: DocumentNodePersistentMetadata { + display_name: "Boundless Footprint".to_string(), + node_type_metadata: NodeTypePersistentMetadata::node(IVec2::new(28, 0)), + ..Default::default() + }, + ..Default::default() + }, + ] + .into_iter() + .enumerate() + .map(|(id, node)| (NodeId(id as u64), node)) + .collect(), + ..Default::default() + }, + ..Default::default() + }), + input_metadata: vec![ + ("Vector Data", "The shape to be resampled and converted into a polyline.").into(), + ("Spacing", node_properties::SAMPLE_POLYLINE_TOOLTIP_SPACING).into(), + InputMetadata::with_name_description_override( + "Separation", + node_properties::SAMPLE_POLYLINE_TOOLTIP_SEPARATION, + WidgetOverride::Number(NumberInputSettings { + min: Some(0.), + unit: Some(" px".to_string()), + ..Default::default() + }), + ), + InputMetadata::with_name_description_override( + "Quantity", + node_properties::SAMPLE_POLYLINE_TOOLTIP_QUANTITY, + WidgetOverride::Number(NumberInputSettings { + min: Some(2.), + is_integer: true, + ..Default::default() + }), + ), + InputMetadata::with_name_description_override( + "Start Offset", + node_properties::SAMPLE_POLYLINE_TOOLTIP_START_OFFSET, + WidgetOverride::Number(NumberInputSettings { + min: Some(0.), + unit: Some(" px".to_string()), + ..Default::default() + }), + ), + InputMetadata::with_name_description_override( + "Stop Offset", + node_properties::SAMPLE_POLYLINE_TOOLTIP_STOP_OFFSET, + WidgetOverride::Number(NumberInputSettings { + min: Some(0.), + unit: Some(" px".to_string()), + ..Default::default() + }), + ), + ("Adaptive Spacing", node_properties::SAMPLE_POLYLINE_TOOLTIP_ADAPTIVE_SPACING).into(), + ], + output_names: vec!["Vector".to_string()], + ..Default::default() + }, + }, + description: Cow::Borrowed("Convert vector geometry into a polyline composed of evenly spaced points."), + properties: Some("sample_polyline_properties"), + }, + DocumentNodeDefinition { + identifier: "Scatter Points", + category: "Vector: Modifier", + node_template: NodeTemplate { + document_node: DocumentNode { + implementation: DocumentNodeImplementation::Network(NodeNetwork { + exports: vec![NodeInput::node(NodeId(3), 0)], + nodes: [ + DocumentNode { + inputs: vec![ + NodeInput::network(concrete!(graphene_std::vector::VectorDataTable), 0), + NodeInput::network(concrete!(f64), 1), + NodeInput::network(concrete!(u32), 2), + ], + manual_composition: Some(generic!(T)), + implementation: DocumentNodeImplementation::proto("graphene_core::vector::PoissonDiskPointsNode"), + ..Default::default() + }, + DocumentNode { + inputs: vec![NodeInput::node(NodeId(0), 0)], + implementation: DocumentNodeImplementation::ProtoNode(ProtoNodeIdentifier::new("graphene_core::memo::MemoNode")), + manual_composition: Some(generic!(T)), + ..Default::default() + }, + DocumentNode { + inputs: vec![NodeInput::node(NodeId(1), 0)], + implementation: DocumentNodeImplementation::ProtoNode(ProtoNodeIdentifier::new("graphene_core::transform_nodes::FreezeRealTimeNode")), + manual_composition: Some(generic!(T)), + ..Default::default() + }, + DocumentNode { + inputs: vec![NodeInput::node(NodeId(2), 0)], + implementation: DocumentNodeImplementation::ProtoNode(ProtoNodeIdentifier::new("graphene_core::transform_nodes::BoundlessFootprintNode")), + manual_composition: Some(generic!(T)), + ..Default::default() + }, + ] + .into_iter() + .enumerate() + .map(|(id, node)| (NodeId(id as u64), node)) + .collect(), + ..Default::default() + }), + inputs: vec![ + NodeInput::value(TaggedValue::VectorData(graphene_std::vector::VectorDataTable::default()), true), + NodeInput::value(TaggedValue::F64(10.), false), + NodeInput::value(TaggedValue::U32(0), false), + ], + ..Default::default() + }, + persistent_node_metadata: DocumentNodePersistentMetadata { + network_metadata: Some(NodeNetworkMetadata { + persistent_metadata: NodeNetworkPersistentMetadata { + node_metadata: [ + DocumentNodeMetadata { + persistent_metadata: DocumentNodePersistentMetadata { + display_name: "Poisson-Disk Points".to_string(), + node_type_metadata: NodeTypePersistentMetadata::node(IVec2::new(0, 0)), + ..Default::default() + }, + ..Default::default() + }, + DocumentNodeMetadata { + persistent_metadata: DocumentNodePersistentMetadata { + display_name: "Memoize".to_string(), + node_type_metadata: NodeTypePersistentMetadata::node(IVec2::new(7, 0)), + ..Default::default() + }, + ..Default::default() + }, + DocumentNodeMetadata { + persistent_metadata: DocumentNodePersistentMetadata { + display_name: "Freeze Real Time".to_string(), + node_type_metadata: NodeTypePersistentMetadata::node(IVec2::new(14, 0)), + ..Default::default() + }, + ..Default::default() + }, + DocumentNodeMetadata { + persistent_metadata: DocumentNodePersistentMetadata { + display_name: "Boundless Footprint".to_string(), + node_type_metadata: NodeTypePersistentMetadata::node(IVec2::new(21, 0)), + ..Default::default() + }, + ..Default::default() + }, + ] + .into_iter() + .enumerate() + .map(|(id, node)| (NodeId(id as u64), node)) + .collect(), + ..Default::default() + }, + ..Default::default() + }), + input_metadata: vec![ + ("Vector Data", "TODO").into(), + InputMetadata::with_name_description_override( + "Separation Disk Diameter", + "TODO", + WidgetOverride::Number(NumberInputSettings { + min: Some(0.01), + mode: NumberInputMode::Range, + range_min: Some(1.), + range_max: Some(100.), + ..Default::default() + }), + ), + InputMetadata::with_name_description_override( + "Seed", + "TODO", + WidgetOverride::Number(NumberInputSettings { + min: Some(0.), + is_integer: true, + ..Default::default() + }), + ), + ], + output_names: vec!["Vector".to_string()], + ..Default::default() + }, + }, + description: Cow::Borrowed("TODO"), + properties: None, + }, + ]; + + document_node_derive::post_process_nodes(custom) +} + +type NodeProperties = HashMap Vec + Send + Sync>>; + +pub static NODE_OVERRIDES: once_cell::sync::Lazy = once_cell::sync::Lazy::new(static_node_properties); + +/// Defines the logic for inputs to display a custom properties panel widget. +fn static_node_properties() -> NodeProperties { + let mut map: NodeProperties = HashMap::new(); + map.insert("brightness_contrast_properties".to_string(), Box::new(node_properties::brightness_contrast_properties)); + map.insert("channel_mixer_properties".to_string(), Box::new(node_properties::channel_mixer_properties)); + map.insert("fill_properties".to_string(), Box::new(node_properties::fill_properties)); + map.insert("stroke_properties".to_string(), Box::new(node_properties::stroke_properties)); + map.insert("offset_path_properties".to_string(), Box::new(node_properties::offset_path_properties)); + map.insert("selective_color_properties".to_string(), Box::new(node_properties::selective_color_properties)); + map.insert("exposure_properties".to_string(), Box::new(node_properties::exposure_properties)); + map.insert("math_properties".to_string(), Box::new(node_properties::math_properties)); + map.insert("rectangle_properties".to_string(), Box::new(node_properties::rectangle_properties)); + map.insert("grid_properties".to_string(), Box::new(node_properties::grid_properties)); + map.insert("sample_polyline_properties".to_string(), Box::new(node_properties::sample_polyline_properties)); + map.insert( + "identity_properties".to_string(), + Box::new(|_node_id, _context| node_properties::string_properties("The identity node passes its data through.")), + ); + map.insert( + "monitor_properties".to_string(), + Box::new(|_node_id, _context| node_properties::string_properties("The Monitor node is used by the editor to access the data flowing through it.")), + ); + map +} + +type InputProperties = HashMap Result, String> + Send + Sync>>; + +static INPUT_OVERRIDES: once_cell::sync::Lazy = once_cell::sync::Lazy::new(static_input_properties); + +/// Defines the logic for inputs to display a custom properties panel widget. +fn static_input_properties() -> InputProperties { + let mut map: InputProperties = HashMap::new(); + map.insert("hidden".to_string(), Box::new(|_node_id, _index, _context| Ok(Vec::new()))); + map.insert( + "string".to_string(), + Box::new(|node_id, index, context| { + let Some(value) = context.network_interface.input_data(&node_id, index, "string_properties", context.selection_network_path) else { + return Err(format!("Could not get string properties for node {}", node_id)); + }; + let Some(string) = value.as_str() else { + return Err(format!("Could not downcast string properties for node {}", node_id)); + }; + Ok(node_properties::string_properties(string)) + }), + ); + map.insert( + "number".to_string(), + Box::new(|node_id, index, context| { + let mut number_input = NumberInput::default(); + if let Some(unit) = context + .network_interface + .input_data(&node_id, index, "unit", context.selection_network_path) + .and_then(|value| value.as_str()) + { + number_input = number_input.unit(unit); + } + if let Some(min) = context + .network_interface + .input_data(&node_id, index, "min", context.selection_network_path) + .and_then(|value| value.as_f64()) + { + number_input = number_input.min(min); + } + if let Some(max) = context + .network_interface + .input_data(&node_id, index, "max", context.selection_network_path) + .and_then(|value| value.as_f64()) + { + number_input = number_input.max(max); + } + if let Some(step) = context + .network_interface + .input_data(&node_id, index, "step", context.selection_network_path) + .and_then(|value| value.as_f64()) + { + number_input = number_input.step(step); + } + if let Some(mode) = context.network_interface.input_data(&node_id, index, "mode", context.selection_network_path).map(|value| { + let mode: NumberInputMode = serde_json::from_value(value.clone()).unwrap(); + mode + }) { + number_input = number_input.mode(mode); + } + if let Some(range_min) = context + .network_interface + .input_data(&node_id, index, "range_min", context.selection_network_path) + .and_then(|value| value.as_f64()) + { + number_input = number_input.range_min(Some(range_min)); + } + if let Some(range_max) = context + .network_interface + .input_data(&node_id, index, "range_max", context.selection_network_path) + .and_then(|value| value.as_f64()) + { + number_input = number_input.range_max(Some(range_max)); + } + if let Some(is_integer) = context + .network_interface + .input_data(&node_id, index, "is_integer", context.selection_network_path) + .and_then(|value| value.as_bool()) + { + number_input = number_input.is_integer(is_integer); + } + let blank_assist = context + .network_interface + .input_data(&node_id, index, "blank_assist", context.selection_network_path) + .and_then(|value| value.as_bool()) + .unwrap_or_else(|| { + log::error!("Could not get blank assist when displaying number input for node {node_id}, index {index}"); + true + }); + + Ok(vec![LayoutGroup::Row { + widgets: node_properties::number_widget(ParameterWidgetsInfo::new(node_id, index, blank_assist, context), number_input), + }]) + }), + ); + map.insert( + "vec2".to_string(), + Box::new(|node_id, index, context| { + let x = context + .network_interface + .input_data(&node_id, index, "x", context.selection_network_path) + .and_then(|value| value.as_str()) + .unwrap_or_else(|| { + log::error!("Could not get x for vec2 input"); + "" + }) + .to_string(); + let y = context + .network_interface + .input_data(&node_id, index, "y", context.selection_network_path) + .and_then(|value| value.as_str()) + .unwrap_or_else(|| { + log::error!("Could not get y for vec2 input"); + "" + }) + .to_string(); + let unit = context + .network_interface + .input_data(&node_id, index, "unit", context.selection_network_path) + .and_then(|value| value.as_str()) + .unwrap_or_else(|| { + log::error!("Could not get unit for vec2 input"); + "" + }) + .to_string(); + let min = context + .network_interface + .input_data(&node_id, index, "min", context.selection_network_path) + .and_then(|value| value.as_f64()); + + Ok(vec![node_properties::coordinate_widget(ParameterWidgetsInfo::new(node_id, index, true, context), &x, &y, &unit, min)]) + }), + ); + map.insert( + "noise_properties_scale".to_string(), + Box::new(|node_id, index, context| { + let (_, coherent_noise_active, _, _, _, _) = node_properties::query_noise_pattern_state(node_id, context)?; + let scale = node_properties::number_widget( + ParameterWidgetsInfo::new(node_id, index, true, context), + NumberInput::default().min(0.).disabled(!coherent_noise_active), + ); + Ok(vec![scale.into()]) + }), + ); + map.insert( + "noise_properties_noise_type".to_string(), + Box::new(|node_id, index, context| { + let noise_type_row = enum_choice::().for_socket(ParameterWidgetsInfo::new(node_id, index, true, context)).property_row(); + Ok(vec![noise_type_row, LayoutGroup::Row { widgets: Vec::new() }]) + }), + ); + map.insert( + "noise_properties_domain_warp_type".to_string(), + Box::new(|node_id, index, context| { + let (_, coherent_noise_active, _, _, _, _) = node_properties::query_noise_pattern_state(node_id, context)?; + let domain_warp_type = enum_choice::() + .for_socket(ParameterWidgetsInfo::new(node_id, index, true, context)) + .disabled(!coherent_noise_active) + .property_row(); + Ok(vec![domain_warp_type]) + }), + ); + map.insert( + "noise_properties_domain_warp_amplitude".to_string(), + Box::new(|node_id, index, context| { + let (_, coherent_noise_active, _, _, domain_warp_active, _) = node_properties::query_noise_pattern_state(node_id, context)?; + let domain_warp_amplitude = node_properties::number_widget( + ParameterWidgetsInfo::new(node_id, index, true, context), + NumberInput::default().min(0.).disabled(!coherent_noise_active || !domain_warp_active), + ); + Ok(vec![domain_warp_amplitude.into(), LayoutGroup::Row { widgets: Vec::new() }]) + }), + ); + map.insert( + "noise_properties_fractal_type".to_string(), + Box::new(|node_id, index, context| { + let (_, coherent_noise_active, _, _, _, _) = node_properties::query_noise_pattern_state(node_id, context)?; + let fractal_type_row = enum_choice::() + .for_socket(ParameterWidgetsInfo::new(node_id, index, true, context)) + .disabled(!coherent_noise_active) + .property_row(); + Ok(vec![fractal_type_row]) + }), + ); + map.insert( + "noise_properties_fractal_octaves".to_string(), + Box::new(|node_id, index, context| { + let (fractal_active, coherent_noise_active, _, _, _, domain_warp_only_fractal_type_wrongly_active) = node_properties::query_noise_pattern_state(node_id, context)?; + let fractal_octaves = node_properties::number_widget( + ParameterWidgetsInfo::new(node_id, index, true, context), + NumberInput::default() + .mode_range() + .min(1.) + .max(10.) + .range_max(Some(4.)) + .is_integer(true) + .disabled(!coherent_noise_active || !fractal_active || domain_warp_only_fractal_type_wrongly_active), + ); + Ok(vec![fractal_octaves.into()]) + }), + ); + map.insert( + "noise_properties_fractal_lacunarity".to_string(), + Box::new(|node_id, index, context| { + let (fractal_active, coherent_noise_active, _, _, _, domain_warp_only_fractal_type_wrongly_active) = node_properties::query_noise_pattern_state(node_id, context)?; + let fractal_lacunarity = node_properties::number_widget( + ParameterWidgetsInfo::new(node_id, index, true, context), + NumberInput::default() + .mode_range() + .min(0.) + .range_max(Some(10.)) + .disabled(!coherent_noise_active || !fractal_active || domain_warp_only_fractal_type_wrongly_active), + ); + Ok(vec![fractal_lacunarity.into()]) + }), + ); + map.insert( + "noise_properties_fractal_gain".to_string(), + Box::new(|node_id, index, context| { + let (fractal_active, coherent_noise_active, _, _, _, domain_warp_only_fractal_type_wrongly_active) = node_properties::query_noise_pattern_state(node_id, context)?; + let fractal_gain = node_properties::number_widget( + ParameterWidgetsInfo::new(node_id, index, true, context), + NumberInput::default() + .mode_range() + .min(0.) + .range_max(Some(10.)) + .disabled(!coherent_noise_active || !fractal_active || domain_warp_only_fractal_type_wrongly_active), + ); + Ok(vec![fractal_gain.into()]) + }), + ); + map.insert( + "noise_properties_fractal_weighted_strength".to_string(), + Box::new(|node_id, index, context| { + let (fractal_active, coherent_noise_active, _, _, _, domain_warp_only_fractal_type_wrongly_active) = node_properties::query_noise_pattern_state(node_id, context)?; + let fractal_weighted_strength = node_properties::number_widget( + ParameterWidgetsInfo::new(node_id, index, true, context), + NumberInput::default() + .mode_range() + .min(0.) + .max(1.) // Defined for the 0-1 range + .disabled(!coherent_noise_active || !fractal_active || domain_warp_only_fractal_type_wrongly_active), + ); + Ok(vec![fractal_weighted_strength.into()]) + }), + ); + map.insert( + "noise_properties_ping_pong_strength".to_string(), + Box::new(|node_id, index, context| { + let (fractal_active, coherent_noise_active, _, ping_pong_active, _, domain_warp_only_fractal_type_wrongly_active) = node_properties::query_noise_pattern_state(node_id, context)?; + let fractal_ping_pong_strength = node_properties::number_widget( + ParameterWidgetsInfo::new(node_id, index, true, context), + NumberInput::default() + .mode_range() + .min(0.) + .range_max(Some(10.)) + .disabled(!ping_pong_active || !coherent_noise_active || !fractal_active || domain_warp_only_fractal_type_wrongly_active), + ); + Ok(vec![fractal_ping_pong_strength.into(), LayoutGroup::Row { widgets: Vec::new() }]) + }), + ); + map.insert( + "noise_properties_cellular_distance_function".to_string(), + Box::new(|node_id, index, context| { + let (_, coherent_noise_active, cellular_noise_active, _, _, _) = node_properties::query_noise_pattern_state(node_id, context)?; + let cellular_distance_function_row = enum_choice::() + .for_socket(ParameterWidgetsInfo::new(node_id, index, true, context)) + .disabled(!coherent_noise_active || !cellular_noise_active) + .property_row(); + Ok(vec![cellular_distance_function_row]) + }), + ); + map.insert( + "noise_properties_cellular_return_type".to_string(), + Box::new(|node_id, index, context| { + let (_, coherent_noise_active, cellular_noise_active, _, _, _) = node_properties::query_noise_pattern_state(node_id, context)?; + let cellular_return_type = enum_choice::() + .for_socket(ParameterWidgetsInfo::new(node_id, index, true, context)) + .disabled(!coherent_noise_active || !cellular_noise_active) + .property_row(); + Ok(vec![cellular_return_type]) + }), + ); + map.insert( + "noise_properties_cellular_jitter".to_string(), + Box::new(|node_id, index, context| { + let (_, coherent_noise_active, cellular_noise_active, _, _, _) = node_properties::query_noise_pattern_state(node_id, context)?; + let cellular_jitter = node_properties::number_widget( + ParameterWidgetsInfo::new(node_id, index, true, context), + NumberInput::default() + .mode_range() + .range_min(Some(0.)) + .range_max(Some(1.)) + .disabled(!coherent_noise_active || !cellular_noise_active), + ); + Ok(vec![cellular_jitter.into()]) + }), + ); + map.insert( + "brightness".to_string(), + Box::new(|node_id, index, context| { + let document_node = node_properties::get_document_node(node_id, context)?; + let is_use_classic = document_node + .inputs + .iter() + .find_map(|input| match input.as_value() { + Some(&TaggedValue::Bool(use_classic)) => Some(use_classic), + _ => None, + }) + .unwrap_or(false); + let (b_min, b_max) = if is_use_classic { (-100., 100.) } else { (-100., 150.) }; + let brightness = node_properties::number_widget( + ParameterWidgetsInfo::new(node_id, index, true, context), + NumberInput::default().mode_range().range_min(Some(b_min)).range_max(Some(b_max)).unit("%").display_decimal_places(2), + ); + Ok(vec![brightness.into()]) + }), + ); + map.insert( + "contrast".to_string(), + Box::new(|node_id, index, context| { + let document_node = node_properties::get_document_node(node_id, context)?; + + let is_use_classic = document_node + .inputs + .iter() + .find_map(|input| match input.as_value() { + Some(&TaggedValue::Bool(use_classic)) => Some(use_classic), + _ => None, + }) + .unwrap_or(false); + let (c_min, c_max) = if is_use_classic { (-100., 100.) } else { (-50., 100.) }; + let contrast = node_properties::number_widget( + ParameterWidgetsInfo::new(node_id, index, true, context), + NumberInput::default().mode_range().range_min(Some(c_min)).range_max(Some(c_max)).unit("%").display_decimal_places(2), + ); + Ok(vec![contrast.into()]) + }), + ); + map.insert( + "assign_colors_gradient".to_string(), + Box::new(|node_id, index, context| { + let gradient_row = node_properties::color_widget(ParameterWidgetsInfo::new(node_id, index, true, context), ColorInput::default().allow_none(false)); + Ok(vec![gradient_row]) + }), + ); + map.insert( + "assign_colors_seed".to_string(), + Box::new(|node_id, index, context| { + let randomize_enabled = node_properties::query_assign_colors_randomize(node_id, context)?; + let seed_row = node_properties::number_widget( + ParameterWidgetsInfo::new(node_id, index, true, context), + NumberInput::default().min(0.).int().disabled(!randomize_enabled), + ); + Ok(vec![seed_row.into()]) + }), + ); + map.insert( + "assign_colors_repeat_every".to_string(), + Box::new(|node_id, index, context| { + let randomize_enabled = node_properties::query_assign_colors_randomize(node_id, context)?; + let repeat_every_row = node_properties::number_widget( + ParameterWidgetsInfo::new(node_id, index, true, context), + NumberInput::default().min(0.).int().disabled(randomize_enabled), + ); + Ok(vec![repeat_every_row.into()]) + }), + ); + map.insert( + "mask_stencil".to_string(), + Box::new(|node_id, index, context| { + let mask = node_properties::color_widget(ParameterWidgetsInfo::new(node_id, index, true, context), ColorInput::default()); + Ok(vec![mask]) + }), + ); + map.insert( + "spline_input".to_string(), + Box::new(|node_id, index, context| { + Ok(vec![LayoutGroup::Row { + widgets: node_properties::array_of_coordinates_widget(ParameterWidgetsInfo::new(node_id, index, true, context), TextInput::default().centered(true)), + }]) + }), + ); + map.insert( + "transform_rotation".to_string(), + Box::new(|node_id, index, context| { + let mut widgets = node_properties::start_widgets(ParameterWidgetsInfo::new(node_id, index, true, context)); + + let document_node = node_properties::get_document_node(node_id, context)?; + let Some(input) = document_node.inputs.get(index) else { + return Err("Input not found in transform rotation input override".to_string()); + }; + if let Some(&TaggedValue::F64(val)) = input.as_non_exposed_value() { + widgets.extend_from_slice(&[ + Separator::new(SeparatorType::Unrelated).widget_holder(), + NumberInput::new(Some(val.to_degrees())) + .unit("°") + .mode(NumberInputMode::Range) + .range_min(Some(-180.)) + .range_max(Some(180.)) + .on_update(node_properties::update_value( + |number_input: &NumberInput| TaggedValue::F64(number_input.value.unwrap().to_radians()), + node_id, + index, + )) + .on_commit(node_properties::commit_value) + .widget_holder(), + ]); + } + + Ok(vec![LayoutGroup::Row { widgets }]) + }), + ); + // Skew has a custom override that maps to degrees + map.insert( + "transform_skew".to_string(), + Box::new(|node_id, index, context| { + let mut widgets = node_properties::start_widgets(ParameterWidgetsInfo::new(node_id, index, true, context)); + + let document_node = node_properties::get_document_node(node_id, context)?; + let Some(input) = document_node.inputs.get(index) else { + return Err("Input not found in transform skew input override".to_string()); + }; + if let Some(&TaggedValue::DVec2(val)) = input.as_non_exposed_value() { + let to_skew = |input: &NumberInput| input.value.unwrap().to_radians().tan(); + widgets.extend_from_slice(&[ + Separator::new(SeparatorType::Unrelated).widget_holder(), + NumberInput::new(Some(val.x.atan().to_degrees())) + .label("X") + .unit("°") + .min(-89.9) + .max(89.9) + .on_update(node_properties::update_value( + move |input: &NumberInput| TaggedValue::DVec2(DVec2::new(to_skew(input), val.y)), + node_id, + index, + )) + .on_commit(node_properties::commit_value) + .widget_holder(), + Separator::new(SeparatorType::Related).widget_holder(), + NumberInput::new(Some(val.y.atan().to_degrees())) + .label("Y") + .unit("°") + .min(-89.9) + .max(89.9) + .on_update(node_properties::update_value( + move |input: &NumberInput| TaggedValue::DVec2(DVec2::new(val.x, to_skew(input))), + node_id, + index, + )) + .on_commit(node_properties::commit_value) + .widget_holder(), + ]); + } + + Ok(vec![LayoutGroup::Row { widgets }]) + }), + ); + map.insert( + "text_area".to_string(), + Box::new(|node_id, index, context| { + Ok(vec![LayoutGroup::Row { + widgets: node_properties::text_area_widget(ParameterWidgetsInfo::new(node_id, index, true, context)), + }]) + }), + ); + map.insert( + "text_font".to_string(), + Box::new(|node_id, index, context| { + let (font, style) = node_properties::font_inputs(ParameterWidgetsInfo::new(node_id, index, true, context)); + let mut result = vec![LayoutGroup::Row { widgets: font }]; + if let Some(style) = style { + result.push(LayoutGroup::Row { widgets: style }); + } + Ok(result) + }), + ); + map.insert( + "artboard_background".to_string(), + Box::new(|node_id, index, context| { + Ok(vec![node_properties::color_widget( + ParameterWidgetsInfo::new(node_id, index, true, context), + ColorInput::default().allow_none(false), + )]) + }), + ); + map +} + +pub fn resolve_document_node_type(identifier: &str) -> Option<&DocumentNodeDefinition> { + DOCUMENT_NODE_TYPES.iter().find(|definition| definition.identifier == identifier) +} + +pub fn collect_node_types() -> Vec { + // Create a mapping from registry ID to document node identifier + let id_to_identifier_map: HashMap = DOCUMENT_NODE_TYPES + .iter() + .filter_map(|definition| { + if let DocumentNodeImplementation::ProtoNode(ProtoNodeIdentifier { name }) = &definition.node_template.document_node.implementation { + Some((name.to_string(), definition.identifier)) + } else { + None + } + }) + .collect(); + let mut extracted_node_types = Vec::new(); + + let node_registry = graphene_std::registry::NODE_REGISTRY.lock().unwrap(); + let node_metadata = graphene_std::registry::NODE_METADATA.lock().unwrap(); + for (id, metadata) in node_metadata.iter() { + if let Some(implementations) = node_registry.get(id) { + let identifier = match id_to_identifier_map.get(id) { + Some(&id) => id.to_string(), + None => continue, + }; + + // Extract category from metadata (already creates an owned String) + let category = metadata.category.unwrap_or_default().to_string(); + + // Extract input types (already creates owned Strings) + let input_types = implementations + .iter() + .flat_map(|(_, node_io)| node_io.inputs.iter().map(|ty| ty.nested_type().to_string())) + .collect::>() + .into_iter() + .collect::>(); + + // Create a FrontendNodeType + let node_type = FrontendNodeType::with_owned_strings_and_input_types(identifier, category, input_types); + + // Store the created node_type + extracted_node_types.push(node_type); + } + } + + let node_types: Vec = DOCUMENT_NODE_TYPES + .iter() + .filter(|definition| !definition.category.is_empty()) + .map(|definition| { + let input_types = definition + .node_template + .document_node + .inputs + .iter() + .filter_map(|node_input| node_input.as_value().map(|node_value| node_value.ty().nested_type().to_string())) + .collect::>(); + + FrontendNodeType::with_input_types(definition.identifier, definition.category, input_types) + }) + .collect(); + + // Update categories in extracted_node_types from node_types + for extracted_node in &mut extracted_node_types { + if extracted_node.category.is_empty() { + // Find matching node in node_types and update category if found + if let Some(matching_node) = node_types.iter().find(|node_type| node_type.name == extracted_node.name) { + extracted_node.category = matching_node.category.clone(); + } + } + } + let missing_nodes: Vec = node_types + .iter() + .filter(|node| !extracted_node_types.iter().any(|extracted| extracted.name == node.name)) + .cloned() + .collect(); + + // Add the missing nodes to extracted_node_types + for node in missing_nodes { + extracted_node_types.push(node); + } + // Remove entries with empty categories + extracted_node_types.retain(|node| !node.category.is_empty()); + + extracted_node_types +} + +pub fn collect_node_descriptions() -> Vec<(String, String)> { + DOCUMENT_NODE_TYPES + .iter() + .map(|definition| { + ( + definition.identifier.to_string(), + if definition.description != "TODO" { definition.description.to_string() } else { String::new() }, + ) + }) + .collect() +} + +impl DocumentNodeDefinition { + /// Converts the [DocumentNodeDefinition] type to a [NodeTemplate], using the provided `input_override` and falling back to the default inputs. + /// `input_override` does not have to be the correct length. + pub fn node_template_input_override(&self, input_override: impl IntoIterator>) -> NodeTemplate { + let mut template = self.node_template.clone(); + input_override.into_iter().enumerate().for_each(|(index, input_override)| { + if let Some(input_override) = input_override { + // Only value inputs can be overridden, since node inputs change graph structure and must be handled by the network interface + // assert!(matches!(input_override, NodeInput::Value { .. }), "Only value inputs are supported for input overrides"); + template.document_node.inputs[index] = input_override; + } + }); + + // Ensure that the input properties are initialized for every Document Node input for every node + fn populate_input_properties(node_template: &mut NodeTemplate, mut path: Vec) { + if let Some(current_node) = path.pop() { + let DocumentNodeImplementation::Network(template_network) = &node_template.document_node.implementation else { + log::error!("Template network should always exist"); + return; + }; + let Some(nested_network) = template_network.nested_network(&path) else { + log::error!("Nested network should exist for path"); + return; + }; + let Some(input_length) = nested_network.nodes.get(¤t_node).map(|node| node.inputs.len()) else { + log::error!("Could not get current node in nested network"); + return; + }; + let Some(template_network_metadata) = &mut node_template.persistent_node_metadata.network_metadata else { + log::error!("Template should have metadata if it has network implementation"); + return; + }; + let Some(nested_network_metadata) = template_network_metadata.nested_metadata_mut(&path) else { + log::error!("Path is not valid for network"); + return; + }; + let Some(nested_node_metadata) = nested_network_metadata.persistent_metadata.node_metadata.get_mut(¤t_node) else { + log::error!("Path is not valid for network"); + return; + }; + nested_node_metadata.persistent_metadata.input_metadata.resize_with(input_length, InputMetadata::default); + + // Recurse over all sub-nodes if the current node is a network implementation + let mut current_path = path.clone(); + current_path.push(current_node); + let DocumentNodeImplementation::Network(template_network) = &node_template.document_node.implementation else { + log::error!("Template network should always exist"); + return; + }; + if let Some(current_nested_network) = template_network.nested_network(¤t_path) { + for sub_node_id in current_nested_network.nodes.keys().cloned().collect::>() { + let mut sub_path = current_path.clone(); + sub_path.push(sub_node_id); + populate_input_properties(node_template, sub_path); + } + }; + } else { + // Base case + let input_len = node_template.document_node.inputs.len(); + node_template.persistent_node_metadata.input_metadata.resize_with(input_len, InputMetadata::default); + if let DocumentNodeImplementation::Network(node_template_network) = &node_template.document_node.implementation { + for sub_node_id in node_template_network.nodes.keys().cloned().collect::>() { + populate_input_properties(node_template, vec![sub_node_id]); + } + } + } + } + populate_input_properties(&mut template, Vec::new()); + + // Set the reference to the node definition + template.persistent_node_metadata.reference = Some(self.identifier.to_string()); + // If the display name is empty and it is not a merge node, then set it to the reference + if template.persistent_node_metadata.display_name.is_empty() && self.identifier != "Merge" { + template.persistent_node_metadata.display_name = self.identifier.to_string(); + } + template + } + + /// Converts the [DocumentNodeDefinition] type to a [NodeTemplate], completely default. + pub fn default_node_template(&self) -> NodeTemplate { + self.node_template_input_override(self.node_template.document_node.inputs.clone().into_iter().map(Some)) + } +} diff --git a/editor/src/messages/portfolio/document/node_graph/document_node_definitions/document_node_derive.rs b/editor/src/messages/portfolio/document/node_graph/document_node_definitions/document_node_derive.rs new file mode 100644 index 0000000000000000000000000000000000000000..8fcec559a7d73a6ce6c48348aabe968d85c16840 --- /dev/null +++ b/editor/src/messages/portfolio/document/node_graph/document_node_definitions/document_node_derive.rs @@ -0,0 +1,94 @@ +use super::DocumentNodeDefinition; +use crate::messages::portfolio::document::utility_types::network_interface::{DocumentNodePersistentMetadata, InputMetadata, NodeTemplate, WidgetOverride}; +use graph_craft::ProtoNodeIdentifier; +use graph_craft::document::*; +use graphene_std::registry::*; +use graphene_std::*; +use std::collections::HashSet; + +pub(super) fn post_process_nodes(mut custom: Vec) -> Vec { + // Remove struct generics + for DocumentNodeDefinition { node_template, .. } in custom.iter_mut() { + let NodeTemplate { + document_node: DocumentNode { implementation, .. }, + .. + } = node_template; + + if let DocumentNodeImplementation::ProtoNode(ProtoNodeIdentifier { name }) = implementation { + if let Some((new_name, _suffix)) = name.rsplit_once("<") { + *name = Cow::Owned(new_name.to_string()) + } + }; + } + + let node_registry = graphene_core::registry::NODE_REGISTRY.lock().unwrap(); + 'outer: for (id, metadata) in NODE_METADATA.lock().unwrap().iter() { + for node in custom.iter() { + let DocumentNodeDefinition { + node_template: NodeTemplate { + document_node: DocumentNode { implementation, .. }, + .. + }, + .. + } = node; + match implementation { + DocumentNodeImplementation::ProtoNode(ProtoNodeIdentifier { name }) if name == id => continue 'outer, + _ => (), + } + } + + let NodeMetadata { + display_name, + category, + fields, + description, + properties, + } = metadata; + + let Some(implementations) = &node_registry.get(id) else { continue }; + + let valid_inputs: HashSet<_> = implementations.iter().map(|(_, node_io)| node_io.call_argument.clone()).collect(); + let first_node_io = implementations.first().map(|(_, node_io)| node_io).unwrap_or(const { &NodeIOTypes::empty() }); + + let input_type = if valid_inputs.len() > 1 { &const { generic!(D) } } else { &first_node_io.call_argument }; + let output_type = &first_node_io.return_value; + + let inputs = preprocessor::node_inputs(fields, first_node_io); + let node = DocumentNodeDefinition { + identifier: display_name, + node_template: NodeTemplate { + document_node: DocumentNode { + inputs, + manual_composition: Some(input_type.clone()), + implementation: DocumentNodeImplementation::ProtoNode(id.clone().into()), + visible: true, + skip_deduplication: false, + ..Default::default() + }, + persistent_node_metadata: DocumentNodePersistentMetadata { + // TODO: Store information for input overrides in the node macro + input_metadata: fields + .iter() + .map(|f| match f.widget_override { + RegistryWidgetOverride::None => (f.name, f.description).into(), + RegistryWidgetOverride::Hidden => InputMetadata::with_name_description_override(f.name, f.description, WidgetOverride::Hidden), + RegistryWidgetOverride::String(str) => InputMetadata::with_name_description_override(f.name, f.description, WidgetOverride::String(str.to_string())), + RegistryWidgetOverride::Custom(str) => InputMetadata::with_name_description_override(f.name, f.description, WidgetOverride::Custom(str.to_string())), + }) + .collect(), + output_names: vec![output_type.to_string()], + has_primary_output: true, + locked: false, + ..Default::default() + }, + }, + category: category.unwrap_or("UNCATEGORIZED"), + description: Cow::Borrowed(description), + properties: *properties, + }; + + custom.push(node); + } + + custom +} diff --git a/editor/src/messages/portfolio/document/node_graph/mod.rs b/editor/src/messages/portfolio/document/node_graph/mod.rs new file mode 100644 index 0000000000000000000000000000000000000000..bd250164380024a366e5735fc71119511ffab90a --- /dev/null +++ b/editor/src/messages/portfolio/document/node_graph/mod.rs @@ -0,0 +1,10 @@ +pub mod document_node_definitions; +mod node_graph_message; +mod node_graph_message_handler; +pub mod node_properties; +pub mod utility_types; + +#[doc(inline)] +pub use node_graph_message::{NodeGraphMessage, NodeGraphMessageDiscriminant}; +#[doc(inline)] +pub use node_graph_message_handler::*; diff --git a/editor/src/messages/portfolio/document/node_graph/node_graph_message.rs b/editor/src/messages/portfolio/document/node_graph/node_graph_message.rs new file mode 100644 index 0000000000000000000000000000000000000000..a730f47cad49781d523a1eb03e20950e26f9fafd --- /dev/null +++ b/editor/src/messages/portfolio/document/node_graph/node_graph_message.rs @@ -0,0 +1,222 @@ +use super::utility_types::Direction; +use crate::messages::input_mapper::utility_types::input_keyboard::Key; +use crate::messages::portfolio::document::utility_types::document_metadata::LayerNodeIdentifier; +use crate::messages::portfolio::document::utility_types::network_interface::{ImportOrExport, InputConnector, NodeTemplate, OutputConnector}; +use crate::messages::prelude::*; +use glam::IVec2; +use graph_craft::document::value::TaggedValue; +use graph_craft::document::{NodeId, NodeInput}; +use graph_craft::proto::GraphErrors; +use interpreted_executor::dynamic_executor::ResolvedDocumentNodeTypesDelta; + +#[impl_message(Message, DocumentMessage, NodeGraph)] +#[derive(PartialEq, Clone, Debug, serde::Serialize, serde::Deserialize)] +pub enum NodeGraphMessage { + AddNodes { + nodes: Vec<(NodeId, NodeTemplate)>, + new_ids: HashMap, + }, + AddImport, + AddExport, + Init, + SelectedNodesUpdated, + Copy, + CreateNodeInLayerNoTransaction { + node_type: String, + layer: LayerNodeIdentifier, + }, + CreateNodeInLayerWithTransaction { + node_type: String, + layer: LayerNodeIdentifier, + }, + CreateNodeFromContextMenu { + node_id: Option, + node_type: String, + xy: Option<(i32, i32)>, + add_transaction: bool, + }, + CreateWire { + output_connector: OutputConnector, + input_connector: InputConnector, + }, + ConnectUpstreamOutputToInput { + downstream_input: InputConnector, + input_connector: InputConnector, + }, + Cut, + DeleteNodes { + node_ids: Vec, + delete_children: bool, + }, + DeleteSelectedNodes { + delete_children: bool, + }, + DisconnectInput { + input_connector: InputConnector, + }, + DisconnectRootNode, + EnterNestedNetwork, + DuplicateSelectedNodes, + ExposeInput { + input_connector: InputConnector, + set_to_exposed: bool, + start_transaction: bool, + }, + InsertNode { + node_id: NodeId, + node_template: NodeTemplate, + }, + InsertNodeBetween { + node_id: NodeId, + input_connector: InputConnector, + insert_node_input_index: usize, + }, + MergeSelectedNodes, + MoveLayerToStack { + layer: LayerNodeIdentifier, + parent: LayerNodeIdentifier, + insert_index: usize, + }, + MoveNodeToChainStart { + node_id: NodeId, + parent: LayerNodeIdentifier, + }, + PasteNodes { + serialized_nodes: String, + }, + PointerDown { + shift_click: bool, + control_click: bool, + alt_click: bool, + right_click: bool, + }, + PointerMove { + shift: Key, + }, + PointerUp, + PointerOutsideViewport { + shift: Key, + }, + RemoveImport { + import_index: usize, + }, + RemoveExport { + export_index: usize, + }, + ReorderImport { + start_index: usize, + end_index: usize, + }, + ReorderExport { + start_index: usize, + end_index: usize, + }, + RunDocumentGraph, + ForceRunDocumentGraph, + SelectedNodesAdd { + nodes: Vec, + }, + SelectedNodesRemove { + nodes: Vec, + }, + SelectedNodesSet { + nodes: Vec, + }, + SendClickTargets, + EndSendClickTargets, + UnloadWires, + SendWires, + UpdateVisibleNodes, + SendGraph, + SetGridAlignedEdges, + SetInputValue { + node_id: NodeId, + input_index: usize, + value: TaggedValue, + }, + SetInput { + input_connector: InputConnector, + input: NodeInput, + }, + SetDisplayName { + node_id: NodeId, + alias: String, + skip_adding_history_step: bool, + }, + SetDisplayNameImpl { + node_id: NodeId, + alias: String, + }, + SetToNodeOrLayer { + node_id: NodeId, + is_layer: bool, + }, + ShiftNodePosition { + node_id: NodeId, + x: i32, + y: i32, + }, + ShiftSelectedNodes { + direction: Direction, + rubber_band: bool, + }, + ShiftSelectedNodesByAmount { + graph_delta: IVec2, + rubber_band: bool, + }, + TogglePreview { + node_id: NodeId, + }, + TogglePreviewImpl { + node_id: NodeId, + }, + SetImportExportName { + name: String, + index: ImportOrExport, + }, + SetImportExportNameImpl { + name: String, + index: ImportOrExport, + }, + ToggleSelectedAsLayersOrNodes, + ToggleSelectedLocked, + ToggleLocked { + node_id: NodeId, + }, + SetLocked { + node_id: NodeId, + locked: bool, + }, + ToggleSelectedIsPinned, + ToggleSelectedVisibility, + ToggleVisibility { + node_id: NodeId, + }, + SetPinned { + node_id: NodeId, + pinned: bool, + }, + SetVisibility { + node_id: NodeId, + visible: bool, + }, + SetLockedOrVisibilitySideEffects { + node_ids: Vec, + }, + UpdateEdges, + UpdateBoxSelection, + UpdateImportsExports, + UpdateLayerPanel, + UpdateNewNodeGraph, + UpdateTypes { + #[serde(skip)] + resolved_types: ResolvedDocumentNodeTypesDelta, + #[serde(skip)] + node_graph_errors: GraphErrors, + }, + UpdateActionButtons, + UpdateGraphBarRight, + UpdateInSelectedNetwork, + UpdateHints, + SendSelectedNodes, +} diff --git a/editor/src/messages/portfolio/document/node_graph/node_graph_message_handler.rs b/editor/src/messages/portfolio/document/node_graph/node_graph_message_handler.rs new file mode 100644 index 0000000000000000000000000000000000000000..b3f1596cd2cb5dd4535ee3e52ade85e615036cc0 --- /dev/null +++ b/editor/src/messages/portfolio/document/node_graph/node_graph_message_handler.rs @@ -0,0 +1,2595 @@ +use super::utility_types::{BoxSelection, ContextMenuInformation, DragStart, FrontendGraphInput, FrontendGraphOutput, FrontendNode}; +use super::{document_node_definitions, node_properties}; +use crate::consts::GRID_SIZE; +use crate::messages::input_mapper::utility_types::macros::action_keys; +use crate::messages::layout::utility_types::widget_prelude::*; +use crate::messages::portfolio::document::document_message_handler::navigation_controls; +use crate::messages::portfolio::document::graph_operation::utility_types::ModifyInputsContext; +use crate::messages::portfolio::document::node_graph::document_node_definitions::NodePropertiesContext; +use crate::messages::portfolio::document::node_graph::utility_types::{ContextMenuData, Direction, FrontendGraphDataType}; +use crate::messages::portfolio::document::utility_types::document_metadata::LayerNodeIdentifier; +use crate::messages::portfolio::document::utility_types::misc::GroupFolderType; +use crate::messages::portfolio::document::utility_types::network_interface::{ + self, InputConnector, NodeNetworkInterface, NodeTemplate, NodeTypePersistentMetadata, OutputConnector, Previewing, TypeSource, +}; +use crate::messages::portfolio::document::utility_types::nodes::{CollapsedLayers, LayerPanelEntry}; +use crate::messages::portfolio::document::utility_types::wires::{GraphWireStyle, WirePath, WirePathUpdate, build_vector_wire}; +use crate::messages::prelude::*; +use crate::messages::tool::common_functionality::auto_panning::AutoPanning; +use crate::messages::tool::common_functionality::graph_modification_utils::get_clip_mode; +use crate::messages::tool::tool_messages::tool_prelude::{Key, MouseMotion}; +use crate::messages::tool::utility_types::{HintData, HintGroup, HintInfo}; +use glam::{DAffine2, DVec2, IVec2}; +use graph_craft::document::{DocumentNodeImplementation, NodeId, NodeInput}; +use graph_craft::proto::GraphErrors; +use graphene_std::math::math_ext::QuadExt; +use graphene_std::*; +use renderer::Quad; +use std::cmp::Ordering; + +#[derive(Debug)] +pub struct NodeGraphHandlerData<'a> { + pub network_interface: &'a mut NodeNetworkInterface, + pub selection_network_path: &'a [NodeId], + pub breadcrumb_network_path: &'a [NodeId], + pub document_id: DocumentId, + pub collapsed: &'a mut CollapsedLayers, + pub ipp: &'a InputPreprocessorMessageHandler, + pub graph_view_overlay_open: bool, + pub graph_fade_artwork_percentage: f64, + pub navigation_handler: &'a NavigationMessageHandler, + pub preferences: &'a PreferencesMessageHandler, +} + +#[derive(Debug, Clone)] +pub struct NodeGraphMessageHandler { + // TODO: Remove network and move to NodeNetworkInterface + pub network: Vec, + pub node_graph_errors: GraphErrors, + has_selection: bool, + widgets: [LayoutGroup; 2], + /// Used to add a transaction for the first node move when dragging. + begin_dragging: bool, + /// Used to prevent entering a nested network if the node is dragged after double clicking + node_has_moved_in_drag: bool, + /// If dragging the selected nodes, this stores the starting position both in viewport and node graph coordinates, + /// plus a flag indicating if it has been dragged since the mousedown began. + pub drag_start: Option<(DragStart, bool)>, + /// If dragging the background to create a box selection, this stores its starting point in node graph coordinates, + /// plus a flag indicating if it has been dragged since the mousedown began. + box_selection_start: Option<(DVec2, bool)>, + /// Restore the selection before box selection if it is aborted + selection_before_pointer_down: Vec, + /// If the grip icon is held during a drag, then shift without pushing other nodes + shift_without_push: bool, + disconnecting: Option, + initial_disconnecting: bool, + /// Node to select on pointer up if multiple nodes are selected and they were not dragged. + select_if_not_dragged: Option, + /// The start of the dragged line (cannot be moved), stored in node graph coordinates + pub wire_in_progress_from_connector: Option, + wire_in_progress_type: FrontendGraphDataType, + /// The end point of the dragged line (cannot be moved), stored in node graph coordinates + pub wire_in_progress_to_connector: Option, + /// State for the context menu popups. + pub context_menu: Option, + /// Index of selected node to be deselected on pointer up when shift clicking an already selected node + pub deselect_on_pointer_up: Option, + /// Adds the auto panning functionality to the node graph when dragging a node or selection box to the edge of the viewport. + auto_panning: AutoPanning, + /// The node to preview on mouse up if alt-clicked + preview_on_mouse_up: Option, + /// The index of the import that is being moved + reordering_import: Option, + /// The index of the export that is being moved + reordering_export: Option, + /// The end index of the moved port + end_index: Option, + /// Used to keep track of what nodes are sent to the front end so that only visible ones are sent to the frontend + frontend_nodes: Vec, + /// Used to keep track of what wires are sent to the front end so the old ones can be removed + frontend_wires: HashSet<(NodeId, usize)>, +} + +/// NodeGraphMessageHandler always modifies the network which the selected nodes are in. No GraphOperationMessages should be added here, since those messages will always affect the document network. +impl<'a> MessageHandler> for NodeGraphMessageHandler { + fn process_message(&mut self, message: NodeGraphMessage, responses: &mut VecDeque, data: NodeGraphHandlerData<'a>) { + let NodeGraphHandlerData { + network_interface, + selection_network_path, + breadcrumb_network_path, + document_id, + collapsed, + ipp, + graph_view_overlay_open, + graph_fade_artwork_percentage, + navigation_handler, + preferences, + } = data; + + match message { + // TODO: automatically remove broadcast messages. + NodeGraphMessage::AddNodes { nodes, new_ids } => { + let Some(new_layer_id) = new_ids.get(&NodeId(0)).cloned().or_else(|| nodes.first().map(|(node_id, _)| *node_id)) else { + log::error!("No nodes to add in AddNodes"); + return; + }; + network_interface.insert_node_group(nodes, new_ids, selection_network_path); + + responses.add(NodeGraphMessage::SelectedNodesSet { nodes: vec![new_layer_id] }); + } + NodeGraphMessage::AddImport => { + network_interface.add_import(graph_craft::document::value::TaggedValue::None, true, -1, "", "", breadcrumb_network_path); + responses.add(NodeGraphMessage::SendGraph); + } + NodeGraphMessage::AddExport => { + network_interface.add_export(graph_craft::document::value::TaggedValue::None, -1, "", breadcrumb_network_path); + responses.add(NodeGraphMessage::SendGraph); + } + NodeGraphMessage::Init => { + responses.add(BroadcastMessage::SubscribeEvent { + on: BroadcastEvent::SelectionChanged, + send: Box::new(NodeGraphMessage::SelectedNodesUpdated.into()), + }); + network_interface.load_structure(); + collapsed.0.retain(|&layer| network_interface.document_metadata().layer_exists(layer)); + } + NodeGraphMessage::SelectedNodesUpdated => { + let selected_layers = network_interface.selected_nodes().selected_layers(network_interface.document_metadata()).collect::>(); + if selected_layers.len() <= 1 { + responses.add(DocumentMessage::SetRangeSelectionLayer { + new_layer: selected_layers.first().cloned(), + }); + } + responses.add(MenuBarMessage::SendLayout); + responses.add(NodeGraphMessage::UpdateLayerPanel); + responses.add(NodeGraphMessage::SendSelectedNodes); + responses.add(ArtboardToolMessage::UpdateSelectedArtboard); + responses.add(DocumentMessage::DocumentStructureChanged); + responses.add(OverlaysMessage::Draw); + responses.add(NodeGraphMessage::SendGraph); + } + NodeGraphMessage::CreateWire { output_connector, input_connector } => { + // TODO: Add support for flattening NodeInput::Network exports in flatten_with_fns https://github.com/GraphiteEditor/Graphite/issues/1762 + if matches!(input_connector, InputConnector::Export(_)) && matches!(output_connector, OutputConnector::Import { .. }) { + responses.add(DialogMessage::RequestComingSoonDialog { issue: Some(1762) }); + return; + } + network_interface.create_wire(&output_connector, &input_connector, selection_network_path); + } + NodeGraphMessage::Copy => { + let all_selected_nodes = network_interface.upstream_chain_nodes(selection_network_path); + // Collect the selected nodes + let new_ids = &all_selected_nodes.iter().enumerate().map(|(new, old)| (*old, NodeId(new as u64))).collect(); + let copied_nodes = network_interface.copy_nodes(new_ids, selection_network_path).collect::>(); + + // Prefix to show that these are nodes + let mut copy_text = String::from("graphite/nodes: "); + copy_text += &serde_json::to_string(&copied_nodes).expect("Could not serialize copy"); + + responses.add(FrontendMessage::TriggerTextCopy { copy_text }); + } + NodeGraphMessage::CreateNodeInLayerNoTransaction { node_type, layer } => { + let Some(mut modify_inputs) = ModifyInputsContext::new_with_layer(layer, network_interface, responses) else { + return; + }; + modify_inputs.create_node(&node_type); + } + NodeGraphMessage::CreateNodeInLayerWithTransaction { node_type, layer } => { + responses.add(DocumentMessage::AddTransaction); + responses.add(NodeGraphMessage::CreateNodeInLayerNoTransaction { node_type, layer }); + responses.add(PropertiesPanelMessage::Refresh); + responses.add(NodeGraphMessage::RunDocumentGraph); + } + NodeGraphMessage::CreateNodeFromContextMenu { + node_id, + node_type, + xy, + add_transaction, + } => { + let (x, y) = if let Some((x, y)) = xy { + (x, y) + } else if let Some(node_graph_ptz) = network_interface.node_graph_ptz(breadcrumb_network_path) { + ((-node_graph_ptz.pan.x / GRID_SIZE as f64) as i32, (-node_graph_ptz.pan.y / GRID_SIZE as f64) as i32) + } else { + (0, 0) + }; + + let node_id = node_id.unwrap_or_else(NodeId::new); + + let Some(document_node_type) = document_node_definitions::resolve_document_node_type(&node_type) else { + responses.add(DialogMessage::DisplayDialogError { + title: "Cannot insert node".to_string(), + description: format!("The document node '{node_type}' does not exist in the document node list"), + }); + return; + }; + + let node_template = document_node_type.default_node_template(); + self.context_menu = None; + + if add_transaction { + responses.add(DocumentMessage::AddTransaction); + } + + responses.add(NodeGraphMessage::InsertNode { + node_id, + node_template: node_template.clone(), + }); + responses.add(NodeGraphMessage::ShiftNodePosition { node_id, x, y }); + // Only auto connect to the dragged wire if the node is being added to the currently opened network + if let Some(output_connector_position) = self.wire_in_progress_from_connector { + let Some(network_metadata) = network_interface.network_metadata(selection_network_path) else { + log::error!("Could not get network metadata in CreateNodeFromContextMenu"); + return; + }; + let output_connector_position_viewport = network_metadata + .persistent_metadata + .navigation_metadata + .node_graph_to_viewport + .transform_point2(output_connector_position); + let Some(output_connector) = &network_interface.output_connector_from_click(output_connector_position_viewport, breadcrumb_network_path) else { + log::error!("Could not get output from connector start"); + return; + }; + + // Ensure connection is to correct input of new node. If it does not have an input then do not connect + if let Some((input_index, _)) = node_template.document_node.inputs.iter().enumerate().find(|(_, input)| input.is_exposed()) { + responses.add(NodeGraphMessage::CreateWire { + output_connector: *output_connector, + input_connector: InputConnector::node(node_id, input_index), + }); + + responses.add(NodeGraphMessage::RunDocumentGraph); + } + + self.wire_in_progress_from_connector = None; + self.wire_in_progress_type = FrontendGraphDataType::General; + self.wire_in_progress_to_connector = None; + } + responses.add(FrontendMessage::UpdateWirePathInProgress { wire_path: None }); + responses.add(FrontendMessage::UpdateContextMenuInformation { + context_menu_information: self.context_menu.clone(), + }); + responses.add(NodeGraphMessage::SendGraph); + } + NodeGraphMessage::ConnectUpstreamOutputToInput { downstream_input, input_connector } => { + let Some(upstream_node) = network_interface.upstream_output_connector(&downstream_input, selection_network_path) else { + log::error!("Failed to find upstream node for downstream_input"); + return; + }; + responses.add(NodeGraphMessage::CreateWire { + output_connector: upstream_node, + input_connector, + }); + } + NodeGraphMessage::Cut => { + responses.add(NodeGraphMessage::Copy); + responses.add(NodeGraphMessage::DeleteSelectedNodes { delete_children: true }); + } + NodeGraphMessage::DeleteNodes { node_ids, delete_children } => { + network_interface.delete_nodes(node_ids, delete_children, selection_network_path); + } + // Deletes selected_nodes. If `reconnect` is true, then all children nodes (secondary input) of the selected nodes are deleted and the siblings (primary input/output) are reconnected. + // If `reconnect` is false, then only the selected nodes are deleted and not reconnected. + NodeGraphMessage::DeleteSelectedNodes { delete_children } => { + let Some(selected_nodes) = network_interface.selected_nodes_in_nested_network(selection_network_path) else { + log::error!("Could not get selected nodes in DeleteSelectedNodes"); + return; + }; + responses.add(DocumentMessage::AddTransaction); + responses.add(NodeGraphMessage::DeleteNodes { + node_ids: selected_nodes.selected_nodes().cloned().collect::>(), + delete_children, + }); + responses.add(NodeGraphMessage::RunDocumentGraph); + responses.add(NodeGraphMessage::SelectedNodesUpdated); + responses.add(NodeGraphMessage::SendGraph); + } + NodeGraphMessage::DisconnectInput { input_connector } => { + network_interface.disconnect_input(&input_connector, selection_network_path); + } + NodeGraphMessage::DisconnectRootNode => { + network_interface.start_previewing_without_restore(selection_network_path); + } + NodeGraphMessage::DuplicateSelectedNodes => { + let all_selected_nodes = network_interface.upstream_chain_nodes(selection_network_path); + + let copy_ids = all_selected_nodes.iter().enumerate().map(|(new, id)| (*id, NodeId(new as u64))).collect::>(); + + // Copy the selected nodes + let nodes = network_interface.copy_nodes(©_ids, selection_network_path).collect::>(); + + let new_ids = nodes.iter().map(|(id, _)| (*id, NodeId::new())).collect::>(); + responses.add(DocumentMessage::AddTransaction); + responses.add(NodeGraphMessage::AddNodes { nodes, new_ids: new_ids.clone() }); + responses.add(NodeGraphMessage::SelectedNodesSet { + nodes: new_ids.values().cloned().collect(), + }); + } + NodeGraphMessage::EnterNestedNetwork => { + // Do not enter the nested network if the node was dragged + if self.node_has_moved_in_drag { + return; + } + + let Some(node_id) = network_interface.node_from_click(ipp.mouse.position, selection_network_path) else { + return; + }; + if network_interface + .layer_click_target_from_click(ipp.mouse.position, network_interface::LayerClickTargetTypes::Visibility, selection_network_path) + .is_some() + { + return; + }; + if let Some(DocumentNodeImplementation::Network(_)) = network_interface.implementation(&node_id, selection_network_path) { + responses.add(DocumentMessage::EnterNestedNetwork { node_id }); + } + } + NodeGraphMessage::ExposeInput { + input_connector, + set_to_exposed, + start_transaction, + } => { + let InputConnector::Node { node_id, input_index } = input_connector else { + log::error!("Cannot expose/hide export"); + return; + }; + let Some(node) = network_interface.document_node(&node_id, selection_network_path) else { + log::error!("Could not find node {node_id} in NodeGraphMessage::ExposeInput"); + return; + }; + let Some(mut node_input) = node.inputs.get(input_index).cloned() else { + log::error!("Could not find input {input_index} in NodeGraphMessage::ExposeInput"); + return; + }; + + // If we're un-exposing an input that is not a value, then disconnect it. This will convert it to a value input, + // so we can come back to handle this message again to set the exposed value in the second run-through. + if !set_to_exposed && node_input.as_value().is_none() { + // Reversed order because we are pushing front + responses.add_front(NodeGraphMessage::ExposeInput { + input_connector, + set_to_exposed, + start_transaction: false, + }); + responses.add_front(NodeGraphMessage::DisconnectInput { input_connector }); + responses.add_front(DocumentMessage::StartTransaction); + return; + } + + // Add a history step, but only do so if we didn't already start a transaction in the first run-through of this message in the above code + if start_transaction { + responses.add_front(DocumentMessage::StartTransaction); + } + + // If this node's input is a value type, we set its chosen exposed state + if let NodeInput::Value { exposed, .. } = &mut node_input { + *exposed = set_to_exposed; + } + responses.add(NodeGraphMessage::SetInput { + input_connector: InputConnector::node(node_id, input_index), + input: node_input, + }); + + // Finish the history step + responses.add(DocumentMessage::CommitTransaction); + + // Update the graph UI and re-render + if graph_view_overlay_open { + responses.add(PropertiesPanelMessage::Refresh); + responses.add(NodeGraphMessage::SendGraph); + } else { + responses.add(DocumentMessage::GraphViewOverlay { open: true }); + responses.add(NavigationMessage::FitViewportToSelection); + responses.add(DocumentMessage::ZoomCanvasTo100Percent); + } + } + NodeGraphMessage::InsertNode { node_id, node_template } => { + network_interface.insert_node(node_id, node_template, selection_network_path); + } + NodeGraphMessage::InsertNodeBetween { + node_id, + input_connector, + insert_node_input_index, + } => { + network_interface.insert_node_between(&node_id, &input_connector, insert_node_input_index, selection_network_path); + } + NodeGraphMessage::MergeSelectedNodes => { + let new_ids = network_interface + .selected_nodes_in_nested_network(breadcrumb_network_path) + .unwrap() + .selected_nodes() + .map(|id| (*id, *id)) + .collect::>(); + + let copied_nodes = network_interface.copy_nodes(&new_ids, breadcrumb_network_path).collect::>(); + let selected_node_ids = copied_nodes.iter().map(|(node_id, _)| *node_id).collect::>(); + let selected_node_ids_vec = copied_nodes.iter().map(|(node_id, _)| *node_id).collect::>(); + // Mapping of the encapsulating node inputs/outputs to where it needs to be connected + let mut input_connections = Vec::new(); + let mut output_connections = Vec::new(); + // Mapping of the inner nodes that need to be connected to the imports/exports + let mut import_connections = Vec::new(); + let mut export_connections = Vec::new(); + // Scan current nodes top to bottom and find all inputs/outputs connected to nodes that are not in the copied nodes. These will represent the new imports and exports. + let Some(nodes_sorted_top_to_bottom) = network_interface.nodes_sorted_top_to_bottom( + network_interface.selected_nodes_in_nested_network(breadcrumb_network_path).unwrap().selected_nodes(), + breadcrumb_network_path, + ) else { + return; + }; + // Ensure that nodes can be grouped by checking if there is an unselected node between selected nodes + for selected_node_id in &selected_node_ids { + for input_index in 0..network_interface.number_of_inputs(selected_node_id, breadcrumb_network_path) { + let input_connector = InputConnector::node(*selected_node_id, input_index); + if let Some(upstream_deselected_node_id) = network_interface + .upstream_output_connector(&input_connector, breadcrumb_network_path) + .and_then(|output_connector| output_connector.node_id()) + .filter(|node_id| !selected_node_ids.contains(node_id)) + { + for upstream_node_id in + network_interface.upstream_flow_back_from_nodes(vec![upstream_deselected_node_id], breadcrumb_network_path, network_interface::FlowType::UpstreamFlow) + { + if selected_node_ids.contains(&upstream_node_id) { + responses.add(DialogMessage::DisplayDialogError { + title: "Error Grouping Nodes".to_string(), + description: "A discontinuous selection of nodes cannot be grouped.\nEnsure no deselected nodes are between selected nodes".to_string(), + }); + return; + } + } + } + } + } + for node_id in nodes_sorted_top_to_bottom { + for input_index in 0..network_interface.number_of_inputs(&node_id, breadcrumb_network_path) { + let current_input_connector = InputConnector::node(node_id, input_index); + let Some(upstream_connector) = network_interface.upstream_output_connector(¤t_input_connector, breadcrumb_network_path) else { + continue; + }; + if upstream_connector + .node_id() + .is_some_and(|upstream_node_id| selected_node_ids.iter().any(|copied_id| *copied_id == upstream_node_id)) + { + continue; + } + + // If the upstream connection is not part of the copied nodes, then connect it to the new imports, or add it if it has not already been added. + let import_index = input_connections.iter().position(|old_connection| old_connection == &upstream_connector).unwrap_or_else(|| { + input_connections.push(upstream_connector); + input_connections.len() - 1 + }); + import_connections.push((current_input_connector, import_index)); + } + for output_index in 0..network_interface.number_of_outputs(&node_id, breadcrumb_network_path) { + let current_output_connector = OutputConnector::node(node_id, output_index); + let Some(outward_wires) = network_interface.outward_wires(breadcrumb_network_path) else { + log::error!("Could not get outward wires in upstream_nodes_below_layer"); + continue; + }; + let Some(downstream_connections) = outward_wires.get(¤t_output_connector).cloned() else { + log::error!("Could not get downstream connections for {current_output_connector:?}"); + continue; + }; + + // The output gets connected to all the previous inputs the node was connected to + let mut connect_output_to = Vec::new(); + for downstream_connection in downstream_connections { + if downstream_connection.node_id().is_some_and(|downstream_node_id| selected_node_ids.contains(&downstream_node_id)) { + continue; + } + connect_output_to.push(downstream_connection); + } + if !connect_output_to.is_empty() { + // Every output connected to some non selected node forms a new export + export_connections.push(current_output_connector); + output_connections.push(connect_output_to); + } + } + } + + // Use the network interface to add a default node, then set the imports, exports, paste the nodes inside, and connect them to the imports/exports + let encapsulating_node_id = NodeId::new(); + let mut default_node_template = document_node_definitions::resolve_document_node_type("Default Network") + .expect("Default Network node should exist") + .default_node_template(); + let Some(center_of_selected_nodes) = network_interface.selected_nodes_bounding_box(breadcrumb_network_path).map(|[a, b]| (a + b) / 2.) else { + log::error!("Could not get center of selected_nodes"); + return; + }; + let center_of_selected_nodes_grid_space = IVec2::new((center_of_selected_nodes.x / 24. + 0.5).floor() as i32, (center_of_selected_nodes.y / 24. + 0.5).floor() as i32); + default_node_template.persistent_node_metadata.node_type_metadata = NodeTypePersistentMetadata::node(center_of_selected_nodes_grid_space - IVec2::new(3, 1)); + responses.add(DocumentMessage::AddTransaction); + responses.add(NodeGraphMessage::InsertNode { + node_id: encapsulating_node_id, + node_template: default_node_template, + }); + responses.add(NodeGraphMessage::SetDisplayNameImpl { + node_id: encapsulating_node_id, + alias: "Untitled Node".to_string(), + }); + + responses.add(DocumentMessage::EnterNestedNetwork { node_id: encapsulating_node_id }); + for _ in 0..input_connections.len() { + responses.add(NodeGraphMessage::AddImport); + } + for _ in 0..output_connections.len() { + responses.add(NodeGraphMessage::AddExport); + } + responses.add(NodeGraphMessage::AddNodes { nodes: copied_nodes, new_ids }); + responses.add(NodeGraphMessage::SelectedNodesSet { nodes: selected_node_ids_vec.clone() }); + + // Shift the nodes back to the origin + responses.add(NodeGraphMessage::ShiftSelectedNodesByAmount { + graph_delta: -center_of_selected_nodes_grid_space - IVec2::new(2, 2), + rubber_band: false, + }); + + for (input_connector, import_index) in import_connections { + responses.add(NodeGraphMessage::CreateWire { + output_connector: OutputConnector::Import(import_index), + input_connector, + }); + } + for (export_index, output_connector) in export_connections.into_iter().enumerate() { + responses.add(NodeGraphMessage::CreateWire { + output_connector, + input_connector: InputConnector::Export(export_index), + }); + } + responses.add(DocumentMessage::ExitNestedNetwork { steps_back: 1 }); + for (input_index, output_connector) in input_connections.into_iter().enumerate() { + responses.add(NodeGraphMessage::CreateWire { + output_connector, + input_connector: InputConnector::node(encapsulating_node_id, input_index), + }); + } + for (output_index, input_connectors) in output_connections.into_iter().enumerate() { + for input_connector in input_connectors { + responses.add(NodeGraphMessage::CreateWire { + output_connector: OutputConnector::node(encapsulating_node_id, output_index), + input_connector, + }); + } + } + responses.add(NodeGraphMessage::DeleteNodes { + node_ids: selected_node_ids_vec, + delete_children: false, + }); + responses.add(NodeGraphMessage::SelectedNodesSet { nodes: vec![encapsulating_node_id] }); + responses.add(NodeGraphMessage::SendGraph); + responses.add(NodeGraphMessage::RunDocumentGraph); + } + NodeGraphMessage::MoveLayerToStack { layer, parent, insert_index } => { + network_interface.move_layer_to_stack(layer, parent, insert_index, selection_network_path); + } + NodeGraphMessage::MoveNodeToChainStart { node_id, parent } => { + network_interface.move_node_to_chain_start(&node_id, parent, selection_network_path); + } + NodeGraphMessage::PasteNodes { serialized_nodes } => { + let data = match serde_json::from_str::>(&serialized_nodes) { + Ok(d) => d, + Err(e) => { + warn!("Invalid node data {e:?}"); + return; + } + }; + if data.is_empty() { + return; + } + + responses.add(DocumentMessage::AddTransaction); + + let new_ids: HashMap<_, _> = data.iter().map(|(id, _)| (*id, NodeId::new())).collect(); + let nodes: Vec<_> = new_ids.values().copied().collect(); + responses.add(NodeGraphMessage::AddNodes { + nodes: data, + new_ids: new_ids.clone(), + }); + responses.add(NodeGraphMessage::SelectedNodesSet { nodes }) + } + NodeGraphMessage::PointerDown { + shift_click, + control_click, + alt_click, + right_click, + } => { + if selection_network_path != breadcrumb_network_path { + log::error!("Selection network path does not match breadcrumb network path in PointerDown"); + return; + } + let Some(network_metadata) = network_interface.network_metadata(selection_network_path) else { + log::error!("Could not get network metadata in PointerDown"); + return; + }; + + let click = ipp.mouse.position; + + let node_graph_point = network_metadata.persistent_metadata.navigation_metadata.node_graph_to_viewport.inverse().transform_point2(click); + + if network_interface + .layer_click_target_from_click(click, network_interface::LayerClickTargetTypes::Grip, selection_network_path) + .is_some() + { + self.shift_without_push = true; + } + + let clicked_id = network_interface.node_from_click(click, selection_network_path); + let clicked_input = network_interface.input_connector_from_click(click, selection_network_path); + let clicked_output = network_interface.output_connector_from_click(click, selection_network_path); + let network_metadata = network_interface.network_metadata(selection_network_path).unwrap(); + + // Create the add node popup on right click, then exit + if right_click { + // Abort dragging a node + if self.drag_start.is_some() { + self.drag_start = None; + responses.add(DocumentMessage::AbortTransaction); + responses.add(NodeGraphMessage::SelectedNodesSet { + nodes: self.selection_before_pointer_down.clone(), + }); + return; + } + // Abort a box selection + if self.box_selection_start.is_some() { + self.box_selection_start = None; + responses.add(NodeGraphMessage::SelectedNodesSet { + nodes: self.selection_before_pointer_down.clone(), + }); + responses.add(FrontendMessage::UpdateBox { box_selection: None }); + return; + } + // Abort dragging a wire + if self.wire_in_progress_from_connector.is_some() { + self.wire_in_progress_from_connector = None; + self.wire_in_progress_type = FrontendGraphDataType::General; + self.wire_in_progress_to_connector = None; + responses.add(DocumentMessage::AbortTransaction); + responses.add(FrontendMessage::UpdateWirePathInProgress { wire_path: None }); + return; + } + + let context_menu_data = if let Some(node_id) = clicked_id { + let currently_is_node = !network_interface.is_layer(&node_id, selection_network_path); + ContextMenuData::ToggleLayer { node_id, currently_is_node } + } else { + ContextMenuData::CreateNode { compatible_type: None } + }; + + // TODO: Create function + let node_graph_shift = if matches!(context_menu_data, ContextMenuData::CreateNode { compatible_type: None }) { + let appear_right_of_mouse = if click.x > ipp.viewport_bounds.size().x - 180. { -180. } else { 0. }; + let appear_above_mouse = if click.y > ipp.viewport_bounds.size().y - 200. { -200. } else { 0. }; + DVec2::new(appear_right_of_mouse, appear_above_mouse) / network_metadata.persistent_metadata.navigation_metadata.node_graph_to_viewport.matrix2.x_axis.x + } else { + let appear_right_of_mouse = if click.x > ipp.viewport_bounds.size().x - 173. { -173. } else { 0. }; + let appear_above_mouse = if click.y > ipp.viewport_bounds.size().y - 34. { -34. } else { 0. }; + DVec2::new(appear_right_of_mouse, appear_above_mouse) / network_metadata.persistent_metadata.navigation_metadata.node_graph_to_viewport.matrix2.x_axis.x + }; + + let context_menu_coordinates = ((node_graph_point.x + node_graph_shift.x) as i32, (node_graph_point.y + node_graph_shift.y) as i32); + + self.context_menu = Some(ContextMenuInformation { + context_menu_coordinates, + context_menu_data, + }); + + responses.add(FrontendMessage::UpdateContextMenuInformation { + context_menu_information: self.context_menu.clone(), + }); + + return; + } + + let Some(modify_import_export) = network_interface.modify_import_export(selection_network_path) else { + log::error!("Could not get modify import export in PointerDown"); + return; + }; + + if modify_import_export.add_import_export.clicked_input_port_from_point(node_graph_point).is_some() { + responses.add(DocumentMessage::AddTransaction); + responses.add(NodeGraphMessage::AddExport); + return; + } else if modify_import_export.add_import_export.clicked_output_port_from_point(node_graph_point).is_some() { + responses.add(DocumentMessage::AddTransaction); + responses.add(NodeGraphMessage::AddImport); + return; + } else if let Some(remove_import_index) = modify_import_export.remove_imports_exports.clicked_output_port_from_point(node_graph_point) { + responses.add(DocumentMessage::AddTransaction); + responses.add(NodeGraphMessage::RemoveImport { import_index: remove_import_index }); + return; + } else if let Some(remove_export_index) = modify_import_export.remove_imports_exports.clicked_input_port_from_point(node_graph_point) { + responses.add(DocumentMessage::AddTransaction); + responses.add(NodeGraphMessage::RemoveExport { export_index: remove_export_index }); + return; + } else if let Some(move_import_index) = modify_import_export.reorder_imports_exports.clicked_output_port_from_point(node_graph_point) { + responses.add(DocumentMessage::StartTransaction); + self.reordering_import = Some(move_import_index); + return; + } else if let Some(move_export_index) = modify_import_export.reorder_imports_exports.clicked_input_port_from_point(node_graph_point) { + responses.add(DocumentMessage::StartTransaction); + self.reordering_export = Some(move_export_index); + return; + } + + self.selection_before_pointer_down = network_interface + .selected_nodes_in_nested_network(selection_network_path) + .map(|selected_nodes| selected_nodes.selected_nodes().cloned().collect()) + .unwrap_or_default(); + + // Since the user is clicking elsewhere in the graph, ensure the add nodes list is closed + if self.context_menu.is_some() { + self.context_menu = None; + self.wire_in_progress_from_connector = None; + self.wire_in_progress_type = FrontendGraphDataType::General; + self.wire_in_progress_to_connector = None; + responses.add(FrontendMessage::UpdateContextMenuInformation { + context_menu_information: self.context_menu.clone(), + }); + responses.add(FrontendMessage::UpdateWirePathInProgress { wire_path: None }); + } + + // Toggle visibility of clicked node and return + if let Some(clicked_visibility) = network_interface.layer_click_target_from_click(click, network_interface::LayerClickTargetTypes::Visibility, selection_network_path) { + responses.add(NodeGraphMessage::ToggleVisibility { node_id: clicked_visibility }); + return; + } + + // Alt-click sets the clicked node as previewed + if alt_click { + if let Some(clicked_node) = clicked_id { + self.preview_on_mouse_up = Some(clicked_node); + } + } + + // Begin moving an existing wire + if let Some(clicked_input) = &clicked_input { + responses.add(DocumentMessage::StartTransaction); + self.initial_disconnecting = true; + self.disconnecting = Some(*clicked_input); + + let output_connector = if *clicked_input == InputConnector::Export(0) { + network_interface.root_node(selection_network_path).map(|root_node| root_node.to_connector()) + } else { + network_interface.upstream_output_connector(clicked_input, selection_network_path) + }; + let Some(output_connector) = output_connector else { return }; + self.wire_in_progress_from_connector = network_interface.output_position(&output_connector, selection_network_path); + self.wire_in_progress_type = FrontendGraphDataType::from_type(&network_interface.input_type(clicked_input, breadcrumb_network_path).0); + return; + } + + // Begin creating a new wire + if let Some(clicked_output) = clicked_output { + responses.add(DocumentMessage::StartTransaction); + self.initial_disconnecting = false; + + self.wire_in_progress_from_connector = network_interface.output_position(&clicked_output, selection_network_path); + if let Some((output_type, source)) = clicked_output + .node_id() + .map(|node_id| network_interface.output_type(&node_id, clicked_output.index(), breadcrumb_network_path)) + { + self.wire_in_progress_type = FrontendGraphDataType::displayed_type(&output_type, &source); + } else { + self.wire_in_progress_type = FrontendGraphDataType::General; + } + + self.update_node_graph_hints(responses); + return; + } + + if let Some(clicked_id) = clicked_id { + let Some(selected_nodes) = network_interface.selected_nodes_in_nested_network(selection_network_path) else { + log::error!("Could not get selected nodes in PointerDown"); + return; + }; + let mut updated_selected = selected_nodes.selected_nodes().cloned().collect::>(); + let mut modified_selected = false; + + // Add to/remove from selection if holding Shift or Ctrl + if shift_click || control_click { + modified_selected = true; + + let index = updated_selected.iter().enumerate().find_map(|(i, node_id)| if *node_id == clicked_id { Some(i) } else { None }); + // Remove from selection (on PointerUp) if already selected + self.deselect_on_pointer_up = index; + + // Add to selection if not already selected. Necessary in order to drag multiple nodes + if index.is_none() { + updated_selected.push(clicked_id); + }; + } + // Replace selection with a non-selected node + else if !updated_selected.contains(&clicked_id) { + modified_selected = true; + updated_selected = vec![clicked_id]; + } + // Replace selection (of multiple nodes including this one) with just this one, but only upon pointer up if the user didn't drag the selected nodes + else { + self.select_if_not_dragged = Some(clicked_id); + } + + // If this node is selected (whether from before or just now), prepare it for dragging + if updated_selected.contains(&clicked_id) { + let drag_start = DragStart { + start_x: node_graph_point.x, + start_y: node_graph_point.y, + round_x: 0, + round_y: 0, + }; + + self.drag_start = Some((drag_start, false)); + self.begin_dragging = true; + self.node_has_moved_in_drag = false; + self.update_node_graph_hints(responses); + } + + // Update the selection if it was modified + if modified_selected { + responses.add(NodeGraphMessage::SelectedNodesSet { nodes: updated_selected }) + } + // Start the transaction after setting the node, since when the transactions ends it aborts any changes after this + responses.add(DocumentMessage::StartTransaction); + + return; + } + + // Clicked on the graph background so we box select + if !shift_click { + responses.add(NodeGraphMessage::SelectedNodesSet { nodes: Vec::new() }) + } + self.box_selection_start = Some((node_graph_point, false)); + self.update_node_graph_hints(responses); + } + NodeGraphMessage::PointerMove { shift } => { + if selection_network_path != breadcrumb_network_path { + log::error!("Selection network path does not match breadcrumb network path in PointerMove"); + return; + } + let Some(network_metadata) = network_interface.network_metadata(selection_network_path) else { + return; + }; + + // Auto-panning + let messages = [NodeGraphMessage::PointerOutsideViewport { shift }.into(), NodeGraphMessage::PointerMove { shift }.into()]; + self.auto_panning.setup_by_mouse_position(ipp, &messages, responses); + + let viewport_location = ipp.mouse.position; + let point = network_metadata + .persistent_metadata + .navigation_metadata + .node_graph_to_viewport + .inverse() + .transform_point2(viewport_location); + + if self.wire_in_progress_from_connector.is_some() && self.context_menu.is_none() { + let to_connector = network_interface.input_connector_from_click(ipp.mouse.position, selection_network_path); + if let Some(to_connector) = &to_connector { + let Some(input_position) = network_interface.input_position(to_connector, selection_network_path) else { + log::error!("Could not get input position for connector: {to_connector:?}"); + return; + }; + self.wire_in_progress_to_connector = Some(input_position); + } + // Not hovering over a node input or node output, update with the mouse position. + else { + self.wire_in_progress_to_connector = Some(point); + // Disconnect if the wire was previously connected to an input + if let Some(disconnecting) = &self.disconnecting { + let mut disconnect_root_node = false; + if let Previewing::Yes { root_node_to_restore } = network_interface.previewing(selection_network_path) { + if root_node_to_restore.is_some() && *disconnecting == InputConnector::Export(0) { + disconnect_root_node = true; + } + } + if disconnect_root_node { + responses.add(NodeGraphMessage::DisconnectRootNode); + } else { + responses.add(NodeGraphMessage::DisconnectInput { input_connector: *disconnecting }); + } + // Update the frontend that the node is disconnected + responses.add(NodeGraphMessage::RunDocumentGraph); + responses.add(NodeGraphMessage::SendGraph); + self.disconnecting = None; + } + } + + if let (Some(wire_in_progress_from_connector), Some(wire_in_progress_to_connector)) = (self.wire_in_progress_from_connector, self.wire_in_progress_to_connector) { + // If performance is a concern this can be stored as a field in the wire_in_progress_from/to_connector struct, and updated when snapping to an output + let Some(network_metadata) = network_interface.network_metadata(selection_network_path) else { + return; + }; + let from_connector_viewport = network_metadata + .persistent_metadata + .navigation_metadata + .node_graph_to_viewport + .transform_point2(wire_in_progress_from_connector); + let from_connector_is_layer = network_interface + .output_connector_from_click(from_connector_viewport, selection_network_path) + .is_some_and(|output_connector| { + if let OutputConnector::Node { node_id, .. } = output_connector { + network_interface.is_layer(&node_id, selection_network_path) + } else { + false + } + }); + let to_connector_is_layer = to_connector.is_some_and(|to_connector| { + if let InputConnector::Node { node_id, input_index } = to_connector { + input_index == 0 && network_interface.is_layer(&node_id, selection_network_path) + } else { + false + } + }); + let vector_wire = build_vector_wire( + wire_in_progress_from_connector, + wire_in_progress_to_connector, + from_connector_is_layer, + to_connector_is_layer, + GraphWireStyle::Direct, + ); + let mut path_string = String::new(); + let _ = vector_wire.subpath_to_svg(&mut path_string, DAffine2::IDENTITY); + let wire_path = WirePath { + path_string, + data_type: self.wire_in_progress_type, + thick: false, + dashed: false, + }; + responses.add(FrontendMessage::UpdateWirePathInProgress { wire_path: Some(wire_path) }); + } + } else if let Some((drag_start, dragged)) = &mut self.drag_start { + if drag_start.start_x != point.x || drag_start.start_y != point.y { + *dragged = true; + } + + self.node_has_moved_in_drag = true; + if self.begin_dragging { + self.begin_dragging = false; + if ipp.keyboard.get(Key::Alt as usize) { + responses.add(NodeGraphMessage::DuplicateSelectedNodes); + // Duplicating sets a 2x2 offset, so shift the nodes back to the original position + responses.add(NodeGraphMessage::ShiftSelectedNodesByAmount { + graph_delta: IVec2::new(-2, -2), + rubber_band: false, + }); + self.preview_on_mouse_up = None; + } + } + + let mut graph_delta = IVec2::new(((point.x - drag_start.start_x) / 24.).round() as i32, ((point.y - drag_start.start_y) / 24.).round() as i32); + let previous_round_x = drag_start.round_x; + let previous_round_y = drag_start.round_y; + + drag_start.round_x = graph_delta.x; + drag_start.round_y = graph_delta.y; + + graph_delta.x -= previous_round_x; + graph_delta.y -= previous_round_y; + + responses.add(NodeGraphMessage::ShiftSelectedNodesByAmount { graph_delta, rubber_band: true }); + + self.update_node_graph_hints(responses); + } else if let Some((_, box_selection_dragged)) = &mut self.box_selection_start { + *box_selection_dragged = true; + responses.add(NodeGraphMessage::UpdateBoxSelection); + self.update_node_graph_hints(responses); + } else if self.reordering_import.is_some() { + let Some(modify_import_export) = network_interface.modify_import_export(selection_network_path) else { + log::error!("Could not get modify import export in PointerMove"); + return; + }; + // Find the first import that is below the mouse position + self.end_index = Some( + modify_import_export + .reorder_imports_exports + .output_ports() + .find_map(|(index, click_target)| { + let Some(position) = click_target.bounding_box().map(|bbox| (bbox[0].y + bbox[1].y) / 2.) else { + log::error!("Could not get bounding box for import: {index}"); + return None; + }; + (position > point.y).then_some(*index) + }) + .unwrap_or(modify_import_export.reorder_imports_exports.output_ports().count()), + ); + responses.add(FrontendMessage::UpdateImportReorderIndex { index: self.end_index }); + } else if self.reordering_export.is_some() { + let Some(modify_import_export) = network_interface.modify_import_export(selection_network_path) else { + log::error!("Could not get modify import export in PointerMove"); + return; + }; + // Find the first export that is below the mouse position + self.end_index = Some( + modify_import_export + .reorder_imports_exports + .input_ports() + .find_map(|(index, click_target)| { + let Some(position) = click_target.bounding_box().map(|bbox| (bbox[0].y + bbox[1].y) / 2.) else { + log::error!("Could not get bounding box for export: {index}"); + return None; + }; + (position > point.y).then_some(*index) + }) + .unwrap_or(modify_import_export.reorder_imports_exports.input_ports().count()), + ); + responses.add(FrontendMessage::UpdateExportReorderIndex { index: self.end_index }); + } + } + NodeGraphMessage::PointerUp => { + if selection_network_path != breadcrumb_network_path { + log::error!("Selection network path does not match breadcrumb network path in PointerUp"); + return; + } + let Some(selected_nodes) = network_interface.selected_nodes_in_nested_network(selection_network_path) else { + log::error!("Could not get selected nodes in PointerUp"); + return; + }; + let Some(network_metadata) = network_interface.network_metadata(selection_network_path) else { + warn!("No network_metadata"); + return; + }; + + if let Some(preview_node) = self.preview_on_mouse_up { + responses.add(NodeGraphMessage::TogglePreview { node_id: preview_node }); + self.preview_on_mouse_up = None; + } + if let Some(node_to_deselect) = self.deselect_on_pointer_up.take() { + if !self.drag_start.as_ref().is_some_and(|t| t.1) { + let mut new_selected_nodes = selected_nodes.selected_nodes_ref().clone(); + new_selected_nodes.remove(node_to_deselect); + responses.add(NodeGraphMessage::SelectedNodesSet { nodes: new_selected_nodes }); + return; + } + } + let point = network_metadata + .persistent_metadata + .navigation_metadata + .node_graph_to_viewport + .inverse() + .transform_point2(ipp.mouse.position); + // Disconnect if the wire was previously connected to an input + if let (Some(wire_in_progress_from_connector), Some(wire_in_progress_to_connector)) = (self.wire_in_progress_from_connector, self.wire_in_progress_to_connector) { + // Check if dragged connector is reconnected to another input + let node_graph_to_viewport = network_metadata.persistent_metadata.navigation_metadata.node_graph_to_viewport; + let from_connector_viewport = node_graph_to_viewport.transform_point2(wire_in_progress_from_connector); + let to_connector_viewport = node_graph_to_viewport.transform_point2(wire_in_progress_to_connector); + let output_connector = network_interface.output_connector_from_click(from_connector_viewport, selection_network_path); + let input_connector = network_interface.input_connector_from_click(to_connector_viewport, selection_network_path); + + if let (Some(output_connector), Some(input_connector)) = (&output_connector, &input_connector) { + responses.add(NodeGraphMessage::CreateWire { + input_connector: *input_connector, + output_connector: *output_connector, + }); + + responses.add(NodeGraphMessage::RunDocumentGraph); + + responses.add(NodeGraphMessage::SendGraph); + } else if output_connector.is_some() && input_connector.is_none() && !self.initial_disconnecting { + // If the add node menu is already open, we don't want to open it again + if self.context_menu.is_some() { + return; + } + let Some(network_metadata) = network_interface.network_metadata(selection_network_path) else { + warn!("No network_metadata"); + return; + }; + // Get the compatible type from the output connector + let compatible_type = output_connector.and_then(|output_connector| { + output_connector.node_id().and_then(|node_id| { + // Get the output types from the network interface + let (output_type, type_source) = network_interface.output_type(&node_id, output_connector.index(), selection_network_path); + + match type_source { + TypeSource::RandomProtonodeImplementation | TypeSource::Error(_) => None, + _ => Some(format!("type:{}", output_type.nested_type())), + } + }) + }); + let appear_right_of_mouse = if ipp.mouse.position.x > ipp.viewport_bounds.size().x - 173. { -173. } else { 0. }; + let appear_above_mouse = if ipp.mouse.position.y > ipp.viewport_bounds.size().y - 34. { -34. } else { 0. }; + let node_graph_shift = DVec2::new(appear_right_of_mouse, appear_above_mouse) / network_metadata.persistent_metadata.navigation_metadata.node_graph_to_viewport.matrix2.x_axis.x; + + self.context_menu = Some(ContextMenuInformation { + context_menu_coordinates: ((point.x + node_graph_shift.x) as i32, (point.y + node_graph_shift.y) as i32), + context_menu_data: ContextMenuData::CreateNode { compatible_type }, + }); + + responses.add(FrontendMessage::UpdateContextMenuInformation { + context_menu_information: self.context_menu.clone(), + }); + return; + } + } + // End of dragging a node + else if let Some((drag_start, _)) = &self.drag_start { + self.shift_without_push = false; + + // Reset all offsets to end the rubber banding while dragging + network_interface.unload_stack_dependents_y_offset(selection_network_path); + let Some(selected_nodes) = network_interface.selected_nodes_in_nested_network(selection_network_path) else { + log::error!("Could not get selected nodes in PointerUp"); + return; + }; + + // Only select clicked node if multiple are selected and they were not dragged + if let Some(select_if_not_dragged) = self.select_if_not_dragged { + let not_dragged = drag_start.start_x == point.x && drag_start.start_y == point.y; + if not_dragged + && (selected_nodes.selected_nodes_ref().len() != 1 + || selected_nodes + .selected_nodes_ref() + .first() + .is_some_and(|first_selected_node| *first_selected_node != select_if_not_dragged)) + { + responses.add(NodeGraphMessage::SelectedNodesSet { nodes: vec![select_if_not_dragged] }) + } + } + + // Try expand the upstream chain for all layers if there is an eligible node + let Some(network) = network_interface.nested_network(selection_network_path) else { return }; + for layer in network + .nodes + .keys() + .filter(|node_id| network_interface.is_layer(node_id, selection_network_path)) + .cloned() + .collect::>() + { + network_interface.try_set_upstream_to_chain(&InputConnector::node(layer, 1), selection_network_path); + } + responses.add(NodeGraphMessage::SendGraph); + + let Some(selected_nodes) = network_interface.selected_nodes_in_nested_network(selection_network_path) else { + log::error!("Could not get selected nodes in PointerUp"); + return; + }; + // Check if a single node was dragged onto a wire and that the node was dragged onto the wire + if selected_nodes.selected_nodes_ref().len() == 1 && !self.begin_dragging { + let selected_node_id = selected_nodes.selected_nodes_ref()[0]; + let has_primary_output_connection = network_interface + .outward_wires(selection_network_path) + .is_some_and(|outward_wires| outward_wires.get(&OutputConnector::node(selected_node_id, 0)).is_some_and(|outward_wires| !outward_wires.is_empty())); + if !has_primary_output_connection { + let Some(network) = network_interface.nested_network(selection_network_path) else { + return; + }; + let Some(selected_node) = network.nodes.get(&selected_node_id) else { + return; + }; + // Check that the first visible input is disconnected + let selected_node_input_connect_index = selected_node + .inputs + .iter() + .enumerate() + .find(|input| input.1.is_exposed()) + .filter(|input| input.1.as_value().is_some()) + .map(|input| input.0); + if let Some(selected_node_input_connect_index) = selected_node_input_connect_index { + let Some(bounding_box) = network_interface.node_bounding_box(&selected_node_id, selection_network_path) else { + log::error!("Could not get bounding box for node: {selected_node_id}"); + return; + }; + let mut wires_to_check = network_interface.node_graph_input_connectors(selection_network_path).into_iter().collect::>(); + // Prevent inserting on a link that is connected upstream to the selected node + for upstream_node in network_interface.upstream_flow_back_from_nodes(vec![selected_node_id], selection_network_path, network_interface::FlowType::UpstreamFlow) { + for input_index in 0..network_interface.number_of_inputs(&upstream_node, selection_network_path) { + wires_to_check.remove(&InputConnector::node(upstream_node, input_index)); + } + } + + let overlapping_wires = wires_to_check + .into_iter() + .filter_map(|input| { + // Prevent inserting a layer into a chain + if network_interface.is_layer(&selected_node_id, selection_network_path) + && input.node_id().is_some_and(|input_node_id| network_interface.is_chain(&input_node_id, selection_network_path)) + { + return None; + } + let (wire, is_stack) = network_interface.vector_wire_from_input(&input, preferences.graph_wire_style, selection_network_path)?; + wire.rectangle_intersections_exist(bounding_box[0], bounding_box[1]).then_some((input, is_stack)) + }) + .collect::>(); + // Prioritize vertical thick lines and cancel if there are multiple potential wires + let mut node_wires = Vec::new(); + let mut stack_wires = Vec::new(); + for (overlapping_wire_input, is_stack) in overlapping_wires { + if is_stack { + stack_wires.push(overlapping_wire_input) + } else { + node_wires.push(overlapping_wire_input) + } + } + + let overlapping_wire = if network_interface.is_layer(&selected_node_id, selection_network_path) { + if stack_wires.len() == 1 { + stack_wires.first() + } else if stack_wires.is_empty() && node_wires.len() == 1 { + node_wires.first() + } else { + None + } + } else if node_wires.len() == 1 { + node_wires.first() + } else { + None + }; + if let Some(overlapping_wire) = overlapping_wire { + responses.add(NodeGraphMessage::InsertNodeBetween { + node_id: selected_node_id, + input_connector: *overlapping_wire, + insert_node_input_index: selected_node_input_connect_index, + }); + responses.add(NodeGraphMessage::RunDocumentGraph); + responses.add(NodeGraphMessage::SendGraph); + } + } + } + } + self.select_if_not_dragged = None; + } + // End of reordering an import + else if let (Some(moving_import), Some(end_index)) = (self.reordering_import, self.end_index) { + responses.add(NodeGraphMessage::ReorderImport { + start_index: moving_import, + end_index, + }); + responses.add(DocumentMessage::EndTransaction); + } + // End of reordering an export + else if let (Some(moving_export), Some(end_index)) = (self.reordering_export, self.end_index) { + responses.add(NodeGraphMessage::ReorderExport { + start_index: moving_export, + end_index, + }); + responses.add(DocumentMessage::EndTransaction); + } + self.drag_start = None; + self.begin_dragging = false; + self.box_selection_start = None; + self.wire_in_progress_from_connector = None; + self.wire_in_progress_type = FrontendGraphDataType::General; + self.wire_in_progress_to_connector = None; + self.reordering_export = None; + self.reordering_import = None; + responses.add(DocumentMessage::EndTransaction); + responses.add(FrontendMessage::UpdateWirePathInProgress { wire_path: None }); + responses.add(FrontendMessage::UpdateBox { box_selection: None }); + responses.add(FrontendMessage::UpdateImportReorderIndex { index: None }); + responses.add(FrontendMessage::UpdateExportReorderIndex { index: None }); + self.update_node_graph_hints(responses); + } + NodeGraphMessage::PointerOutsideViewport { shift } => { + if self.drag_start.is_some() || self.box_selection_start.is_some() || (self.wire_in_progress_from_connector.is_some() && self.context_menu.is_none()) { + let _ = self.auto_panning.shift_viewport(ipp, responses); + } else { + // Auto-panning + let messages = [NodeGraphMessage::PointerOutsideViewport { shift }.into(), NodeGraphMessage::PointerMove { shift }.into()]; + self.auto_panning.stop(&messages, responses); + } + } + NodeGraphMessage::RemoveImport { import_index: usize } => { + network_interface.remove_import(usize, selection_network_path); + responses.add(NodeGraphMessage::SendGraph); + responses.add(NodeGraphMessage::RunDocumentGraph); + } + NodeGraphMessage::RemoveExport { export_index: usize } => { + network_interface.remove_export(usize, selection_network_path); + responses.add(NodeGraphMessage::SendGraph); + responses.add(NodeGraphMessage::RunDocumentGraph); + } + NodeGraphMessage::ReorderImport { start_index, end_index } => { + network_interface.reorder_import(start_index, end_index, selection_network_path); + responses.add(NodeGraphMessage::SendGraph); + responses.add(NodeGraphMessage::RunDocumentGraph); + } + NodeGraphMessage::ReorderExport { start_index, end_index } => { + network_interface.reorder_export(start_index, end_index, selection_network_path); + responses.add(NodeGraphMessage::SendGraph); + responses.add(NodeGraphMessage::RunDocumentGraph); + } + NodeGraphMessage::RunDocumentGraph => { + responses.add(PortfolioMessage::SubmitGraphRender { document_id, ignore_hash: false }); + } + NodeGraphMessage::ForceRunDocumentGraph => { + responses.add(PortfolioMessage::SubmitGraphRender { document_id, ignore_hash: true }); + } + NodeGraphMessage::SelectedNodesAdd { nodes } => { + let Some(selected_nodes) = network_interface.selected_nodes_mut(selection_network_path) else { + log::error!("Could not get selected nodes in NodeGraphMessage::SelectedNodesAdd"); + return; + }; + selected_nodes.add_selected_nodes(nodes); + responses.add(BroadcastEvent::SelectionChanged); + } + NodeGraphMessage::SelectedNodesRemove { nodes } => { + let Some(selected_nodes) = network_interface.selected_nodes_mut(selection_network_path) else { + log::error!("Could not get selected nodes in NodeGraphMessage::SelectedNodesRemove"); + return; + }; + selected_nodes.retain_selected_nodes(|node| !nodes.contains(node)); + responses.add(BroadcastEvent::SelectionChanged); + } + NodeGraphMessage::SelectedNodesSet { nodes } => { + let Some(selected_nodes) = network_interface.selected_nodes_mut(selection_network_path) else { + log::error!("Could not get selected nodes in NodeGraphMessage::SelectedNodesSet"); + return; + }; + selected_nodes.set_selected_nodes(nodes); + responses.add(BroadcastEvent::SelectionChanged); + responses.add(PropertiesPanelMessage::Refresh); + } + NodeGraphMessage::SendClickTargets => responses.add(FrontendMessage::UpdateClickTargets { + click_targets: Some(network_interface.collect_frontend_click_targets(breadcrumb_network_path)), + }), + NodeGraphMessage::EndSendClickTargets => responses.add(FrontendMessage::UpdateClickTargets { click_targets: None }), + NodeGraphMessage::UnloadWires => { + for input in network_interface.node_graph_input_connectors(breadcrumb_network_path) { + network_interface.unload_wire(&input, breadcrumb_network_path); + } + + responses.add(FrontendMessage::ClearAllNodeGraphWires); + } + NodeGraphMessage::SendWires => { + let wires = self.collect_wires(network_interface, preferences.graph_wire_style, breadcrumb_network_path); + responses.add(FrontendMessage::UpdateNodeGraphWires { wires }); + } + NodeGraphMessage::UpdateVisibleNodes => { + let Some(network_metadata) = network_interface.network_metadata(breadcrumb_network_path) else { + return; + }; + + let viewport_bbox = ipp.document_bounds(); + let document_bbox: [DVec2; 2] = viewport_bbox.map(|p| network_metadata.persistent_metadata.navigation_metadata.node_graph_to_viewport.inverse().transform_point2(p)); + + let mut nodes = Vec::new(); + for node_id in &self.frontend_nodes { + let Some(node_bbox) = network_interface.node_bounding_box(node_id, breadcrumb_network_path) else { + log::error!("Could not get bbox for node: {:?}", node_id); + continue; + }; + + if node_bbox[1].x >= document_bbox[0].x && node_bbox[0].x <= document_bbox[1].x && node_bbox[1].y >= document_bbox[0].y && node_bbox[0].y <= document_bbox[1].y { + nodes.push(*node_id); + } + } + + responses.add(FrontendMessage::UpdateVisibleNodes { nodes }); + } + NodeGraphMessage::SendGraph => { + responses.add(NodeGraphMessage::UpdateLayerPanel); + responses.add(DocumentMessage::DocumentStructureChanged); + responses.add(PropertiesPanelMessage::Refresh); + if breadcrumb_network_path == selection_network_path && graph_view_overlay_open { + let nodes = self.collect_nodes(network_interface, breadcrumb_network_path); + self.frontend_nodes = nodes.iter().map(|node| node.id).collect(); + responses.add(FrontendMessage::UpdateNodeGraphNodes { nodes }); + responses.add(NodeGraphMessage::UpdateVisibleNodes); + + let (layer_widths, chain_widths, has_left_input_wire) = network_interface.collect_layer_widths(breadcrumb_network_path); + + responses.add(NodeGraphMessage::UpdateImportsExports); + responses.add(FrontendMessage::UpdateLayerWidths { + layer_widths, + chain_widths, + has_left_input_wire, + }); + responses.add(NodeGraphMessage::SendSelectedNodes); + self.update_node_graph_hints(responses); + } + } + NodeGraphMessage::SetGridAlignedEdges => { + if graph_view_overlay_open { + network_interface.set_grid_aligned_edges(DVec2::new(ipp.viewport_bounds.bottom_right.x - ipp.viewport_bounds.top_left.x, 0.), breadcrumb_network_path); + // Send the new edges to the frontend + responses.add(NodeGraphMessage::UpdateImportsExports); + } + } + NodeGraphMessage::SetInputValue { node_id, input_index, value } => { + let input = NodeInput::value(value, false); + responses.add(NodeGraphMessage::SetInput { + input_connector: InputConnector::node(node_id, input_index), + input, + }); + responses.add(PropertiesPanelMessage::Refresh); + if !(network_interface.reference(&node_id, selection_network_path).is_none() || input_index == 0) && network_interface.connected_to_output(&node_id, selection_network_path) { + responses.add(NodeGraphMessage::RunDocumentGraph); + } + } + NodeGraphMessage::SetInput { input_connector, input } => { + network_interface.set_input(&input_connector, input, selection_network_path); + } + NodeGraphMessage::ShiftSelectedNodes { direction, rubber_band } => { + network_interface.shift_selected_nodes(direction, self.shift_without_push, selection_network_path); + + if !rubber_band { + network_interface.unload_stack_dependents_y_offset(selection_network_path); + } + + if graph_view_overlay_open { + responses.add(NodeGraphMessage::SendGraph); + responses.add(DocumentMessage::RenderRulers); + responses.add(DocumentMessage::RenderScrollbars); + } + } + NodeGraphMessage::ShiftSelectedNodesByAmount { mut graph_delta, rubber_band } => { + while graph_delta != IVec2::ZERO { + match graph_delta.x.cmp(&0) { + Ordering::Greater => { + responses.add(NodeGraphMessage::ShiftSelectedNodes { + direction: Direction::Right, + rubber_band, + }); + graph_delta.x -= 1; + } + Ordering::Less => { + responses.add(NodeGraphMessage::ShiftSelectedNodes { + direction: Direction::Left, + rubber_band, + }); + graph_delta.x += 1; + } + Ordering::Equal => {} + } + + match graph_delta.y.cmp(&0) { + Ordering::Greater => { + responses.add(NodeGraphMessage::ShiftSelectedNodes { + direction: Direction::Down, + rubber_band, + }); + graph_delta.y -= 1; + } + Ordering::Less => { + responses.add(NodeGraphMessage::ShiftSelectedNodes { + direction: Direction::Up, + rubber_band, + }); + graph_delta.y += 1; + } + Ordering::Equal => {} + } + } + + responses.add(NodeGraphMessage::SendWires); + } + NodeGraphMessage::ToggleSelectedAsLayersOrNodes => { + let Some(selected_nodes) = network_interface.selected_nodes_in_nested_network(selection_network_path) else { + log::error!("Could not get selected nodes in NodeGraphMessage::ToggleSelectedAsLayersOrNodes"); + return; + }; + responses.add(DocumentMessage::AddTransaction); + for node_id in selected_nodes.selected_nodes() { + responses.add(NodeGraphMessage::SetToNodeOrLayer { + node_id: *node_id, + is_layer: !network_interface.is_layer(node_id, selection_network_path), + }); + } + if selected_nodes.selected_nodes().any(|node_id| network_interface.connected_to_output(node_id, selection_network_path)) { + responses.add(NodeGraphMessage::RunDocumentGraph); + } + } + NodeGraphMessage::ShiftNodePosition { node_id, x, y } => { + network_interface.shift_absolute_node_position(&node_id, IVec2::new(x, y), selection_network_path); + + responses.add(NodeGraphMessage::SendWires); + } + NodeGraphMessage::SetToNodeOrLayer { node_id, is_layer } => { + if is_layer && !network_interface.is_eligible_to_be_layer(&node_id, selection_network_path) { + return; + } + network_interface.set_to_node_or_layer(&node_id, selection_network_path, is_layer); + + self.context_menu = None; + responses.add(FrontendMessage::UpdateContextMenuInformation { + context_menu_information: self.context_menu.clone(), + }); + responses.add(NodeGraphMessage::RunDocumentGraph); + responses.add(NodeGraphMessage::SendGraph); + responses.add(NodeGraphMessage::SendWires); + } + NodeGraphMessage::SetDisplayName { + node_id, + alias, + skip_adding_history_step, + } => { + if !skip_adding_history_step { + responses.add(DocumentMessage::StartTransaction); + } + responses.add(NodeGraphMessage::SetDisplayNameImpl { node_id, alias }); + if !skip_adding_history_step { + // Does not add a history step if the name was not changed + responses.add(DocumentMessage::EndTransaction); + } + responses.add(DocumentMessage::RenderRulers); + responses.add(DocumentMessage::RenderScrollbars); + responses.add(NodeGraphMessage::SendGraph); + } + NodeGraphMessage::SetDisplayNameImpl { node_id, alias } => { + network_interface.set_display_name(&node_id, alias, selection_network_path); + } + NodeGraphMessage::SetImportExportName { name, index } => { + responses.add(DocumentMessage::StartTransaction); + responses.add(NodeGraphMessage::SetImportExportNameImpl { name, index }); + responses.add(DocumentMessage::EndTransaction); + responses.add(NodeGraphMessage::UpdateImportsExports); + } + NodeGraphMessage::SetImportExportNameImpl { name, index } => network_interface.set_import_export_name(name, index, breadcrumb_network_path), + NodeGraphMessage::TogglePreview { node_id } => { + responses.add(DocumentMessage::AddTransaction); + responses.add(NodeGraphMessage::TogglePreviewImpl { node_id }); + responses.add(NodeGraphMessage::UpdateActionButtons); + responses.add(NodeGraphMessage::RunDocumentGraph); + } + NodeGraphMessage::TogglePreviewImpl { node_id } => { + network_interface.toggle_preview(node_id, selection_network_path); + } + NodeGraphMessage::ToggleSelectedLocked => { + let Some(selected_nodes) = network_interface.selected_nodes_in_nested_network(selection_network_path) else { + log::error!("Could not get selected nodes in NodeGraphMessage::ToggleSelectedLocked"); + return; + }; + let node_ids = selected_nodes.selected_nodes().cloned().collect::>(); + + // If any of the selected layers are locked, show them all. Otherwise, hide them all. + let locked = !node_ids.iter().all(|node_id| network_interface.is_locked(node_id, selection_network_path)); + + responses.add(DocumentMessage::AddTransaction); + + for node_id in &node_ids { + responses.add(NodeGraphMessage::SetLocked { node_id: *node_id, locked }); + } + + responses.add(NodeGraphMessage::SetLockedOrVisibilitySideEffects { node_ids }) + } + NodeGraphMessage::ToggleLocked { node_id } => { + let Some(node_metadata) = network_interface.document_network_metadata().persistent_metadata.node_metadata.get(&node_id) else { + log::error!("Cannot get node {:?} in NodeGraphMessage::ToggleLocked", node_id); + return; + }; + + let locked = !node_metadata.persistent_metadata.locked; + + responses.add(DocumentMessage::AddTransaction); + responses.add(NodeGraphMessage::SetLocked { node_id, locked }); + responses.add(NodeGraphMessage::SetLockedOrVisibilitySideEffects { node_ids: vec![node_id] }) + } + NodeGraphMessage::SetLocked { node_id, locked } => { + network_interface.set_locked(&node_id, selection_network_path, locked); + } + NodeGraphMessage::ToggleSelectedIsPinned => { + let Some(selected_nodes) = network_interface.selected_nodes_in_nested_network(selection_network_path) else { + log::error!("Could not get selected nodes in NodeGraphMessage::ToggleSelectedIsPinned"); + return; + }; + let node_ids = selected_nodes.selected_nodes().cloned().collect::>(); + + // If any of the selected nodes are pinned, unpin them all. Otherwise, pin them all. + let pinned = !node_ids.iter().all(|node_id| network_interface.is_pinned(node_id, breadcrumb_network_path)); + + responses.add(DocumentMessage::AddTransaction); + for node_id in &node_ids { + responses.add(NodeGraphMessage::SetPinned { node_id: *node_id, pinned }); + } + responses.add(NodeGraphMessage::SetLockedOrVisibilitySideEffects { node_ids }); + } + NodeGraphMessage::ToggleSelectedVisibility => { + let Some(selected_nodes) = network_interface.selected_nodes_in_nested_network(selection_network_path) else { + log::error!("Could not get selected nodes in NodeGraphMessage::ToggleSelectedLocked"); + return; + }; + let node_ids = selected_nodes.selected_nodes().cloned().collect::>(); + + // If any of the selected nodes are hidden, show them all. Otherwise, hide them all. + let visible = !node_ids.iter().all(|node_id| network_interface.is_visible(node_id, selection_network_path)); + + responses.add(DocumentMessage::AddTransaction); + for node_id in &node_ids { + responses.add(NodeGraphMessage::SetVisibility { node_id: *node_id, visible }); + } + responses.add(NodeGraphMessage::SetLockedOrVisibilitySideEffects { node_ids }); + } + NodeGraphMessage::ToggleVisibility { node_id } => { + let visible = !network_interface.is_visible(&node_id, selection_network_path); + + responses.add(DocumentMessage::AddTransaction); + responses.add(NodeGraphMessage::SetVisibility { node_id, visible }); + responses.add(NodeGraphMessage::SetLockedOrVisibilitySideEffects { node_ids: vec![node_id] }); + } + NodeGraphMessage::SetPinned { node_id, pinned } => { + network_interface.set_pinned(&node_id, selection_network_path, pinned); + } + NodeGraphMessage::SetVisibility { node_id, visible } => { + network_interface.set_visibility(&node_id, selection_network_path, visible); + } + NodeGraphMessage::SetLockedOrVisibilitySideEffects { node_ids } => { + if node_ids.iter().any(|node_id| network_interface.connected_to_output(node_id, selection_network_path)) { + responses.add(NodeGraphMessage::RunDocumentGraph); + } + responses.add(NodeGraphMessage::UpdateActionButtons); + responses.add(NodeGraphMessage::SendGraph); + + responses.add(PropertiesPanelMessage::Refresh); + } + NodeGraphMessage::UpdateBoxSelection => { + if let Some((box_selection_start, _)) = self.box_selection_start { + // The mouse button was released but we missed the pointer up event + // if ((e.buttons & 1) === 0) { + // completeBoxSelection(); + // boxSelection = undefined; + // } else if ((e.buttons & 2) !== 0) { + // editor.handle.selectNodes(new BigUint64Array(previousSelection)); + // boxSelection = undefined; + // } + + let Some(network_metadata) = network_interface.network_metadata(selection_network_path) else { + log::error!("Could not get network metadata in UpdateBoxSelection"); + return; + }; + + let box_selection_start_viewport = network_metadata.persistent_metadata.navigation_metadata.node_graph_to_viewport.transform_point2(box_selection_start); + + let box_selection = Some(BoxSelection { + start_x: box_selection_start_viewport.x.max(0.) as u32, + start_y: box_selection_start_viewport.y.max(0.) as u32, + end_x: ipp.mouse.position.x.max(0.) as u32, + end_y: ipp.mouse.position.y.max(0.) as u32, + }); + let box_selection_end_graph = network_metadata + .persistent_metadata + .navigation_metadata + .node_graph_to_viewport + .inverse() + .transform_point2(ipp.mouse.position); + + let shift = ipp.keyboard.get(Key::Shift as usize); + let Some(selected_nodes) = network_interface.selected_nodes_in_nested_network(selection_network_path) else { + log::error!("Could not get selected nodes in PointerMove"); + return; + }; + let previous_selection = selected_nodes.selected_nodes_ref().iter().cloned().collect::>(); + let mut nodes = if shift { + selected_nodes.selected_nodes_ref().iter().cloned().collect::>() + } else { + HashSet::new() + }; + let all_nodes = network_metadata.persistent_metadata.node_metadata.keys().cloned().collect::>(); + for node_id in all_nodes { + let Some(click_targets) = network_interface.node_click_targets(&node_id, selection_network_path) else { + log::error!("Could not get transient metadata for node {node_id}"); + continue; + }; + let quad = Quad::from_box([box_selection_start, box_selection_end_graph]); + if click_targets.node_click_target.intersect_path(|| quad.bezier_lines(), DAffine2::IDENTITY) { + nodes.insert(node_id); + } + } + if nodes != previous_selection { + responses.add(NodeGraphMessage::SelectedNodesSet { + nodes: nodes.into_iter().collect::>(), + }); + } + responses.add(FrontendMessage::UpdateBox { box_selection }) + } + } + NodeGraphMessage::UpdateImportsExports => { + let imports = network_interface.frontend_imports(breadcrumb_network_path).unwrap_or_default(); + let exports = network_interface.frontend_exports(breadcrumb_network_path).unwrap_or_default(); + let add_import = network_interface + .frontend_import_export_modify( + |modify_import_export_click_target| modify_import_export_click_target.add_import_export.output_ports().collect::>(), + breadcrumb_network_path, + ) + .into_iter() + .next(); + let add_export = network_interface + .frontend_import_export_modify( + |modify_import_export_click_target| modify_import_export_click_target.add_import_export.input_ports().collect::>(), + breadcrumb_network_path, + ) + .into_iter() + .next(); + responses.add(NodeGraphMessage::UpdateVisibleNodes); + responses.add(NodeGraphMessage::SendWires); + responses.add(FrontendMessage::UpdateImportsExports { + imports, + exports, + add_import, + add_export, + }); + } + + NodeGraphMessage::UpdateLayerPanel => { + Self::update_layer_panel(network_interface, selection_network_path, collapsed, responses); + } + NodeGraphMessage::UpdateEdges => { + // Update the import/export UI edges whenever the PTZ changes or the bounding box of all nodes changes + } + NodeGraphMessage::UpdateNewNodeGraph => { + let Some(selected_nodes) = network_interface.selected_nodes_mut(selection_network_path) else { + log::error!("Could not get selected nodes in NodeGraphMessage::UpdateNewNodeGraph"); + return; + }; + selected_nodes.clear_selected_nodes(); + responses.add(BroadcastEvent::SelectionChanged); + + responses.add(NodeGraphMessage::SendGraph); + } + NodeGraphMessage::UpdateTypes { resolved_types, node_graph_errors } => { + for (path, node_type) in resolved_types.add { + network_interface.resolved_types.types.insert(path.to_vec(), node_type); + } + for path in resolved_types.remove { + network_interface.resolved_types.types.remove(&path.to_vec()); + } + self.node_graph_errors = node_graph_errors; + } + NodeGraphMessage::UpdateActionButtons => { + if selection_network_path == breadcrumb_network_path { + self.update_graph_bar_left(network_interface, breadcrumb_network_path, responses); + self.send_node_bar_layout(responses); + } + } + NodeGraphMessage::UpdateGraphBarRight => { + self.update_graph_bar_right(graph_fade_artwork_percentage, network_interface, breadcrumb_network_path, navigation_handler); + self.send_node_bar_layout(responses); + } + NodeGraphMessage::UpdateInSelectedNetwork => responses.add(FrontendMessage::UpdateInSelectedNetwork { + in_selected_network: selection_network_path == breadcrumb_network_path, + }), + NodeGraphMessage::UpdateHints => { + self.update_node_graph_hints(responses); + } + NodeGraphMessage::SendSelectedNodes => { + let Some(selected_nodes) = network_interface.selected_nodes_in_nested_network(breadcrumb_network_path) else { + log::error!("Could not get selected nodes in NodeGraphMessage::SendSelectedNodes"); + return; + }; + responses.add(NodeGraphMessage::UpdateActionButtons); + responses.add(FrontendMessage::UpdateNodeGraphSelection { + selected: selected_nodes.selected_nodes().cloned().collect::>(), + }); + } + } + let Some(selected_nodes) = network_interface.selected_nodes_in_nested_network(selection_network_path) else { + log::error!("Could not get selected nodes in NodeGraphMessageHandler"); + return; + }; + self.has_selection = selected_nodes.has_selected_nodes(); + } + + fn actions(&self) -> ActionList { + let common = vec![]; + common + } +} + +impl NodeGraphMessageHandler { + /// Similar to [`NodeGraphMessageHandler::actions`], but this provides additional actions if the node graph is open and should only be called in that circumstance. + pub fn actions_additional_if_node_graph_is_open(&self) -> ActionList { + let mut common = actions!(NodeGraphMessageDiscriminant; EnterNestedNetwork, PointerDown, PointerMove, PointerUp, SendClickTargets, EndSendClickTargets); + + if self.has_selection { + common.extend(actions!(NodeGraphMessageDiscriminant; + Copy, + Cut, + DeleteSelectedNodes, + DuplicateSelectedNodes, + MergeSelectedNodes, + ToggleSelectedAsLayersOrNodes, + ToggleSelectedLocked, + ToggleSelectedVisibility, + ShiftSelectedNodes, + )); + } + + common + } + + /// Send the cached layout to the frontend for the control bar at the top of the node panel + fn send_node_bar_layout(&self, responses: &mut VecDeque) { + responses.add(LayoutMessage::SendLayout { + layout: Layout::WidgetLayout(WidgetLayout::new(self.widgets.to_vec())), + layout_target: LayoutTarget::NodeGraphControlBar, + }); + } + + /// Updates the buttons for visibility, locked, and preview + fn update_graph_bar_left(&mut self, network_interface: &mut NodeNetworkInterface, breadcrumb_network_path: &[NodeId], responses: &mut VecDeque) { + let Some(subgraph_path_names) = Self::collect_subgraph_names(network_interface, breadcrumb_network_path) else { + // If a node in a nested network could not be found, exit the nested network + let breadcrumb_network_path_len = breadcrumb_network_path.len(); + if breadcrumb_network_path_len > 0 { + responses.add(DocumentMessage::ExitNestedNetwork { + steps_back: breadcrumb_network_path_len, + }); + } + return; + }; + + let Some(network) = network_interface.nested_network(breadcrumb_network_path) else { + warn!("No network in update_selection_action_buttons"); + return; + }; + + let Some(selected_nodes) = network_interface.selected_nodes_in_nested_network(breadcrumb_network_path) else { + warn!("No selected nodes in update_selection_action_buttons"); + return; + }; + + let has_selection = selected_nodes.has_selected_nodes(); + let selection_includes_layers = network_interface.selected_nodes().selected_layers(network_interface.document_metadata()).count() > 0; + let selection_all_locked = network_interface.selected_nodes().selected_unlocked_layers(network_interface).count() == 0; + let selection_all_visible = selected_nodes.selected_nodes().all(|node_id| network_interface.is_visible(node_id, breadcrumb_network_path)); + + let mut widgets = vec![ + PopoverButton::new() + .icon(Some("Node".to_string())) + .tooltip("New Node (Right Click)") + .popover_layout({ + let node_chooser = NodeCatalog::new() + .on_update(move |node_type| { + let node_id = NodeId::new(); + + Message::Batched(Box::new([ + NodeGraphMessage::CreateNodeFromContextMenu { + node_id: Some(node_id), + node_type: node_type.clone(), + xy: None, + add_transaction: true, + } + .into(), + NodeGraphMessage::SelectedNodesSet { nodes: vec![node_id] }.into(), + ])) + }) + .widget_holder(); + vec![LayoutGroup::Row { widgets: vec![node_chooser] }] + }) + .widget_holder(), + // + Separator::new(SeparatorType::Unrelated).widget_holder(), + // + IconButton::new("Folder", 24) + .tooltip("Group Selected") + .tooltip_shortcut(action_keys!(DocumentMessageDiscriminant::GroupSelectedLayers)) + .on_update(|_| { + let group_folder_type = GroupFolderType::Layer; + DocumentMessage::GroupSelectedLayers { group_folder_type }.into() + }) + .disabled(!has_selection) + .widget_holder(), + IconButton::new("NewLayer", 24) + .tooltip("New Layer") + .tooltip_shortcut(action_keys!(DocumentMessageDiscriminant::CreateEmptyFolder)) + .on_update(|_| DocumentMessage::CreateEmptyFolder.into()) + .widget_holder(), + IconButton::new("Trash", 24) + .tooltip("Delete Selected") + .tooltip_shortcut(action_keys!(DocumentMessageDiscriminant::DeleteSelectedLayers)) + .on_update(|_| DocumentMessage::DeleteSelectedLayers.into()) + .disabled(!has_selection) + .widget_holder(), + // + Separator::new(SeparatorType::Unrelated).widget_holder(), + // + IconButton::new(if selection_all_locked { "PadlockLocked" } else { "PadlockUnlocked" }, 24) + .hover_icon(Some((if selection_all_locked { "PadlockUnlocked" } else { "PadlockLocked" }).into())) + .tooltip(if selection_all_locked { "Unlock Selected" } else { "Lock Selected" }) + .tooltip_shortcut(action_keys!(NodeGraphMessageDiscriminant::ToggleSelectedLocked)) + .on_update(|_| NodeGraphMessage::ToggleSelectedLocked.into()) + .disabled(!has_selection || !selection_includes_layers) + .widget_holder(), + IconButton::new(if selection_all_visible { "EyeVisible" } else { "EyeHidden" }, 24) + .hover_icon(Some((if selection_all_visible { "EyeHide" } else { "EyeShow" }).into())) + .tooltip(if selection_all_visible { "Hide Selected" } else { "Show Selected" }) + .tooltip_shortcut(action_keys!(NodeGraphMessageDiscriminant::ToggleSelectedVisibility)) + .on_update(|_| NodeGraphMessage::ToggleSelectedVisibility.into()) + .disabled(!has_selection) + .widget_holder(), + ]; + + let mut selection = selected_nodes.selected_nodes(); + let (selection, no_other_selections) = (selection.next(), selection.count() == 0); + let previewing = if matches!(network_interface.previewing(breadcrumb_network_path), Previewing::Yes { .. }) { + network.exports.iter().find_map(|export| { + let NodeInput::Node { node_id, .. } = export else { return None }; + Some(*node_id) + }) + } else { + None + }; + + // If only one node is selected then show the preview or stop previewing button + if let Some(node_id) = previewing { + let button = TextButton::new("End Preview") + .icon(Some("FrameAll".to_string())) + .tooltip("Restore preview to the graph output") + .on_update(move |_| NodeGraphMessage::TogglePreview { node_id }.into()) + .widget_holder(); + widgets.extend([Separator::new(SeparatorType::Unrelated).widget_holder(), button]); + } else if let Some(&node_id) = selection { + let selection_is_not_already_the_output = !network + .exports + .iter() + .any(|export| matches!(export, NodeInput::Node { node_id: export_node_id, .. } if *export_node_id == node_id)); + if selection_is_not_already_the_output && no_other_selections { + let button = TextButton::new("Preview") + .icon(Some("FrameAll".to_string())) + .tooltip("Preview selected node/layer (Shortcut: Alt-click node/layer)") + .on_update(move |_| NodeGraphMessage::TogglePreview { node_id }.into()) + .widget_holder(); + widgets.extend([Separator::new(SeparatorType::Unrelated).widget_holder(), button]); + } + } + + let subgraph_path_names_length = subgraph_path_names.len(); + if subgraph_path_names_length >= 2 { + widgets.extend([ + Separator::new(SeparatorType::Unrelated).widget_holder(), + BreadcrumbTrailButtons::new(subgraph_path_names) + .on_update(move |index| { + DocumentMessage::ExitNestedNetwork { + steps_back: subgraph_path_names_length - (*index as usize) - 1, + } + .into() + }) + .widget_holder(), + ]); + } + + self.widgets[0] = LayoutGroup::Row { widgets }; + } + + fn update_graph_bar_right( + &mut self, + graph_fade_artwork_percentage: f64, + network_interface: &NodeNetworkInterface, + breadcrumb_network_path: &[NodeId], + navigation_handler: &NavigationMessageHandler, + ) { + let Some(node_graph_ptz) = network_interface.node_graph_ptz(breadcrumb_network_path) else { + log::error!("Could not get node graph PTZ"); + return; + }; + + let mut widgets = vec![ + NumberInput::new(Some(graph_fade_artwork_percentage)) + .percentage() + .display_decimal_places(0) + .label("Fade Artwork") + .tooltip("Opacity of the graph background that covers the artwork") + .on_update(move |number_input: &NumberInput| { + DocumentMessage::SetGraphFadeArtwork { + percentage: number_input.value.unwrap_or(graph_fade_artwork_percentage), + } + .into() + }) + .widget_holder(), + Separator::new(SeparatorType::Unrelated).widget_holder(), + ]; + widgets.extend(navigation_controls(node_graph_ptz, navigation_handler, true)); + widgets.extend([ + Separator::new(SeparatorType::Unrelated).widget_holder(), + TextButton::new("Node Graph") + .icon(Some("GraphViewOpen".into())) + .hover_icon(Some("GraphViewClosed".into())) + .tooltip("Hide Node Graph") + .tooltip_shortcut(action_keys!(DocumentMessageDiscriminant::GraphViewOverlayToggle)) + .on_update(move |_| DocumentMessage::GraphViewOverlayToggle.into()) + .widget_holder(), + ]); + + self.widgets[1] = LayoutGroup::Row { widgets }; + } + + /// Collate the properties panel sections for a node graph + pub fn collate_properties(context: &mut NodePropertiesContext) -> Vec { + // If the selected nodes are in the document network, use the document network. Otherwise, use the nested network + let Some(selected_nodes) = context.network_interface.selected_nodes_in_nested_network(context.selection_network_path) else { + warn!("No selected nodes in collate_properties"); + return Vec::new(); + }; + + // We want: + // - If only nodes (no layers) are selected: display each node's properties + // - If one layer is selected, and zero or more of its (primary flow) upstream nodes: display the properties for the layer and all its upstream nodes + // - If multiple layers are selected, or one node plus other non-upstream nodes: display nothing + // - If nothing is selected, display any pinned nodes/layers + + // First, we filter all the selections into layers and nodes + let (mut layers, mut nodes) = (Vec::new(), Vec::new()); + for node_id in selected_nodes.selected_nodes() { + if context.network_interface.is_layer(node_id, context.selection_network_path) { + layers.push(*node_id); + } else { + nodes.push(*node_id); + } + } + + // Next, we decide what to display based on the number of layers and nodes selected + match *layers.as_slice() { + // If no layers are selected, show properties for all selected nodes + [] => { + let selected_nodes = nodes.iter().map(|node_id| node_properties::generate_node_properties(*node_id, context)).collect::>(); + if !selected_nodes.is_empty() { + let mut properties = Vec::new(); + + if let [node_id] = *nodes.as_slice() { + properties.push(LayoutGroup::Row { + widgets: vec![ + Separator::new(SeparatorType::Related).widget_holder(), + IconLabel::new("Node").tooltip("Name of the selected node").widget_holder(), + Separator::new(SeparatorType::Related).widget_holder(), + TextInput::new(context.network_interface.display_name(&node_id, context.selection_network_path)) + .tooltip("Name of the selected node") + .on_update(move |text_input| { + NodeGraphMessage::SetDisplayName { + node_id, + alias: text_input.value.clone(), + skip_adding_history_step: false, + } + .into() + }) + .widget_holder(), + Separator::new(SeparatorType::Related).widget_holder(), + ], + }); + } + + properties.extend(selected_nodes); + + return properties; + } + + // TODO: Display properties for encapsulating node when no nodes are selected in a nested network + // This may require store a separate path for the properties panel + let mut properties = vec![LayoutGroup::Row { + widgets: vec![ + Separator::new(SeparatorType::Related).widget_holder(), + IconLabel::new("File").tooltip("Name of the current document").widget_holder(), + Separator::new(SeparatorType::Related).widget_holder(), + TextInput::new(context.document_name) + .tooltip("Name of the current document") + .on_update(|text_input| DocumentMessage::RenameDocument { new_name: text_input.value.clone() }.into()) + .widget_holder(), + Separator::new(SeparatorType::Related).widget_holder(), + ], + }]; + + let Some(network) = context.network_interface.nested_network(context.selection_network_path) else { + warn!("No network in collate_properties"); + return Vec::new(); + }; + // And if no nodes are selected, show properties for all pinned nodes + let pinned_node_properties = network + .nodes + .keys() + .cloned() + .collect::>() + .iter() + .filter_map(|node_id| { + if context.network_interface.is_pinned(node_id, context.selection_network_path) { + Some(node_properties::generate_node_properties(*node_id, context)) + } else { + None + } + }) + .collect::>(); + + properties.extend(pinned_node_properties); + properties + } + // If one layer is selected, filter out all selected nodes that are not upstream of it. If there are no nodes left, show properties for the layer. Otherwise, show nothing. + [layer] => { + let nodes_not_upstream_of_layer = nodes.into_iter().filter(|&selected_node_id| { + !context + .network_interface + .is_node_upstream_of_another_by_horizontal_flow(layer, context.selection_network_path, selected_node_id) + }); + if nodes_not_upstream_of_layer.count() > 0 { + return Vec::new(); + } + + let mut layer_properties = vec![LayoutGroup::Row { + widgets: vec![ + Separator::new(SeparatorType::Related).widget_holder(), + IconLabel::new("Layer").tooltip("Name of the selected layer").widget_holder(), + Separator::new(SeparatorType::Related).widget_holder(), + TextInput::new(context.network_interface.display_name(&layer, context.selection_network_path)) + .tooltip("Name of the selected layer") + .on_update(move |text_input| { + NodeGraphMessage::SetDisplayName { + node_id: layer, + alias: text_input.value.clone(), + skip_adding_history_step: false, + } + .into() + }) + .widget_holder(), + Separator::new(SeparatorType::Related).widget_holder(), + PopoverButton::new() + .icon(Some("Node".to_string())) + .tooltip("Add an operation to the end of this layer's chain of nodes") + .popover_layout({ + let node_chooser = NodeCatalog::new() + .on_update(move |node_type| { + NodeGraphMessage::CreateNodeInLayerWithTransaction { + node_type: node_type.clone(), + layer: LayerNodeIdentifier::new_unchecked(layer), + } + .into() + }) + .widget_holder(); + vec![LayoutGroup::Row { widgets: vec![node_chooser] }] + }) + .widget_holder(), + Separator::new(SeparatorType::Related).widget_holder(), + ], + }]; + + // Iterate through all the upstream nodes, but stop when we reach another layer (since that's a point where we switch from horizontal to vertical flow) + let node_properties = context + .network_interface + .upstream_flow_back_from_nodes(vec![layer], context.selection_network_path, network_interface::FlowType::HorizontalFlow) + .enumerate() + .take_while(|(i, node_id)| { + if *i == 0 { + true + } else { + !context.network_interface.is_layer(node_id, context.selection_network_path) + } + }) + .map(|(_, node_id)| node_id) + .collect::>() + .into_iter() + .map(|node_id| node_properties::generate_node_properties(node_id, context)) + .collect::>(); + + layer_properties.extend(node_properties); + layer_properties + } + // If multiple layers and/or nodes are selected, show nothing + _ => Vec::new(), + } + } + + fn collect_wires(&mut self, network_interface: &mut NodeNetworkInterface, graph_wire_style: GraphWireStyle, breadcrumb_network_path: &[NodeId]) -> Vec { + let mut added_wires = network_interface + .node_graph_input_connectors(breadcrumb_network_path) + .iter() + .filter_map(|connector| network_interface.newly_loaded_input_wire(connector, graph_wire_style, breadcrumb_network_path)) + .collect::>(); + + let changed_wire_inputs = added_wires.iter().map(|update| (update.id, update.input_index)).collect::>(); + self.frontend_wires.extend(changed_wire_inputs); + + let mut orphaned_wire_inputs = self.frontend_wires.clone(); + self.frontend_wires = network_interface + .node_graph_wire_inputs(breadcrumb_network_path) + .iter() + .filter_map(|visible_wire_input| orphaned_wire_inputs.take(visible_wire_input)) + .collect::>(); + added_wires.extend(orphaned_wire_inputs.into_iter().map(|(id, input_index)| WirePathUpdate { + id, + input_index, + wire_path_update: None, + })); + + if let Some(wire_to_root) = network_interface.wire_to_root(graph_wire_style, breadcrumb_network_path) { + added_wires.push(wire_to_root); + } else { + added_wires.push(WirePathUpdate { + id: NodeId(u64::MAX), + input_index: usize::MAX, + wire_path_update: None, + }) + } + + added_wires + } + + fn collect_nodes(&self, network_interface: &mut NodeNetworkInterface, breadcrumb_network_path: &[NodeId]) -> Vec { + let Some(outward_wires) = network_interface.outward_wires(breadcrumb_network_path).cloned() else { + return Vec::new(); + }; + let mut can_be_layer_lookup = HashSet::new(); + let mut position_lookup = HashMap::new(); + let Some(network) = network_interface.nested_network(breadcrumb_network_path) else { + log::error!("Could not get nested network when collecting nodes"); + return Vec::new(); + }; + + for node_id in network.nodes.keys().cloned().collect::>() { + if network_interface.is_eligible_to_be_layer(&node_id, breadcrumb_network_path) { + can_be_layer_lookup.insert(node_id); + } + if let Some(position) = network_interface.position(&node_id, breadcrumb_network_path) { + position_lookup.insert(node_id, position); + } else { + log::error!("Could not get position for node {node_id}"); + } + } + + let mut frontend_inputs_lookup = frontend_inputs_lookup(breadcrumb_network_path, network_interface); + let Some(network) = network_interface.nested_network(breadcrumb_network_path) else { + log::error!("Could not get nested network when collecting nodes"); + return Vec::new(); + }; + let Some(network_metadata) = network_interface.network_metadata(breadcrumb_network_path) else { + log::error!("Could not get network_metadata when collecting nodes"); + return Vec::new(); + }; + + let mut nodes = Vec::new(); + for (&node_id, node) in &network.nodes { + let node_id_path = [breadcrumb_network_path, (&[node_id])].concat(); + + let inputs = frontend_inputs_lookup.remove(&node_id).unwrap_or_default(); + + let mut inputs = inputs.into_iter().map(|input| { + input.map(|input| FrontendGraphInput { + data_type: FrontendGraphDataType::displayed_type(&input.ty, &input.type_source), + resolved_type: format!("{:?}", &input.ty), + valid_types: input.valid_types.iter().map(|ty| ty.to_string()).collect(), + name: input.input_name, + description: input.input_description, + connected_to: input.output_connector, + }) + }); + + let primary_input = inputs.next().flatten(); + let exposed_inputs = inputs.flatten().collect(); + + let (output_type, type_source) = network_interface.output_type(&node_id, 0, breadcrumb_network_path); + let frontend_data_type = FrontendGraphDataType::displayed_type(&output_type, &type_source); + + let connected_to = outward_wires.get(&OutputConnector::node(node_id, 0)).cloned().unwrap_or_default(); + let primary_output = if network_interface.has_primary_output(&node_id, breadcrumb_network_path) { + Some(FrontendGraphOutput { + data_type: frontend_data_type, + name: "Output 1".to_string(), + description: String::new(), + resolved_type: format!("{:?}", output_type), + connected_to, + }) + } else { + None + }; + + let mut exposed_outputs = Vec::new(); + for output_index in 0..network_interface.number_of_outputs(&node_id, breadcrumb_network_path) { + if output_index == 0 && network_interface.has_primary_output(&node_id, breadcrumb_network_path) { + continue; + } + let (output_type, type_source) = network_interface.output_type(&node_id, 0, breadcrumb_network_path); + let data_type = FrontendGraphDataType::displayed_type(&output_type, &type_source); + + let Some(node_metadata) = network_metadata.persistent_metadata.node_metadata.get(&node_id) else { + log::error!("Could not get node_metadata when getting output for {node_id}"); + continue; + }; + let output_name = node_metadata + .persistent_metadata + .output_names + .get(output_index) + .cloned() + .filter(|output_name| !output_name.is_empty()) + .unwrap_or_else(|| output_type.nested_type().to_string()); + + let connected_to = outward_wires.get(&OutputConnector::node(node_id, output_index)).cloned().unwrap_or_default(); + exposed_outputs.push(FrontendGraphOutput { + data_type, + name: output_name, + description: String::new(), + resolved_type: format!("{:?}", output_type), + connected_to, + }); + } + let Some(network) = network_interface.nested_network(breadcrumb_network_path) else { + log::error!("Could not get nested network when collecting nodes"); + return Vec::new(); + }; + let is_export = network.exports.first().is_some_and(|export| export.as_node().is_some_and(|export_node_id| node_id == export_node_id)); + let is_root_node = network_interface.root_node(breadcrumb_network_path).is_some_and(|root_node| root_node.node_id == node_id); + + let Some(position) = position_lookup.get(&node_id).map(|pos| (pos.x, pos.y)) else { + log::error!("Could not get position for node: {node_id}"); + continue; + }; + let previewed = is_export && !is_root_node; + + let locked = network_interface.is_locked(&node_id, breadcrumb_network_path); + + let errors = self + .node_graph_errors + .iter() + .find(|error| error.node_path == node_id_path) + .map(|error| format!("{:?}", error.error.clone())) + .or_else(|| { + if self.node_graph_errors.iter().any(|error| error.node_path.starts_with(&node_id_path)) { + Some("Node graph type error within this node".to_string()) + } else { + None + } + }); + + nodes.push(FrontendNode { + id: node_id, + is_layer: network_interface + .node_metadata(&node_id, breadcrumb_network_path) + .is_some_and(|node_metadata| node_metadata.persistent_metadata.is_layer()), + can_be_layer: can_be_layer_lookup.contains(&node_id), + reference: network_interface.reference(&node_id, breadcrumb_network_path).cloned().unwrap_or_default(), + display_name: network_interface.display_name(&node_id, breadcrumb_network_path), + primary_input, + exposed_inputs, + primary_output, + exposed_outputs, + position, + previewed, + visible: node.visible, + locked, + errors, + ui_only: false, + }); + } + + nodes + } + + fn collect_subgraph_names(network_interface: &mut NodeNetworkInterface, breadcrumb_network_path: &[NodeId]) -> Option> { + let mut current_network_path = vec![]; + let mut current_network = network_interface.nested_network(¤t_network_path).unwrap(); + let mut subgraph_names = vec!["Document".to_string()]; + for node_id in breadcrumb_network_path { + let node = current_network.nodes.get(node_id)?; + if let Some(network) = node.implementation.get_network() { + current_network = network; + }; + subgraph_names.push(network_interface.display_name(node_id, ¤t_network_path)); + current_network_path.push(*node_id) + } + Some(subgraph_names) + } + + fn update_layer_panel(network_interface: &NodeNetworkInterface, selection_network_path: &[NodeId], collapsed: &CollapsedLayers, responses: &mut VecDeque) { + let selected_layers = network_interface + .selected_nodes() + .selected_layers(network_interface.document_metadata()) + .map(|layer| layer.to_node()) + .collect::>(); + + let mut ancestors_of_selected = HashSet::new(); + let mut descendants_of_selected = HashSet::new(); + for selected_layer in &selected_layers { + for ancestor in LayerNodeIdentifier::new(*selected_layer, network_interface, &[]).ancestors(network_interface.document_metadata()) { + if ancestor != LayerNodeIdentifier::ROOT_PARENT && ancestor.to_node() != *selected_layer { + ancestors_of_selected.insert(ancestor.to_node()); + } + } + for descendant in LayerNodeIdentifier::new(*selected_layer, network_interface, &[]).descendants(network_interface.document_metadata()) { + descendants_of_selected.insert(descendant.to_node()); + } + } + + for (&node_id, node_metadata) in &network_interface.document_network_metadata().persistent_metadata.node_metadata { + if node_metadata.persistent_metadata.is_layer() { + let layer = LayerNodeIdentifier::new(node_id, network_interface, &[]); + + let children_allowed = + // The layer has other layers as children along the secondary input's horizontal flow + layer.has_children(network_interface.document_metadata()) + || ( + // Check if the last node in the chain has an exposed left input + network_interface.upstream_flow_back_from_nodes(vec![node_id], &[], network_interface::FlowType::HorizontalFlow).last().is_some_and(|node_id| + network_interface.document_node(&node_id, &[]).map_or_else(||{log::error!("Could not get node {node_id} in update_layer_panel"); false}, |node| { + if network_interface.is_layer(&node_id, &[]) { + node.inputs.iter().filter(|input| input.is_exposed()).nth(1).is_some_and(|input| input.as_value().is_some()) + } else { + node.inputs.iter().filter(|input| input.is_exposed()).nth(0).is_some_and(|input| input.as_value().is_some()) + } + })) + ); + + let parents_visible = layer.ancestors(network_interface.document_metadata()).filter(|&ancestor| ancestor != layer).all(|layer| { + if layer != LayerNodeIdentifier::ROOT_PARENT { + network_interface.document_node(&layer.to_node(), &[]).map(|node| node.visible).unwrap_or_default() + } else { + true + } + }); + + let parents_unlocked: bool = layer.ancestors(network_interface.document_metadata()).filter(|&ancestor| ancestor != layer).all(|layer| { + if layer != LayerNodeIdentifier::ROOT_PARENT { + !network_interface.is_locked(&layer.to_node(), &[]) + } else { + true + } + }); + + let clippable = layer.can_be_clipped(network_interface.document_metadata()); + let data = LayerPanelEntry { + id: node_id, + alias: network_interface.display_name(&node_id, &[]), + tooltip: if cfg!(debug_assertions) { format!("Layer ID: {node_id}") } else { "".into() }, + in_selected_network: selection_network_path.is_empty(), + children_allowed, + children_present: layer.has_children(network_interface.document_metadata()), + expanded: layer.has_children(network_interface.document_metadata()) && !collapsed.0.contains(&layer), + depth: layer.ancestors(network_interface.document_metadata()).count() - 1, + visible: network_interface.is_visible(&node_id, &[]), + parents_visible, + unlocked: !network_interface.is_locked(&node_id, &[]), + parents_unlocked, + parent_id: layer + .parent(network_interface.document_metadata()) + .and_then(|parent| if parent != LayerNodeIdentifier::ROOT_PARENT { Some(parent.to_node()) } else { None }), + selected: selected_layers.contains(&node_id), + ancestor_of_selected: ancestors_of_selected.contains(&node_id), + descendant_of_selected: descendants_of_selected.contains(&node_id), + clipped: get_clip_mode(layer, network_interface).unwrap_or(false) && clippable, + clippable, + }; + responses.add(FrontendMessage::UpdateDocumentLayerDetails { data }); + } + } + } + + pub fn update_node_graph_hints(&self, responses: &mut VecDeque) { + // A wire is in progress and its start and end connectors are set + let wiring = self.wire_in_progress_from_connector.is_some(); + + // Node gragging is in progress (having already moved at least one pixel from the mouse down position) + let dragging_nodes = self.drag_start.as_ref().is_some_and(|(_, dragged)| *dragged); + + // A box selection is in progress + let dragging_box_selection = self.box_selection_start.is_some_and(|(_, box_selection_dragged)| box_selection_dragged); + + // Cancel the ongoing action + if wiring || dragging_nodes || dragging_box_selection { + let hint_data = HintData(vec![HintGroup(vec![HintInfo::mouse(MouseMotion::Rmb, ""), HintInfo::keys([Key::Escape], "Cancel").prepend_slash()])]); + responses.add(FrontendMessage::UpdateInputHints { hint_data }); + return; + } + + // Default hints for all other states + let mut hint_data = HintData(vec![ + HintGroup(vec![HintInfo::mouse(MouseMotion::Rmb, "Add Node")]), + HintGroup(vec![HintInfo::mouse(MouseMotion::Lmb, "Select Node"), HintInfo::keys([Key::Shift], "Extend").prepend_plus()]), + HintGroup(vec![HintInfo::mouse(MouseMotion::LmbDrag, "Select Area"), HintInfo::keys([Key::Shift], "Extend").prepend_plus()]), + ]); + if self.has_selection { + hint_data.0.extend([ + HintGroup(vec![HintInfo::mouse(MouseMotion::LmbDrag, "Drag Selected")]), + HintGroup(vec![HintInfo::keys([Key::Delete], "Delete Selected"), HintInfo::keys([Key::Control], "Keep Children").prepend_plus()]), + HintGroup(vec![ + HintInfo::keys_and_mouse([Key::Alt], MouseMotion::LmbDrag, "Move Duplicate"), + HintInfo::keys([Key::Control, Key::KeyD], "Duplicate").add_mac_keys([Key::Command, Key::KeyD]), + ]), + ]); + } + hint_data.0.extend([ + HintGroup(vec![HintInfo::mouse(MouseMotion::LmbDouble, "Enter Node Subgraph")]), + HintGroup(vec![HintInfo::keys_and_mouse([Key::Alt], MouseMotion::Lmb, "Preview Node Output")]), + ]); + responses.add(FrontendMessage::UpdateInputHints { hint_data }); + } +} + +#[derive(Default)] +struct InputLookup { + input_name: String, + input_description: String, + ty: Type, + type_source: TypeSource, + valid_types: Vec, + output_connector: Option, +} + +type FrontendInputsLookup = HashMap>>; + +/// Create a lookup hashmap that can be used to create the frontend inputs. This is needed because `input_type` requires a mutable `network_interface`. +fn frontend_inputs_lookup(breadcrumb_network_path: &[NodeId], network_interface: &mut NodeNetworkInterface) -> FrontendInputsLookup { + let Some(network) = network_interface.nested_network(breadcrumb_network_path) else { + return Default::default(); + }; + let mut frontend_inputs_lookup = HashMap::new(); + for (node_id, index, output_connector, is_exposed) in network + .nodes + .iter() + .flat_map(|(node_id, node)| { + node.inputs + .iter() + .enumerate() + .map(|(index, input)| (*node_id, index, OutputConnector::from_input(input), input.is_exposed())) + }) + .collect::>() + { + // Skip not exposed inputs (they still get an entry to help with finding the primary input) + let lookup = if !is_exposed { + None + } else { + // Get the name from the metadata here (since it also requires a reference to the `network_interface`) + let (input_name, input_description) = network_interface.displayed_input_name_and_description(&node_id, index, breadcrumb_network_path); + Some(InputLookup { + input_name, + input_description, + output_connector, + ..Default::default() + }) + }; + frontend_inputs_lookup.entry(node_id).or_insert_with(Vec::new).push(lookup); + } + + for (&node_id, value) in frontend_inputs_lookup.iter_mut() { + for (index, value) in value.iter_mut().enumerate() { + // Skip not exposed inputs for efficiency + let Some(value) = value else { continue }; + // Resolve the type (done in a separate loop because it requires a mutable reference to the `network_interface`) + let (ty, type_source) = network_interface.input_type(&InputConnector::node(node_id, index), breadcrumb_network_path); + value.ty = ty; + value.type_source = type_source; + } + } + + for (&node_id, value) in frontend_inputs_lookup.iter_mut() { + for (index, value) in value.iter_mut().enumerate() { + // Skip not exposed inputs for efficiency + let Some(value) = value else { continue }; + // Resolve the type (done in a separate loop because it requires a mutable reference to the `network_interface`) + value.valid_types = network_interface.valid_input_types(&InputConnector::node(node_id, index), breadcrumb_network_path); + } + } + frontend_inputs_lookup +} + +impl Default for NodeGraphMessageHandler { + fn default() -> Self { + Self { + network: Vec::new(), + node_graph_errors: Vec::new(), + has_selection: false, + widgets: [LayoutGroup::Row { widgets: Vec::new() }, LayoutGroup::Row { widgets: Vec::new() }], + drag_start: None, + begin_dragging: false, + node_has_moved_in_drag: false, + shift_without_push: false, + box_selection_start: None, + selection_before_pointer_down: Vec::new(), + disconnecting: None, + initial_disconnecting: false, + select_if_not_dragged: None, + wire_in_progress_from_connector: None, + wire_in_progress_to_connector: None, + wire_in_progress_type: FrontendGraphDataType::General, + context_menu: None, + deselect_on_pointer_up: None, + auto_panning: Default::default(), + preview_on_mouse_up: None, + reordering_export: None, + reordering_import: None, + end_index: None, + frontend_nodes: Vec::new(), + frontend_wires: HashSet::new(), + } + } +} + +impl PartialEq for NodeGraphMessageHandler { + fn eq(&self, other: &Self) -> bool { + self.network == other.network + && self.node_graph_errors == other.node_graph_errors + && self.has_selection == other.has_selection + && self.widgets == other.widgets + && self.drag_start == other.drag_start + && self.begin_dragging == other.begin_dragging + && self.node_has_moved_in_drag == other.node_has_moved_in_drag + && self.box_selection_start == other.box_selection_start + && self.initial_disconnecting == other.initial_disconnecting + && self.select_if_not_dragged == other.select_if_not_dragged + && self.wire_in_progress_from_connector == other.wire_in_progress_from_connector + && self.wire_in_progress_to_connector == other.wire_in_progress_to_connector + && self.context_menu == other.context_menu + } +} diff --git a/editor/src/messages/portfolio/document/node_graph/node_properties.rs b/editor/src/messages/portfolio/document/node_graph/node_properties.rs new file mode 100644 index 0000000000000000000000000000000000000000..bc40dd36e4ddab0bc2ac4686cee9bc118000c4b5 --- /dev/null +++ b/editor/src/messages/portfolio/document/node_graph/node_properties.rs @@ -0,0 +1,2041 @@ +#![allow(clippy::too_many_arguments)] + +use super::document_node_definitions::{NODE_OVERRIDES, NodePropertiesContext}; +use super::utility_types::FrontendGraphDataType; +use crate::messages::layout::utility_types::widget_prelude::*; +use crate::messages::portfolio::document::utility_types::network_interface::InputConnector; +use crate::messages::prelude::*; +use choice::enum_choice; +use dyn_any::DynAny; +use glam::{DAffine2, DVec2, IVec2, UVec2}; +use graph_craft::Type; +use graph_craft::document::value::TaggedValue; +use graph_craft::document::{DocumentNode, DocumentNodeImplementation, NodeId, NodeInput}; +use graphene_std::animation::RealTimeMode; +use graphene_std::extract_xy::XY; +use graphene_std::path_bool::BooleanOperation; +use graphene_std::raster::curve::Curve; +use graphene_std::raster::{ + BlendMode, CellularDistanceFunction, CellularReturnType, Color, DomainWarpType, FractalType, LuminanceCalculation, NoiseType, RedGreenBlue, RedGreenBlueAlpha, RelativeAbsolute, + SelectiveColorChoice, +}; +use graphene_std::raster_types::{CPU, GPU, RasterDataTable}; +use graphene_std::text::Font; +use graphene_std::transform::{Footprint, ReferencePoint}; +use graphene_std::vector::VectorDataTable; +use graphene_std::vector::misc::GridType; +use graphene_std::vector::misc::{ArcType, MergeByDistanceAlgorithm}; +use graphene_std::vector::misc::{CentroidType, PointSpacingType}; +use graphene_std::vector::style::{Fill, FillChoice, FillType, GradientStops}; +use graphene_std::vector::style::{GradientType, PaintOrder, StrokeAlign, StrokeCap, StrokeJoin}; +use graphene_std::{GraphicGroupTable, NodeInputDecleration}; + +pub(crate) fn string_properties(text: &str) -> Vec { + let widget = TextLabel::new(text).widget_holder(); + vec![LayoutGroup::Row { widgets: vec![widget] }] +} + +fn optionally_update_value(value: impl Fn(&T) -> Option + 'static + Send + Sync, node_id: NodeId, input_index: usize) -> impl Fn(&T) -> Message + 'static + Send + Sync { + move |input_value: &T| match value(input_value) { + Some(value) => NodeGraphMessage::SetInputValue { node_id, input_index, value }.into(), + _ => Message::NoOp, + } +} + +pub fn update_value(value: impl Fn(&T) -> TaggedValue + 'static + Send + Sync, node_id: NodeId, input_index: usize) -> impl Fn(&T) -> Message + 'static + Send + Sync { + optionally_update_value(move |v| Some(value(v)), node_id, input_index) +} + +pub fn commit_value(_: &T) -> Message { + DocumentMessage::AddTransaction.into() +} + +pub fn expose_widget(node_id: NodeId, index: usize, data_type: FrontendGraphDataType, exposed: bool) -> WidgetHolder { + ParameterExposeButton::new() + .exposed(exposed) + .data_type(data_type) + .tooltip(if exposed { + "Stop exposing this parameter as a node input in the graph" + } else { + "Expose this parameter as a node input in the graph" + }) + .on_update(move |_parameter| { + Message::Batched(Box::new([NodeGraphMessage::ExposeInput { + input_connector: InputConnector::node(node_id, index), + set_to_exposed: !exposed, + start_transaction: true, + } + .into()])) + }) + .widget_holder() +} + +// TODO: Remove this when we have proper entry row formatting that includes room for Assists. +pub fn add_blank_assist(widgets: &mut Vec) { + widgets.extend_from_slice(&[ + // Custom CSS specific to the Properties panel converts this Section separator into the width of an assist (24px). + Separator::new(SeparatorType::Section).widget_holder(), + // This last one is the separator after the 24px assist. + Separator::new(SeparatorType::Unrelated).widget_holder(), + ]); +} + +pub fn start_widgets(parameter_widgets_info: ParameterWidgetsInfo) -> Vec { + let ParameterWidgetsInfo { + document_node, + node_id, + index, + name, + description, + input_type, + blank_assist, + exposeable, + } = parameter_widgets_info; + + let Some(document_node) = document_node else { + log::warn!("A widget failed to be built because its document node is invalid."); + return vec![]; + }; + + let Some(input) = document_node.inputs.get(index) else { + log::warn!("A widget failed to be built because its node's input index is invalid."); + return vec![]; + }; + let description = if description != "TODO" { description } else { String::new() }; + let mut widgets = Vec::with_capacity(6); + if exposeable { + widgets.push(expose_widget(node_id, index, input_type, input.is_exposed())); + } + widgets.push(TextLabel::new(name).tooltip(description).widget_holder()); + if blank_assist { + add_blank_assist(&mut widgets); + } + + widgets +} + +pub(crate) fn property_from_type( + node_id: NodeId, + index: usize, + ty: &Type, + number_options: (Option, Option, Option<(f64, f64)>), + unit: Option<&str>, + display_decimal_places: Option, + step: Option, + context: &mut NodePropertiesContext, +) -> Result, Vec> { + let (mut number_min, mut number_max, range) = number_options; + let mut number_input = NumberInput::default(); + if let Some((range_start, range_end)) = range { + number_min = Some(range_start); + number_max = Some(range_end); + number_input = number_input.mode_range().min(range_start).max(range_end); + } + if let Some(unit) = unit { + number_input = number_input.unit(unit); + } + if let Some(display_decimal_places) = display_decimal_places { + number_input = number_input.display_decimal_places(display_decimal_places); + } + if let Some(step) = step { + number_input = number_input.step(step); + } + + let min = |x: f64| number_min.unwrap_or(x); + let max = |x: f64| number_max.unwrap_or(x); + + let default_info = ParameterWidgetsInfo::new(node_id, index, true, context); + + let mut extra_widgets = vec![]; + let widgets = match ty { + Type::Concrete(concrete_type) => { + match concrete_type.alias.as_ref().map(|x| x.as_ref()) { + // Aliased types (ambiguous values) + Some("Percentage") => number_widget(default_info, number_input.percentage().min(min(0.)).max(max(100.))).into(), + Some("SignedPercentage") => number_widget(default_info, number_input.percentage().min(min(-100.)).max(max(100.))).into(), + Some("Angle") => number_widget(default_info, number_input.mode_range().min(min(-180.)).max(max(180.)).unit(unit.unwrap_or("°"))).into(), + Some("Multiplier") => number_widget(default_info, number_input.unit(unit.unwrap_or("x"))).into(), + Some("PixelLength") => number_widget(default_info, number_input.min(min(0.)).unit(unit.unwrap_or(" px"))).into(), + Some("Length") => number_widget(default_info, number_input.min(min(0.))).into(), + Some("Fraction") => number_widget(default_info, number_input.mode_range().min(min(0.)).max(max(1.))).into(), + Some("IntegerCount") => number_widget(default_info, number_input.int().min(min(1.))).into(), + Some("SeedValue") => number_widget(default_info, number_input.int().min(min(0.))).into(), + Some("Resolution") => coordinate_widget(default_info, "W", "H", unit.unwrap_or(" px"), Some(64.)), + Some("PixelSize") => coordinate_widget(default_info, "X", "Y", unit.unwrap_or(" px"), None), + Some("TextArea") => text_area_widget(default_info).into(), + + // For all other types, use TypeId-based matching + _ => { + use std::any::TypeId; + match concrete_type.id { + // =============== + // PRIMITIVE TYPES + // =============== + Some(x) if x == TypeId::of::() => number_widget(default_info, number_input.min(min(f64::NEG_INFINITY)).max(max(f64::INFINITY))).into(), + Some(x) if x == TypeId::of::() => number_widget(default_info, number_input.int().min(min(0.)).max(max(f64::from(u32::MAX)))).into(), + Some(x) if x == TypeId::of::() => number_widget(default_info, number_input.int().min(min(0.))).into(), + Some(x) if x == TypeId::of::() => bool_widget(default_info, CheckboxInput::default()).into(), + Some(x) if x == TypeId::of::() => text_widget(default_info).into(), + Some(x) if x == TypeId::of::() => coordinate_widget(default_info, "X", "Y", "", None), + Some(x) if x == TypeId::of::() => coordinate_widget(default_info, "X", "Y", "", Some(0.)), + Some(x) if x == TypeId::of::() => coordinate_widget(default_info, "X", "Y", "", None), + // ========================== + // PRIMITIVE COLLECTION TYPES + // ========================== + Some(x) if x == TypeId::of::>() => array_of_number_widget(default_info, TextInput::default()).into(), + Some(x) if x == TypeId::of::>() => array_of_coordinates_widget(default_info, TextInput::default()).into(), + // ==================== + // GRAPHICAL DATA TYPES + // ==================== + Some(x) if x == TypeId::of::() => vector_data_widget(default_info).into(), + Some(x) if x == TypeId::of::>() || x == TypeId::of::>() => raster_widget(default_info).into(), + Some(x) if x == TypeId::of::() => group_widget(default_info).into(), + // ============ + // STRUCT TYPES + // ============ + Some(x) if x == TypeId::of::() => color_widget(default_info, ColorInput::default().allow_none(false)), + Some(x) if x == TypeId::of::>() => color_widget(default_info, ColorInput::default().allow_none(true)), + Some(x) if x == TypeId::of::() => color_widget(default_info, ColorInput::default().allow_none(false)), + Some(x) if x == TypeId::of::() => font_widget(default_info), + Some(x) if x == TypeId::of::() => curve_widget(default_info), + Some(x) if x == TypeId::of::() => footprint_widget(default_info, &mut extra_widgets), + // =============================== + // MANUALLY IMPLEMENTED ENUM TYPES + // =============================== + Some(x) if x == TypeId::of::() => reference_point_widget(default_info, false).into(), + Some(x) if x == TypeId::of::() => blend_mode_widget(default_info), + // ========================= + // AUTO-GENERATED ENUM TYPES + // ========================= + Some(x) if x == TypeId::of::() => enum_choice::().for_socket(default_info).property_row(), + Some(x) if x == TypeId::of::() => enum_choice::().for_socket(default_info).property_row(), + Some(x) if x == TypeId::of::() => enum_choice::().for_socket(default_info).property_row(), + Some(x) if x == TypeId::of::() => enum_choice::().for_socket(default_info).property_row(), + Some(x) if x == TypeId::of::() => enum_choice::().for_socket(default_info).property_row(), + Some(x) if x == TypeId::of::() => enum_choice::().for_socket(default_info).property_row(), + Some(x) if x == TypeId::of::() => enum_choice::().for_socket(default_info).property_row(), + Some(x) if x == TypeId::of::() => enum_choice::().for_socket(default_info).disabled(false).property_row(), + Some(x) if x == TypeId::of::() => enum_choice::().for_socket(default_info).disabled(false).property_row(), + Some(x) if x == TypeId::of::() => enum_choice::().for_socket(default_info).disabled(false).property_row(), + Some(x) if x == TypeId::of::() => enum_choice::().for_socket(default_info).disabled(false).property_row(), + Some(x) if x == TypeId::of::() => enum_choice::().for_socket(default_info).disabled(false).property_row(), + Some(x) if x == TypeId::of::() => enum_choice::().for_socket(default_info).property_row(), + Some(x) if x == TypeId::of::() => enum_choice::().for_socket(default_info).property_row(), + Some(x) if x == TypeId::of::() => enum_choice::().for_socket(default_info).property_row(), + Some(x) if x == TypeId::of::() => enum_choice::().for_socket(default_info).property_row(), + Some(x) if x == TypeId::of::() => enum_choice::().for_socket(default_info).property_row(), + Some(x) if x == TypeId::of::() => enum_choice::().for_socket(default_info).property_row(), + Some(x) if x == TypeId::of::() => enum_choice::().for_socket(default_info).property_row(), + Some(x) if x == TypeId::of::() => enum_choice::().for_socket(default_info).property_row(), + Some(x) if x == TypeId::of::() => enum_choice::().for_socket(default_info).property_row(), + Some(x) if x == TypeId::of::() => enum_choice::().for_socket(default_info).property_row(), + Some(x) if x == TypeId::of::() => enum_choice::().for_socket(default_info).property_row(), + // ===== + // OTHER + // ===== + _ => { + let mut widgets = start_widgets(default_info); + widgets.extend_from_slice(&[ + Separator::new(SeparatorType::Unrelated).widget_holder(), + TextLabel::new("-") + .tooltip(format!( + "This data can only be supplied through the node graph because no widget exists for its type:\n\ + {}", + concrete_type.name + )) + .widget_holder(), + ]); + return Err(vec![widgets.into()]); + } + } + } + } + } + Type::Generic(_) => vec![TextLabel::new("Generic type (not supported)").widget_holder()].into(), + Type::Fn(_, out) => return property_from_type(node_id, index, out, number_options, unit, display_decimal_places, step, context), + Type::Future(out) => return property_from_type(node_id, index, out, number_options, unit, display_decimal_places, step, context), + }; + + extra_widgets.push(widgets); + + Ok(extra_widgets) +} + +pub fn text_widget(parameter_widgets_info: ParameterWidgetsInfo) -> Vec { + let ParameterWidgetsInfo { document_node, node_id, index, .. } = parameter_widgets_info; + + let mut widgets = start_widgets(parameter_widgets_info); + + let Some(document_node) = document_node else { return Vec::new() }; + let Some(input) = document_node.inputs.get(index) else { + log::warn!("A widget failed to be built because its node's input index is invalid."); + return vec![]; + }; + if let Some(TaggedValue::String(x)) = &input.as_non_exposed_value() { + widgets.extend_from_slice(&[ + Separator::new(SeparatorType::Unrelated).widget_holder(), + TextInput::new(x.clone()) + .on_update(update_value(|x: &TextInput| TaggedValue::String(x.value.clone()), node_id, index)) + .on_commit(commit_value) + .widget_holder(), + ]) + } + widgets +} + +pub fn text_area_widget(parameter_widgets_info: ParameterWidgetsInfo) -> Vec { + let ParameterWidgetsInfo { document_node, node_id, index, .. } = parameter_widgets_info; + + let mut widgets = start_widgets(parameter_widgets_info); + + let Some(document_node) = document_node else { return Vec::new() }; + let Some(input) = document_node.inputs.get(index) else { + log::warn!("A widget failed to be built because its node's input index is invalid."); + return vec![]; + }; + if let Some(TaggedValue::String(x)) = &input.as_non_exposed_value() { + widgets.extend_from_slice(&[ + Separator::new(SeparatorType::Unrelated).widget_holder(), + TextAreaInput::new(x.clone()) + .on_update(update_value(|x: &TextAreaInput| TaggedValue::String(x.value.clone()), node_id, index)) + .on_commit(commit_value) + .widget_holder(), + ]) + } + widgets +} + +pub fn bool_widget(parameter_widgets_info: ParameterWidgetsInfo, checkbox_input: CheckboxInput) -> Vec { + let ParameterWidgetsInfo { document_node, node_id, index, .. } = parameter_widgets_info; + + let mut widgets = start_widgets(parameter_widgets_info); + + let Some(document_node) = document_node else { return Vec::new() }; + let Some(input) = document_node.inputs.get(index) else { + log::warn!("A widget failed to be built because its node's input index is invalid."); + return vec![]; + }; + if let Some(&TaggedValue::Bool(x)) = input.as_non_exposed_value() { + widgets.extend_from_slice(&[ + Separator::new(SeparatorType::Unrelated).widget_holder(), + checkbox_input + .checked(x) + .on_update(update_value(|x: &CheckboxInput| TaggedValue::Bool(x.checked), node_id, index)) + .on_commit(commit_value) + .widget_holder(), + ]) + } + widgets +} + +pub fn reference_point_widget(parameter_widgets_info: ParameterWidgetsInfo, disabled: bool) -> Vec { + let ParameterWidgetsInfo { document_node, node_id, index, .. } = parameter_widgets_info; + + let mut widgets = start_widgets(parameter_widgets_info); + + let Some(document_node) = document_node else { return Vec::new() }; + let Some(input) = document_node.inputs.get(index) else { + log::warn!("A widget failed to be built because its node's input index is invalid."); + return vec![]; + }; + if let Some(&TaggedValue::ReferencePoint(reference_point)) = input.as_non_exposed_value() { + widgets.extend_from_slice(&[ + Separator::new(SeparatorType::Unrelated).widget_holder(), + CheckboxInput::new(reference_point != ReferencePoint::None) + .on_update(update_value( + move |x: &CheckboxInput| TaggedValue::ReferencePoint(if x.checked { ReferencePoint::Center } else { ReferencePoint::None }), + node_id, + index, + )) + .disabled(disabled) + .widget_holder(), + Separator::new(SeparatorType::Related).widget_holder(), + ReferencePointInput::new(reference_point) + .on_update(update_value(move |x: &ReferencePointInput| TaggedValue::ReferencePoint(x.value), node_id, index)) + .disabled(disabled) + .widget_holder(), + ]) + } + widgets +} + +pub fn footprint_widget(parameter_widgets_info: ParameterWidgetsInfo, extra_widgets: &mut Vec) -> LayoutGroup { + let ParameterWidgetsInfo { document_node, node_id, index, .. } = parameter_widgets_info; + + let mut location_widgets = start_widgets(parameter_widgets_info); + location_widgets.push(Separator::new(SeparatorType::Unrelated).widget_holder()); + + let mut scale_widgets = vec![TextLabel::new("").widget_holder()]; + add_blank_assist(&mut scale_widgets); + scale_widgets.push(Separator::new(SeparatorType::Unrelated).widget_holder()); + + let mut resolution_widgets = vec![TextLabel::new("").widget_holder()]; + add_blank_assist(&mut resolution_widgets); + resolution_widgets.push(Separator::new(SeparatorType::Unrelated).widget_holder()); + + let Some(document_node) = document_node else { return LayoutGroup::default() }; + let Some(input) = document_node.inputs.get(index) else { + log::warn!("A widget failed to be built because its node's input index is invalid."); + return Vec::new().into(); + }; + + if let Some(&TaggedValue::Footprint(footprint)) = input.as_non_exposed_value() { + let top_left = footprint.transform.transform_point2(DVec2::ZERO); + let bounds = footprint.scale(); + let oversample = footprint.resolution.as_dvec2() / bounds; + + location_widgets.extend_from_slice(&[ + NumberInput::new(Some(top_left.x)) + .label("X") + .unit(" px") + .on_update(update_value( + move |x: &NumberInput| { + let (offset, scale) = { + let diff = DVec2::new(top_left.x - x.value.unwrap_or_default(), 0.); + (top_left - diff, bounds) + }; + + let footprint = Footprint { + transform: DAffine2::from_scale_angle_translation(scale, 0., offset), + resolution: (oversample * scale).as_uvec2(), + ..footprint + }; + + TaggedValue::Footprint(footprint) + }, + node_id, + index, + )) + .on_commit(commit_value) + .widget_holder(), + Separator::new(SeparatorType::Related).widget_holder(), + NumberInput::new(Some(top_left.y)) + .label("Y") + .unit(" px") + .on_update(update_value( + move |x: &NumberInput| { + let (offset, scale) = { + let diff = DVec2::new(0., top_left.y - x.value.unwrap_or_default()); + (top_left - diff, bounds) + }; + + let footprint = Footprint { + transform: DAffine2::from_scale_angle_translation(scale, 0., offset), + resolution: (oversample * scale).as_uvec2(), + ..footprint + }; + + TaggedValue::Footprint(footprint) + }, + node_id, + index, + )) + .on_commit(commit_value) + .widget_holder(), + ]); + + scale_widgets.extend_from_slice(&[ + NumberInput::new(Some(bounds.x)) + .label("W") + .unit(" px") + .on_update(update_value( + move |x: &NumberInput| { + let (offset, scale) = (top_left, DVec2::new(x.value.unwrap_or_default(), bounds.y)); + + let footprint = Footprint { + transform: DAffine2::from_scale_angle_translation(scale, 0., offset), + resolution: (oversample * scale).as_uvec2(), + ..footprint + }; + + TaggedValue::Footprint(footprint) + }, + node_id, + index, + )) + .on_commit(commit_value) + .widget_holder(), + Separator::new(SeparatorType::Related).widget_holder(), + NumberInput::new(Some(bounds.y)) + .label("H") + .unit(" px") + .on_update(update_value( + move |x: &NumberInput| { + let (offset, scale) = (top_left, DVec2::new(bounds.x, x.value.unwrap_or_default())); + + let footprint = Footprint { + transform: DAffine2::from_scale_angle_translation(scale, 0., offset), + resolution: (oversample * scale).as_uvec2(), + ..footprint + }; + + TaggedValue::Footprint(footprint) + }, + node_id, + index, + )) + .on_commit(commit_value) + .widget_holder(), + ]); + + resolution_widgets.push( + NumberInput::new(Some((footprint.resolution.as_dvec2() / bounds).x * 100.)) + .label("Resolution") + .unit("%") + .on_update(update_value( + move |x: &NumberInput| { + let resolution = (bounds * x.value.unwrap_or(100.) / 100.).as_uvec2().max((1, 1).into()).min((4000, 4000).into()); + + let footprint = Footprint { resolution, ..footprint }; + TaggedValue::Footprint(footprint) + }, + node_id, + index, + )) + .on_commit(commit_value) + .widget_holder(), + ); + } + + let widgets = vec![ + LayoutGroup::Row { widgets: location_widgets }, + LayoutGroup::Row { widgets: scale_widgets }, + LayoutGroup::Row { widgets: resolution_widgets }, + ]; + let (last, rest) = widgets.split_last().expect("Footprint widget should return multiple rows"); + *extra_widgets = rest.to_vec(); + last.clone() +} + +pub fn coordinate_widget(parameter_widgets_info: ParameterWidgetsInfo, x: &str, y: &str, unit: &str, min: Option) -> LayoutGroup { + let ParameterWidgetsInfo { document_node, node_id, index, .. } = parameter_widgets_info; + + let mut widgets = start_widgets(parameter_widgets_info); + + let Some(document_node) = document_node else { return LayoutGroup::default() }; + let Some(input) = document_node.inputs.get(index) else { + log::warn!("A widget failed to be built because its node's input index is invalid."); + return LayoutGroup::Row { widgets: vec![] }; + }; + match input.as_non_exposed_value() { + Some(&TaggedValue::DVec2(dvec2)) => { + widgets.extend_from_slice(&[ + Separator::new(SeparatorType::Unrelated).widget_holder(), + NumberInput::new(Some(dvec2.x)) + .label(x) + .unit(unit) + .min(min.unwrap_or(-((1_u64 << f64::MANTISSA_DIGITS) as f64))) + .max((1_u64 << f64::MANTISSA_DIGITS) as f64) + .on_update(update_value(move |input: &NumberInput| TaggedValue::DVec2(DVec2::new(input.value.unwrap(), dvec2.y)), node_id, index)) + .on_commit(commit_value) + .widget_holder(), + Separator::new(SeparatorType::Related).widget_holder(), + NumberInput::new(Some(dvec2.y)) + .label(y) + .unit(unit) + .min(min.unwrap_or(-((1_u64 << f64::MANTISSA_DIGITS) as f64))) + .max((1_u64 << f64::MANTISSA_DIGITS) as f64) + .on_update(update_value(move |input: &NumberInput| TaggedValue::DVec2(DVec2::new(dvec2.x, input.value.unwrap())), node_id, index)) + .on_commit(commit_value) + .widget_holder(), + ]); + } + Some(&TaggedValue::IVec2(ivec2)) => { + let update_x = move |input: &NumberInput| TaggedValue::IVec2(IVec2::new(input.value.unwrap() as i32, ivec2.y)); + let update_y = move |input: &NumberInput| TaggedValue::IVec2(IVec2::new(ivec2.x, input.value.unwrap() as i32)); + widgets.extend_from_slice(&[ + Separator::new(SeparatorType::Unrelated).widget_holder(), + NumberInput::new(Some(ivec2.x as f64)) + .int() + .label(x) + .unit(unit) + .min(min.unwrap_or(-((1_u64 << f64::MANTISSA_DIGITS) as f64))) + .max((1_u64 << f64::MANTISSA_DIGITS) as f64) + .on_update(update_value(update_x, node_id, index)) + .on_commit(commit_value) + .widget_holder(), + Separator::new(SeparatorType::Related).widget_holder(), + NumberInput::new(Some(ivec2.y as f64)) + .int() + .label(y) + .unit(unit) + .min(min.unwrap_or(-((1_u64 << f64::MANTISSA_DIGITS) as f64))) + .max((1_u64 << f64::MANTISSA_DIGITS) as f64) + .on_update(update_value(update_y, node_id, index)) + .on_commit(commit_value) + .widget_holder(), + ]); + } + Some(&TaggedValue::UVec2(uvec2)) => { + let update_x = move |input: &NumberInput| TaggedValue::UVec2(UVec2::new(input.value.unwrap() as u32, uvec2.y)); + let update_y = move |input: &NumberInput| TaggedValue::UVec2(UVec2::new(uvec2.x, input.value.unwrap() as u32)); + widgets.extend_from_slice(&[ + Separator::new(SeparatorType::Unrelated).widget_holder(), + NumberInput::new(Some(uvec2.x as f64)) + .int() + .label(x) + .unit(unit) + .min(min.unwrap_or(0.)) + .max((1_u64 << f64::MANTISSA_DIGITS) as f64) + .on_update(update_value(update_x, node_id, index)) + .on_commit(commit_value) + .widget_holder(), + Separator::new(SeparatorType::Related).widget_holder(), + NumberInput::new(Some(uvec2.y as f64)) + .int() + .label(y) + .unit(unit) + .min(min.unwrap_or(0.)) + .max((1_u64 << f64::MANTISSA_DIGITS) as f64) + .on_update(update_value(update_y, node_id, index)) + .on_commit(commit_value) + .widget_holder(), + ]); + } + Some(&TaggedValue::F64(value)) => { + widgets.extend_from_slice(&[ + Separator::new(SeparatorType::Unrelated).widget_holder(), + NumberInput::new(Some(value)) + .label(x) + .unit(unit) + .min(min.unwrap_or(-((1_u64 << f64::MANTISSA_DIGITS) as f64))) + .max((1_u64 << f64::MANTISSA_DIGITS) as f64) + .on_update(update_value(move |input: &NumberInput| TaggedValue::DVec2(DVec2::new(input.value.unwrap(), value)), node_id, index)) + .on_commit(commit_value) + .widget_holder(), + Separator::new(SeparatorType::Related).widget_holder(), + NumberInput::new(Some(value)) + .label(y) + .unit(unit) + .min(min.unwrap_or(-((1_u64 << f64::MANTISSA_DIGITS) as f64))) + .max((1_u64 << f64::MANTISSA_DIGITS) as f64) + .on_update(update_value(move |input: &NumberInput| TaggedValue::DVec2(DVec2::new(value, input.value.unwrap())), node_id, index)) + .on_commit(commit_value) + .widget_holder(), + ]); + } + _ => {} + } + + LayoutGroup::Row { widgets } +} + +pub fn array_of_number_widget(parameter_widgets_info: ParameterWidgetsInfo, text_input: TextInput) -> Vec { + let ParameterWidgetsInfo { document_node, node_id, index, .. } = parameter_widgets_info; + + let mut widgets = start_widgets(parameter_widgets_info); + + let from_string = |string: &str| { + string + .split(&[',', ' ']) + .filter(|x| !x.is_empty()) + .map(str::parse::) + .collect::, _>>() + .ok() + .map(TaggedValue::VecF64) + }; + + let Some(document_node) = document_node else { return Vec::new() }; + let Some(input) = document_node.inputs.get(index) else { + log::warn!("A widget failed to be built because its node's input index is invalid."); + return vec![]; + }; + if let Some(TaggedValue::VecF64(x)) = &input.as_non_exposed_value() { + widgets.extend_from_slice(&[ + Separator::new(SeparatorType::Unrelated).widget_holder(), + text_input + .value(x.iter().map(|v| v.to_string()).collect::>().join(", ")) + .on_update(optionally_update_value(move |x: &TextInput| from_string(&x.value), node_id, index)) + .widget_holder(), + ]) + } + widgets +} + +pub fn array_of_coordinates_widget(parameter_widgets_info: ParameterWidgetsInfo, text_props: TextInput) -> Vec { + let ParameterWidgetsInfo { document_node, node_id, index, .. } = parameter_widgets_info; + + let mut widgets = start_widgets(parameter_widgets_info); + + let from_string = |string: &str| { + string + .split(|c: char| !c.is_alphanumeric() && !matches!(c, '.' | '+' | '-')) + .filter(|x| !x.is_empty()) + .map(|x| x.parse::().ok()) + .collect::>>() + .map(|numbers| numbers.chunks_exact(2).map(|values| DVec2::new(values[0], values[1])).collect()) + .map(TaggedValue::VecDVec2) + }; + + let Some(document_node) = document_node else { return Vec::new() }; + let Some(input) = document_node.inputs.get(index) else { + log::warn!("A widget failed to be built because its node's input index is invalid."); + return vec![]; + }; + if let Some(TaggedValue::VecDVec2(x)) = &input.as_non_exposed_value() { + widgets.extend_from_slice(&[ + Separator::new(SeparatorType::Unrelated).widget_holder(), + text_props + .value(x.iter().map(|v| format!("({}, {})", v.x, v.y)).collect::>().join(", ")) + .on_update(optionally_update_value(move |x: &TextInput| from_string(&x.value), node_id, index)) + .widget_holder(), + ]) + } + widgets +} + +pub fn font_inputs(parameter_widgets_info: ParameterWidgetsInfo) -> (Vec, Option>) { + let ParameterWidgetsInfo { document_node, node_id, index, .. } = parameter_widgets_info; + + let mut first_widgets = start_widgets(parameter_widgets_info); + let mut second_widgets = None; + + let from_font_input = |font: &FontInput| TaggedValue::Font(Font::new(font.font_family.clone(), font.font_style.clone())); + + let Some(document_node) = document_node else { return (Vec::new(), None) }; + let Some(input) = document_node.inputs.get(index) else { + log::warn!("A widget failed to be built because its node's input index is invalid."); + return (vec![], None); + }; + if let Some(TaggedValue::Font(font)) = &input.as_non_exposed_value() { + first_widgets.extend_from_slice(&[ + Separator::new(SeparatorType::Unrelated).widget_holder(), + FontInput::new(font.font_family.clone(), font.font_style.clone()) + .on_update(update_value(from_font_input, node_id, index)) + .on_commit(commit_value) + .widget_holder(), + ]); + + let mut second_row = vec![TextLabel::new("").widget_holder()]; + add_blank_assist(&mut second_row); + second_row.extend_from_slice(&[ + Separator::new(SeparatorType::Unrelated).widget_holder(), + FontInput::new(font.font_family.clone(), font.font_style.clone()) + .is_style_picker(true) + .on_update(update_value(from_font_input, node_id, index)) + .on_commit(commit_value) + .widget_holder(), + ]); + second_widgets = Some(second_row); + } + (first_widgets, second_widgets) +} + +pub fn vector_data_widget(parameter_widgets_info: ParameterWidgetsInfo) -> Vec { + let mut widgets = start_widgets(parameter_widgets_info); + + widgets.push(Separator::new(SeparatorType::Unrelated).widget_holder()); + widgets.push(TextLabel::new("Vector data is supplied through the node graph").widget_holder()); + + widgets +} + +pub fn raster_widget(parameter_widgets_info: ParameterWidgetsInfo) -> Vec { + let mut widgets = start_widgets(parameter_widgets_info); + + widgets.push(Separator::new(SeparatorType::Unrelated).widget_holder()); + widgets.push(TextLabel::new("Raster data is supplied through the node graph").widget_holder()); + + widgets +} + +pub fn group_widget(parameter_widgets_info: ParameterWidgetsInfo) -> Vec { + let mut widgets = start_widgets(parameter_widgets_info); + + widgets.push(Separator::new(SeparatorType::Unrelated).widget_holder()); + widgets.push(TextLabel::new("Group data is supplied through the node graph").widget_holder()); + + widgets +} + +pub fn number_widget(parameter_widgets_info: ParameterWidgetsInfo, number_props: NumberInput) -> Vec { + let ParameterWidgetsInfo { document_node, node_id, index, .. } = parameter_widgets_info; + + let mut widgets = start_widgets(parameter_widgets_info); + + let Some(document_node) = document_node else { return Vec::new() }; + let Some(input) = document_node.inputs.get(index) else { + log::warn!("A widget failed to be built because its node's input index is invalid."); + return vec![]; + }; + match input.as_non_exposed_value() { + Some(&TaggedValue::F64(x)) => widgets.extend_from_slice(&[ + Separator::new(SeparatorType::Unrelated).widget_holder(), + number_props + .value(Some(x)) + .on_update(update_value(move |x: &NumberInput| TaggedValue::F64(x.value.unwrap()), node_id, index)) + .on_commit(commit_value) + .widget_holder(), + ]), + Some(&TaggedValue::U32(x)) => widgets.extend_from_slice(&[ + Separator::new(SeparatorType::Unrelated).widget_holder(), + number_props + .value(Some(x as f64)) + .on_update(update_value(move |x: &NumberInput| TaggedValue::U32((x.value.unwrap()) as u32), node_id, index)) + .on_commit(commit_value) + .widget_holder(), + ]), + Some(&TaggedValue::U64(x)) => widgets.extend_from_slice(&[ + Separator::new(SeparatorType::Unrelated).widget_holder(), + number_props + .value(Some(x as f64)) + .on_update(update_value(move |x: &NumberInput| TaggedValue::U64((x.value.unwrap()) as u64), node_id, index)) + .on_commit(commit_value) + .widget_holder(), + ]), + Some(&TaggedValue::OptionalF64(x)) => { + // TODO: Don't wipe out the previously set value (setting it back to the default of 100) when reenabling this checkbox back to Some from None + let toggle_enabled = move |checkbox_input: &CheckboxInput| TaggedValue::OptionalF64(if checkbox_input.checked { Some(100.) } else { None }); + widgets.extend_from_slice(&[ + Separator::new(SeparatorType::Unrelated).widget_holder(), + Separator::new(SeparatorType::Related).widget_holder(), + // The checkbox toggles if the value is Some or None + CheckboxInput::new(x.is_some()) + .on_update(update_value(toggle_enabled, node_id, index)) + .on_commit(commit_value) + .widget_holder(), + Separator::new(SeparatorType::Related).widget_holder(), + Separator::new(SeparatorType::Unrelated).widget_holder(), + number_props + .value(x) + .on_update(update_value(move |x: &NumberInput| TaggedValue::OptionalF64(x.value), node_id, index)) + .disabled(x.is_none()) + .on_commit(commit_value) + .widget_holder(), + ]); + } + Some(&TaggedValue::DVec2(dvec2)) => widgets.extend_from_slice(&[ + Separator::new(SeparatorType::Unrelated).widget_holder(), + number_props + // We use an arbitrary `y` instead of an arbitrary `x` here because the "Grid" node's "Spacing" value's height should be used from rectangular mode when transferred to "Y Spacing" in isometric mode + .value(Some(dvec2.y)) + .on_update(update_value(move |x: &NumberInput| TaggedValue::F64(x.value.unwrap()), node_id, index)) + .on_commit(commit_value) + .widget_holder(), + ]), + _ => {} + } + + widgets +} + +// TODO: Auto-generate this enum dropdown menu widget +pub fn blend_mode_widget(parameter_widgets_info: ParameterWidgetsInfo) -> LayoutGroup { + let ParameterWidgetsInfo { document_node, node_id, index, .. } = parameter_widgets_info; + + let mut widgets = start_widgets(parameter_widgets_info); + let Some(document_node) = document_node else { return LayoutGroup::default() }; + let Some(input) = document_node.inputs.get(index) else { + log::warn!("A widget failed to be built because its node's input index is invalid."); + return LayoutGroup::Row { widgets: vec![] }; + }; + if let Some(&TaggedValue::BlendMode(blend_mode)) = input.as_non_exposed_value() { + let entries = BlendMode::list_svg_subset() + .iter() + .map(|category| { + category + .iter() + .map(|blend_mode| { + MenuListEntry::new(format!("{blend_mode:?}")) + .label(blend_mode.to_string()) + .on_update(update_value(move |_| TaggedValue::BlendMode(*blend_mode), node_id, index)) + .on_commit(commit_value) + }) + .collect() + }) + .collect(); + + widgets.extend_from_slice(&[ + Separator::new(SeparatorType::Unrelated).widget_holder(), + DropdownInput::new(entries) + .selected_index(blend_mode.index_in_list_svg_subset().map(|index| index as u32)) + .widget_holder(), + ]); + } + LayoutGroup::Row { widgets }.with_tooltip("Formula used for blending") +} + +pub fn color_widget(parameter_widgets_info: ParameterWidgetsInfo, color_button: ColorInput) -> LayoutGroup { + let ParameterWidgetsInfo { document_node, node_id, index, .. } = parameter_widgets_info; + + let mut widgets = start_widgets(parameter_widgets_info); + + let Some(document_node) = document_node else { return LayoutGroup::default() }; + // Return early with just the label if the input is exposed to the graph, meaning we don't want to show the color picker widget in the Properties panel + let NodeInput::Value { tagged_value, exposed: false } = &document_node.inputs[index] else { + return LayoutGroup::Row { widgets }; + }; + + // Add a separator + widgets.push(Separator::new(SeparatorType::Unrelated).widget_holder()); + + // Add the color input + match &**tagged_value { + TaggedValue::Color(color) => widgets.push( + color_button + .value(FillChoice::Solid(*color)) + .on_update(update_value(|x: &ColorInput| TaggedValue::Color(x.value.as_solid().unwrap_or_default()), node_id, index)) + .on_commit(commit_value) + .widget_holder(), + ), + TaggedValue::OptionalColor(color) => widgets.push( + color_button + .value(match color { + Some(color) => FillChoice::Solid(*color), + None => FillChoice::None, + }) + .on_update(update_value(|x: &ColorInput| TaggedValue::OptionalColor(x.value.as_solid()), node_id, index)) + .on_commit(commit_value) + .widget_holder(), + ), + TaggedValue::GradientStops(x) => widgets.push( + color_button + .value(FillChoice::Gradient(x.clone())) + .on_update(update_value( + |x: &ColorInput| TaggedValue::GradientStops(x.value.as_gradient().cloned().unwrap_or_default()), + node_id, + index, + )) + .on_commit(commit_value) + .widget_holder(), + ), + _ => {} + } + + LayoutGroup::Row { widgets } +} + +pub fn font_widget(parameter_widgets_info: ParameterWidgetsInfo) -> LayoutGroup { + let (font_widgets, style_widgets) = font_inputs(parameter_widgets_info); + font_widgets.into_iter().chain(style_widgets.unwrap_or_default()).collect::>().into() +} + +pub fn curve_widget(parameter_widgets_info: ParameterWidgetsInfo) -> LayoutGroup { + let ParameterWidgetsInfo { document_node, node_id, index, .. } = parameter_widgets_info; + + let mut widgets = start_widgets(parameter_widgets_info); + + let Some(document_node) = document_node else { return LayoutGroup::default() }; + let Some(input) = document_node.inputs.get(index) else { + log::warn!("A widget failed to be built because its node's input index is invalid."); + return LayoutGroup::Row { widgets: vec![] }; + }; + if let Some(TaggedValue::Curve(curve)) = &input.as_non_exposed_value() { + widgets.extend_from_slice(&[ + Separator::new(SeparatorType::Unrelated).widget_holder(), + CurveInput::new(curve.clone()) + .on_update(update_value(|x: &CurveInput| TaggedValue::Curve(x.value.clone()), node_id, index)) + .on_commit(commit_value) + .widget_holder(), + ]) + } + LayoutGroup::Row { widgets } +} + +pub fn get_document_node<'a>(node_id: NodeId, context: &'a NodePropertiesContext<'a>) -> Result<&'a DocumentNode, String> { + let network = context + .network_interface + .nested_network(context.selection_network_path) + .ok_or("network not found in get_document_node")?; + network.nodes.get(&node_id).ok_or(format!("node {node_id} not found in get_document_node")) +} + +pub fn query_node_and_input_info<'a>(node_id: NodeId, input_index: usize, context: &'a mut NodePropertiesContext<'a>) -> Result<(&'a DocumentNode, String, String), String> { + let (name, description) = context.network_interface.displayed_input_name_and_description(&node_id, input_index, context.selection_network_path); + let document_node = get_document_node(node_id, context)?; + + Ok((document_node, name, description)) +} + +pub fn query_noise_pattern_state(node_id: NodeId, context: &NodePropertiesContext) -> Result<(bool, bool, bool, bool, bool, bool), String> { + let document_node = get_document_node(node_id, context)?; + let current_noise_type = document_node.inputs.iter().find_map(|input| match input.as_value() { + Some(&TaggedValue::NoiseType(noise_type)) => Some(noise_type), + _ => None, + }); + let current_fractal_type = document_node.inputs.iter().find_map(|input| match input.as_value() { + Some(&TaggedValue::FractalType(fractal_type)) => Some(fractal_type), + _ => None, + }); + let current_domain_warp_type = document_node.inputs.iter().find_map(|input| match input.as_value() { + Some(&TaggedValue::DomainWarpType(domain_warp_type)) => Some(domain_warp_type), + _ => None, + }); + let fractal_active = current_fractal_type != Some(FractalType::None); + let coherent_noise_active = current_noise_type != Some(NoiseType::WhiteNoise); + let cellular_noise_active = current_noise_type == Some(NoiseType::Cellular); + let ping_pong_active = current_fractal_type == Some(FractalType::PingPong); + let domain_warp_active = current_domain_warp_type != Some(DomainWarpType::None); + let domain_warp_only_fractal_type_wrongly_active = + !domain_warp_active && (current_fractal_type == Some(FractalType::DomainWarpIndependent) || current_fractal_type == Some(FractalType::DomainWarpProgressive)); + + Ok(( + fractal_active, + coherent_noise_active, + cellular_noise_active, + ping_pong_active, + domain_warp_active, + domain_warp_only_fractal_type_wrongly_active, + )) +} + +pub fn query_assign_colors_randomize(node_id: NodeId, context: &NodePropertiesContext) -> Result { + use graphene_std::vector::assign_colors::*; + + let document_node = get_document_node(node_id, context)?; + // This is safe since the node is a proto node and the implementation cannot be changed. + Ok(match document_node.inputs.get(RandomizeInput::INDEX).and_then(|input| input.as_value()) { + Some(TaggedValue::Bool(randomize_enabled)) => *randomize_enabled, + _ => false, + }) +} + +pub(crate) fn brightness_contrast_properties(node_id: NodeId, context: &mut NodePropertiesContext) -> Vec { + use graphene_std::raster::brightness_contrast::*; + + // Use Classic + let use_classic = bool_widget(ParameterWidgetsInfo::new(node_id, UseClassicInput::INDEX, true, context), CheckboxInput::default()); + + let document_node = match get_document_node(node_id, context) { + Ok(document_node) => document_node, + Err(err) => { + log::error!("Could not get document node in brightness_contrast_properties: {err}"); + return Vec::new(); + } + }; + let use_classic_value = match document_node.inputs[UseClassicInput::INDEX].as_value() { + Some(TaggedValue::Bool(use_classic_choice)) => *use_classic_choice, + _ => false, + }; + + // Brightness + let brightness = number_widget( + ParameterWidgetsInfo::new(node_id, BrightnessInput::INDEX, true, context), + NumberInput::default() + .unit("%") + .mode_range() + .display_decimal_places(2) + .range_min(Some(if use_classic_value { -100. } else { -150. })) + .range_max(Some(if use_classic_value { 100. } else { 150. })), + ); + + // Contrast + let contrast = number_widget( + ParameterWidgetsInfo::new(node_id, ContrastInput::INDEX, true, context), + NumberInput::default() + .unit("%") + .mode_range() + .display_decimal_places(2) + .range_min(Some(if use_classic_value { -100. } else { -50. })) + .range_max(Some(100.)), + ); + + let layout = vec![ + LayoutGroup::Row { widgets: brightness }, + LayoutGroup::Row { widgets: contrast }, + LayoutGroup::Row { widgets: use_classic }, + ]; + + layout +} + +pub(crate) fn channel_mixer_properties(node_id: NodeId, context: &mut NodePropertiesContext) -> Vec { + use graphene_std::raster::channel_mixer::*; + + let is_monochrome = bool_widget(ParameterWidgetsInfo::new(node_id, MonochromeInput::INDEX, true, context), CheckboxInput::default()); + let mut parameter_info = ParameterWidgetsInfo::new(node_id, OutputChannelInput::INDEX, true, context); + parameter_info.exposeable = false; + let output_channel = enum_choice::().for_socket(parameter_info).property_row(); + + let document_node = match get_document_node(node_id, context) { + Ok(document_node) => document_node, + Err(err) => { + log::error!("Could not get document node in channel_mixer_properties: {err}"); + return Vec::new(); + } + }; + // Monochrome + let is_monochrome_value = match document_node.inputs[MonochromeInput::INDEX].as_value() { + Some(TaggedValue::Bool(monochrome_choice)) => *monochrome_choice, + _ => false, + }; + // Output channel choice + let output_channel_value = match &document_node.inputs[OutputChannelInput::INDEX].as_value() { + Some(TaggedValue::RedGreenBlue(choice)) => choice, + _ => { + warn!("Channel Mixer node properties panel could not be displayed."); + return vec![]; + } + }; + + // Output Channel modes + let (red_output_index, green_output_index, blue_output_index, constant_output_index) = match (is_monochrome_value, output_channel_value) { + (true, _) => (MonochromeRInput::INDEX, MonochromeGInput::INDEX, MonochromeBInput::INDEX, MonochromeCInput::INDEX), + (false, RedGreenBlue::Red) => (RedRInput::INDEX, RedGInput::INDEX, RedBInput::INDEX, RedCInput::INDEX), + (false, RedGreenBlue::Green) => (GreenRInput::INDEX, GreenGInput::INDEX, GreenBInput::INDEX, GreenCInput::INDEX), + (false, RedGreenBlue::Blue) => (BlueRInput::INDEX, BlueGInput::INDEX, BlueBInput::INDEX, BlueCInput::INDEX), + }; + let number_input = NumberInput::default().mode_range().min(-200.).max(200.).unit("%"); + let red = number_widget(ParameterWidgetsInfo::new(node_id, red_output_index, true, context), number_input.clone()); + let green = number_widget(ParameterWidgetsInfo::new(node_id, green_output_index, true, context), number_input.clone()); + let blue = number_widget(ParameterWidgetsInfo::new(node_id, blue_output_index, true, context), number_input.clone()); + let constant = number_widget(ParameterWidgetsInfo::new(node_id, constant_output_index, true, context), number_input); + + // Monochrome + let mut layout = vec![LayoutGroup::Row { widgets: is_monochrome }]; + // Output channel choice + if !is_monochrome_value { + layout.push(output_channel); + } + // Channel values + layout.extend([ + LayoutGroup::Row { widgets: red }, + LayoutGroup::Row { widgets: green }, + LayoutGroup::Row { widgets: blue }, + LayoutGroup::Row { widgets: constant }, + ]); + layout +} + +pub(crate) fn selective_color_properties(node_id: NodeId, context: &mut NodePropertiesContext) -> Vec { + use graphene_std::raster::selective_color::*; + + let mut default_info = ParameterWidgetsInfo::new(node_id, ColorsInput::INDEX, true, context); + default_info.exposeable = false; + let colors = enum_choice::().for_socket(default_info).property_row(); + + let document_node = match get_document_node(node_id, context) { + Ok(document_node) => document_node, + Err(err) => { + log::error!("Could not get document node in selective_color_properties: {err}"); + return Vec::new(); + } + }; + // Colors choice + let colors_choice = match &document_node.inputs[ColorsInput::INDEX].as_value() { + Some(TaggedValue::SelectiveColorChoice(choice)) => choice, + _ => { + warn!("Selective Color node properties panel could not be displayed."); + return vec![]; + } + }; + // CMYK + let (c_index, m_index, y_index, k_index) = match colors_choice { + SelectiveColorChoice::Reds => (RCInput::INDEX, RMInput::INDEX, RYInput::INDEX, RKInput::INDEX), + SelectiveColorChoice::Yellows => (YCInput::INDEX, YMInput::INDEX, YYInput::INDEX, YKInput::INDEX), + SelectiveColorChoice::Greens => (GCInput::INDEX, GMInput::INDEX, GYInput::INDEX, GKInput::INDEX), + SelectiveColorChoice::Cyans => (CCInput::INDEX, CMInput::INDEX, CYInput::INDEX, CKInput::INDEX), + SelectiveColorChoice::Blues => (BCInput::INDEX, BMInput::INDEX, BYInput::INDEX, BKInput::INDEX), + SelectiveColorChoice::Magentas => (MCInput::INDEX, MMInput::INDEX, MYInput::INDEX, MKInput::INDEX), + SelectiveColorChoice::Whites => (WCInput::INDEX, WMInput::INDEX, WYInput::INDEX, WKInput::INDEX), + SelectiveColorChoice::Neutrals => (NCInput::INDEX, NMInput::INDEX, NYInput::INDEX, NKInput::INDEX), + SelectiveColorChoice::Blacks => (KCInput::INDEX, KMInput::INDEX, KYInput::INDEX, KKInput::INDEX), + }; + let number_input = NumberInput::default().mode_range().min(-100.).max(100.).unit("%"); + let cyan = number_widget(ParameterWidgetsInfo::new(node_id, c_index, true, context), number_input.clone()); + let magenta = number_widget(ParameterWidgetsInfo::new(node_id, m_index, true, context), number_input.clone()); + let yellow = number_widget(ParameterWidgetsInfo::new(node_id, y_index, true, context), number_input.clone()); + let black = number_widget(ParameterWidgetsInfo::new(node_id, k_index, true, context), number_input); + + // Mode + let mode = enum_choice::() + .for_socket(ParameterWidgetsInfo::new(node_id, ModeInput::INDEX, true, context)) + .property_row(); + + vec![ + // Colors choice + colors, + // CMYK + LayoutGroup::Row { widgets: cyan }, + LayoutGroup::Row { widgets: magenta }, + LayoutGroup::Row { widgets: yellow }, + LayoutGroup::Row { widgets: black }, + // Mode + mode, + ] +} + +pub(crate) fn grid_properties(node_id: NodeId, context: &mut NodePropertiesContext) -> Vec { + use graphene_std::vector::generator_nodes::grid::*; + + let grid_type = enum_choice::() + .for_socket(ParameterWidgetsInfo::new(node_id, GridTypeInput::INDEX, true, context)) + .property_row(); + + let mut widgets = vec![grid_type]; + + let document_node = match get_document_node(node_id, context) { + Ok(document_node) => document_node, + Err(err) => { + log::error!("Could not get document node in grid_properties: {err}"); + return Vec::new(); + } + }; + let Some(grid_type_input) = document_node.inputs.get(GridTypeInput::INDEX) else { + log::warn!("A widget failed to be built because its node's input index is invalid."); + return vec![]; + }; + if let Some(&TaggedValue::GridType(grid_type)) = grid_type_input.as_non_exposed_value() { + match grid_type { + GridType::Rectangular => { + let spacing = coordinate_widget(ParameterWidgetsInfo::new(node_id, SpacingInput::::INDEX, true, context), "W", "H", " px", Some(0.)); + widgets.push(spacing); + } + GridType::Isometric => { + let spacing = LayoutGroup::Row { + widgets: number_widget( + ParameterWidgetsInfo::new(node_id, SpacingInput::::INDEX, true, context), + NumberInput::default().label("H").min(0.).unit(" px"), + ), + }; + let angles = coordinate_widget(ParameterWidgetsInfo::new(node_id, AnglesInput::INDEX, true, context), "", "", "°", None); + widgets.extend([spacing, angles]); + } + } + } + + let columns = number_widget(ParameterWidgetsInfo::new(node_id, ColumnsInput::INDEX, true, context), NumberInput::default().min(1.)); + let rows = number_widget(ParameterWidgetsInfo::new(node_id, RowsInput::INDEX, true, context), NumberInput::default().min(1.)); + + widgets.extend([LayoutGroup::Row { widgets: columns }, LayoutGroup::Row { widgets: rows }]); + + widgets +} + +pub(crate) const SAMPLE_POLYLINE_TOOLTIP_SPACING: &str = "Use a point sampling density controlled by a distance between, or specific number of, points."; +pub(crate) const SAMPLE_POLYLINE_TOOLTIP_SEPARATION: &str = "Distance between each instance (exact if 'Adaptive Spacing' is disabled, approximate if enabled)."; +pub(crate) const SAMPLE_POLYLINE_TOOLTIP_QUANTITY: &str = "Number of points to place along the path."; +pub(crate) const SAMPLE_POLYLINE_TOOLTIP_START_OFFSET: &str = "Exclude some distance from the start of the path before the first instance."; +pub(crate) const SAMPLE_POLYLINE_TOOLTIP_STOP_OFFSET: &str = "Exclude some distance from the end of the path after the last instance."; +pub(crate) const SAMPLE_POLYLINE_TOOLTIP_ADAPTIVE_SPACING: &str = "Round 'Separation' to a nearby value that divides into the path length evenly."; + +pub(crate) fn sample_polyline_properties(node_id: NodeId, context: &mut NodePropertiesContext) -> Vec { + use graphene_std::vector::sample_polyline::*; + + let document_node = match get_document_node(node_id, context) { + Ok(document_node) => document_node, + Err(err) => { + log::error!("Could not get document node in sample_polyline_properties: {err}"); + return Vec::new(); + } + }; + + let current_spacing = document_node.inputs.get(SpacingInput::INDEX).and_then(|input| input.as_value()).cloned(); + let is_quantity = matches!(current_spacing, Some(TaggedValue::PointSpacingType(PointSpacingType::Quantity))); + + let spacing = enum_choice::() + .for_socket(ParameterWidgetsInfo::new(node_id, SpacingInput::INDEX, true, context)) + .property_row(); + let separation = number_widget(ParameterWidgetsInfo::new(node_id, SeparationInput::INDEX, true, context), NumberInput::default().min(0.).unit(" px")); + let quantity = number_widget(ParameterWidgetsInfo::new(node_id, QuantityInput::INDEX, true, context), NumberInput::default().min(2.).int()); + let start_offset = number_widget(ParameterWidgetsInfo::new(node_id, StartOffsetInput::INDEX, true, context), NumberInput::default().min(0.).unit(" px")); + let stop_offset = number_widget(ParameterWidgetsInfo::new(node_id, StopOffsetInput::INDEX, true, context), NumberInput::default().min(0.).unit(" px")); + let adaptive_spacing = bool_widget( + ParameterWidgetsInfo::new(node_id, AdaptiveSpacingInput::INDEX, true, context), + CheckboxInput::default().disabled(is_quantity), + ); + + vec![ + spacing.with_tooltip(SAMPLE_POLYLINE_TOOLTIP_SPACING), + match current_spacing { + Some(TaggedValue::PointSpacingType(PointSpacingType::Separation)) => LayoutGroup::Row { widgets: separation }.with_tooltip(SAMPLE_POLYLINE_TOOLTIP_SEPARATION), + Some(TaggedValue::PointSpacingType(PointSpacingType::Quantity)) => LayoutGroup::Row { widgets: quantity }.with_tooltip(SAMPLE_POLYLINE_TOOLTIP_QUANTITY), + _ => LayoutGroup::Row { widgets: vec![] }, + }, + LayoutGroup::Row { widgets: start_offset }.with_tooltip(SAMPLE_POLYLINE_TOOLTIP_START_OFFSET), + LayoutGroup::Row { widgets: stop_offset }.with_tooltip(SAMPLE_POLYLINE_TOOLTIP_STOP_OFFSET), + LayoutGroup::Row { widgets: adaptive_spacing }.with_tooltip(SAMPLE_POLYLINE_TOOLTIP_ADAPTIVE_SPACING), + ] +} + +pub(crate) fn exposure_properties(node_id: NodeId, context: &mut NodePropertiesContext) -> Vec { + use graphene_std::raster::exposure::*; + + let exposure = number_widget(ParameterWidgetsInfo::new(node_id, ExposureInput::INDEX, true, context), NumberInput::default().min(-20.).max(20.)); + let offset = number_widget(ParameterWidgetsInfo::new(node_id, OffsetInput::INDEX, true, context), NumberInput::default().min(-0.5).max(0.5)); + let gamma_correction = number_widget( + ParameterWidgetsInfo::new(node_id, GammaCorrectionInput::INDEX, true, context), + NumberInput::default().min(0.01).max(9.99).increment_step(0.1), + ); + + vec![ + LayoutGroup::Row { widgets: exposure }, + LayoutGroup::Row { widgets: offset }, + LayoutGroup::Row { widgets: gamma_correction }, + ] +} + +pub(crate) fn rectangle_properties(node_id: NodeId, context: &mut NodePropertiesContext) -> Vec { + use graphene_std::vector::generator_nodes::rectangle::*; + + // Corner Radius + let mut corner_radius_row_1 = start_widgets(ParameterWidgetsInfo::new(node_id, CornerRadiusInput::::INDEX, true, context)); + corner_radius_row_1.push(Separator::new(SeparatorType::Unrelated).widget_holder()); + + let mut corner_radius_row_2 = vec![Separator::new(SeparatorType::Unrelated).widget_holder()]; + corner_radius_row_2.push(TextLabel::new("").widget_holder()); + + let document_node = match get_document_node(node_id, context) { + Ok(document_node) => document_node, + Err(err) => { + log::error!("Could not get document node in rectangle_properties: {err}"); + return Vec::new(); + } + }; + let Some(input) = document_node.inputs.get(IndividualCornerRadiiInput::INDEX) else { + log::warn!("A widget failed to be built because its node's input index is invalid."); + return vec![]; + }; + if let Some(&TaggedValue::Bool(is_individual)) = input.as_non_exposed_value() { + // Values + let Some(input) = document_node.inputs.get(CornerRadiusInput::::INDEX) else { + log::warn!("A widget failed to be built because its node's input index is invalid."); + return vec![]; + }; + let uniform_val = match input.as_non_exposed_value() { + Some(TaggedValue::F64(x)) => *x, + Some(TaggedValue::F64Array4(x)) => x[0], + _ => 0., + }; + let individual_val = match input.as_non_exposed_value() { + Some(&TaggedValue::F64Array4(x)) => x, + Some(&TaggedValue::F64(x)) => [x; 4], + _ => [0.; 4], + }; + + // Uniform/individual radio input widget + let uniform = RadioEntryData::new("Uniform") + .label("Uniform") + .on_update(move |_| { + Message::Batched(Box::new([ + NodeGraphMessage::SetInputValue { + node_id, + input_index: IndividualCornerRadiiInput::INDEX, + value: TaggedValue::Bool(false), + } + .into(), + NodeGraphMessage::SetInputValue { + node_id, + input_index: CornerRadiusInput::::INDEX, + value: TaggedValue::F64(uniform_val), + } + .into(), + ])) + }) + .on_commit(commit_value); + let individual = RadioEntryData::new("Individual") + .label("Individual") + .on_update(move |_| { + Message::Batched(Box::new([ + NodeGraphMessage::SetInputValue { + node_id, + input_index: IndividualCornerRadiiInput::INDEX, + value: TaggedValue::Bool(true), + } + .into(), + NodeGraphMessage::SetInputValue { + node_id, + input_index: CornerRadiusInput::::INDEX, + value: TaggedValue::F64Array4(individual_val), + } + .into(), + ])) + }) + .on_commit(commit_value); + let radio_input = RadioInput::new(vec![uniform, individual]).selected_index(Some(is_individual as u32)).widget_holder(); + corner_radius_row_1.push(radio_input); + + // Radius value input widget + let input_widget = if is_individual { + let from_string = |string: &str| { + string + .split(&[',', ' ']) + .filter(|x| !x.is_empty()) + .map(str::parse::) + .collect::, _>>() + .ok() + .map(|v| { + let arr: Box<[f64; 4]> = v.into_boxed_slice().try_into().unwrap_or_default(); + *arr + }) + .map(TaggedValue::F64Array4) + }; + TextInput::default() + .value(individual_val.iter().map(|v| v.to_string()).collect::>().join(", ")) + .on_update(optionally_update_value(move |x: &TextInput| from_string(&x.value), node_id, CornerRadiusInput::::INDEX)) + .widget_holder() + } else { + NumberInput::default() + .value(Some(uniform_val)) + .unit(" px") + .on_update(update_value(move |x: &NumberInput| TaggedValue::F64(x.value.unwrap()), node_id, CornerRadiusInput::::INDEX)) + .on_commit(commit_value) + .widget_holder() + }; + corner_radius_row_2.push(input_widget); + } + + // Size X + let size_x = number_widget(ParameterWidgetsInfo::new(node_id, WidthInput::INDEX, true, context), NumberInput::default()); + + // Size Y + let size_y = number_widget(ParameterWidgetsInfo::new(node_id, HeightInput::INDEX, true, context), NumberInput::default()); + + add_blank_assist(&mut corner_radius_row_2); + + // Clamped + let clamped = bool_widget(ParameterWidgetsInfo::new(node_id, ClampedInput::INDEX, true, context), CheckboxInput::default()); + + vec![ + LayoutGroup::Row { widgets: size_x }, + LayoutGroup::Row { widgets: size_y }, + LayoutGroup::Row { widgets: corner_radius_row_1 }, + LayoutGroup::Row { widgets: corner_radius_row_2 }, + LayoutGroup::Row { widgets: clamped }, + ] +} + +pub(crate) fn node_no_properties(node_id: NodeId, context: &mut NodePropertiesContext) -> Vec { + let text = if context.network_interface.is_layer(&node_id, context.selection_network_path) { + "Layer has no properties" + } else { + "Node has no properties" + }; + string_properties(text) +} + +pub(crate) fn generate_node_properties(node_id: NodeId, context: &mut NodePropertiesContext) -> LayoutGroup { + let mut layout = Vec::new(); + + if let Some(properties_override) = context + .network_interface + .reference(&node_id, context.selection_network_path) + .cloned() + .unwrap_or_default() + .as_ref() + .and_then(|reference| super::document_node_definitions::resolve_document_node_type(reference)) + .and_then(|definition| definition.properties) + .and_then(|properties| NODE_OVERRIDES.get(properties)) + { + layout = properties_override(node_id, context); + } else { + let number_of_inputs = context.network_interface.number_of_inputs(&node_id, context.selection_network_path); + for input_index in 1..number_of_inputs { + let row = context.call_widget_override(&node_id, input_index).unwrap_or_else(|| { + let Some(implementation) = context.network_interface.implementation(&node_id, context.selection_network_path) else { + log::error!("Could not get implementation for node {node_id}"); + return Vec::new(); + }; + + let mut number_options = (None, None, None); + let mut display_decimal_places = None; + let mut step = None; + let mut unit_suffix = None; + let input_type = match implementation { + DocumentNodeImplementation::ProtoNode(proto_node_identifier) => 'early_return: { + if let Some(field) = graphene_std::registry::NODE_METADATA + .lock() + .unwrap() + .get(&proto_node_identifier.name.clone().into_owned()) + .and_then(|metadata| metadata.fields.get(input_index)) + { + number_options = (field.number_min, field.number_max, field.number_mode_range); + display_decimal_places = field.number_display_decimal_places; + unit_suffix = field.unit; + step = field.number_step; + if let Some(ref default) = field.default_type { + break 'early_return default.clone(); + } + } + + let Some(implementations) = &interpreted_executor::node_registry::NODE_REGISTRY.get(proto_node_identifier) else { + log::error!("Could not get implementation for protonode {proto_node_identifier:?}"); + return Vec::new(); + }; + + let mut input_types = implementations + .keys() + .filter_map(|item| item.inputs.get(input_index)) + .filter(|ty| property_from_type(node_id, input_index, ty, number_options, unit_suffix, display_decimal_places, step, context).is_ok()) + .collect::>(); + input_types.sort_by_key(|ty| ty.type_name()); + let input_type = input_types.first().cloned(); + + let Some(input_type) = input_type else { + return Vec::new(); + }; + + input_type.clone() + } + _ => context.network_interface.input_type(&InputConnector::node(node_id, input_index), context.selection_network_path).0, + }; + + property_from_type(node_id, input_index, &input_type, number_options, unit_suffix, display_decimal_places, step, context).unwrap_or_else(|value| value) + }); + + layout.extend(row); + } + } + + if layout.is_empty() { + layout = node_no_properties(node_id, context); + } + let name = context + .network_interface + .reference(&node_id, context.selection_network_path) + .cloned() + .unwrap_or_default() // If there is an error getting the reference, default to empty string + .or_else(|| { + // If there is no reference, try to get the proto node name + context.network_interface.implementation(&node_id, context.selection_network_path).and_then(|implementation|{ + if let DocumentNodeImplementation::ProtoNode(protonode) = implementation { + Some(protonode.name.clone().into_owned()) + } else { + None + } + }) + }) + .unwrap_or("Custom Node".to_string()); + let description = context.network_interface.description(&node_id, context.selection_network_path); + let visible = context.network_interface.is_visible(&node_id, context.selection_network_path); + let pinned = context.network_interface.is_pinned(&node_id, context.selection_network_path); + LayoutGroup::Section { + name, + description, + visible, + pinned, + id: node_id.0, + layout, + } +} + +/// Fill Node Widgets LayoutGroup +pub(crate) fn fill_properties(node_id: NodeId, context: &mut NodePropertiesContext) -> Vec { + use graphene_std::vector::fill::*; + + let mut widgets_first_row = start_widgets(ParameterWidgetsInfo::new(node_id, FillInput::::INDEX, true, context)); + + let document_node = match get_document_node(node_id, context) { + Ok(document_node) => document_node, + Err(err) => { + log::error!("Could not get document node in fill_properties: {err}"); + return Vec::new(); + } + }; + + let (fill, backup_color, backup_gradient) = if let (Some(TaggedValue::Fill(fill)), &Some(&TaggedValue::OptionalColor(backup_color)), Some(TaggedValue::Gradient(backup_gradient))) = ( + &document_node.inputs[FillInput::::INDEX].as_value(), + &document_node.inputs[BackupColorInput::INDEX].as_value(), + &document_node.inputs[BackupGradientInput::INDEX].as_value(), + ) { + (fill, backup_color, backup_gradient) + } else { + return vec![LayoutGroup::Row { widgets: widgets_first_row }]; + }; + let fill2 = fill.clone(); + let backup_color_fill: Fill = backup_color.into(); + let backup_gradient_fill: Fill = backup_gradient.clone().into(); + + widgets_first_row.push(Separator::new(SeparatorType::Unrelated).widget_holder()); + widgets_first_row.push( + ColorInput::default() + .value(fill.clone().into()) + .on_update(move |x: &ColorInput| { + Message::Batched(Box::new([ + match &fill2 { + Fill::None => NodeGraphMessage::SetInputValue { + node_id, + input_index: BackupColorInput::INDEX, + value: TaggedValue::OptionalColor(None), + } + .into(), + Fill::Solid(color) => NodeGraphMessage::SetInputValue { + node_id, + input_index: BackupColorInput::INDEX, + value: TaggedValue::OptionalColor(Some(*color)), + } + .into(), + Fill::Gradient(gradient) => NodeGraphMessage::SetInputValue { + node_id, + input_index: BackupGradientInput::INDEX, + value: TaggedValue::Gradient(gradient.clone()), + } + .into(), + }, + NodeGraphMessage::SetInputValue { + node_id, + input_index: FillInput::::INDEX, + value: TaggedValue::Fill(x.value.to_fill(fill2.as_gradient())), + } + .into(), + ])) + }) + .on_commit(commit_value) + .widget_holder(), + ); + let mut widgets = vec![LayoutGroup::Row { widgets: widgets_first_row }]; + + let fill_type_switch = { + let mut row = vec![TextLabel::new("").widget_holder()]; + match fill { + Fill::Solid(_) | Fill::None => add_blank_assist(&mut row), + Fill::Gradient(gradient) => { + let reverse_button = IconButton::new("Reverse", 24) + .tooltip("Reverse the gradient color stops") + .on_update(update_value( + { + let gradient = gradient.clone(); + move |_| { + let mut gradient = gradient.clone(); + gradient.stops = gradient.stops.reversed(); + TaggedValue::Fill(Fill::Gradient(gradient)) + } + }, + node_id, + FillInput::::INDEX, + )) + .widget_holder(); + row.push(Separator::new(SeparatorType::Unrelated).widget_holder()); + row.push(reverse_button); + } + } + + let entries = vec![ + RadioEntryData::new("solid") + .label("Solid") + .on_update(update_value(move |_| TaggedValue::Fill(backup_color_fill.clone()), node_id, FillInput::::INDEX)) + .on_commit(commit_value), + RadioEntryData::new("gradient") + .label("Gradient") + .on_update(update_value(move |_| TaggedValue::Fill(backup_gradient_fill.clone()), node_id, FillInput::::INDEX)) + .on_commit(commit_value), + ]; + + row.extend_from_slice(&[ + Separator::new(SeparatorType::Unrelated).widget_holder(), + RadioInput::new(entries).selected_index(Some(if fill.as_gradient().is_some() { 1 } else { 0 })).widget_holder(), + ]); + + LayoutGroup::Row { widgets: row } + }; + widgets.push(fill_type_switch); + + if let Fill::Gradient(gradient) = fill.clone() { + let mut row = vec![TextLabel::new("").widget_holder()]; + match gradient.gradient_type { + GradientType::Linear => add_blank_assist(&mut row), + GradientType::Radial => { + let orientation = if (gradient.end.x - gradient.start.x).abs() > f64::EPSILON * 1e6 { + gradient.end.x > gradient.start.x + } else { + (gradient.start.x + gradient.start.y) < (gradient.end.x + gradient.end.y) + }; + let reverse_radial_gradient_button = IconButton::new(if orientation { "ReverseRadialGradientToRight" } else { "ReverseRadialGradientToLeft" }, 24) + .tooltip("Reverse which end the gradient radiates from") + .on_update(update_value( + { + let gradient = gradient.clone(); + move |_| { + let mut gradient = gradient.clone(); + std::mem::swap(&mut gradient.start, &mut gradient.end); + TaggedValue::Fill(Fill::Gradient(gradient)) + } + }, + node_id, + FillInput::::INDEX, + )) + .widget_holder(); + row.push(Separator::new(SeparatorType::Unrelated).widget_holder()); + row.push(reverse_radial_gradient_button); + } + } + + let new_gradient1 = gradient.clone(); + let new_gradient2 = gradient.clone(); + + let entries = vec![ + RadioEntryData::new("Linear") + .label("Linear") + .on_update(update_value( + move |_| { + let mut new_gradient = new_gradient1.clone(); + new_gradient.gradient_type = GradientType::Linear; + TaggedValue::Fill(Fill::Gradient(new_gradient)) + }, + node_id, + FillInput::::INDEX, + )) + .on_commit(commit_value), + RadioEntryData::new("Radial") + .label("Radial") + .on_update(update_value( + move |_| { + let mut new_gradient = new_gradient2.clone(); + new_gradient.gradient_type = GradientType::Radial; + TaggedValue::Fill(Fill::Gradient(new_gradient)) + }, + node_id, + FillInput::::INDEX, + )) + .on_commit(commit_value), + ]; + + row.extend_from_slice(&[ + Separator::new(SeparatorType::Unrelated).widget_holder(), + RadioInput::new(entries).selected_index(Some(gradient.gradient_type as u32)).widget_holder(), + ]); + + widgets.push(LayoutGroup::Row { widgets: row }); + } + + widgets +} + +pub fn stroke_properties(node_id: NodeId, context: &mut NodePropertiesContext) -> Vec { + use graphene_std::vector::stroke::*; + + let document_node = match get_document_node(node_id, context) { + Ok(document_node) => document_node, + Err(err) => { + log::error!("Could not get document node in fill_properties: {err}"); + return Vec::new(); + } + }; + let join_value = match &document_node.inputs[JoinInput::INDEX].as_value() { + Some(TaggedValue::StrokeJoin(x)) => x, + _ => &StrokeJoin::Miter, + }; + + let dash_lengths_val = match &document_node.inputs[DashLengthsInput::INDEX].as_value() { + Some(TaggedValue::VecF64(x)) => x, + _ => &vec![], + }; + let has_dash_lengths = dash_lengths_val.is_empty(); + let miter_limit_disabled = join_value != &StrokeJoin::Miter; + + let color = color_widget( + ParameterWidgetsInfo::new(node_id, ColorInput::>::INDEX, true, context), + crate::messages::layout::utility_types::widgets::button_widgets::ColorInput::default(), + ); + let weight = number_widget(ParameterWidgetsInfo::new(node_id, WeightInput::INDEX, true, context), NumberInput::default().unit(" px").min(0.)); + let align = enum_choice::() + .for_socket(ParameterWidgetsInfo::new(node_id, AlignInput::INDEX, true, context)) + .property_row(); + let cap = enum_choice::().for_socket(ParameterWidgetsInfo::new(node_id, CapInput::INDEX, true, context)).property_row(); + let join = enum_choice::() + .for_socket(ParameterWidgetsInfo::new(node_id, JoinInput::INDEX, true, context)) + .property_row(); + + let miter_limit = number_widget( + ParameterWidgetsInfo::new(node_id, MiterLimitInput::INDEX, true, context), + NumberInput::default().min(0.).disabled(miter_limit_disabled), + ); + let paint_order = enum_choice::() + .for_socket(ParameterWidgetsInfo::new(node_id, PaintOrderInput::INDEX, true, context)) + .property_row(); + let disabled_number_input = NumberInput::default().unit(" px").disabled(has_dash_lengths); + let dash_lengths = array_of_number_widget(ParameterWidgetsInfo::new(node_id, DashLengthsInput::INDEX, true, context), TextInput::default().centered(true)); + let number_input = disabled_number_input; + let dash_offset = number_widget(ParameterWidgetsInfo::new(node_id, DashOffsetInput::INDEX, true, context), number_input); + + vec![ + color, + LayoutGroup::Row { widgets: weight }, + align, + cap, + join, + LayoutGroup::Row { widgets: miter_limit }, + paint_order, + LayoutGroup::Row { widgets: dash_lengths }, + LayoutGroup::Row { widgets: dash_offset }, + ] +} + +pub fn offset_path_properties(node_id: NodeId, context: &mut NodePropertiesContext) -> Vec { + use graphene_std::vector::offset_path::*; + + let number_input = NumberInput::default().unit(" px"); + let distance = number_widget(ParameterWidgetsInfo::new(node_id, DistanceInput::INDEX, true, context), number_input); + + let join = enum_choice::() + .for_socket(ParameterWidgetsInfo::new(node_id, JoinInput::INDEX, true, context)) + .property_row(); + + let document_node = match get_document_node(node_id, context) { + Ok(document_node) => document_node, + Err(err) => { + log::error!("Could not get document node in offset_path_properties: {err}"); + return Vec::new(); + } + }; + let number_input = NumberInput::default().min(0.).disabled({ + let join_val = match &document_node.inputs[JoinInput::INDEX].as_value() { + Some(TaggedValue::StrokeJoin(x)) => x, + _ => &StrokeJoin::Miter, + }; + join_val != &StrokeJoin::Miter + }); + let miter_limit = number_widget(ParameterWidgetsInfo::new(node_id, MiterLimitInput::INDEX, true, context), number_input); + + vec![LayoutGroup::Row { widgets: distance }, join, LayoutGroup::Row { widgets: miter_limit }] +} + +pub fn math_properties(node_id: NodeId, context: &mut NodePropertiesContext) -> Vec { + use graphene_std::math_nodes::math::*; + + let expression = (|| { + let mut widgets = start_widgets(ParameterWidgetsInfo::new(node_id, ExpressionInput::INDEX, true, context)); + + let document_node = match get_document_node(node_id, context) { + Ok(document_node) => document_node, + Err(err) => { + log::error!("Could not get document node in offset_path_properties: {err}"); + return Vec::new(); + } + }; + let Some(input) = document_node.inputs.get(ExpressionInput::INDEX) else { + log::warn!("A widget failed to be built because its node's input index is invalid."); + return vec![]; + }; + if let Some(TaggedValue::String(x)) = &input.as_non_exposed_value() { + widgets.extend_from_slice(&[ + Separator::new(SeparatorType::Unrelated).widget_holder(), + TextInput::new(x.clone()) + .centered(true) + .on_update(update_value( + |x: &TextInput| { + TaggedValue::String({ + let mut expression = x.value.trim().to_string(); + + if ["+", "-", "*", "/", "^", "%"].iter().any(|&infix| infix == expression) { + expression = format!("A {} B", expression); + } else if expression == "^" { + expression = String::from("A^B"); + } + + expression + }) + }, + node_id, + ExpressionInput::INDEX, + )) + .on_commit(commit_value) + .widget_holder(), + ]) + } + widgets + })(); + let operand_b = number_widget(ParameterWidgetsInfo::new(node_id, OperandBInput::::INDEX, true, context), NumberInput::default()); + let operand_a_hint = vec![TextLabel::new("(Operand A is the primary input)").widget_holder()]; + + vec![ + LayoutGroup::Row { widgets: expression }.with_tooltip(r#"A math expression that may incorporate "A" and/or "B", such as "sqrt(A + B) - B^2""#), + LayoutGroup::Row { widgets: operand_b }.with_tooltip(r#"The value of "B" when calculating the expression"#), + LayoutGroup::Row { widgets: operand_a_hint }.with_tooltip(r#""A" is fed by the value from the previous node in the primary data flow, or it is 0 if disconnected"#), + ] +} + +pub struct ParameterWidgetsInfo<'a> { + document_node: Option<&'a DocumentNode>, + node_id: NodeId, + index: usize, + name: String, + description: String, + input_type: FrontendGraphDataType, + blank_assist: bool, + exposeable: bool, +} + +impl<'a> ParameterWidgetsInfo<'a> { + pub fn new(node_id: NodeId, index: usize, blank_assist: bool, context: &'a mut NodePropertiesContext) -> ParameterWidgetsInfo<'a> { + let (name, description) = context.network_interface.displayed_input_name_and_description(&node_id, index, context.selection_network_path); + let input_type = FrontendGraphDataType::from_type(&context.network_interface.input_type(&InputConnector::node(node_id, index), context.selection_network_path).0); + let document_node = context.network_interface.document_node(&node_id, context.selection_network_path); + + ParameterWidgetsInfo { + document_node, + node_id, + index, + name, + description, + input_type, + blank_assist, + exposeable: true, + } + } +} + +pub mod choice { + use super::ParameterWidgetsInfo; + use crate::messages::tool::tool_messages::tool_prelude::*; + use graph_craft::document::value::TaggedValue; + use graphene_std::registry::{ChoiceTypeStatic, ChoiceWidgetHint}; + use std::marker::PhantomData; + + pub trait WidgetFactory { + type Value: Clone + 'static; + + fn disabled(self, disabled: bool) -> Self; + + fn build(&self, current: Self::Value, updater_factory: impl Fn() -> U, committer_factory: impl Fn() -> C) -> WidgetHolder + where + U: Fn(&Self::Value) -> Message + 'static + Send + Sync, + C: Fn(&()) -> Message + 'static + Send + Sync; + + fn description(&self) -> Option<&str>; + } + + pub fn enum_choice() -> EnumChoice { + EnumChoice { + disabled: false, + phantom: PhantomData, + } + } + + pub struct EnumChoice { + disabled: bool, + phantom: PhantomData, + } + + impl EnumChoice { + pub fn for_socket(self, parameter_info: ParameterWidgetsInfo) -> ForSocket { + ForSocket { widget_factory: self, parameter_info } + } + + /// Not yet implemented! + pub fn for_value(self, _current: E) -> ForValue { + todo!() + } + + pub fn disabled(self, disabled: bool) -> Self { + Self { disabled, ..self } + } + + /// Not yet implemented! + pub fn into_menu_entries(self, _action: impl Fn(E) -> Message + 'static + Send + Sync) -> Vec> { + todo!() + } + + fn dropdown_menu(&self, current: E, updater_factory: impl Fn() -> U, committer_factory: impl Fn() -> C) -> WidgetHolder + where + U: Fn(&E) -> Message + 'static + Send + Sync, + C: Fn(&()) -> Message + 'static + Send + Sync, + { + let items = E::list() + .iter() + .map(|group| { + group + .iter() + .map(|(item, metadata)| { + let updater = updater_factory(); + let committer = committer_factory(); + MenuListEntry::new(metadata.name.as_ref()) + .label(metadata.label.as_ref()) + .on_update(move |_| updater(item)) + .on_commit(committer) + }) + .collect() + }) + .collect(); + DropdownInput::new(items).disabled(self.disabled).selected_index(Some(current.as_u32())).widget_holder() + } + + fn radio_buttons(&self, current: E, updater_factory: impl Fn() -> U, committer_factory: impl Fn() -> C) -> WidgetHolder + where + U: Fn(&E) -> Message + 'static + Send + Sync, + C: Fn(&()) -> Message + 'static + Send + Sync, + { + let items = E::list() + .iter() + .flat_map(|group| group.iter()) + .map(|(item, var_meta)| { + let updater = updater_factory(); + let committer = committer_factory(); + let entry = RadioEntryData::new(var_meta.name.as_ref()).on_update(move |_| updater(item)).on_commit(committer); + match (var_meta.icon.as_deref(), var_meta.docstring.as_deref()) { + (None, None) => entry.label(var_meta.label.as_ref()), + (None, Some(doc)) => entry.label(var_meta.label.as_ref()).tooltip(doc), + (Some(icon), None) => entry.icon(icon).tooltip(var_meta.label.as_ref()), + (Some(icon), Some(doc)) => entry.icon(icon).tooltip(format!("{}\n\n{}", var_meta.label, doc)), + } + }) + .collect(); + RadioInput::new(items).selected_index(Some(current.as_u32())).widget_holder() + } + } + + impl WidgetFactory for EnumChoice { + type Value = E; + + fn disabled(self, disabled: bool) -> Self { + Self { disabled, ..self } + } + + fn description(&self) -> Option<&str> { + E::DESCRIPTION + } + + fn build(&self, current: Self::Value, updater_factory: impl Fn() -> U, committer_factory: impl Fn() -> C) -> WidgetHolder + where + U: Fn(&Self::Value) -> Message + 'static + Send + Sync, + C: Fn(&()) -> Message + 'static + Send + Sync, + { + match E::WIDGET_HINT { + ChoiceWidgetHint::Dropdown => self.dropdown_menu(current, updater_factory, committer_factory), + ChoiceWidgetHint::RadioButtons => self.radio_buttons(current, updater_factory, committer_factory), + } + } + } + + pub struct ForSocket<'p, W> { + widget_factory: W, + parameter_info: ParameterWidgetsInfo<'p>, + } + + impl<'p, W> ForSocket<'p, W> + where + W: WidgetFactory, + W::Value: Clone, + for<'a> &'a W::Value: TryFrom<&'a TaggedValue>, + TaggedValue: From, + { + pub fn disabled(self, disabled: bool) -> Self { + Self { + widget_factory: self.widget_factory.disabled(disabled), + ..self + } + } + + pub fn property_row(self) -> LayoutGroup { + let ParameterWidgetsInfo { document_node, node_id, index, .. } = self.parameter_info; + let Some(document_node) = document_node else { + log::error!("Could not get document node when building property row for node {:?}", node_id); + return LayoutGroup::Row { widgets: Vec::new() }; + }; + + let mut widgets = super::start_widgets(self.parameter_info); + + let Some(input) = document_node.inputs.get(index) else { + log::warn!("A widget failed to be built because its node's input index is invalid."); + return LayoutGroup::Row { widgets: vec![] }; + }; + + let input: Option = input.as_non_exposed_value().and_then(|v| <&W::Value as TryFrom<&TaggedValue>>::try_from(v).ok()).cloned(); + + if let Some(current) = input { + let committer = || super::commit_value; + let updater = || super::update_value(move |v: &W::Value| TaggedValue::from(v.clone()), node_id, index); + let widget = self.widget_factory.build(current, updater, committer); + widgets.extend_from_slice(&[Separator::new(SeparatorType::Unrelated).widget_holder(), widget]); + } + + let mut row = LayoutGroup::Row { widgets }; + if let Some(desc) = self.widget_factory.description() { + row = row.with_tooltip(desc); + } + row + } + } + + pub struct ForValue(PhantomData); +} diff --git a/editor/src/messages/portfolio/document/node_graph/utility_types.rs b/editor/src/messages/portfolio/document/node_graph/utility_types.rs new file mode 100644 index 0000000000000000000000000000000000000000..b743cb1fc61e810341f28f0cd4b32229dd6de5ed --- /dev/null +++ b/editor/src/messages/portfolio/document/node_graph/utility_types.rs @@ -0,0 +1,207 @@ +use crate::messages::portfolio::document::utility_types::network_interface::{InputConnector, OutputConnector, TypeSource}; +use graph_craft::document::NodeId; +use graph_craft::document::value::TaggedValue; +use graphene_std::Type; + +#[derive(Clone, Copy, Debug, Default, Eq, PartialEq, Hash, serde::Serialize, serde::Deserialize, specta::Type)] +pub enum FrontendGraphDataType { + #[default] + General, + Raster, + VectorData, + Number, + Group, + Artboard, +} + +impl FrontendGraphDataType { + pub fn from_type(input: &Type) -> Self { + match TaggedValue::from_type_or_none(input) { + TaggedValue::Image(_) | TaggedValue::RasterData(_) => Self::Raster, + TaggedValue::Subpaths(_) | TaggedValue::VectorData(_) => Self::VectorData, + TaggedValue::U32(_) + | TaggedValue::U64(_) + | TaggedValue::F64(_) + | TaggedValue::UVec2(_) + | TaggedValue::IVec2(_) + | TaggedValue::DVec2(_) + | TaggedValue::OptionalDVec2(_) + | TaggedValue::F64Array4(_) + | TaggedValue::VecF64(_) + | TaggedValue::VecDVec2(_) => Self::Number, + TaggedValue::GraphicGroup(_) | TaggedValue::GraphicElement(_) => Self::Group, // TODO: Is GraphicElement supposed to be included here? + TaggedValue::ArtboardGroup(_) => Self::Artboard, + _ => Self::General, + } + } + + pub fn displayed_type(input: &Type, type_source: &TypeSource) -> Self { + match type_source { + TypeSource::Error(_) | TypeSource::RandomProtonodeImplementation => Self::General, + _ => Self::from_type(input), + } + } +} + +#[derive(Clone, Debug, Eq, PartialEq, serde::Serialize, serde::Deserialize, specta::Type)] +pub struct FrontendGraphInput { + #[serde(rename = "dataType")] + pub data_type: FrontendGraphDataType, + pub name: String, + pub description: String, + #[serde(rename = "resolvedType")] + pub resolved_type: String, + #[serde(rename = "validTypes")] + pub valid_types: Vec, + #[serde(rename = "connectedTo")] + pub connected_to: Option, +} + +#[derive(Clone, Debug, Eq, PartialEq, serde::Serialize, serde::Deserialize, specta::Type)] +pub struct FrontendGraphOutput { + #[serde(rename = "dataType")] + pub data_type: FrontendGraphDataType, + pub name: String, + pub description: String, + #[serde(rename = "resolvedType")] + pub resolved_type: String, + #[serde(rename = "connectedTo")] + pub connected_to: Vec, +} + +#[derive(Clone, Debug, Eq, PartialEq, serde::Serialize, serde::Deserialize, specta::Type)] +pub struct FrontendNode { + pub id: graph_craft::document::NodeId, + #[serde(rename = "isLayer")] + pub is_layer: bool, + #[serde(rename = "canBeLayer")] + pub can_be_layer: bool, + pub reference: Option, + #[serde(rename = "displayName")] + pub display_name: String, + #[serde(rename = "primaryInput")] + pub primary_input: Option, + #[serde(rename = "exposedInputs")] + pub exposed_inputs: Vec, + #[serde(rename = "primaryOutput")] + pub primary_output: Option, + #[serde(rename = "exposedOutputs")] + pub exposed_outputs: Vec, + pub position: (i32, i32), + pub visible: bool, + pub locked: bool, + pub previewed: bool, + pub errors: Option, + #[serde(rename = "uiOnly")] + pub ui_only: bool, +} + +#[derive(Clone, Debug, Eq, PartialEq, serde::Serialize, serde::Deserialize, specta::Type)] +pub struct FrontendNodeType { + pub name: String, + pub category: String, + #[serde(rename = "inputTypes")] + pub input_types: Option>, +} + +impl FrontendNodeType { + pub fn new(name: &'static str, category: &'static str) -> Self { + Self { + name: name.to_string(), + category: category.to_string(), + input_types: None, + } + } + + pub fn with_input_types(name: &'static str, category: &'static str, input_types: Vec) -> Self { + Self { + name: name.to_string(), + category: category.to_string(), + input_types: Some(input_types), + } + } + + pub fn with_owned_strings_and_input_types(name: String, category: String, input_types: Vec) -> Self { + Self { + name, + category, + input_types: Some(input_types), + } + } +} +#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize, specta::Type)] +pub struct DragStart { + pub start_x: f64, + pub start_y: f64, + pub round_x: i32, + pub round_y: i32, +} + +#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize, specta::Type)] +pub struct Transform { + pub scale: f64, + pub x: f64, + pub y: f64, +} + +#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize, specta::Type)] +pub struct BoxSelection { + #[serde(rename = "startX")] + pub start_x: u32, + #[serde(rename = "startY")] + pub start_y: u32, + #[serde(rename = "endX")] + pub end_x: u32, + #[serde(rename = "endY")] + pub end_y: u32, +} + +#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize, specta::Type)] +pub enum ContextMenuData { + ToggleLayer { + #[serde(rename = "nodeId")] + node_id: NodeId, + #[serde(rename = "currentlyIsNode")] + currently_is_node: bool, + }, + CreateNode { + #[serde(rename = "compatibleType")] + #[serde(default)] + compatible_type: Option, + }, +} + +#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize, specta::Type)] +pub struct ContextMenuInformation { + // Stores whether the context menu is open and its position in graph coordinates + #[serde(rename = "contextMenuCoordinates")] + pub context_menu_coordinates: (i32, i32), + #[serde(rename = "contextMenuData")] + pub context_menu_data: ContextMenuData, +} + +#[derive(Clone, Debug, PartialEq, Default, serde::Serialize, serde::Deserialize, specta::Type)] +pub struct FrontendClickTargets { + #[serde(rename = "nodeClickTargets")] + pub node_click_targets: Vec, + #[serde(rename = "layerClickTargets")] + pub layer_click_targets: Vec, + #[serde(rename = "portClickTargets")] + pub port_click_targets: Vec, + #[serde(rename = "iconClickTargets")] + pub icon_click_targets: Vec, + #[serde(rename = "allNodesBoundingBox")] + pub all_nodes_bounding_box: String, + #[serde(rename = "importExportsBoundingBox")] + pub import_exports_bounding_box: String, + #[serde(rename = "modifyImportExport")] + pub modify_import_export: Vec, +} + +#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize, specta::Type)] +pub enum Direction { + Up, + Down, + Left, + Right, +} diff --git a/editor/src/messages/portfolio/document/overlays/grid_overlays.rs b/editor/src/messages/portfolio/document/overlays/grid_overlays.rs new file mode 100644 index 0000000000000000000000000000000000000000..97cf2fdf7d333a1f17562aefa94a6573d63e6150 --- /dev/null +++ b/editor/src/messages/portfolio/document/overlays/grid_overlays.rs @@ -0,0 +1,361 @@ +use crate::messages::layout::utility_types::widget_prelude::*; +use crate::messages::portfolio::document::overlays::utility_types::OverlayContext; +use crate::messages::portfolio::document::utility_types::misc::{GridSnapping, GridType}; +use crate::messages::prelude::*; +use glam::DVec2; +use graphene_std::raster::color::Color; +use graphene_std::renderer::Quad; +use graphene_std::vector::style::FillChoice; + +fn grid_overlay_rectangular(document: &DocumentMessageHandler, overlay_context: &mut OverlayContext, spacing: DVec2) { + let origin = document.snapping_state.grid.origin; + let grid_color = "#".to_string() + &document.snapping_state.grid.grid_color.to_rgba_hex_srgb(); + let Some(spacing) = GridSnapping::compute_rectangle_spacing(spacing, &document.document_ptz) else { + return; + }; + let document_to_viewport = document.navigation_handler.calculate_offset_transform(overlay_context.size / 2., &document.document_ptz); + + let bounds = document_to_viewport.inverse() * Quad::from_box([DVec2::ZERO, overlay_context.size]); + + for primary in 0..2 { + let secondary = 1 - primary; + let min = bounds.0.iter().map(|&corner| corner[secondary]).min_by(|a, b| a.partial_cmp(b).unwrap()).unwrap_or_default(); + let max = bounds.0.iter().map(|&corner| corner[secondary]).max_by(|a, b| a.partial_cmp(b).unwrap()).unwrap_or_default(); + let primary_start = bounds.0.iter().map(|&corner| corner[primary]).min_by(|a, b| a.partial_cmp(b).unwrap()).unwrap_or_default(); + let primary_end = bounds.0.iter().map(|&corner| corner[primary]).max_by(|a, b| a.partial_cmp(b).unwrap()).unwrap_or_default(); + let spacing = spacing[secondary]; + for line_index in 0..=((max - min) / spacing).ceil() as i32 { + let secondary_pos = (((min - origin[secondary]) / spacing).ceil() + line_index as f64) * spacing + origin[secondary]; + let start = if primary == 0 { + DVec2::new(primary_start, secondary_pos) + } else { + DVec2::new(secondary_pos, primary_start) + }; + let end = if primary == 0 { + DVec2::new(primary_end, secondary_pos) + } else { + DVec2::new(secondary_pos, primary_end) + }; + overlay_context.line(document_to_viewport.transform_point2(start), document_to_viewport.transform_point2(end), Some(&grid_color), None); + } + } +} + +// In the best case, where the x distance/total dots is an integer, this will reduce draw requests from the current m(horizontal dots)*n(vertical dots) to m(horizontal lines) * 1(line changes). +// In the worst case, where the x distance/total dots is an integer+0.5, then each pixel will require a new line, and requests will be m(horizontal lines)*n(line changes = horizontal dots). +// The draw dashed line method will also be not grid aligned for tilted grids. +// TODO: Potentially create an image and render the image onto the canvas a single time. +// TODO: Implement this with a dashed line (`set_line_dash`), with integer spacing which is continuously adjusted to correct the accumulated error. +fn grid_overlay_rectangular_dot(document: &DocumentMessageHandler, overlay_context: &mut OverlayContext, spacing: DVec2) { + let origin = document.snapping_state.grid.origin; + let grid_color = "#".to_string() + &document.snapping_state.grid.grid_color.to_rgba_hex_srgb(); + let Some(spacing) = GridSnapping::compute_rectangle_spacing(spacing, &document.document_ptz) else { + return; + }; + let document_to_viewport = document.navigation_handler.calculate_offset_transform(overlay_context.size / 2., &document.document_ptz); + + let bounds = document_to_viewport.inverse() * Quad::from_box([DVec2::ZERO, overlay_context.size]); + + let min = bounds.0.iter().map(|corner| corner.y).min_by(|a, b| a.partial_cmp(b).unwrap()).unwrap_or_default(); + let max = bounds.0.iter().map(|corner| corner.y).max_by(|a, b| a.partial_cmp(b).unwrap()).unwrap_or_default(); + + let mut primary_start = bounds.0.iter().map(|corner| corner.x).min_by(|a, b| a.partial_cmp(b).unwrap()).unwrap_or_default(); + let mut primary_end = bounds.0.iter().map(|corner| corner.x).max_by(|a, b| a.partial_cmp(b).unwrap()).unwrap_or_default(); + + primary_start = (primary_start / spacing.x).floor() * spacing.x + origin.x % spacing.x; + primary_end = (primary_end / spacing.x).floor() * spacing.x + origin.x % spacing.x; + + // Round to avoid floating point errors + let total_dots = ((primary_end - primary_start) / spacing.x).round(); + + for line_index in 0..=((max - min) / spacing.y).ceil() as i32 { + let secondary_pos = (((min - origin.y) / spacing.y).ceil() + line_index as f64) * spacing.y + origin.y; + let start = DVec2::new(primary_start, secondary_pos); + let end = DVec2::new(primary_end, secondary_pos); + + let x_per_dot = (end.x - start.x) / total_dots; + for dot_index in 0..=total_dots as usize { + let exact_x = x_per_dot * dot_index as f64; + overlay_context.pixel(document_to_viewport.transform_point2(DVec2::new(start.x + exact_x, start.y)).round(), Some(&grid_color)) + } + } +} + +fn grid_overlay_isometric(document: &DocumentMessageHandler, overlay_context: &mut OverlayContext, y_axis_spacing: f64, angle_a: f64, angle_b: f64) { + let grid_color = "#".to_string() + &document.snapping_state.grid.grid_color.to_rgba_hex_srgb(); + let cmp = |a: &f64, b: &f64| a.partial_cmp(b).unwrap(); + let origin = document.snapping_state.grid.origin; + let document_to_viewport = document.navigation_handler.calculate_offset_transform(overlay_context.size / 2., &document.document_ptz); + + let bounds = document_to_viewport.inverse() * Quad::from_box([DVec2::ZERO, overlay_context.size]); + let tan_a = angle_a.to_radians().tan(); + let tan_b = angle_b.to_radians().tan(); + let spacing = DVec2::new(y_axis_spacing / (tan_a + tan_b), y_axis_spacing); + let Some(spacing_multiplier) = GridSnapping::compute_isometric_multiplier(y_axis_spacing, tan_a + tan_b, &document.document_ptz) else { + return; + }; + let isometric_spacing = spacing * spacing_multiplier; + + let min_x = bounds.0.iter().map(|&corner| corner.x).min_by(cmp).unwrap_or_default(); + let max_x = bounds.0.iter().map(|&corner| corner.x).max_by(cmp).unwrap_or_default(); + let min_y = bounds.0.iter().map(|&corner| corner.y).min_by(cmp).unwrap_or_default(); + let max_y = bounds.0.iter().map(|&corner| corner.y).max_by(cmp).unwrap_or_default(); + let spacing = isometric_spacing.x; + for line_index in 0..=((max_x - min_x) / spacing).ceil() as i32 { + let x_pos = (((min_x - origin.x) / spacing).ceil() + line_index as f64) * spacing + origin.x; + let start = DVec2::new(x_pos, min_y); + let end = DVec2::new(x_pos, max_y); + overlay_context.line(document_to_viewport.transform_point2(start), document_to_viewport.transform_point2(end), Some(&grid_color), None); + } + + for (tan, multiply) in [(tan_a, -1.), (tan_b, 1.)] { + let project = |corner: &DVec2| corner.y + multiply * tan * (corner.x - origin.x); + let inverse_project = |corner: &DVec2| corner.y - tan * multiply * (corner.x - origin.x); + let min_y = bounds.0.into_iter().min_by(|a, b| inverse_project(a).partial_cmp(&inverse_project(b)).unwrap()).unwrap_or_default(); + let max_y = bounds.0.into_iter().max_by(|a, b| inverse_project(a).partial_cmp(&inverse_project(b)).unwrap()).unwrap_or_default(); + let spacing = isometric_spacing.y; + let lines = ((inverse_project(&max_y) - inverse_project(&min_y)) / spacing).ceil() as i32; + for line_index in 0..=lines { + let y_pos = (((inverse_project(&min_y) - origin.y) / spacing).ceil() + line_index as f64) * spacing + origin.y; + let start = DVec2::new(min_x, project(&DVec2::new(min_x, y_pos))); + let end = DVec2::new(max_x, project(&DVec2::new(max_x, y_pos))); + overlay_context.line(document_to_viewport.transform_point2(start), document_to_viewport.transform_point2(end), Some(&grid_color), None); + } + } +} + +fn grid_overlay_isometric_dot(document: &DocumentMessageHandler, overlay_context: &mut OverlayContext, y_axis_spacing: f64, angle_a: f64, angle_b: f64) { + let grid_color = "#".to_string() + &document.snapping_state.grid.grid_color.to_rgba_hex_srgb(); + let cmp = |a: &f64, b: &f64| a.partial_cmp(b).unwrap(); + let origin = document.snapping_state.grid.origin; + let document_to_viewport = document.navigation_handler.calculate_offset_transform(overlay_context.size / 2., &document.document_ptz); + + let bounds = document_to_viewport.inverse() * Quad::from_box([DVec2::ZERO, overlay_context.size]); + let tan_a = angle_a.to_radians().tan(); + let tan_b = angle_b.to_radians().tan(); + let spacing = DVec2::new(y_axis_spacing / (tan_a + tan_b), y_axis_spacing); + let Some(spacing_multiplier) = GridSnapping::compute_isometric_multiplier(y_axis_spacing, tan_a + tan_b, &document.document_ptz) else { + return; + }; + let isometric_spacing = spacing * spacing_multiplier; + + let min_x = bounds.0.iter().map(|&corner| corner.x).min_by(cmp).unwrap_or_default(); + let max_x = bounds.0.iter().map(|&corner| corner.x).max_by(cmp).unwrap_or_default(); + let spacing_x = isometric_spacing.x; + let tan = tan_a; + let multiply = -1.; + let project = |corner: &DVec2| corner.y + multiply * tan * (corner.x - origin.x); + let inverse_project = |corner: &DVec2| corner.y - tan * multiply * (corner.x - origin.x); + let min_y = bounds.0.into_iter().min_by(|a, b| inverse_project(a).partial_cmp(&inverse_project(b)).unwrap()).unwrap_or_default(); + let max_y = bounds.0.into_iter().max_by(|a, b| inverse_project(a).partial_cmp(&inverse_project(b)).unwrap()).unwrap_or_default(); + let spacing_y = isometric_spacing.y; + let lines = ((inverse_project(&max_y) - inverse_project(&min_y)) / spacing_y).ceil() as i32; + + let cos_a = angle_a.to_radians().cos(); + // If cos_a is 0 then there will be no intersections and thus no dots should be drawn + if cos_a.abs() <= 0.00001 { + return; + } + let x_offset = (((min_x - origin.x) / spacing_x).ceil()) * spacing_x + origin.x - min_x; + for line_index in 0..=lines { + let y_pos = (((inverse_project(&min_y) - origin.y) / spacing_y).ceil() + line_index as f64) * spacing_y + origin.y; + let start = DVec2::new(min_x + x_offset, project(&DVec2::new(min_x + x_offset, y_pos))); + let end = DVec2::new(max_x + x_offset, project(&DVec2::new(max_x + x_offset, y_pos))); + + overlay_context.dashed_line( + document_to_viewport.transform_point2(start), + document_to_viewport.transform_point2(end), + Some(&grid_color), + None, + Some(1.), + Some((spacing_x / cos_a) * document_to_viewport.matrix2.x_axis.length() - 1.), + None, + ); + } +} + +pub fn grid_overlay(document: &DocumentMessageHandler, overlay_context: &mut OverlayContext) { + match document.snapping_state.grid.grid_type { + GridType::Rectangular { spacing } => { + if document.snapping_state.grid.dot_display { + grid_overlay_rectangular_dot(document, overlay_context, spacing) + } else { + grid_overlay_rectangular(document, overlay_context, spacing) + } + } + GridType::Isometric { y_axis_spacing, angle_a, angle_b } => { + if document.snapping_state.grid.dot_display { + grid_overlay_isometric_dot(document, overlay_context, y_axis_spacing, angle_a, angle_b) + } else { + grid_overlay_isometric(document, overlay_context, y_axis_spacing, angle_a, angle_b) + } + } + } +} + +pub fn overlay_options(grid: &GridSnapping) -> Vec { + let mut widgets = Vec::new(); + fn update_val(grid: &GridSnapping, update: F) -> impl Fn(&I) -> Message + use { + let grid = grid.clone(); + move |input: &I| { + let mut grid = grid.clone(); + update(&mut grid, input); + DocumentMessage::GridOptions(grid).into() + } + } + let update_origin = |grid, update: fn(&mut GridSnapping) -> Option<&mut f64>| { + update_val::(grid, move |grid, val| { + if let Some(val) = val.value { + if let Some(update) = update(grid) { + *update = val; + } + } + }) + }; + let update_color = |grid, update: fn(&mut GridSnapping) -> Option<&mut Color>| { + update_val::(grid, move |grid, color| { + if let (Some(color), Some(update_color)) = (color.value.as_solid(), update(grid)) { + *update_color = color.to_linear_srgb(); + } + }) + }; + let update_display = |grid, update: fn(&mut GridSnapping) -> Option<&mut bool>| { + update_val::(grid, move |grid, checkbox| { + if let Some(update) = update(grid) { + *update = checkbox.checked; + } + }) + }; + + widgets.push(LayoutGroup::Row { + widgets: vec![TextLabel::new("Grid").bold(true).widget_holder()], + }); + + widgets.push(LayoutGroup::Row { + widgets: vec![ + TextLabel::new("Type").table_align(true).widget_holder(), + Separator::new(SeparatorType::Unrelated).widget_holder(), + RadioInput::new(vec![ + RadioEntryData::new("rectangular").label("Rectangular").on_update(update_val(grid, |grid, _| { + if let GridType::Isometric { y_axis_spacing, angle_a, angle_b } = grid.grid_type { + grid.isometric_y_spacing = y_axis_spacing; + grid.isometric_angle_a = angle_a; + grid.isometric_angle_b = angle_b; + } + grid.grid_type = GridType::Rectangular { spacing: grid.rectangular_spacing }; + })), + RadioEntryData::new("isometric").label("Isometric").on_update(update_val(grid, |grid, _| { + if let GridType::Rectangular { spacing } = grid.grid_type { + grid.rectangular_spacing = spacing; + } + grid.grid_type = GridType::Isometric { + y_axis_spacing: grid.isometric_y_spacing, + angle_a: grid.isometric_angle_a, + angle_b: grid.isometric_angle_b, + }; + })), + ]) + .min_width(200) + .selected_index(Some(match grid.grid_type { + GridType::Rectangular { .. } => 0, + GridType::Isometric { .. } => 1, + })) + .widget_holder(), + ], + }); + + let mut color_widgets = vec![TextLabel::new("Display").table_align(true).widget_holder(), Separator::new(SeparatorType::Unrelated).widget_holder()]; + color_widgets.extend([ + CheckboxInput::new(grid.dot_display) + .icon("GridDotted") + .tooltip("Display as dotted grid") + .on_update(update_display(grid, |grid| Some(&mut grid.dot_display))) + .widget_holder(), + Separator::new(SeparatorType::Related).widget_holder(), + ]); + color_widgets.push( + ColorInput::new(FillChoice::Solid(grid.grid_color.to_gamma_srgb())) + .tooltip("Grid display color") + .allow_none(false) + .on_update(update_color(grid, |grid| Some(&mut grid.grid_color))) + .widget_holder(), + ); + widgets.push(LayoutGroup::Row { widgets: color_widgets }); + + widgets.push(LayoutGroup::Row { + widgets: vec![ + TextLabel::new("Origin").table_align(true).widget_holder(), + Separator::new(SeparatorType::Unrelated).widget_holder(), + NumberInput::new(Some(grid.origin.x)) + .label("X") + .unit(" px") + .min_width(98) + .on_update(update_origin(grid, |grid| Some(&mut grid.origin.x))) + .widget_holder(), + Separator::new(SeparatorType::Related).widget_holder(), + NumberInput::new(Some(grid.origin.y)) + .label("Y") + .unit(" px") + .min_width(98) + .on_update(update_origin(grid, |grid| Some(&mut grid.origin.y))) + .widget_holder(), + ], + }); + + match grid.grid_type { + GridType::Rectangular { spacing } => widgets.push(LayoutGroup::Row { + widgets: vec![ + TextLabel::new("Spacing").table_align(true).widget_holder(), + Separator::new(SeparatorType::Unrelated).widget_holder(), + NumberInput::new(Some(spacing.x)) + .label("X") + .unit(" px") + .min(0.) + .min_width(98) + .on_update(update_origin(grid, |grid| grid.grid_type.rectangular_spacing().map(|spacing| &mut spacing.x))) + .widget_holder(), + Separator::new(SeparatorType::Related).widget_holder(), + NumberInput::new(Some(spacing.y)) + .label("Y") + .unit(" px") + .min(0.) + .min_width(98) + .on_update(update_origin(grid, |grid| grid.grid_type.rectangular_spacing().map(|spacing| &mut spacing.y))) + .widget_holder(), + ], + }), + GridType::Isometric { y_axis_spacing, angle_a, angle_b } => { + widgets.push(LayoutGroup::Row { + widgets: vec![ + TextLabel::new("Y Spacing").table_align(true).widget_holder(), + Separator::new(SeparatorType::Unrelated).widget_holder(), + NumberInput::new(Some(y_axis_spacing)) + .unit(" px") + .min(0.) + .min_width(200) + .on_update(update_origin(grid, |grid| grid.grid_type.isometric_y_spacing())) + .widget_holder(), + ], + }); + widgets.push(LayoutGroup::Row { + widgets: vec![ + TextLabel::new("Angles").table_align(true).widget_holder(), + Separator::new(SeparatorType::Unrelated).widget_holder(), + NumberInput::new(Some(angle_a)) + .unit("°") + .min_width(98) + .on_update(update_origin(grid, |grid| grid.grid_type.angle_a())) + .widget_holder(), + Separator::new(SeparatorType::Related).widget_holder(), + NumberInput::new(Some(angle_b)) + .unit("°") + .min_width(98) + .on_update(update_origin(grid, |grid| grid.grid_type.angle_b())) + .widget_holder(), + ], + }); + } + } + + widgets +} diff --git a/editor/src/messages/portfolio/document/overlays/mod.rs b/editor/src/messages/portfolio/document/overlays/mod.rs new file mode 100644 index 0000000000000000000000000000000000000000..2102b3a322ba794a8b02627cf148c76aab3dc672 --- /dev/null +++ b/editor/src/messages/portfolio/document/overlays/mod.rs @@ -0,0 +1,10 @@ +pub mod grid_overlays; +mod overlays_message; +mod overlays_message_handler; +pub mod utility_functions; +pub mod utility_types; + +#[doc(inline)] +pub use overlays_message::{OverlaysMessage, OverlaysMessageDiscriminant}; +#[doc(inline)] +pub use overlays_message_handler::{OverlaysMessageData, OverlaysMessageHandler}; diff --git a/editor/src/messages/portfolio/document/overlays/overlays_message.rs b/editor/src/messages/portfolio/document/overlays/overlays_message.rs new file mode 100644 index 0000000000000000000000000000000000000000..5ab1e7773cf3a3aefd03f7be73dd3bbfbb8d3c43 --- /dev/null +++ b/editor/src/messages/portfolio/document/overlays/overlays_message.rs @@ -0,0 +1,20 @@ +use super::utility_types::{OverlayProvider, empty_provider}; +use crate::messages::prelude::*; + +#[impl_message(Message, DocumentMessage, Overlays)] +#[derive(derivative::Derivative, Clone, serde::Serialize, serde::Deserialize)] +#[derivative(Debug, PartialEq)] +pub enum OverlaysMessage { + Draw, + // Serde functionality isn't used but is required by the message system macros + AddProvider( + #[serde(skip, default = "empty_provider")] + #[derivative(Debug = "ignore", PartialEq = "ignore")] + OverlayProvider, + ), + RemoveProvider( + #[serde(skip, default = "empty_provider")] + #[derivative(Debug = "ignore", PartialEq = "ignore")] + OverlayProvider, + ), +} diff --git a/editor/src/messages/portfolio/document/overlays/overlays_message_handler.rs b/editor/src/messages/portfolio/document/overlays/overlays_message_handler.rs new file mode 100644 index 0000000000000000000000000000000000000000..0db542da751fb4285aa34325f56c8639ac92bc54 --- /dev/null +++ b/editor/src/messages/portfolio/document/overlays/overlays_message_handler.rs @@ -0,0 +1,84 @@ +use super::utility_types::{OverlayProvider, OverlaysVisibilitySettings}; +use crate::messages::prelude::*; + +pub struct OverlaysMessageData<'a> { + pub visibility_settings: OverlaysVisibilitySettings, + pub ipp: &'a InputPreprocessorMessageHandler, + pub device_pixel_ratio: f64, +} + +#[derive(Debug, Clone, Default)] +pub struct OverlaysMessageHandler { + pub overlay_providers: HashSet, + #[cfg(target_arch = "wasm32")] + canvas: Option, + #[cfg(target_arch = "wasm32")] + context: Option, +} + +impl MessageHandler> for OverlaysMessageHandler { + fn process_message(&mut self, message: OverlaysMessage, responses: &mut VecDeque, data: OverlaysMessageData) { + let OverlaysMessageData { visibility_settings, ipp, .. } = data; + + match message { + #[cfg(target_arch = "wasm32")] + OverlaysMessage::Draw => { + use super::utility_functions::overlay_canvas_element; + use super::utility_types::OverlayContext; + use glam::{DAffine2, DVec2}; + use wasm_bindgen::JsCast; + + let device_pixel_ratio = data.device_pixel_ratio; + + let canvas = match &self.canvas { + Some(canvas) => canvas, + None => { + let Some(new_canvas) = overlay_canvas_element() else { return }; + self.canvas.get_or_insert(new_canvas) + } + }; + + let context = self.context.get_or_insert_with(|| { + let context = canvas.get_context("2d").ok().flatten().expect("Failed to get canvas context"); + context.dyn_into().expect("Context should be a canvas 2d context") + }); + + let size = ipp.viewport_bounds.size().as_uvec2(); + + let [a, b, c, d, e, f] = DAffine2::from_scale(DVec2::splat(device_pixel_ratio)).to_cols_array(); + let _ = context.set_transform(a, b, c, d, e, f); + context.clear_rect(0., 0., ipp.viewport_bounds.size().x, ipp.viewport_bounds.size().y); + let _ = context.reset_transform(); + + if visibility_settings.all() { + responses.add(DocumentMessage::GridOverlays(OverlayContext { + render_context: context.clone(), + size: size.as_dvec2(), + device_pixel_ratio, + visibility_settings: visibility_settings.clone(), + })); + for provider in &self.overlay_providers { + responses.add(provider(OverlayContext { + render_context: context.clone(), + size: size.as_dvec2(), + device_pixel_ratio, + visibility_settings: visibility_settings.clone(), + })); + } + } + } + #[cfg(not(target_arch = "wasm32"))] + OverlaysMessage::Draw => { + warn!("Cannot render overlays on non-Wasm targets.\n{responses:?} {visibility_settings:?} {ipp:?}",); + } + OverlaysMessage::AddProvider(message) => { + self.overlay_providers.insert(message); + } + OverlaysMessage::RemoveProvider(message) => { + self.overlay_providers.remove(&message); + } + } + } + + advertise_actions!(OverlaysMessage;); +} diff --git a/editor/src/messages/portfolio/document/overlays/utility_functions.rs b/editor/src/messages/portfolio/document/overlays/utility_functions.rs new file mode 100644 index 0000000000000000000000000000000000000000..1e012b867a0e35de6905269841ae9a8b05e36ab2 --- /dev/null +++ b/editor/src/messages/portfolio/document/overlays/utility_functions.rs @@ -0,0 +1,209 @@ +use super::utility_types::{DrawHandles, OverlayContext}; +use crate::consts::HIDE_HANDLE_DISTANCE; +use crate::messages::portfolio::document::utility_types::network_interface::NodeNetworkInterface; +use crate::messages::tool::common_functionality::shape_editor::{SelectedLayerState, ShapeState}; +use crate::messages::tool::tool_messages::tool_prelude::{DocumentMessageHandler, PreferencesMessageHandler}; +use bezier_rs::{Bezier, BezierHandles}; +use glam::{DAffine2, DVec2}; +use graphene_std::vector::ManipulatorPointId; +use graphene_std::vector::{PointId, SegmentId}; +use wasm_bindgen::JsCast; + +pub fn overlay_canvas_element() -> Option { + let window = web_sys::window()?; + let document = window.document()?; + let canvas = document.query_selector("[data-overlays-canvas]").ok().flatten()?; + canvas.dyn_into::().ok() +} + +pub fn overlay_canvas_context() -> web_sys::CanvasRenderingContext2d { + let create_context = || { + let context = overlay_canvas_element()?.get_context("2d").ok().flatten()?; + context.dyn_into().ok() + }; + create_context().expect("Failed to get canvas context") +} + +pub fn selected_segments(network_interface: &NodeNetworkInterface, shape_editor: &ShapeState) -> Vec { + let selected_points = shape_editor.selected_points(); + let selected_anchors = selected_points + .filter_map(|point_id| if let ManipulatorPointId::Anchor(p) = point_id { Some(*p) } else { None }) + .collect::>(); + + // Collect the segments whose handles are selected + let mut selected_segments = shape_editor + .selected_points() + .filter_map(|point_id| match point_id { + ManipulatorPointId::PrimaryHandle(segment_id) | ManipulatorPointId::EndHandle(segment_id) => Some(*segment_id), + ManipulatorPointId::Anchor(_) => None, + }) + .collect::>(); + + // TODO: Currently if there are two duplicate layers, both of their segments get overlays + // Adding segments which are are connected to selected anchors + for layer in network_interface.selected_nodes().selected_layers(network_interface.document_metadata()) { + let Some(vector_data) = network_interface.compute_modified_vector(layer) else { continue }; + + for (segment_id, _bezier, start, end) in vector_data.segment_bezier_iter() { + if selected_anchors.contains(&start) || selected_anchors.contains(&end) { + selected_segments.push(segment_id); + } + } + } + + selected_segments +} + +fn overlay_bezier_handles(bezier: Bezier, segment_id: SegmentId, transform: DAffine2, is_selected: impl Fn(ManipulatorPointId) -> bool, overlay_context: &mut OverlayContext) { + let bezier = bezier.apply_transformation(|point| transform.transform_point2(point)); + let not_under_anchor = |position: DVec2, anchor: DVec2| position.distance_squared(anchor) >= HIDE_HANDLE_DISTANCE * HIDE_HANDLE_DISTANCE; + + match bezier.handles { + BezierHandles::Quadratic { handle } if not_under_anchor(handle, bezier.start) && not_under_anchor(handle, bezier.end) => { + overlay_context.line(handle, bezier.start, None, None); + overlay_context.line(handle, bezier.end, None, None); + overlay_context.manipulator_handle(handle, is_selected(ManipulatorPointId::PrimaryHandle(segment_id)), None); + } + BezierHandles::Cubic { handle_start, handle_end } => { + if not_under_anchor(handle_start, bezier.start) { + overlay_context.line(handle_start, bezier.start, None, None); + overlay_context.manipulator_handle(handle_start, is_selected(ManipulatorPointId::PrimaryHandle(segment_id)), None); + } + if not_under_anchor(handle_end, bezier.end) { + overlay_context.line(handle_end, bezier.end, None, None); + overlay_context.manipulator_handle(handle_end, is_selected(ManipulatorPointId::EndHandle(segment_id)), None); + } + } + _ => {} + } +} + +fn overlay_bezier_handle_specific_point( + bezier: Bezier, + segment_id: SegmentId, + (start, end): (PointId, PointId), + point_to_render: PointId, + transform: DAffine2, + is_selected: impl Fn(ManipulatorPointId) -> bool, + overlay_context: &mut OverlayContext, +) { + let bezier = bezier.apply_transformation(|point| transform.transform_point2(point)); + let not_under_anchor = |position: DVec2, anchor: DVec2| position.distance_squared(anchor) >= HIDE_HANDLE_DISTANCE * HIDE_HANDLE_DISTANCE; + + match bezier.handles { + BezierHandles::Quadratic { handle } => { + if not_under_anchor(handle, bezier.start) && not_under_anchor(handle, bezier.end) { + let end = if start == point_to_render { bezier.start } else { bezier.end }; + overlay_context.line(handle, end, None, None); + overlay_context.manipulator_handle(handle, is_selected(ManipulatorPointId::PrimaryHandle(segment_id)), None); + } + } + BezierHandles::Cubic { handle_start, handle_end } => { + if not_under_anchor(handle_start, bezier.start) && (point_to_render == start) { + overlay_context.line(handle_start, bezier.start, None, None); + overlay_context.manipulator_handle(handle_start, is_selected(ManipulatorPointId::PrimaryHandle(segment_id)), None); + } + if not_under_anchor(handle_end, bezier.end) && (point_to_render == end) { + overlay_context.line(handle_end, bezier.end, None, None); + overlay_context.manipulator_handle(handle_end, is_selected(ManipulatorPointId::EndHandle(segment_id)), None); + } + } + _ => {} + } +} + +pub fn path_overlays(document: &DocumentMessageHandler, draw_handles: DrawHandles, shape_editor: &mut ShapeState, overlay_context: &mut OverlayContext) { + let display_path = overlay_context.visibility_settings.path(); + let display_handles = overlay_context.visibility_settings.handles(); + let display_anchors = overlay_context.visibility_settings.anchors(); + + for layer in document.network_interface.selected_nodes().selected_layers(document.metadata()) { + let Some(vector_data) = document.network_interface.compute_modified_vector(layer) else { continue }; + let transform = document.metadata().transform_to_viewport(layer); + if display_path { + overlay_context.outline_vector(&vector_data, transform); + } + + // Get the selected segments and then add a bold line overlay on them + for (segment_id, bezier, _, _) in vector_data.segment_bezier_iter() { + let Some(selected_shape_state) = shape_editor.selected_shape_state.get_mut(&layer) else { + continue; + }; + + if selected_shape_state.is_segment_selected(segment_id) { + overlay_context.outline_select_bezier(bezier, transform); + } + } + + let selected = shape_editor.selected_shape_state.get(&layer); + let is_selected = |point: ManipulatorPointId| selected.is_some_and(|selected| selected.is_point_selected(point)); + + if display_handles { + let opposite_handles_data: Vec<(PointId, SegmentId)> = shape_editor.selected_points().filter_map(|point_id| vector_data.adjacent_segment(point_id)).collect(); + + match draw_handles { + DrawHandles::All => { + vector_data.segment_bezier_iter().for_each(|(segment_id, bezier, _start, _end)| { + overlay_bezier_handles(bezier, segment_id, transform, is_selected, overlay_context); + }); + } + DrawHandles::SelectedAnchors(ref selected_segments) => { + vector_data + .segment_bezier_iter() + .filter(|(segment_id, ..)| selected_segments.contains(segment_id)) + .for_each(|(segment_id, bezier, _start, _end)| { + overlay_bezier_handles(bezier, segment_id, transform, is_selected, overlay_context); + }); + + for (segment_id, bezier, start, end) in vector_data.segment_bezier_iter() { + if let Some((corresponding_anchor, _)) = opposite_handles_data.iter().find(|(_, adj_segment_id)| adj_segment_id == &segment_id) { + overlay_bezier_handle_specific_point(bezier, segment_id, (start, end), *corresponding_anchor, transform, is_selected, overlay_context); + } + } + } + DrawHandles::FrontierHandles(ref segment_endpoints) => { + vector_data + .segment_bezier_iter() + .filter(|(segment_id, ..)| segment_endpoints.contains_key(segment_id)) + .for_each(|(segment_id, bezier, start, end)| { + if segment_endpoints.get(&segment_id).unwrap().len() == 1 { + let point_to_render = segment_endpoints.get(&segment_id).unwrap()[0]; + overlay_bezier_handle_specific_point(bezier, segment_id, (start, end), point_to_render, transform, is_selected, overlay_context); + } else { + overlay_bezier_handles(bezier, segment_id, transform, is_selected, overlay_context); + } + }); + } + DrawHandles::None => {} + } + } + + if display_anchors { + for (&id, &position) in vector_data.point_domain.ids().iter().zip(vector_data.point_domain.positions()) { + overlay_context.manipulator_anchor(transform.transform_point2(position), is_selected(ManipulatorPointId::Anchor(id)), None); + } + } + } +} + +pub fn path_endpoint_overlays(document: &DocumentMessageHandler, shape_editor: &mut ShapeState, overlay_context: &mut OverlayContext, preferences: &PreferencesMessageHandler) { + if !overlay_context.visibility_settings.anchors() { + return; + } + + for layer in document.network_interface.selected_nodes().selected_layers(document.metadata()) { + let Some(vector_data) = document.network_interface.compute_modified_vector(layer) else { + continue; + }; + //let document_to_viewport = document.navigation_handler.calculate_offset_transform(overlay_context.size / 2., &document.document_ptz); + let transform = document.metadata().transform_to_viewport(layer); + let selected = shape_editor.selected_shape_state.get(&layer); + let is_selected = |selected: Option<&SelectedLayerState>, point: ManipulatorPointId| selected.is_some_and(|selected| selected.is_point_selected(point)); + + for point in vector_data.extendable_points(preferences.vector_meshes) { + let Some(position) = vector_data.point_domain.position_from_id(point) else { continue }; + let position = transform.transform_point2(position); + overlay_context.manipulator_anchor(position, is_selected(selected, ManipulatorPointId::Anchor(point)), None); + } + } +} diff --git a/editor/src/messages/portfolio/document/overlays/utility_types.rs b/editor/src/messages/portfolio/document/overlays/utility_types.rs new file mode 100644 index 0000000000000000000000000000000000000000..a17d711a3807ace9c6f7a9d9f7192de3281054f9 --- /dev/null +++ b/editor/src/messages/portfolio/document/overlays/utility_types.rs @@ -0,0 +1,796 @@ +use super::utility_functions::overlay_canvas_context; +use crate::consts::{ + COLOR_OVERLAY_BLUE, COLOR_OVERLAY_BLUE_50, COLOR_OVERLAY_GREEN, COLOR_OVERLAY_RED, COLOR_OVERLAY_WHITE, COLOR_OVERLAY_YELLOW, COMPASS_ROSE_ARROW_SIZE, COMPASS_ROSE_HOVER_RING_DIAMETER, + COMPASS_ROSE_MAIN_RING_DIAMETER, COMPASS_ROSE_RING_INNER_DIAMETER, MANIPULATOR_GROUP_MARKER_SIZE, PIVOT_CROSSHAIR_LENGTH, PIVOT_CROSSHAIR_THICKNESS, PIVOT_DIAMETER, +}; +use crate::messages::prelude::Message; +use bezier_rs::{Bezier, Subpath}; +use core::borrow::Borrow; +use core::f64::consts::{FRAC_PI_2, TAU}; +use glam::{DAffine2, DVec2}; +use graphene_std::Color; +use graphene_std::math::quad::Quad; +use graphene_std::vector::click_target::ClickTargetType; +use graphene_std::vector::{PointId, SegmentId, VectorData}; +use std::collections::HashMap; +use wasm_bindgen::{JsCast, JsValue}; +use web_sys::{OffscreenCanvas, OffscreenCanvasRenderingContext2d}; + +pub type OverlayProvider = fn(OverlayContext) -> Message; + +pub fn empty_provider() -> OverlayProvider { + |_| Message::NoOp +} + +// Types of overlays used by DocumentMessage to enable/disable select group of overlays in the frontend +#[derive(PartialEq, Clone, Debug, serde::Serialize, serde::Deserialize, specta::Type)] +pub enum OverlaysType { + ArtboardName, + CompassRose, + QuickMeasurement, + TransformMeasurement, + TransformCage, + HoverOutline, + SelectionOutline, + Pivot, + Path, + Anchors, + Handles, +} + +#[derive(PartialEq, Copy, Clone, Debug, serde::Serialize, serde::Deserialize, specta::Type)] +pub struct OverlaysVisibilitySettings { + pub all: bool, + pub artboard_name: bool, + pub compass_rose: bool, + pub quick_measurement: bool, + pub transform_measurement: bool, + pub transform_cage: bool, + pub hover_outline: bool, + pub selection_outline: bool, + pub pivot: bool, + pub path: bool, + pub anchors: bool, + pub handles: bool, +} + +impl Default for OverlaysVisibilitySettings { + fn default() -> Self { + Self { + all: true, + artboard_name: true, + compass_rose: true, + quick_measurement: true, + transform_measurement: true, + transform_cage: true, + hover_outline: true, + selection_outline: true, + pivot: true, + path: true, + anchors: true, + handles: true, + } + } +} + +impl OverlaysVisibilitySettings { + pub fn all(&self) -> bool { + self.all + } + + pub fn artboard_name(&self) -> bool { + self.all && self.artboard_name + } + + pub fn compass_rose(&self) -> bool { + self.all && self.compass_rose + } + + pub fn quick_measurement(&self) -> bool { + self.all && self.quick_measurement + } + + pub fn transform_measurement(&self) -> bool { + self.all && self.transform_measurement + } + + pub fn transform_cage(&self) -> bool { + self.all && self.transform_cage + } + + pub fn hover_outline(&self) -> bool { + self.all && self.hover_outline + } + + pub fn selection_outline(&self) -> bool { + self.all && self.selection_outline + } + + pub fn pivot(&self) -> bool { + self.all && self.pivot + } + + pub fn path(&self) -> bool { + self.all && self.path + } + + pub fn anchors(&self) -> bool { + self.all && self.anchors + } + + pub fn handles(&self) -> bool { + self.all && self.anchors && self.handles + } +} + +#[derive(PartialEq, Clone, Debug, serde::Serialize, serde::Deserialize, specta::Type)] +pub struct OverlayContext { + // Serde functionality isn't used but is required by the message system macros + #[serde(skip, default = "overlay_canvas_context")] + #[specta(skip)] + pub render_context: web_sys::CanvasRenderingContext2d, + pub size: DVec2, + // The device pixel ratio is a property provided by the browser window and is the CSS pixel size divided by the physical monitor's pixel size. + // It allows better pixel density of visualizations on high-DPI displays where the OS display scaling is not 100%, or where the browser is zoomed. + pub device_pixel_ratio: f64, + pub visibility_settings: OverlaysVisibilitySettings, +} +// Message hashing isn't used but is required by the message system macros +impl core::hash::Hash for OverlayContext { + fn hash(&self, _state: &mut H) {} +} + +impl OverlayContext { + pub fn quad(&mut self, quad: Quad, stroke_color: Option<&str>, color_fill: Option<&str>) { + self.dashed_polygon(&quad.0, stroke_color, color_fill, None, None, None); + } + + pub fn draw_triangle(&mut self, base: DVec2, direction: DVec2, size: f64, color_fill: Option<&str>, color_stroke: Option<&str>) { + let color_fill = color_fill.unwrap_or(COLOR_OVERLAY_WHITE); + let color_stroke = color_stroke.unwrap_or(COLOR_OVERLAY_BLUE); + let normal = direction.perp(); + let top = base + direction * size; + let edge1 = base + normal * size / 2.; + let edge2 = base - normal * size / 2.; + + self.start_dpi_aware_transform(); + + self.render_context.begin_path(); + self.render_context.move_to(top.x, top.y); + self.render_context.line_to(edge1.x, edge1.y); + self.render_context.line_to(edge2.x, edge2.y); + self.render_context.close_path(); + + self.render_context.set_fill_style_str(color_fill); + self.render_context.set_stroke_style_str(color_stroke); + self.render_context.fill(); + self.render_context.stroke(); + + self.end_dpi_aware_transform(); + } + + pub fn dashed_quad(&mut self, quad: Quad, stroke_color: Option<&str>, color_fill: Option<&str>, dash_width: Option, dash_gap_width: Option, dash_offset: Option) { + self.dashed_polygon(&quad.0, stroke_color, color_fill, dash_width, dash_gap_width, dash_offset); + } + + pub fn polygon(&mut self, polygon: &[DVec2], stroke_color: Option<&str>, color_fill: Option<&str>) { + self.dashed_polygon(polygon, stroke_color, color_fill, None, None, None); + } + + pub fn dashed_polygon(&mut self, polygon: &[DVec2], stroke_color: Option<&str>, color_fill: Option<&str>, dash_width: Option, dash_gap_width: Option, dash_offset: Option) { + if polygon.len() < 2 { + return; + } + + self.start_dpi_aware_transform(); + + // Set the dash pattern + if let Some(dash_width) = dash_width { + let dash_gap_width = dash_gap_width.unwrap_or(1.); + let array = js_sys::Array::new(); + array.push(&JsValue::from(dash_width)); + array.push(&JsValue::from(dash_gap_width)); + + if let Some(dash_offset) = dash_offset { + if dash_offset != 0. { + self.render_context.set_line_dash_offset(dash_offset); + } + } + + self.render_context + .set_line_dash(&JsValue::from(array)) + .map_err(|error| log::warn!("Error drawing dashed line: {:?}", error)) + .ok(); + } + + self.render_context.begin_path(); + self.render_context.move_to(polygon.last().unwrap().x.round() - 0.5, polygon.last().unwrap().y.round() - 0.5); + + for point in polygon { + self.render_context.line_to(point.x.round() - 0.5, point.y.round() - 0.5); + } + + if let Some(color_fill) = color_fill { + self.render_context.set_fill_style_str(color_fill); + self.render_context.fill(); + } + + let stroke_color = stroke_color.unwrap_or(COLOR_OVERLAY_BLUE); + self.render_context.set_stroke_style_str(stroke_color); + self.render_context.stroke(); + + // Reset the dash pattern back to solid + if dash_width.is_some() { + self.render_context + .set_line_dash(&JsValue::from(js_sys::Array::new())) + .map_err(|error| log::warn!("Error drawing dashed line: {:?}", error)) + .ok(); + } + if dash_offset.is_some() && dash_offset != Some(0.) { + self.render_context.set_line_dash_offset(0.); + } + + self.end_dpi_aware_transform(); + } + + pub fn line(&mut self, start: DVec2, end: DVec2, color: Option<&str>, thickness: Option) { + self.dashed_line(start, end, color, thickness, None, None, None) + } + + #[allow(clippy::too_many_arguments)] + pub fn dashed_line(&mut self, start: DVec2, end: DVec2, color: Option<&str>, thickness: Option, dash_width: Option, dash_gap_width: Option, dash_offset: Option) { + self.start_dpi_aware_transform(); + + // Set the dash pattern + if let Some(dash_width) = dash_width { + let dash_gap_width = dash_gap_width.unwrap_or(1.); + let array = js_sys::Array::new(); + array.push(&JsValue::from(dash_width)); + array.push(&JsValue::from(dash_gap_width)); + + if let Some(dash_offset) = dash_offset { + if dash_offset != 0. { + self.render_context.set_line_dash_offset(dash_offset); + } + } + + self.render_context + .set_line_dash(&JsValue::from(array)) + .map_err(|error| log::warn!("Error drawing dashed line: {:?}", error)) + .ok(); + } + + let start = start.round() - DVec2::splat(0.5); + let end = end.round() - DVec2::splat(0.5); + + self.render_context.begin_path(); + self.render_context.move_to(start.x, start.y); + self.render_context.line_to(end.x, end.y); + self.render_context.set_line_width(thickness.unwrap_or(1.)); + self.render_context.set_stroke_style_str(color.unwrap_or(COLOR_OVERLAY_BLUE)); + self.render_context.stroke(); + self.render_context.set_line_width(1.); + + // Reset the dash pattern back to solid + if dash_width.is_some() { + self.render_context + .set_line_dash(&JsValue::from(js_sys::Array::new())) + .map_err(|error| log::warn!("Error drawing dashed line: {:?}", error)) + .ok(); + } + if dash_offset.is_some() && dash_offset != Some(0.) { + self.render_context.set_line_dash_offset(0.); + } + + self.end_dpi_aware_transform(); + } + + pub fn manipulator_handle(&mut self, position: DVec2, selected: bool, color: Option<&str>) { + self.start_dpi_aware_transform(); + + let position = position.round() - DVec2::splat(0.5); + + self.render_context.begin_path(); + self.render_context + .arc(position.x, position.y, MANIPULATOR_GROUP_MARKER_SIZE / 2., 0., TAU) + .expect("Failed to draw the circle"); + + let fill = if selected { COLOR_OVERLAY_BLUE } else { COLOR_OVERLAY_WHITE }; + self.render_context.set_fill_style_str(fill); + self.render_context.set_stroke_style_str(color.unwrap_or(COLOR_OVERLAY_BLUE)); + self.render_context.fill(); + self.render_context.stroke(); + + self.end_dpi_aware_transform(); + } + + pub fn manipulator_anchor(&mut self, position: DVec2, selected: bool, color: Option<&str>) { + let color_stroke = color.unwrap_or(COLOR_OVERLAY_BLUE); + let color_fill = if selected { color_stroke } else { COLOR_OVERLAY_WHITE }; + self.square(position, None, Some(color_fill), Some(color_stroke)); + } + + /// Transforms the canvas context to adjust for DPI scaling + /// + /// Overwrites all existing tranforms. This operation can be reversed with [`Self::reset_transform`]. + fn start_dpi_aware_transform(&self) { + let [a, b, c, d, e, f] = DAffine2::from_scale(DVec2::splat(self.device_pixel_ratio)).to_cols_array(); + self.render_context + .set_transform(a, b, c, d, e, f) + .expect("transform should be able to be set to be able to account for DPI"); + } + + /// Un-transforms the Canvas context to adjust for DPI scaling + /// + /// Warning: this function doesn't only reset the DPI scaling adjustment, it resets the entire transform. + fn end_dpi_aware_transform(&self) { + self.render_context.reset_transform().expect("transform should be able to be reset to be able to account for DPI"); + } + + pub fn square(&mut self, position: DVec2, size: Option, color_fill: Option<&str>, color_stroke: Option<&str>) { + let size = size.unwrap_or(MANIPULATOR_GROUP_MARKER_SIZE); + let color_fill = color_fill.unwrap_or(COLOR_OVERLAY_WHITE); + let color_stroke = color_stroke.unwrap_or(COLOR_OVERLAY_BLUE); + + let position = position.round() - DVec2::splat(0.5); + let corner = position - DVec2::splat(size) / 2.; + + self.start_dpi_aware_transform(); + + self.render_context.begin_path(); + self.render_context.rect(corner.x, corner.y, size, size); + self.render_context.set_fill_style_str(color_fill); + self.render_context.set_stroke_style_str(color_stroke); + self.render_context.fill(); + self.render_context.stroke(); + + self.end_dpi_aware_transform(); + } + + pub fn pixel(&mut self, position: DVec2, color: Option<&str>) { + let size = 1.; + let color_fill = color.unwrap_or(COLOR_OVERLAY_WHITE); + + let position = position.round() - DVec2::splat(0.5); + let corner = position - DVec2::splat(size) / 2.; + + self.start_dpi_aware_transform(); + + self.render_context.begin_path(); + self.render_context.rect(corner.x, corner.y, size, size); + self.render_context.set_fill_style_str(color_fill); + self.render_context.fill(); + + self.end_dpi_aware_transform(); + } + + pub fn circle(&mut self, position: DVec2, radius: f64, color_fill: Option<&str>, color_stroke: Option<&str>) { + let color_fill = color_fill.unwrap_or(COLOR_OVERLAY_WHITE); + let color_stroke = color_stroke.unwrap_or(COLOR_OVERLAY_BLUE); + let position = position.round(); + + self.start_dpi_aware_transform(); + + self.render_context.begin_path(); + self.render_context.arc(position.x, position.y, radius, 0., TAU).expect("Failed to draw the circle"); + self.render_context.set_fill_style_str(color_fill); + self.render_context.set_stroke_style_str(color_stroke); + self.render_context.fill(); + self.render_context.stroke(); + + self.end_dpi_aware_transform(); + } + + pub fn draw_arc(&mut self, center: DVec2, radius: f64, start_from: f64, end_at: f64) { + let segments = ((end_at - start_from).abs() / (std::f64::consts::PI / 4.)).ceil() as usize; + let step = (end_at - start_from) / segments as f64; + let half_step = step / 2.; + let factor = 4. / 3. * half_step.sin() / (1. + half_step.cos()); + + self.render_context.begin_path(); + + for i in 0..segments { + let start_angle = start_from + step * i as f64; + let end_angle = start_angle + step; + let start_vec = DVec2::from_angle(start_angle); + let end_vec = DVec2::from_angle(end_angle); + + let start = center + radius * start_vec; + let end = center + radius * end_vec; + + let handle_start = start + start_vec.perp() * radius * factor; + let handle_end = end - end_vec.perp() * radius * factor; + + let bezier = Bezier { + start, + end, + handles: bezier_rs::BezierHandles::Cubic { handle_start, handle_end }, + }; + + self.bezier_command(bezier, DAffine2::IDENTITY, i == 0); + } + + self.render_context.stroke(); + } + + pub fn draw_angle(&mut self, pivot: DVec2, radius: f64, arc_radius: f64, offset_angle: f64, angle: f64) { + let end_point1 = pivot + radius * DVec2::from_angle(angle + offset_angle); + let end_point2 = pivot + radius * DVec2::from_angle(offset_angle); + self.line(pivot, end_point1, None, None); + self.dashed_line(pivot, end_point2, None, None, Some(2.), Some(2.), Some(0.5)); + self.draw_arc(pivot, arc_radius, offset_angle, (angle) % TAU + offset_angle); + } + + pub fn draw_scale(&mut self, start: DVec2, scale: f64, radius: f64, text: &str) { + let sign = scale.signum(); + let mut fill_color = graphene_std::Color::from_rgb_str(crate::consts::COLOR_OVERLAY_WHITE.strip_prefix('#').unwrap()) + .unwrap() + .with_alpha(0.05) + .to_rgba_hex_srgb(); + fill_color.insert(0, '#'); + let fill_color = Some(fill_color.as_str()); + self.line(start + DVec2::X * radius * sign, start + DVec2::X * (radius * scale), None, None); + self.circle(start, radius, fill_color, None); + self.circle(start, radius * scale.abs(), fill_color, None); + self.text( + text, + COLOR_OVERLAY_BLUE, + None, + DAffine2::from_translation(start + sign * DVec2::X * radius * (1. + scale.abs()) / 2.), + 2., + [Pivot::Middle, Pivot::End], + ) + } + + pub fn compass_rose(&mut self, compass_center: DVec2, angle: f64, show_compass_with_hover_ring: Option) { + const HOVER_RING_OUTER_RADIUS: f64 = COMPASS_ROSE_HOVER_RING_DIAMETER / 2.; + const MAIN_RING_OUTER_RADIUS: f64 = COMPASS_ROSE_MAIN_RING_DIAMETER / 2.; + const MAIN_RING_INNER_RADIUS: f64 = COMPASS_ROSE_RING_INNER_DIAMETER / 2.; + const ARROW_RADIUS: f64 = COMPASS_ROSE_ARROW_SIZE / 2.; + const HOVER_RING_STROKE_WIDTH: f64 = HOVER_RING_OUTER_RADIUS - MAIN_RING_INNER_RADIUS; + const HOVER_RING_CENTERLINE_RADIUS: f64 = (HOVER_RING_OUTER_RADIUS + MAIN_RING_INNER_RADIUS) / 2.; + const MAIN_RING_STROKE_WIDTH: f64 = MAIN_RING_OUTER_RADIUS - MAIN_RING_INNER_RADIUS; + const MAIN_RING_CENTERLINE_RADIUS: f64 = (MAIN_RING_OUTER_RADIUS + MAIN_RING_INNER_RADIUS) / 2.; + + let Some(show_hover_ring) = show_compass_with_hover_ring else { return }; + + self.start_dpi_aware_transform(); + + let center = compass_center.round() - DVec2::splat(0.5); + + // Save the old line width to restore it later + let old_line_width = self.render_context.line_width(); + + // Hover ring + if show_hover_ring { + let mut fill_color = graphene_std::Color::from_rgb_str(COLOR_OVERLAY_BLUE.strip_prefix('#').unwrap()) + .unwrap() + .with_alpha(0.5) + .to_rgba_hex_srgb(); + fill_color.insert(0, '#'); + + self.render_context.set_line_width(HOVER_RING_STROKE_WIDTH); + self.render_context.begin_path(); + self.render_context.arc(center.x, center.y, HOVER_RING_CENTERLINE_RADIUS, 0., TAU).expect("Failed to draw hover ring"); + self.render_context.set_stroke_style_str(&fill_color); + self.render_context.stroke(); + } + + // Arrows + self.render_context.set_line_width(0.01); + for i in 0..4 { + let direction = DVec2::from_angle(i as f64 * FRAC_PI_2 + angle); + let color = if i % 2 == 0 { COLOR_OVERLAY_RED } else { COLOR_OVERLAY_GREEN }; + + let tip = center + direction * HOVER_RING_OUTER_RADIUS; + let base = center + direction * (MAIN_RING_INNER_RADIUS + MAIN_RING_OUTER_RADIUS) / 2.; + + let r = (ARROW_RADIUS.powi(2) + MAIN_RING_INNER_RADIUS.powi(2)).sqrt(); + let (cos, sin) = (MAIN_RING_INNER_RADIUS / r, ARROW_RADIUS / r); + let side1 = center + r * DVec2::new(cos * direction.x - sin * direction.y, sin * direction.x + direction.y * cos); + let side2 = center + r * DVec2::new(cos * direction.x + sin * direction.y, -sin * direction.x + direction.y * cos); + + self.render_context.begin_path(); + self.render_context.move_to(tip.x, tip.y); + self.render_context.line_to(side1.x, side1.y); + self.render_context.line_to(base.x, base.y); + self.render_context.line_to(side2.x, side2.y); + self.render_context.close_path(); + + self.render_context.set_fill_style_str(color); + self.render_context.fill(); + self.render_context.set_stroke_style_str(color); + self.render_context.stroke(); + } + + // Main ring + self.render_context.set_line_width(MAIN_RING_STROKE_WIDTH); + self.render_context.begin_path(); + self.render_context.arc(center.x, center.y, MAIN_RING_CENTERLINE_RADIUS, 0., TAU).expect("Failed to draw main ring"); + self.render_context.set_stroke_style_str(COLOR_OVERLAY_BLUE); + self.render_context.stroke(); + + // Restore the old line width + self.render_context.set_line_width(old_line_width); + } + + pub fn pivot(&mut self, position: DVec2, angle: f64) { + let uv = DVec2::from_angle(angle); + let (x, y) = (position.round() - DVec2::splat(0.5)).into(); + + self.start_dpi_aware_transform(); + + // Circle + + self.render_context.begin_path(); + self.render_context.arc(x, y, PIVOT_DIAMETER / 2., 0., TAU).expect("Failed to draw the circle"); + self.render_context.set_fill_style_str(COLOR_OVERLAY_YELLOW); + self.render_context.fill(); + + // Crosshair + + // Round line caps add half the stroke width to the length on each end, so we subtract that here before halving to get the radius + const CROSSHAIR_RADIUS: f64 = (PIVOT_CROSSHAIR_LENGTH - PIVOT_CROSSHAIR_THICKNESS) / 2.; + + self.render_context.set_stroke_style_str(COLOR_OVERLAY_YELLOW); + self.render_context.set_line_cap("round"); + + self.render_context.begin_path(); + self.render_context.move_to(x + CROSSHAIR_RADIUS * uv.x, y + CROSSHAIR_RADIUS * uv.y); + self.render_context.line_to(x - CROSSHAIR_RADIUS * uv.x, y - CROSSHAIR_RADIUS * uv.y); + self.render_context.stroke(); + + self.render_context.begin_path(); + self.render_context.move_to(x - CROSSHAIR_RADIUS * uv.y, y + CROSSHAIR_RADIUS * uv.x); + self.render_context.line_to(x + CROSSHAIR_RADIUS * uv.y, y - CROSSHAIR_RADIUS * uv.x); + self.render_context.stroke(); + + self.render_context.set_line_cap("butt"); + + self.end_dpi_aware_transform(); + } + + /// Used by the Pen and Path tools to outline the path of the shape. + pub fn outline_vector(&mut self, vector_data: &VectorData, transform: DAffine2) { + self.start_dpi_aware_transform(); + + self.render_context.begin_path(); + let mut last_point = None; + for (_, bezier, start_id, end_id) in vector_data.segment_bezier_iter() { + let move_to = last_point != Some(start_id); + last_point = Some(end_id); + + self.bezier_command(bezier, transform, move_to); + } + + self.render_context.set_stroke_style_str(COLOR_OVERLAY_BLUE); + self.render_context.stroke(); + + self.end_dpi_aware_transform(); + } + + /// Used by the Pen tool in order to show how the bezier curve would look like. + pub fn outline_bezier(&mut self, bezier: Bezier, transform: DAffine2) { + self.start_dpi_aware_transform(); + + self.render_context.begin_path(); + self.bezier_command(bezier, transform, true); + self.render_context.set_stroke_style_str(COLOR_OVERLAY_BLUE); + self.render_context.stroke(); + + self.end_dpi_aware_transform(); + } + + /// Used by the path tool segment mode in order to show the selected segments. + pub fn outline_select_bezier(&mut self, bezier: Bezier, transform: DAffine2) { + self.start_dpi_aware_transform(); + + self.render_context.begin_path(); + self.bezier_command(bezier, transform, true); + self.render_context.set_stroke_style_str(COLOR_OVERLAY_BLUE); + self.render_context.set_line_width(4.); + self.render_context.stroke(); + + self.render_context.set_line_width(1.); + + self.end_dpi_aware_transform(); + } + + pub fn outline_overlay_bezier(&mut self, bezier: Bezier, transform: DAffine2) { + self.start_dpi_aware_transform(); + + self.render_context.begin_path(); + self.bezier_command(bezier, transform, true); + self.render_context.set_stroke_style_str(COLOR_OVERLAY_BLUE_50); + self.render_context.set_line_width(4.); + self.render_context.stroke(); + + self.render_context.set_line_width(1.); + + self.end_dpi_aware_transform(); + } + + fn bezier_command(&self, bezier: Bezier, transform: DAffine2, move_to: bool) { + self.start_dpi_aware_transform(); + + let Bezier { start, end, handles } = bezier.apply_transformation(|point| transform.transform_point2(point)); + if move_to { + self.render_context.move_to(start.x, start.y); + } + + match handles { + bezier_rs::BezierHandles::Linear => self.render_context.line_to(end.x, end.y), + bezier_rs::BezierHandles::Quadratic { handle } => self.render_context.quadratic_curve_to(handle.x, handle.y, end.x, end.y), + bezier_rs::BezierHandles::Cubic { handle_start, handle_end } => self.render_context.bezier_curve_to(handle_start.x, handle_start.y, handle_end.x, handle_end.y, end.x, end.y), + } + + self.end_dpi_aware_transform(); + } + + fn push_path(&mut self, subpaths: impl Iterator>>, transform: DAffine2) { + self.start_dpi_aware_transform(); + + self.render_context.begin_path(); + for subpath in subpaths { + let subpath = subpath.borrow(); + let mut curves = subpath.iter().peekable(); + + let Some(first) = curves.peek() else { + continue; + }; + + self.render_context.move_to(transform.transform_point2(first.start()).x, transform.transform_point2(first.start()).y); + for curve in curves { + match curve.handles { + bezier_rs::BezierHandles::Linear => { + let a = transform.transform_point2(curve.end()); + let a = a.round() - DVec2::splat(0.5); + + self.render_context.line_to(a.x, a.y) + } + bezier_rs::BezierHandles::Quadratic { handle } => { + let a = transform.transform_point2(handle); + let b = transform.transform_point2(curve.end()); + let a = a.round() - DVec2::splat(0.5); + let b = b.round() - DVec2::splat(0.5); + + self.render_context.quadratic_curve_to(a.x, a.y, b.x, b.y) + } + bezier_rs::BezierHandles::Cubic { handle_start, handle_end } => { + let a = transform.transform_point2(handle_start); + let b = transform.transform_point2(handle_end); + let c = transform.transform_point2(curve.end()); + let a = a.round() - DVec2::splat(0.5); + let b = b.round() - DVec2::splat(0.5); + let c = c.round() - DVec2::splat(0.5); + + self.render_context.bezier_curve_to(a.x, a.y, b.x, b.y, c.x, c.y) + } + } + } + + if subpath.closed() { + self.render_context.close_path(); + } + } + + self.end_dpi_aware_transform(); + } + + /// Used by the Select tool to outline a path or a free point when selected or hovered. + pub fn outline(&mut self, target_types: impl Iterator>, transform: DAffine2, color: Option<&str>) { + let mut subpaths: Vec> = vec![]; + + target_types.for_each(|target_type| match target_type.borrow() { + ClickTargetType::FreePoint(point) => { + self.manipulator_anchor(transform.transform_point2(point.position), false, None); + } + ClickTargetType::Subpath(subpath) => subpaths.push(subpath.clone()), + }); + + if !subpaths.is_empty() { + self.push_path(subpaths.iter(), transform); + + let color = color.unwrap_or(COLOR_OVERLAY_BLUE); + self.render_context.set_stroke_style_str(color); + self.render_context.stroke(); + } + } + + /// Fills the area inside the path. Assumes `color` is in gamma space. + /// Used by the Pen tool to show the path being closed. + pub fn fill_path(&mut self, subpaths: impl Iterator>>, transform: DAffine2, color: &str) { + self.push_path(subpaths, transform); + + self.render_context.set_fill_style_str(color); + self.render_context.fill(); + } + + /// Fills the area inside the path with a pattern. Assumes `color` is in gamma space. + /// Used by the fill tool to show the area to be filled. + pub fn fill_path_pattern(&mut self, subpaths: impl Iterator>>, transform: DAffine2, color: &Color) { + const PATTERN_WIDTH: usize = 4; + const PATTERN_HEIGHT: usize = 4; + + let pattern_canvas = OffscreenCanvas::new(PATTERN_WIDTH as u32, PATTERN_HEIGHT as u32).unwrap(); + let pattern_context: OffscreenCanvasRenderingContext2d = pattern_canvas + .get_context("2d") + .ok() + .flatten() + .expect("Failed to get canvas context") + .dyn_into() + .expect("Context should be a canvas 2d context"); + + // 4x4 pixels, 4 components (RGBA) per pixel + let mut data = [0_u8; 4 * PATTERN_WIDTH * PATTERN_HEIGHT]; + + // ┌▄▄┬──┬──┬──┐ + // ├▀▀┼──┼──┼──┤ + // ├──┼──┼▄▄┼──┤ + // ├──┼──┼▀▀┼──┤ + // └──┴──┴──┴──┘ + let pixels = [(0, 0), (2, 2)]; + for &(x, y) in &pixels { + let index = (x + y * PATTERN_WIDTH as usize) * 4; + data[index..index + 4].copy_from_slice(&color.to_rgba8_srgb()); + } + + let image_data = web_sys::ImageData::new_with_u8_clamped_array_and_sh(wasm_bindgen::Clamped(&mut data), PATTERN_WIDTH as u32, PATTERN_HEIGHT as u32).unwrap(); + pattern_context.put_image_data(&image_data, 0., 0.).unwrap(); + let pattern = self.render_context.create_pattern_with_offscreen_canvas(&pattern_canvas, "repeat").unwrap().unwrap(); + + self.push_path(subpaths, transform); + + self.render_context.set_fill_style_canvas_pattern(&pattern); + self.render_context.fill(); + } + + pub fn get_width(&self, text: &str) -> f64 { + self.render_context.measure_text(text).expect("Failed to measure text dimensions").width() + } + + pub fn text(&self, text: &str, font_color: &str, background_color: Option<&str>, transform: DAffine2, padding: f64, pivot: [Pivot; 2]) { + let metrics = self.render_context.measure_text(text).expect("Failed to measure the text dimensions"); + let x = match pivot[0] { + Pivot::Start => padding, + Pivot::Middle => -(metrics.actual_bounding_box_right() + metrics.actual_bounding_box_left()) / 2., + Pivot::End => -padding - metrics.actual_bounding_box_right() + metrics.actual_bounding_box_left(), + }; + let y = match pivot[1] { + Pivot::Start => padding + metrics.font_bounding_box_ascent() - metrics.font_bounding_box_descent(), + Pivot::Middle => (metrics.font_bounding_box_ascent() + metrics.font_bounding_box_descent()) / 2., + Pivot::End => -padding, + }; + + let [a, b, c, d, e, f] = (DAffine2::from_scale(DVec2::splat(self.device_pixel_ratio)) * transform * DAffine2::from_translation(DVec2::new(x, y))).to_cols_array(); + self.render_context.set_transform(a, b, c, d, e, f).expect("Failed to rotate the render context to the specified angle"); + + if let Some(background) = background_color { + self.render_context.set_fill_style_str(background); + self.render_context.fill_rect( + -padding, + padding, + metrics.actual_bounding_box_right() - metrics.actual_bounding_box_left() + padding * 2., + metrics.font_bounding_box_descent() - metrics.font_bounding_box_ascent() - padding * 2., + ); + } + + self.render_context.set_font(r#"12px "Source Sans Pro", Arial, sans-serif"#); + self.render_context.set_fill_style_str(font_color); + self.render_context.fill_text(text, 0., 0.).expect("Failed to draw the text at the calculated position"); + self.render_context.reset_transform().expect("Failed to reset the render context transform"); + } +} + +pub enum Pivot { + Start, + Middle, + End, +} + +pub enum DrawHandles { + All, + SelectedAnchors(Vec), + FrontierHandles(HashMap>), + None, +} diff --git a/editor/src/messages/portfolio/document/properties_panel/mod.rs b/editor/src/messages/portfolio/document/properties_panel/mod.rs new file mode 100644 index 0000000000000000000000000000000000000000..7508ecada4c42183daf1d79ec421d33982f3fc22 --- /dev/null +++ b/editor/src/messages/portfolio/document/properties_panel/mod.rs @@ -0,0 +1,9 @@ +mod properties_panel_message; +mod properties_panel_message_handler; + +pub mod utility_types; + +#[doc(inline)] +pub use properties_panel_message::{PropertiesPanelMessage, PropertiesPanelMessageDiscriminant}; +#[doc(inline)] +pub use properties_panel_message_handler::PropertiesPanelMessageHandler; diff --git a/editor/src/messages/portfolio/document/properties_panel/properties_panel_message.rs b/editor/src/messages/portfolio/document/properties_panel/properties_panel_message.rs new file mode 100644 index 0000000000000000000000000000000000000000..a87d8fb07d7829b8d29e21943c6078bc51e8a6e7 --- /dev/null +++ b/editor/src/messages/portfolio/document/properties_panel/properties_panel_message.rs @@ -0,0 +1,9 @@ +use crate::messages::prelude::*; + +#[impl_message(Message, DocumentMessage, PropertiesPanel)] +#[derive(PartialEq, Clone, Debug, serde::Serialize, serde::Deserialize)] +pub enum PropertiesPanelMessage { + // Messages + Clear, + Refresh, +} diff --git a/editor/src/messages/portfolio/document/properties_panel/properties_panel_message_handler.rs b/editor/src/messages/portfolio/document/properties_panel/properties_panel_message_handler.rs new file mode 100644 index 0000000000000000000000000000000000000000..a783b24aae3089ed85a66bd7ee0a390bbff9ca4b --- /dev/null +++ b/editor/src/messages/portfolio/document/properties_panel/properties_panel_message_handler.rs @@ -0,0 +1,48 @@ +use super::utility_types::PropertiesPanelMessageHandlerData; +use crate::messages::layout::utility_types::widget_prelude::*; +use crate::messages::portfolio::document::node_graph::document_node_definitions::NodePropertiesContext; +use crate::messages::portfolio::utility_types::PersistentData; +use crate::messages::prelude::*; + +#[derive(Debug, Clone, Default)] +pub struct PropertiesPanelMessageHandler {} + +impl MessageHandler)> for PropertiesPanelMessageHandler { + fn process_message(&mut self, message: PropertiesPanelMessage, responses: &mut VecDeque, (persistent_data, data): (&PersistentData, PropertiesPanelMessageHandlerData)) { + let PropertiesPanelMessageHandlerData { + network_interface, + selection_network_path, + document_name, + executor, + } = data; + + match message { + PropertiesPanelMessage::Clear => { + responses.add(LayoutMessage::SendLayout { + layout: Layout::WidgetLayout(WidgetLayout::new(vec![])), + layout_target: LayoutTarget::PropertiesSections, + }); + } + PropertiesPanelMessage::Refresh => { + let mut context = NodePropertiesContext { + persistent_data, + responses, + network_interface, + selection_network_path, + document_name, + executor, + }; + let properties_sections = NodeGraphMessageHandler::collate_properties(&mut context); + + context.responses.add(LayoutMessage::SendLayout { + layout: Layout::WidgetLayout(WidgetLayout::new(properties_sections)), + layout_target: LayoutTarget::PropertiesSections, + }); + } + } + } + + fn actions(&self) -> ActionList { + actions!(PropertiesMessageDiscriminant;) + } +} diff --git a/editor/src/messages/portfolio/document/properties_panel/utility_types.rs b/editor/src/messages/portfolio/document/properties_panel/utility_types.rs new file mode 100644 index 0000000000000000000000000000000000000000..ee2553a1e98f2d3905c146d0620bcf68035af85d --- /dev/null +++ b/editor/src/messages/portfolio/document/properties_panel/utility_types.rs @@ -0,0 +1,10 @@ +use crate::messages::portfolio::document::utility_types::network_interface::NodeNetworkInterface; +use crate::node_graph_executor::NodeGraphExecutor; +use graph_craft::document::NodeId; + +pub struct PropertiesPanelMessageHandlerData<'a> { + pub network_interface: &'a mut NodeNetworkInterface, + pub selection_network_path: &'a [NodeId], + pub document_name: &'a str, + pub executor: &'a mut NodeGraphExecutor, +} diff --git a/editor/src/messages/portfolio/document/utility_types/clipboards.rs b/editor/src/messages/portfolio/document/utility_types/clipboards.rs new file mode 100644 index 0000000000000000000000000000000000000000..158372cd4074d9a17d1287729bd3b194ef2f12e4 --- /dev/null +++ b/editor/src/messages/portfolio/document/utility_types/clipboards.rs @@ -0,0 +1,23 @@ +use super::network_interface::NodeTemplate; +use graph_craft::document::NodeId; + +#[repr(u8)] +#[derive(serde::Serialize, serde::Deserialize, Clone, Copy, PartialEq, Eq, Debug, specta::Type)] +pub enum Clipboard { + Internal, + + _InternalClipboardCount, // Keep this as the last entry of **internal** clipboards since it is used for counting the number of enum variants + + Device, +} + +pub const INTERNAL_CLIPBOARD_COUNT: u8 = Clipboard::_InternalClipboardCount as u8; + +#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)] +pub struct CopyBufferEntry { + pub nodes: Vec<(NodeId, NodeTemplate)>, + pub selected: bool, + pub visible: bool, + pub locked: bool, + pub collapsed: bool, +} diff --git a/editor/src/messages/portfolio/document/utility_types/document_metadata.rs b/editor/src/messages/portfolio/document/utility_types/document_metadata.rs new file mode 100644 index 0000000000000000000000000000000000000000..23887db3e55963418d9cfc7acc6ac4ab32dba3b5 --- /dev/null +++ b/editor/src/messages/portfolio/document/utility_types/document_metadata.rs @@ -0,0 +1,575 @@ +use super::network_interface::NodeNetworkInterface; +use crate::messages::portfolio::document::graph_operation::transform_utils; +use crate::messages::portfolio::document::graph_operation::utility_types::ModifyInputsContext; +use glam::{DAffine2, DVec2}; +use graph_craft::document::NodeId; +use graphene_std::math::quad::Quad; +use graphene_std::transform::Footprint; +use graphene_std::vector::click_target::{ClickTarget, ClickTargetType}; +use graphene_std::vector::{PointId, VectorData}; +use std::collections::{HashMap, HashSet}; +use std::num::NonZeroU64; + +// ================ +// DocumentMetadata +// ================ + +// TODO: To avoid storing a stateful snapshot of some other system's state (which is easily to accidentally get out of sync), +// TODO: it might be better to have a system that can query the state of the node network on demand. +#[derive(Debug, Clone)] +pub struct DocumentMetadata { + pub upstream_footprints: HashMap, + pub local_transforms: HashMap, + pub structure: HashMap, + pub click_targets: HashMap>, + pub clip_targets: HashSet, + pub vector_modify: HashMap, + /// Transform from document space to viewport space. + pub document_to_viewport: DAffine2, +} + +impl Default for DocumentMetadata { + fn default() -> Self { + Self { + upstream_footprints: HashMap::new(), + local_transforms: HashMap::new(), + structure: HashMap::new(), + vector_modify: HashMap::new(), + click_targets: HashMap::new(), + clip_targets: HashSet::new(), + document_to_viewport: DAffine2::IDENTITY, + } + } +} + +// ================================= +// DocumentMetadata: Layer iterators +// ================================= + +impl DocumentMetadata { + pub fn all_layers(&self) -> DescendantsIter<'_> { + LayerNodeIdentifier::ROOT_PARENT.descendants(self) + } + + pub fn layer_exists(&self, layer: LayerNodeIdentifier) -> bool { + self.structure.contains_key(&layer) + } + + pub fn click_targets(&self, layer: LayerNodeIdentifier) -> Option<&Vec> { + self.click_targets.get(&layer) + } + + /// Access the [`NodeRelations`] of a layer. + fn get_relations(&self, node_identifier: LayerNodeIdentifier) -> Option<&NodeRelations> { + self.structure.get(&node_identifier) + } + + /// Mutably access the [`NodeRelations`] of a layer. + fn get_structure_mut(&mut self, node_identifier: LayerNodeIdentifier) -> &mut NodeRelations { + self.structure.entry(node_identifier).or_default() + } +} +// ============================ +// DocumentMetadata: Transforms +// ============================ + +impl DocumentMetadata { + /// Access the cached transformation to document space from layer space + pub fn transform_to_document(&self, layer: LayerNodeIdentifier) -> DAffine2 { + self.document_to_viewport.inverse() * self.transform_to_viewport(layer) + } + + pub fn transform_to_viewport(&self, layer: LayerNodeIdentifier) -> DAffine2 { + // We're not allowed to convert the root parent to a node id + if layer == LayerNodeIdentifier::ROOT_PARENT { + return self.document_to_viewport; + } + + let footprint = self.upstream_footprints.get(&layer.to_node()).map(|footprint| footprint.transform).unwrap_or(self.document_to_viewport); + let local_transform = self.local_transforms.get(&layer.to_node()).copied().unwrap_or_default(); + + footprint * local_transform + } + + pub fn transform_to_viewport_with_first_transform_node_if_group(&self, layer: LayerNodeIdentifier, network_interface: &NodeNetworkInterface) -> DAffine2 { + let footprint = self.upstream_footprints.get(&layer.to_node()).map(|footprint| footprint.transform).unwrap_or(self.document_to_viewport); + let local_transform = self.local_transforms.get(&layer.to_node()).copied(); + + let transform = local_transform.unwrap_or_else(|| { + let transform_node_id = ModifyInputsContext::locate_node_in_layer_chain("Transform", layer, network_interface); + let transform_node = transform_node_id.and_then(|id| network_interface.document_node(&id, &[])); + transform_node.map(|node| transform_utils::get_current_transform(node.inputs.as_slice())).unwrap_or_default() + }); + + footprint * transform + } + + pub fn upstream_transform(&self, node_id: NodeId) -> DAffine2 { + self.local_transforms.get(&node_id).copied().unwrap_or(DAffine2::IDENTITY) + } + + pub fn downstream_transform_to_document(&self, layer: LayerNodeIdentifier) -> DAffine2 { + self.document_to_viewport.inverse() * self.downstream_transform_to_viewport(layer) + } + + pub fn downstream_transform_to_viewport(&self, layer: LayerNodeIdentifier) -> DAffine2 { + if layer == LayerNodeIdentifier::ROOT_PARENT { + return self.transform_to_viewport(layer); + } + + self.upstream_footprints + .get(&layer.to_node()) + .copied() + .map(|footprint| footprint.transform) + .unwrap_or_else(|| self.transform_to_viewport(layer)) + } +} + +// =============================== +// DocumentMetadata: Click targets +// =============================== + +impl DocumentMetadata { + /// Get the bounding box of the click target of the specified layer in the specified transform space + pub fn bounding_box_with_transform(&self, layer: LayerNodeIdentifier, transform: DAffine2) -> Option<[DVec2; 2]> { + self.click_targets(layer)? + .iter() + .filter_map(|click_target| match click_target.target_type() { + ClickTargetType::Subpath(subpath) => subpath.bounding_box_with_transform(transform), + ClickTargetType::FreePoint(_) => click_target.bounding_box_with_transform(transform), + }) + .reduce(Quad::combine_bounds) + } + + /// Calculate the corners of the bounding box but with a nonzero size. + /// + /// If the layer bounds are `0` in either axis then they are changed to be `1`. + pub fn nonzero_bounding_box(&self, layer: LayerNodeIdentifier) -> [DVec2; 2] { + let [mut bounds_min, mut bounds_max] = self.bounding_box_with_transform(layer, DAffine2::IDENTITY).unwrap_or_default(); + + let bounds_size = bounds_max - bounds_min; + let bounds_midpoint = bounds_min.midpoint(bounds_max); + const BOX_NUDGE: f64 = 5e-9; + if bounds_size.x < 1e-10 { + bounds_max.x = bounds_midpoint.x + BOX_NUDGE; + bounds_min.x = bounds_midpoint.x - BOX_NUDGE; + } + if bounds_size.y < 1e-10 { + bounds_max.y = bounds_midpoint.y + BOX_NUDGE; + bounds_min.y = bounds_midpoint.y - BOX_NUDGE; + } + + [bounds_min, bounds_max] + } + + /// Get the bounding box of the click target of the specified layer in document space + pub fn bounding_box_document(&self, layer: LayerNodeIdentifier) -> Option<[DVec2; 2]> { + self.bounding_box_with_transform(layer, self.transform_to_document(layer)) + } + + /// Get the bounding box of the click target of the specified layer in viewport space + pub fn bounding_box_viewport(&self, layer: LayerNodeIdentifier) -> Option<[DVec2; 2]> { + self.bounding_box_with_transform(layer, self.transform_to_viewport(layer)) + } + + /// Calculates the document bounds in viewport space + pub fn document_bounds_viewport_space(&self) -> Option<[DVec2; 2]> { + self.all_layers().filter_map(|layer| self.bounding_box_viewport(layer)).reduce(Quad::combine_bounds) + } + + pub fn layer_outline(&self, layer: LayerNodeIdentifier) -> impl Iterator> { + static EMPTY: Vec = Vec::new(); + let click_targets = self.click_targets.get(&layer).unwrap_or(&EMPTY); + click_targets.iter().filter_map(|target| match target.target_type() { + ClickTargetType::Subpath(subpath) => Some(subpath), + _ => None, + }) + } + + pub fn layer_with_free_points_outline(&self, layer: LayerNodeIdentifier) -> impl Iterator { + static EMPTY: Vec = Vec::new(); + let click_targets = self.click_targets.get(&layer).unwrap_or(&EMPTY); + click_targets.iter().map(|target| target.target_type()) + } + + pub fn is_clip(&self, node: NodeId) -> bool { + self.clip_targets.contains(&node) + } +} + +// =================== +// LayerNodeIdentifier +// =================== + +/// ID of a layer node +#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, serde::Serialize, serde::Deserialize, specta::Type)] +pub struct LayerNodeIdentifier(NonZeroU64); + +impl core::fmt::Debug for LayerNodeIdentifier { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + let node_id = if *self != LayerNodeIdentifier::ROOT_PARENT { self.to_node() } else { NodeId(0) }; + + f.debug_tuple("LayerNodeIdentifier").field(&node_id).finish() + } +} + +impl Default for LayerNodeIdentifier { + fn default() -> Self { + Self::ROOT_PARENT + } +} + +impl LayerNodeIdentifier { + /// A conceptual layer used to represent the parent of layers that feed into the export + pub const ROOT_PARENT: Self = LayerNodeIdentifier::new_unchecked(NodeId(0)); + + /// Construct a [`LayerNodeIdentifier`] without checking if it is a layer node + pub const fn new_unchecked(node_id: NodeId) -> Self { + // # Safety: will always be >=1 + Self(unsafe { NonZeroU64::new_unchecked(node_id.0 + 1) }) + } + + /// Construct a [`LayerNodeIdentifier`], debug asserting that it is a layer node. This should only be used in the document network since the structure is not loaded in nested networks. + #[track_caller] + pub fn new(node_id: NodeId, network_interface: &NodeNetworkInterface, network_path: &[NodeId]) -> Self { + debug_assert!( + network_interface.is_layer(&node_id, network_path), + "Layer identifier constructed from non-layer node {node_id}: {:#?}", + network_interface.nested_network(network_path).unwrap().nodes.get(&node_id) + ); + Self::new_unchecked(node_id) + } + + /// Access the node id of this layer + pub fn to_node(self) -> NodeId { + let id = NodeId(u64::from(self.0) - 1); + debug_assert!(id != NodeId(0), "LayerNodeIdentifier::ROOT_PARENT cannot be converted to NodeId"); + + id + } + + /// Access the parent layer if possible + pub fn parent(self, metadata: &DocumentMetadata) -> Option { + metadata.get_relations(self).and_then(|relations| relations.parent) + } + + /// Access the previous sibling of this layer (up the Layers panel) + pub fn previous_sibling(self, metadata: &DocumentMetadata) -> Option { + metadata.get_relations(self).and_then(|relations| relations.previous_sibling) + } + + /// Access the next sibling of this layer (down the Layers panel) + pub fn next_sibling(self, metadata: &DocumentMetadata) -> Option { + metadata.get_relations(self).and_then(|relations| relations.next_sibling) + } + + /// Access the first child of this layer (top most in Layers panel) + pub fn first_child(self, metadata: &DocumentMetadata) -> Option { + metadata.get_relations(self).and_then(|relations| relations.first_child) + } + + /// Access the last child of this layer (bottom most in Layers panel) + pub fn last_child(self, metadata: &DocumentMetadata) -> Option { + metadata.get_relations(self).and_then(|relations| relations.last_child) + } + + /// Does the layer have children? If so, then it is a folder. + pub fn has_children(self, metadata: &DocumentMetadata) -> bool { + self.first_child(metadata).is_some() + } + + /// Is the layer a child of the given layer? + pub fn is_child_of(self, metadata: &DocumentMetadata, parent: &LayerNodeIdentifier) -> bool { + parent.children(metadata).any(|child| child == self) + } + + /// Is the layer an ancestor of the given layer? + pub fn is_ancestor_of(self, metadata: &DocumentMetadata, child: &LayerNodeIdentifier) -> bool { + child.ancestors(metadata).any(|ancestor| ancestor == self) + } + + /// Is the layer last child of parent group? Used for clipping + pub fn can_be_clipped(self, metadata: &DocumentMetadata) -> bool { + self.parent(metadata) + .map_or(false, |layer| layer.last_child(metadata).expect("Parent accessed via child should have children") != self) + } + + /// Iterator over all direct children (excluding self and recursive children) + pub fn children(self, metadata: &DocumentMetadata) -> AxisIter<'_> { + AxisIter { + layer_node: self.first_child(metadata), + next_node: Self::next_sibling, + metadata, + } + } + + pub fn downstream_siblings(self, metadata: &DocumentMetadata) -> AxisIter<'_> { + AxisIter { + layer_node: Some(self), + next_node: Self::previous_sibling, + metadata, + } + } + + /// All ancestors of this layer, including self, going to the document root + pub fn ancestors(self, metadata: &DocumentMetadata) -> AxisIter<'_> { + AxisIter { + layer_node: Some(self), + next_node: Self::parent, + metadata, + } + } + + /// Iterator through all the last children, starting from self + pub fn last_children(self, metadata: &DocumentMetadata) -> AxisIter<'_> { + AxisIter { + layer_node: Some(self), + next_node: Self::last_child, + metadata, + } + } + + /// Iterator through all descendants, including recursive children (not including self) + pub fn descendants(self, metadata: &DocumentMetadata) -> DescendantsIter<'_> { + DescendantsIter { + front: self.first_child(metadata), + back: self.last_child(metadata).and_then(|child| child.last_children(metadata).last()), + metadata, + } + } + + /// Add a child towards the top of the Layers panel + pub fn push_front_child(self, metadata: &mut DocumentMetadata, new: LayerNodeIdentifier) { + assert!(!metadata.structure.contains_key(&new), "Cannot add already existing layer"); + let parent = metadata.get_structure_mut(self); + let old_first_child = parent.first_child.replace(new); + parent.last_child.get_or_insert(new); + if let Some(old_first_child) = old_first_child { + metadata.get_structure_mut(old_first_child).previous_sibling = Some(new); + } + metadata.get_structure_mut(new).next_sibling = old_first_child; + metadata.get_structure_mut(new).parent = Some(self); + } + + /// Add a child towards the bottom of the Layers panel + pub fn push_child(self, metadata: &mut DocumentMetadata, new: LayerNodeIdentifier) { + assert!(!metadata.structure.contains_key(&new), "Cannot add already existing layer"); + let parent = metadata.get_structure_mut(self); + let old_last_child = parent.last_child.replace(new); + parent.first_child.get_or_insert(new); + if let Some(old_last_child) = old_last_child { + metadata.get_structure_mut(old_last_child).next_sibling = Some(new); + } + metadata.get_structure_mut(new).previous_sibling = old_last_child; + metadata.get_structure_mut(new).parent = Some(self); + } + + /// Add sibling above in the Layers panel + pub fn add_before(self, metadata: &mut DocumentMetadata, new: LayerNodeIdentifier) { + assert!(!metadata.structure.contains_key(&new), "Cannot add already existing layer"); + metadata.get_structure_mut(new).next_sibling = Some(self); + metadata.get_structure_mut(new).parent = self.parent(metadata); + let old_previous_sibling = metadata.get_structure_mut(self).previous_sibling.replace(new); + if let Some(old_previous_sibling) = old_previous_sibling { + metadata.get_structure_mut(old_previous_sibling).next_sibling = Some(new); + metadata.get_structure_mut(new).previous_sibling = Some(old_previous_sibling); + } else if let Some(structure) = self + .parent(metadata) + .map(|parent| metadata.get_structure_mut(parent)) + .filter(|structure| structure.first_child == Some(self)) + { + structure.first_child = Some(new); + } + } + + /// Add sibling below in the Layers panel + pub fn add_after(self, metadata: &mut DocumentMetadata, new: LayerNodeIdentifier) { + assert!(!metadata.structure.contains_key(&new), "Cannot add already existing layer"); + metadata.get_structure_mut(new).previous_sibling = Some(self); + metadata.get_structure_mut(new).parent = self.parent(metadata); + let old_next_sibling = metadata.get_structure_mut(self).next_sibling.replace(new); + if let Some(old_next_sibling) = old_next_sibling { + metadata.get_structure_mut(old_next_sibling).previous_sibling = Some(new); + metadata.get_structure_mut(new).next_sibling = Some(old_next_sibling); + } else if let Some(structure) = self + .parent(metadata) + .map(|parent| metadata.get_structure_mut(parent)) + .filter(|structure| structure.last_child == Some(self)) + { + structure.last_child = Some(new); + } + } + + /// Delete layer and all children + pub fn delete(self, metadata: &mut DocumentMetadata) { + let previous_sibling = self.previous_sibling(metadata); + let next_sibling = self.next_sibling(metadata); + + if let Some(previous_sibling) = previous_sibling.map(|node| metadata.get_structure_mut(node)) { + previous_sibling.next_sibling = next_sibling; + } + + if let Some(next_sibling) = next_sibling.map(|node| metadata.get_structure_mut(node)) { + next_sibling.previous_sibling = previous_sibling; + } + let mut parent = self.parent(metadata).map(|parent| metadata.get_structure_mut(parent)); + if let Some(structure) = parent.as_mut().filter(|structure| structure.first_child == Some(self)) { + structure.first_child = next_sibling; + } + if let Some(structure) = parent.as_mut().filter(|structure| structure.last_child == Some(self)) { + structure.last_child = previous_sibling; + } + + let mut delete = vec![self]; + delete.extend(self.descendants(metadata)); + for node in delete { + metadata.structure.remove(&node); + } + } + + pub fn exists(&self, metadata: &DocumentMetadata) -> bool { + metadata.get_relations(*self).is_some() + } + + pub fn starts_with(&self, other: Self, metadata: &DocumentMetadata) -> bool { + self.ancestors(metadata).any(|parent| parent == other) + } +} + +// ======== +// AxisIter +// ======== + +/// Iterator over specified axis. +#[derive(Clone)] +pub struct AxisIter<'a> { + pub layer_node: Option, + pub next_node: fn(LayerNodeIdentifier, &DocumentMetadata) -> Option, + pub metadata: &'a DocumentMetadata, +} + +impl Iterator for AxisIter<'_> { + type Item = LayerNodeIdentifier; + + fn next(&mut self) -> Option { + let layer_node = self.layer_node.take(); + self.layer_node = layer_node.and_then(|node| (self.next_node)(node, self.metadata)); + layer_node + } +} + +// =============== +// DescendantsIter +// =============== + +#[derive(Clone)] +pub struct DescendantsIter<'a> { + front: Option, + back: Option, + metadata: &'a DocumentMetadata, +} + +impl Iterator for DescendantsIter<'_> { + type Item = LayerNodeIdentifier; + + fn next(&mut self) -> Option { + if self.front == self.back { + self.back = None; + self.front.take() + } else { + let layer_node = self.front.take(); + if let Some(layer_node) = layer_node { + self.front = layer_node + .first_child(self.metadata) + .or_else(|| layer_node.ancestors(self.metadata).find_map(|ancestor| ancestor.next_sibling(self.metadata))); + } + layer_node + } + } +} +impl DoubleEndedIterator for DescendantsIter<'_> { + fn next_back(&mut self) -> Option { + if self.front == self.back { + self.front = None; + self.back.take() + } else { + let layer_node = self.back.take(); + if let Some(layer_node) = layer_node { + self.back = layer_node + .previous_sibling(self.metadata) + .and_then(|sibling| sibling.last_children(self.metadata).last()) + .or_else(|| layer_node.parent(self.metadata)); + } + + layer_node + } + } +} + +// ============= +// NodeRelations +// ============= + +#[derive(Debug, Clone, Copy, Default)] +pub struct NodeRelations { + pub parent: Option, + previous_sibling: Option, + next_sibling: Option, + first_child: Option, + last_child: Option, +} + +// ================ +// Helper functions +// ================ + +#[cfg(test)] +mod tests { + use super::*; + #[test] + fn test_tree() { + let mut metadata = DocumentMetadata::default(); + let root = LayerNodeIdentifier::ROOT_PARENT; + let metadata = &mut metadata; + root.push_child(metadata, LayerNodeIdentifier::new_unchecked(NodeId(3))); + assert_eq!(root.children(metadata).collect::>(), vec![LayerNodeIdentifier::new_unchecked(NodeId(3))]); + root.push_child(metadata, LayerNodeIdentifier::new_unchecked(NodeId(6))); + assert_eq!(root.children(metadata).map(LayerNodeIdentifier::to_node).collect::>(), vec![NodeId(3), NodeId(6)]); + assert_eq!(root.descendants(metadata).map(LayerNodeIdentifier::to_node).collect::>(), vec![NodeId(3), NodeId(6)]); + LayerNodeIdentifier::new_unchecked(NodeId(3)).add_after(metadata, LayerNodeIdentifier::new_unchecked(NodeId(4))); + LayerNodeIdentifier::new_unchecked(NodeId(3)).add_before(metadata, LayerNodeIdentifier::new_unchecked(NodeId(2))); + LayerNodeIdentifier::new_unchecked(NodeId(6)).add_before(metadata, LayerNodeIdentifier::new_unchecked(NodeId(5))); + LayerNodeIdentifier::new_unchecked(NodeId(6)).add_after(metadata, LayerNodeIdentifier::new_unchecked(NodeId(9))); + LayerNodeIdentifier::new_unchecked(NodeId(6)).push_child(metadata, LayerNodeIdentifier::new_unchecked(NodeId(8))); + LayerNodeIdentifier::new_unchecked(NodeId(6)).push_front_child(metadata, LayerNodeIdentifier::new_unchecked(NodeId(7))); + root.push_front_child(metadata, LayerNodeIdentifier::new_unchecked(NodeId(1))); + assert_eq!( + root.children(metadata).map(LayerNodeIdentifier::to_node).collect::>(), + vec![NodeId(1), NodeId(2), NodeId(3), NodeId(4), NodeId(5), NodeId(6), NodeId(9)] + ); + assert_eq!( + root.descendants(metadata).map(LayerNodeIdentifier::to_node).collect::>(), + vec![NodeId(1), NodeId(2), NodeId(3), NodeId(4), NodeId(5), NodeId(6), NodeId(7), NodeId(8), NodeId(9)] + ); + assert_eq!( + root.descendants(metadata).map(LayerNodeIdentifier::to_node).rev().collect::>(), + vec![NodeId(9), NodeId(8), NodeId(7), NodeId(6), NodeId(5), NodeId(4), NodeId(3), NodeId(2), NodeId(1)] + ); + assert!(root.children(metadata).all(|child| child.parent(metadata) == Some(root))); + LayerNodeIdentifier::new_unchecked(NodeId(6)).delete(metadata); + LayerNodeIdentifier::new_unchecked(NodeId(1)).delete(metadata); + LayerNodeIdentifier::new_unchecked(NodeId(9)).push_child(metadata, LayerNodeIdentifier::new_unchecked(NodeId(10))); + assert_eq!( + root.children(metadata).map(LayerNodeIdentifier::to_node).collect::>(), + vec![NodeId(2), NodeId(3), NodeId(4), NodeId(5), NodeId(9)] + ); + assert_eq!( + root.descendants(metadata).map(LayerNodeIdentifier::to_node).collect::>(), + vec![NodeId(2), NodeId(3), NodeId(4), NodeId(5), NodeId(9), NodeId(10)] + ); + assert_eq!( + root.descendants(metadata).map(LayerNodeIdentifier::to_node).rev().collect::>(), + vec![NodeId(10), NodeId(9), NodeId(5), NodeId(4), NodeId(3), NodeId(2)] + ); + } +} diff --git a/editor/src/messages/portfolio/document/utility_types/error.rs b/editor/src/messages/portfolio/document/utility_types/error.rs new file mode 100644 index 0000000000000000000000000000000000000000..96211441b0357fa7a2d100947ea76352bca2be89 --- /dev/null +++ b/editor/src/messages/portfolio/document/utility_types/error.rs @@ -0,0 +1,38 @@ +use graphene_std::raster::color::Color; +use thiserror::Error; + +/// The error type used by the Graphite editor. +#[derive(Clone, Debug, Error)] +pub enum EditorError { + #[error("Failed to execute operation:\n{0}")] + InvalidOperation(String), + + #[error("Tried to construct an invalid color:\n{0:?}")] + Color(String), + + #[error("The requested tool does not exist")] + UnknownTool, + + #[error("The operation caused a document error:\n{0:?}")] + Document(String), + + #[error("This document was created in an older version of the editor.\n\nBackwards compatibility is, regrettably, not present in the current alpha release.\n\nTechnical details:\n{0:?}")] + DocumentDeserialization(String), + + #[error("{0}")] + Misc(String), +} + +macro_rules! derive_from { + ($type:ty, $kind:ident) => { + impl From<$type> for EditorError { + fn from(error: $type) -> Self { + EditorError::$kind(format!("{error:?}")) + } + } + }; +} + +derive_from!(&str, Misc); +derive_from!(String, Misc); +derive_from!(Color, Color); diff --git a/editor/src/messages/portfolio/document/utility_types/misc.rs b/editor/src/messages/portfolio/document/utility_types/misc.rs new file mode 100644 index 0000000000000000000000000000000000000000..ae8fd73532cbe8e3abbd546d36602fdf89204d60 --- /dev/null +++ b/editor/src/messages/portfolio/document/utility_types/misc.rs @@ -0,0 +1,697 @@ +use crate::consts::COLOR_OVERLAY_GRAY; +use glam::DVec2; +use graphene_std::raster::Color; +use std::fmt; + +#[repr(transparent)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, serde::Serialize, serde::Deserialize, specta::Type)] +pub struct DocumentId(pub u64); + +#[derive(PartialEq, Eq, Clone, Copy, Debug, serde::Serialize, serde::Deserialize, Hash)] +pub enum FlipAxis { + X, + Y, +} + +#[derive(PartialEq, Eq, Clone, Copy, Debug, serde::Serialize, serde::Deserialize, Hash, specta::Type)] +pub enum AlignAxis { + X, + Y, +} + +#[derive(PartialEq, Eq, Clone, Copy, Debug, serde::Serialize, serde::Deserialize, Hash, specta::Type)] +pub enum AlignAggregate { + Min, + Max, + Center, +} + +#[derive(Default, PartialEq, Eq, Clone, Copy, Debug, serde::Serialize, serde::Deserialize)] +pub enum DocumentMode { + #[default] + DesignMode, + SelectMode, + GuideMode, +} + +impl fmt::Display for DocumentMode { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + DocumentMode::DesignMode => write!(f, "Design Mode"), + DocumentMode::SelectMode => write!(f, "Select Mode"), + DocumentMode::GuideMode => write!(f, "Guide Mode"), + } + } +} + +impl DocumentMode { + pub fn icon_name(&self) -> String { + match self { + DocumentMode::DesignMode => "ViewportDesignMode".to_string(), + DocumentMode::SelectMode => "ViewportSelectMode".to_string(), + DocumentMode::GuideMode => "ViewportGuideMode".to_string(), + } + } +} + +/// SnappingState determines the current individual snapping states +#[derive(Clone, Debug, serde::Serialize, serde::Deserialize)] +#[serde(default)] +pub struct SnappingState { + pub snapping_enabled: bool, + pub grid_snapping: bool, + pub artboards: bool, + pub tolerance: f64, + pub bounding_box: BoundingBoxSnapping, + pub path: PathSnapping, + pub grid: GridSnapping, +} + +impl Default for SnappingState { + fn default() -> Self { + Self { + snapping_enabled: true, + grid_snapping: false, + artboards: true, + tolerance: 8., + bounding_box: BoundingBoxSnapping::default(), + path: PathSnapping::default(), + grid: GridSnapping::default(), + } + } +} + +impl SnappingState { + pub const fn target_enabled(&self, target: SnapTarget) -> bool { + if !self.snapping_enabled { + return false; + } + match target { + SnapTarget::BoundingBox(target) => match target { + BoundingBoxSnapTarget::CornerPoint => self.bounding_box.corner_point, + BoundingBoxSnapTarget::EdgeMidpoint => self.bounding_box.edge_midpoint, + BoundingBoxSnapTarget::CenterPoint => self.bounding_box.center_point, + }, + SnapTarget::Path(target) => match target { + PathSnapTarget::AnchorPointWithColinearHandles | PathSnapTarget::AnchorPointWithFreeHandles => self.path.anchor_point, + PathSnapTarget::LineMidpoint => self.path.line_midpoint, + PathSnapTarget::AlongPath => self.path.along_path, + PathSnapTarget::NormalToPath => self.path.normal_to_path, + PathSnapTarget::TangentToPath => self.path.tangent_to_path, + PathSnapTarget::IntersectionPoint => self.path.path_intersection_point, + PathSnapTarget::PerpendicularToEndpoint => self.path.perpendicular_from_endpoint, + }, + SnapTarget::Artboard(_) => self.artboards, + SnapTarget::Grid(_) => self.grid_snapping, + SnapTarget::Alignment(AlignmentSnapTarget::AlignWithAnchorPoint) => self.path.align_with_anchor_point, + SnapTarget::Alignment(_) => self.bounding_box.align_with_edges, + SnapTarget::DistributeEvenly(_) => self.bounding_box.distribute_evenly, + _ => false, + } + } +} + +#[derive(Clone, Debug, serde::Serialize, serde::Deserialize)] +#[serde(default)] +pub struct BoundingBoxSnapping { + pub center_point: bool, + pub corner_point: bool, + pub edge_midpoint: bool, + pub align_with_edges: bool, + pub distribute_evenly: bool, +} + +impl Default for BoundingBoxSnapping { + fn default() -> Self { + Self { + center_point: true, + corner_point: true, + edge_midpoint: true, + align_with_edges: true, + distribute_evenly: true, + } + } +} + +#[derive(Clone, Debug, serde::Serialize, serde::Deserialize)] +#[serde(default)] +pub struct PathSnapping { + pub anchor_point: bool, + pub line_midpoint: bool, + pub along_path: bool, + pub normal_to_path: bool, + pub tangent_to_path: bool, + pub path_intersection_point: bool, + pub align_with_anchor_point: bool, // TODO: Rename + pub perpendicular_from_endpoint: bool, +} + +impl Default for PathSnapping { + fn default() -> Self { + Self { + anchor_point: true, + line_midpoint: true, + along_path: true, + normal_to_path: true, + tangent_to_path: true, + path_intersection_point: true, + align_with_anchor_point: true, + perpendicular_from_endpoint: true, + } + } +} + +#[derive(Clone, Copy, Debug, serde::Serialize, serde::Deserialize, PartialEq)] +pub enum GridType { + #[serde(alias = "Rectangle")] + Rectangular { + spacing: DVec2, + }, + Isometric { + y_axis_spacing: f64, + angle_a: f64, + angle_b: f64, + }, +} + +impl Default for GridType { + fn default() -> Self { + Self::Rectangular { spacing: DVec2::ONE } + } +} + +impl GridType { + pub fn rectangular_spacing(&mut self) -> Option<&mut DVec2> { + match self { + Self::Rectangular { spacing } => Some(spacing), + _ => None, + } + } + pub fn isometric_y_spacing(&mut self) -> Option<&mut f64> { + match self { + Self::Isometric { y_axis_spacing, .. } => Some(y_axis_spacing), + _ => None, + } + } + pub fn angle_a(&mut self) -> Option<&mut f64> { + match self { + Self::Isometric { angle_a, .. } => Some(angle_a), + _ => None, + } + } + pub fn angle_b(&mut self) -> Option<&mut f64> { + match self { + Self::Isometric { angle_b, .. } => Some(angle_b), + _ => None, + } + } +} + +#[derive(Clone, Debug, serde::Serialize, serde::Deserialize, PartialEq)] +#[serde(default)] +pub struct GridSnapping { + pub origin: DVec2, + pub grid_type: GridType, + pub rectangular_spacing: DVec2, + pub isometric_y_spacing: f64, + pub isometric_angle_a: f64, + pub isometric_angle_b: f64, + pub grid_color: Color, + pub dot_display: bool, +} + +impl Default for GridSnapping { + fn default() -> Self { + Self { + origin: DVec2::ZERO, + grid_type: Default::default(), + rectangular_spacing: DVec2::ONE, + isometric_y_spacing: 1., + isometric_angle_a: 30., + isometric_angle_b: 30., + grid_color: Color::from_rgb_str(COLOR_OVERLAY_GRAY.strip_prefix('#').unwrap()).unwrap(), + dot_display: false, + } + } +} + +impl GridSnapping { + // Double grid size until it takes up at least 10px. + pub fn compute_rectangle_spacing(mut size: DVec2, navigation: &PTZ) -> Option { + let mut iterations = 0; + size = size.abs(); + while (size * navigation.zoom()).cmplt(DVec2::splat(10.)).any() { + if iterations > 100 { + return None; + } + size *= 2.; + iterations += 1; + } + Some(size) + } + + // Double grid size until it takes up at least 10px. + pub fn compute_isometric_multiplier(length: f64, divisor: f64, navigation: &PTZ) -> Option { + let length = length.abs(); + let mut iterations = 0; + let mut multiplier = 1.; + while (length / divisor.abs().max(1.)) * multiplier * navigation.zoom() < 10. { + if iterations > 100 { + return None; + } + multiplier *= 2.; + iterations += 1; + } + Some(multiplier) + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum BoundingBoxSnapSource { + CornerPoint, + CenterPoint, + EdgeMidpoint, +} + +impl fmt::Display for BoundingBoxSnapSource { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + BoundingBoxSnapSource::CornerPoint => write!(f, "Bounding Box: Corner Point"), + BoundingBoxSnapSource::CenterPoint => write!(f, "Bounding Box: Center Point"), + BoundingBoxSnapSource::EdgeMidpoint => write!(f, "Bounding Box: Edge Midpoint"), + } + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum ArtboardSnapSource { + CornerPoint, + CenterPoint, +} + +impl fmt::Display for ArtboardSnapSource { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + ArtboardSnapSource::CornerPoint => write!(f, "Artboard: Corner Point"), + ArtboardSnapSource::CenterPoint => write!(f, "Artboard: Center Point"), + } + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum PathSnapSource { + AnchorPointWithColinearHandles, + AnchorPointWithFreeHandles, + HandlePoint, + LineMidpoint, + IntersectionPoint, +} + +impl fmt::Display for PathSnapSource { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + PathSnapSource::AnchorPointWithColinearHandles | PathSnapSource::AnchorPointWithFreeHandles => write!(f, "Path: Anchor Point"), + PathSnapSource::HandlePoint => write!(f, "Path: Handle Point"), + PathSnapSource::LineMidpoint => write!(f, "Path: Line Midpoint"), + PathSnapSource::IntersectionPoint => write!(f, "Path: Intersection Point"), + } + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum AlignmentSnapSource { + BoundingBoxCornerPoint, + BoundingBoxCenterPoint, + BoundingBoxEdgeMidpoint, + ArtboardCornerPoint, + ArtboardCenterPoint, +} + +impl fmt::Display for AlignmentSnapSource { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + AlignmentSnapSource::BoundingBoxCornerPoint => write!(f, "{}", BoundingBoxSnapSource::CornerPoint), + AlignmentSnapSource::BoundingBoxCenterPoint => write!(f, "{}", BoundingBoxSnapSource::CenterPoint), + AlignmentSnapSource::BoundingBoxEdgeMidpoint => write!(f, "{}", BoundingBoxSnapSource::EdgeMidpoint), + AlignmentSnapSource::ArtboardCornerPoint => write!(f, "{}", ArtboardSnapSource::CornerPoint), + AlignmentSnapSource::ArtboardCenterPoint => write!(f, "{}", ArtboardSnapSource::CenterPoint), + } + } +} + +#[derive(Default, Debug, Clone, Copy, PartialEq, Eq)] +pub enum SnapSource { + #[default] + None, + BoundingBox(BoundingBoxSnapSource), + Artboard(ArtboardSnapSource), + Path(PathSnapSource), + Alignment(AlignmentSnapSource), +} + +impl SnapSource { + pub fn is_some(&self) -> bool { + self != &Self::None + } + pub fn bounding_box(&self) -> bool { + matches!(self, Self::BoundingBox(_) | Self::Artboard(_)) + } + pub fn align(&self) -> bool { + matches!(self, Self::Alignment(_)) + } + pub fn center(&self) -> bool { + matches!( + self, + Self::Alignment(AlignmentSnapSource::ArtboardCenterPoint | AlignmentSnapSource::BoundingBoxCenterPoint) + | Self::Artboard(ArtboardSnapSource::CenterPoint) + | Self::BoundingBox(BoundingBoxSnapSource::CenterPoint) + ) + } +} + +impl fmt::Display for SnapSource { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + SnapSource::None => write!(f, "None"), + SnapSource::BoundingBox(bounding_box_snap_source) => write!(f, "{bounding_box_snap_source}"), + SnapSource::Artboard(artboard_snap_source) => write!(f, "{artboard_snap_source}"), + SnapSource::Path(path_snap_source) => write!(f, "{path_snap_source}"), + SnapSource::Alignment(alignment_snap_source) => write!(f, "{alignment_snap_source}"), + } + } +} + +type GetSnapState = for<'a> fn(&'a mut SnappingState) -> &'a mut bool; +pub const SNAP_FUNCTIONS_FOR_BOUNDING_BOXES: [(&str, GetSnapState, &str); 5] = [ + ( + "Align with Edges", + (|snapping_state| &mut snapping_state.bounding_box.align_with_edges) as GetSnapState, + "Snaps to horizontal/vertical alignment with the edges of any layer's bounding box", + ), + ( + "Corner Points", + (|snapping_state| &mut snapping_state.bounding_box.corner_point) as GetSnapState, + "Snaps to the four corners of any layer's bounding box", + ), + ( + "Center Points", + (|snapping_state| &mut snapping_state.bounding_box.center_point) as GetSnapState, + "Snaps to the center point of any layer's bounding box", + ), + ( + "Edge Midpoints", + (|snapping_state| &mut snapping_state.bounding_box.edge_midpoint) as GetSnapState, + "Snaps to any of the four points at the middle of the edges of any layer's bounding box", + ), + ( + "Distribute Evenly", + (|snapping_state| &mut snapping_state.bounding_box.distribute_evenly) as GetSnapState, + "Snaps to a consistent distance offset established by the bounding boxes of nearby layers", + ), +]; +pub const SNAP_FUNCTIONS_FOR_PATHS: [(&str, GetSnapState, &str); 7] = [ + ( + "Align with Anchor Points", + (|snapping_state: &mut SnappingState| &mut snapping_state.path.align_with_anchor_point) as GetSnapState, + "Snaps to horizontal/vertical alignment with the anchor points of any vector path", + ), + ( + "Anchor Points", + (|snapping_state: &mut SnappingState| &mut snapping_state.path.anchor_point) as GetSnapState, + "Snaps to the anchor point of any vector path", + ), + ( + // TODO: Extend to the midpoints of curved segments and rename to "Segment Midpoint" + "Line Midpoints", + (|snapping_state: &mut SnappingState| &mut snapping_state.path.line_midpoint) as GetSnapState, + "Snaps to the point at the middle of any straight line segment of a vector path", + ), + ( + "Path Intersection Points", + (|snapping_state: &mut SnappingState| &mut snapping_state.path.path_intersection_point) as GetSnapState, + "Snaps to any points where vector paths intersect", + ), + ( + "Along Paths", + (|snapping_state: &mut SnappingState| &mut snapping_state.path.along_path) as GetSnapState, + "Snaps along the length of any vector path", + ), + ( + // TODO: This works correctly for line segments, but not curved segments. + // TODO: Therefore, we should make this use the normal in relation to the incoming curve, not the straight line between the incoming curve's start point and the path. + "Normal to Paths", + (|snapping_state: &mut SnappingState| &mut snapping_state.path.normal_to_path) as GetSnapState, + // TODO: Fix the bug/limitation that requires 'Intersections of Paths' to be enabled + "Snaps a line to a point perpendicular to a vector path\n(due to a bug, 'Intersections of Paths' must be enabled)", + ), + ( + // TODO: This works correctly for line segments, but not curved segments. + // TODO: Therefore, we should make this use the tangent in relation to the incoming curve, not the straight line between the incoming curve's start point and the path. + "Tangent to Paths", + (|snapping_state: &mut SnappingState| &mut snapping_state.path.tangent_to_path) as GetSnapState, + // TODO: Fix the bug/limitation that requires 'Intersections of Paths' to be enabled + "Snaps a line to a point tangent to a vector path\n(due to a bug, 'Intersections of Paths' must be enabled)", + ), +]; + +#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)] +pub enum BoundingBoxSnapTarget { + CornerPoint, + CenterPoint, + EdgeMidpoint, +} + +impl fmt::Display for BoundingBoxSnapTarget { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + BoundingBoxSnapTarget::CornerPoint => write!(f, "Bounding Box: Corner Point"), + BoundingBoxSnapTarget::CenterPoint => write!(f, "Bounding Box: Center Point"), + BoundingBoxSnapTarget::EdgeMidpoint => write!(f, "Bounding Box: Edge Midpoint"), + } + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)] +pub enum PathSnapTarget { + AnchorPointWithColinearHandles, + AnchorPointWithFreeHandles, + LineMidpoint, + AlongPath, + NormalToPath, + TangentToPath, + IntersectionPoint, + PerpendicularToEndpoint, +} + +impl fmt::Display for PathSnapTarget { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + PathSnapTarget::AnchorPointWithColinearHandles | PathSnapTarget::AnchorPointWithFreeHandles => write!(f, "Path: Anchor Point"), + PathSnapTarget::LineMidpoint => write!(f, "Path: Line Midpoint"), + PathSnapTarget::AlongPath => write!(f, "Path: Along Path"), + PathSnapTarget::NormalToPath => write!(f, "Path: Normal to Path"), + PathSnapTarget::TangentToPath => write!(f, "Path: Tangent to Path"), + PathSnapTarget::IntersectionPoint => write!(f, "Path: Intersection Point"), + PathSnapTarget::PerpendicularToEndpoint => write!(f, "Path: Perp. to Endpoint"), + } + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum ArtboardSnapTarget { + CornerPoint, + CenterPoint, + AlongEdge, +} + +impl fmt::Display for ArtboardSnapTarget { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + ArtboardSnapTarget::CornerPoint => write!(f, "Artboard: Corner Point"), + ArtboardSnapTarget::CenterPoint => write!(f, "Artboard: Center Point"), + ArtboardSnapTarget::AlongEdge => write!(f, "Artboard: Along Edge"), + } + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum GridSnapTarget { + Line, + LineNormal, + Intersection, +} + +impl fmt::Display for GridSnapTarget { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + GridSnapTarget::Line => write!(f, "Grid: Along Line"), + GridSnapTarget::LineNormal => write!(f, "Grid: Normal to Line"), + GridSnapTarget::Intersection => write!(f, "Grid: Intersection Point"), + } + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum AlignmentSnapTarget { + BoundingBoxCornerPoint, + BoundingBoxCenterPoint, + ArtboardCornerPoint, + ArtboardCenterPoint, + AlignWithAnchorPoint, + IntersectionPoint, + PerpendicularToEndpoint, +} + +impl fmt::Display for AlignmentSnapTarget { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + AlignmentSnapTarget::BoundingBoxCornerPoint => write!(f, "{}", BoundingBoxSnapTarget::CornerPoint), + AlignmentSnapTarget::BoundingBoxCenterPoint => write!(f, "{}", BoundingBoxSnapTarget::CenterPoint), + AlignmentSnapTarget::ArtboardCornerPoint => write!(f, "{}", ArtboardSnapTarget::CornerPoint), + AlignmentSnapTarget::ArtboardCenterPoint => write!(f, "{}", ArtboardSnapTarget::CenterPoint), + AlignmentSnapTarget::AlignWithAnchorPoint => write!(f, "{}", PathSnapTarget::AnchorPointWithColinearHandles), + AlignmentSnapTarget::IntersectionPoint => write!(f, "{}", PathSnapTarget::IntersectionPoint), + AlignmentSnapTarget::PerpendicularToEndpoint => write!(f, "{}", PathSnapTarget::PerpendicularToEndpoint), + } + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum DistributionSnapTarget { + X, + Y, + Right, + Left, + Up, + Down, + XY, +} + +impl fmt::Display for DistributionSnapTarget { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + DistributionSnapTarget::X => write!(f, "Distribute: X"), + DistributionSnapTarget::Y => write!(f, "Distribute: Y"), + DistributionSnapTarget::Right => write!(f, "Distribute: Right"), + DistributionSnapTarget::Left => write!(f, "Distribute: Left"), + DistributionSnapTarget::Up => write!(f, "Distribute: Up"), + DistributionSnapTarget::Down => write!(f, "Distribute: Down"), + DistributionSnapTarget::XY => write!(f, "Distribute: XY"), + } + } +} + +impl DistributionSnapTarget { + pub const fn is_x(&self) -> bool { + matches!(self, Self::Left | Self::Right | Self::X) + } + pub const fn is_y(&self) -> bool { + matches!(self, Self::Up | Self::Down | Self::Y) + } +} + +#[derive(Default, Debug, Clone, Copy, PartialEq, Eq)] +pub enum SnapTarget { + #[default] + None, + BoundingBox(BoundingBoxSnapTarget), + Path(PathSnapTarget), + Artboard(ArtboardSnapTarget), + Grid(GridSnapTarget), + Alignment(AlignmentSnapTarget), + DistributeEvenly(DistributionSnapTarget), +} + +impl SnapTarget { + pub fn is_some(&self) -> bool { + self != &Self::None + } + pub fn bounding_box(&self) -> bool { + matches!(self, Self::BoundingBox(_) | Self::Artboard(_)) + } +} + +impl fmt::Display for SnapTarget { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + SnapTarget::None => write!(f, "None"), + SnapTarget::BoundingBox(bounding_box_snap_target) => write!(f, "{bounding_box_snap_target}"), + SnapTarget::Path(path_snap_target) => write!(f, "{path_snap_target}"), + SnapTarget::Artboard(artboard_snap_target) => write!(f, "{artboard_snap_target}"), + SnapTarget::Grid(grid_snap_target) => write!(f, "{grid_snap_target}"), + SnapTarget::Alignment(alignment_snap_target) => write!(f, "{alignment_snap_target}"), + SnapTarget::DistributeEvenly(distribution_snap_target) => write!(f, "{distribution_snap_target}"), + } + } +} + +// TODO: implement icons for SnappingOptions eventually +pub enum SnappingOptions { + BoundingBoxes, + Paths, +} + +impl fmt::Display for SnappingOptions { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + SnappingOptions::BoundingBoxes => write!(f, "Bounding Boxes"), + SnappingOptions::Paths => write!(f, "Paths"), + } + } +} + +#[derive(Clone, Copy, Debug, PartialEq, serde::Serialize, serde::Deserialize)] +#[serde(default)] +pub struct PTZ { + /// Offset distance. + pub pan: DVec2, + /// Angle in radians. + tilt: f64, + /// Scale factor. + zoom: f64, + /// Flipped status. + pub flip: bool, +} + +impl Default for PTZ { + fn default() -> Self { + Self { + pan: DVec2::ZERO, + tilt: 0., + zoom: 1., + flip: false, + } + } +} + +impl PTZ { + /// Get the tilt angle between -180° and 180° in radians. + pub fn tilt(&self) -> f64 { + (((self.tilt + std::f64::consts::PI) % std::f64::consts::TAU) + std::f64::consts::TAU) % std::f64::consts::TAU - std::f64::consts::PI + } + + pub fn unmodified_tilt(&self) -> f64 { + self.tilt + } + + /// Set a new tilt angle in radians. + pub fn set_tilt(&mut self, tilt: f64) { + self.tilt = tilt; + } + + /// Get the scale factor. + pub fn zoom(&self) -> f64 { + self.zoom + } + + /// Set a new scale factor. + pub fn set_zoom(&mut self, zoom: f64) { + self.zoom = zoom.clamp(crate::consts::VIEWPORT_ZOOM_SCALE_MIN, crate::consts::VIEWPORT_ZOOM_SCALE_MAX) + } +} + +#[derive(Clone, Copy, Debug, PartialEq, serde::Serialize, serde::Deserialize)] +pub enum GroupFolderType { + Layer, + BooleanOperation(graphene_std::path_bool::BooleanOperation), +} diff --git a/editor/src/messages/portfolio/document/utility_types/mod.rs b/editor/src/messages/portfolio/document/utility_types/mod.rs new file mode 100644 index 0000000000000000000000000000000000000000..8bed0dbb85a588b1a964107fa23f247611eed00d --- /dev/null +++ b/editor/src/messages/portfolio/document/utility_types/mod.rs @@ -0,0 +1,8 @@ +pub mod clipboards; +pub mod document_metadata; +pub mod error; +pub mod misc; +pub mod network_interface; +pub mod nodes; +pub mod transformation; +pub mod wires; diff --git a/editor/src/messages/portfolio/document/utility_types/network_interface.rs b/editor/src/messages/portfolio/document/utility_types/network_interface.rs new file mode 100644 index 0000000000000000000000000000000000000000..65e58693f61eb05506f67582f914c3abcffa5d7f --- /dev/null +++ b/editor/src/messages/portfolio/document/utility_types/network_interface.rs @@ -0,0 +1,6941 @@ +use super::document_metadata::{DocumentMetadata, LayerNodeIdentifier, NodeRelations}; +use super::misc::PTZ; +use super::nodes::SelectedNodes; +use crate::consts::{EXPORTS_TO_RIGHT_EDGE_PIXEL_GAP, EXPORTS_TO_TOP_EDGE_PIXEL_GAP, GRID_SIZE, IMPORTS_TO_LEFT_EDGE_PIXEL_GAP, IMPORTS_TO_TOP_EDGE_PIXEL_GAP}; +use crate::messages::portfolio::document::graph_operation::utility_types::ModifyInputsContext; +use crate::messages::portfolio::document::node_graph::document_node_definitions::{DocumentNodeDefinition, resolve_document_node_type}; +use crate::messages::portfolio::document::node_graph::utility_types::{Direction, FrontendClickTargets, FrontendGraphDataType, FrontendGraphInput, FrontendGraphOutput}; +use crate::messages::portfolio::document::utility_types::wires::{GraphWireStyle, WirePath, WirePathUpdate, build_vector_wire}; +use crate::messages::tool::common_functionality::graph_modification_utils; +use crate::messages::tool::tool_messages::tool_prelude::NumberInputMode; +use bezier_rs::Subpath; +use glam::{DAffine2, DVec2, IVec2}; +use graph_craft::document::value::TaggedValue; +use graph_craft::document::{DocumentNode, DocumentNodeImplementation, NodeId, NodeInput, NodeNetwork, OldDocumentNodeImplementation, OldNodeNetwork}; +use graph_craft::{Type, concrete}; +use graphene_std::math::quad::Quad; +use graphene_std::transform::Footprint; +use graphene_std::vector::click_target::{ClickTarget, ClickTargetType}; +use graphene_std::vector::{PointId, VectorData, VectorModificationType}; +use interpreted_executor::dynamic_executor::ResolvedDocumentNodeTypes; +use interpreted_executor::node_registry::NODE_REGISTRY; +use serde_json::{Value, json}; +use std::collections::{HashMap, HashSet, VecDeque}; +use std::hash::{DefaultHasher, Hash, Hasher}; + +/// All network modifications should be done through this API, so the fields cannot be public. However, all fields within this struct can be public since it it not possible to have a public mutable reference. +#[derive(Debug, Default, serde::Serialize, serde::Deserialize)] +pub struct NodeNetworkInterface { + /// The node graph that generates this document's artwork. It recursively stores its sub-graphs, so this root graph is the whole snapshot of the document content. + /// A public mutable reference should never be created. It should only be mutated through custom setters which perform the necessary side effects to keep network_metadata in sync + network: NodeNetwork, + /// Stores all editor information for a NodeNetwork. Should automatically kept in sync by the setter methods when changes to the document network are made. + network_metadata: NodeNetworkMetadata, + // TODO: Wrap in TransientMetadata Option + /// Stores the document network's structural topology. Should automatically kept in sync by the setter methods when changes to the document network are made. + #[serde(skip)] + document_metadata: DocumentMetadata, + /// All input/output types based on the compiled network. + #[serde(skip)] + pub resolved_types: ResolvedDocumentNodeTypes, + #[serde(skip)] + transaction_status: TransactionStatus, +} + +impl Clone for NodeNetworkInterface { + fn clone(&self) -> Self { + Self { + network: self.network.clone(), + network_metadata: self.network_metadata.clone(), + document_metadata: Default::default(), + resolved_types: Default::default(), + transaction_status: TransactionStatus::Finished, + } + } +} + +impl PartialEq for NodeNetworkInterface { + fn eq(&self, other: &Self) -> bool { + self.network == other.network && self.network_metadata == other.network_metadata + } +} + +// Public immutable getters for the network interface +impl NodeNetworkInterface { + // TODO: Make private and use .field_name getter methods + /// Gets the network of the root document + pub fn document_network(&self) -> &NodeNetwork { + self.network + .nested_network(&[]) + .expect("Could not get root document network in NodeNetworkInterface::document_network()") + } + + // TODO: Make private and use .field_name getter methods + /// Gets the nested network based on network_path + pub fn nested_network(&self, network_path: &[NodeId]) -> Option<&NodeNetwork> { + let Some(network) = self.network.nested_network(network_path) else { + log::error!("Could not get nested network with path {network_path:?} in NodeNetworkInterface::network"); + return None; + }; + Some(network) + } + + /// Get the specified document node in the nested network based on node_id and network_path + pub fn document_node(&self, node_id: &NodeId, network_path: &[NodeId]) -> Option<&DocumentNode> { + let network = self.nested_network(network_path)?; + let Some(node_metadata) = network.nodes.get(node_id) else { + log::error!("Could not get document node with id {node_id} in network {network_path:?}"); + return None; + }; + Some(node_metadata) + } + + pub fn document_network_metadata(&self) -> &NodeNetworkMetadata { + &self.network_metadata + } + + // TODO: Make private and use .field_name getter methods + /// The network metadata should always exist for the current network + pub fn network_metadata(&self, network_path: &[NodeId]) -> Option<&NodeNetworkMetadata> { + let Some(network_metadata) = self.network_metadata.nested_metadata(network_path) else { + log::error!("Could not get nested network_metadata with path {network_path:?}"); + return None; + }; + Some(network_metadata) + } + + // TODO: Make private and use .field_name getter methods + pub fn node_metadata(&self, node_id: &NodeId, network_path: &[NodeId]) -> Option<&DocumentNodeMetadata> { + let network_metadata = self.network_metadata(network_path)?; + let Some(node_metadata) = network_metadata.persistent_metadata.node_metadata.get(node_id) else { + log::error!("Could not get node metadata for node {node_id} in network {network_path:?}"); + return None; + }; + Some(node_metadata) + } + + pub fn document_metadata(&self) -> &DocumentMetadata { + &self.document_metadata + } + + pub fn transaction_status(&self) -> TransactionStatus { + self.transaction_status + } + + pub fn selected_nodes(&self) -> SelectedNodes { + self.selected_nodes_in_nested_network(&[]).unwrap_or_default() + } + + /// Get the selected nodes for the network at the network_path + pub fn selected_nodes_in_nested_network(&self, network_path: &[NodeId]) -> Option { + let Some(network_metadata) = self.network_metadata(network_path) else { + log::error!("Could not get nested network_metadata in selected_nodes"); + return None; + }; + + Some( + network_metadata + .persistent_metadata + .selection_undo_history + .back() + .cloned() + .unwrap_or_default() + .filtered_selected_nodes(network_metadata.persistent_metadata.node_metadata.keys().cloned().collect()), + ) + } + + /// Get the network which the encapsulating node of the currently viewed network is part of. Will always be None in the document network. + pub fn encapsulating_network_metadata(&self, network_path: &[NodeId]) -> Option<&NodeNetworkMetadata> { + let mut encapsulating_path = network_path.to_vec(); + encapsulating_path.pop()?; + let Some(parent_metadata) = self.network_metadata(&encapsulating_path) else { + log::error!("Could not get parent network in encapsulating_node_metadata"); + return None; + }; + Some(parent_metadata) + } + + /// Get the node which encapsulates the currently viewed network. Will always be None in the document network. + pub fn encapsulating_node(&self, network_path: &[NodeId]) -> Option<&DocumentNode> { + let mut encapsulating_path = network_path.to_vec(); + let encapsulating_node_id = encapsulating_path.pop()?; + let Some(encapsulating_node) = self.document_node(&encapsulating_node_id, &encapsulating_path) else { + log::error!("Could not get encapsulating node in encapsulating_node"); + return None; + }; + Some(encapsulating_node) + } + + /// Get the node metadata for the node which encapsulates the currently viewed network. Will always be None in the document network. + pub fn encapsulating_node_metadata(&self, network_path: &[NodeId]) -> Option<&DocumentNodeMetadata> { + let mut encapsulating_path = network_path.to_vec(); + let encapsulating_node_id = encapsulating_path.pop()?; + let Some(parent_metadata) = self.network_metadata(&encapsulating_path) else { + log::error!("Could not get parent network in encapsulating_node_metadata"); + return None; + }; + let Some(encapsulating_node_metadata) = parent_metadata.persistent_metadata.node_metadata.get(&encapsulating_node_id) else { + log::error!("Could not get encapsulating node metadata in encapsulating_node_metadata"); + return None; + }; + Some(encapsulating_node_metadata) + } + + /// Returns the first downstream layer(inclusive) from a node. If the node is a layer, it will return itself. + pub fn downstream_layer(&mut self, node_id: &NodeId, network_path: &[NodeId]) -> Option { + let mut id = *node_id; + while !self.is_layer(&id, network_path) { + id = self.outward_wires(network_path)?.get(&OutputConnector::node(id, 0))?.first()?.node_id()?; + } + Some(LayerNodeIdentifier::new(id, self, network_path)) + } + + /// Returns all downstream layers (inclusive) from a node. If the node is a layer, it will return itself. + pub fn downstream_layers(&mut self, node_id: &NodeId, network_path: &[NodeId]) -> Vec { + let mut stack = vec![*node_id]; + let mut layers = Vec::new(); + while let Some(current_node) = stack.pop() { + if self.is_layer(¤t_node, network_path) { + layers.push(current_node); + } else { + let Some(outward_wires) = self.outward_wires(network_path).and_then(|outward_wires| outward_wires.get(&OutputConnector::node(current_node, 0))) else { + log::error!("Could not get outward wires in downstream_layer"); + return Vec::new(); + }; + stack.extend(outward_wires.iter().filter_map(|input_connector| input_connector.node_id())); + } + } + layers + } + + pub fn chain_width(&self, node_id: &NodeId, network_path: &[NodeId]) -> u32 { + if self.number_of_displayed_inputs(node_id, network_path) > 1 { + let mut last_chain_node_distance = 0u32; + // Iterate upstream from the layer, and get the number of nodes distance to the last node with Position::Chain + for (index, node_id) in self + .upstream_flow_back_from_nodes(vec![*node_id], network_path, FlowType::HorizontalPrimaryOutputFlow) + .skip(1) + .enumerate() + .collect::>() + { + // Check if the node is positioned as a chain + if self.is_chain(&node_id, network_path) { + last_chain_node_distance = (index as u32) + 1; + } else { + return last_chain_node_distance * 7 + 1; + } + } + + last_chain_node_distance * 7 + 1 + } else { + // Layer with no inputs has no chain + 0 + } + } + + /// Check if the specified node id is connected to the output + pub fn connected_to_output(&self, target_node_id: &NodeId, network_path: &[NodeId]) -> bool { + let Some(network) = self.nested_network(network_path) else { + log::error!("Could not get network in connected_to_output"); + return false; + }; + // If the node is the output then return true + if network + .exports + .iter() + .any(|export| if let NodeInput::Node { node_id, .. } = export { node_id == target_node_id } else { false }) + { + return true; + } + + // Get the outputs + let mut stack = network + .exports + .iter() + .filter_map(|output| if let NodeInput::Node { node_id, .. } = output { network.nodes.get(node_id) } else { None }) + .collect::>(); + let mut already_visited = HashSet::new(); + already_visited.extend( + network + .exports + .iter() + .filter_map(|output| if let NodeInput::Node { node_id, .. } = output { Some(node_id) } else { None }), + ); + + while let Some(node) = stack.pop() { + for input in &node.inputs { + if let &NodeInput::Node { node_id: ref_id, .. } = input { + // Skip if already viewed + if already_visited.contains(&ref_id) { + continue; + } + // If the target node is used as input then return true + if ref_id == *target_node_id { + return true; + } + // Add the referenced node to the stack + let Some(ref_node) = network.nodes.get(&ref_id) else { + continue; + }; + already_visited.insert(ref_id); + stack.push(ref_node); + } + } + } + + false + } + + fn number_of_imports(&self, network_path: &[NodeId]) -> usize { + // TODO: Use network.import_types.len() + if let Some(encapsulating_node) = self.encapsulating_node(network_path) { + encapsulating_node.inputs.len() + } else { + // There is one(?) import to the document network, but the imports are not displayed + // I think this is zero now that the scope system has been added + 1 + } + } + + fn number_of_displayed_imports(&self, network_path: &[NodeId]) -> usize { + // TODO: Use network.import_types.len() + if let Some(encapsulating_node) = self.encapsulating_node(network_path) { + encapsulating_node.inputs.len() + } else { + // There is one(?) import to the document network, but the imports are not displayed + 0 + } + } + + fn number_of_displayed_inputs(&self, node_id: &NodeId, network_path: &[NodeId]) -> usize { + let Some(node) = self.document_node(node_id, network_path) else { + log::error!("Could not get node {node_id} in number_of_displayed_inputs"); + return 0; + }; + node.inputs.iter().filter(|input| input.is_exposed()).count() + } + + pub fn number_of_inputs(&self, node_id: &NodeId, network_path: &[NodeId]) -> usize { + let Some(node) = self.document_node(node_id, network_path) else { + log::error!("Could not get node {node_id} in number_of_inputs"); + return 0; + }; + node.inputs.len() + } + + pub fn number_of_outputs(&self, node_id: &NodeId, network_path: &[NodeId]) -> usize { + let Some(implementation) = self.implementation(node_id, network_path) else { + log::error!("Could not get node {node_id} in number_of_outputs"); + return 0; + }; + match &implementation { + DocumentNodeImplementation::ProtoNode(_) => 1, + DocumentNodeImplementation::Network(nested_network) => nested_network.exports.len(), + DocumentNodeImplementation::Extract => 1, + } + } + + /// Creates a copy for each node by disconnecting nodes which are not connected to other copied nodes. + /// Returns an iterator of all persistent metadata for a node and their ids + pub fn copy_nodes<'a>(&'a mut self, new_ids: &'a HashMap, network_path: &'a [NodeId]) -> impl Iterator + 'a { + let mut new_nodes = new_ids + .iter() + .filter_map(|(node_id, &new)| { + self.create_node_template(node_id, network_path).and_then(|mut node_template| { + let Some(outward_wires) = self.outward_wires(network_path) else { + log::error!("Could not get outward wires in copy_nodes"); + return None; + }; + // TODO: Get downstream connections from all outputs + let Some(downstream_connections) = outward_wires.get(&OutputConnector::node(*node_id, 0)) else { + log::error!("Could not get outward wires in copy_nodes"); + return None; + }; + let has_selected_node_downstream = downstream_connections + .iter() + .any(|input_connector| input_connector.node_id().is_some_and(|upstream_id| new_ids.keys().any(|key| *key == upstream_id))); + // If the copied node does not have a downstream connection to another copied node, then set the position to absolute + if !has_selected_node_downstream { + let Some(position) = self.position(node_id, network_path) else { + log::error!("Could not get position in create_node_template"); + return None; + }; + match &mut node_template.persistent_node_metadata.node_type_metadata { + NodeTypePersistentMetadata::Layer(layer_metadata) => layer_metadata.position = LayerPosition::Absolute(position), + NodeTypePersistentMetadata::Node(node_metadata) => node_metadata.position = NodePosition::Absolute(position), + }; + } + + // If a chain node does not have a selected downstream layer, then set the position to absolute + let downstream_layer = self.downstream_layer(node_id, network_path); + if downstream_layer.is_none_or(|downstream_layer| new_ids.keys().all(|key| *key != downstream_layer.to_node())) { + let Some(position) = self.position(node_id, network_path) else { + log::error!("Could not get position in create_node_template"); + return None; + }; + node_template.persistent_node_metadata.node_type_metadata = NodeTypePersistentMetadata::Node(NodePersistentMetadata { + position: NodePosition::Absolute(position), + }); + } + + // Shift all absolute nodes 2 to the right and 2 down + // TODO: Remove 2x2 offset and replace with layout system to find space for new node + match &mut node_template.persistent_node_metadata.node_type_metadata { + NodeTypePersistentMetadata::Layer(layer_metadata) => { + if let LayerPosition::Absolute(position) = &mut layer_metadata.position { + *position += IVec2::new(2, 2) + } + } + NodeTypePersistentMetadata::Node(node_metadata) => { + if let NodePosition::Absolute(position) = &mut node_metadata.position { + *position += IVec2::new(2, 2) + } + } + } + + Some((new, *node_id, node_template)) + }) + }) + .collect::>(); + + for old_id in new_nodes.iter().map(|(_, old_id, _)| *old_id).collect::>() { + // Try set all selected nodes upstream of a layer to be chain nodes + if self.is_layer(&old_id, network_path) { + for valid_upstream_chain_node in self.valid_upstream_chain_nodes(&InputConnector::node(old_id, 1), network_path) { + if let Some(node_template) = new_nodes.iter_mut().find_map(|(_, old_id, template)| (*old_id == valid_upstream_chain_node).then_some(template)) { + match &mut node_template.persistent_node_metadata.node_type_metadata { + NodeTypePersistentMetadata::Node(node_metadata) => node_metadata.position = NodePosition::Chain, + NodeTypePersistentMetadata::Layer(_) => log::error!("Node cannot be a layer"), + }; + } + } + } + } + new_nodes.into_iter().map(move |(new, node_id, node)| (new, self.map_ids(node, &node_id, new_ids, network_path))) + } + + /// Create a node template from an existing node. + pub fn create_node_template(&self, node_id: &NodeId, network_path: &[NodeId]) -> Option { + let Some(node) = self.document_node(node_id, network_path) else { + log::error!("Could not get node {node_id} in create_node_template"); + return None; + }; + let Some(node_metadata) = self.node_metadata(node_id, network_path).cloned() else { + log::error!("Could not get node_metadata in create_node_template"); + return None; + }; + + Some(NodeTemplate { + persistent_node_metadata: node_metadata.persistent_metadata, + document_node: node.clone(), + }) + } + + /// Converts all node id inputs to a new id based on a HashMap. + /// + /// If the node is not in the hashmap then a default input is found based on the compiled network, using the node_id passed as a parameter + pub fn map_ids(&mut self, mut node_template: NodeTemplate, node_id: &NodeId, new_ids: &HashMap, network_path: &[NodeId]) -> NodeTemplate { + for (input_index, input) in node_template.document_node.inputs.iter_mut().enumerate() { + if let &mut NodeInput::Node { node_id: id, output_index, lambda } = input { + if let Some(&new_id) = new_ids.get(&id) { + *input = NodeInput::Node { + node_id: new_id, + output_index, + lambda, + }; + } else { + // Disconnect node input if it is not connected to another node in new_ids + let tagged_value = TaggedValue::from_type_or_none(&self.input_type(&InputConnector::node(*node_id, input_index), network_path).0); + *input = NodeInput::value(tagged_value, true); + } + } else if let &mut NodeInput::Network { .. } = input { + // Always disconnect network node input + let tagged_value = TaggedValue::from_type_or_none(&self.input_type(&InputConnector::node(*node_id, input_index), network_path).0); + *input = NodeInput::value(tagged_value, true); + } + } + node_template + } + + /// Try and get the [`DocumentNodeDefinition`] for a node + pub fn get_node_definition(&self, network_path: &[NodeId], node_id: NodeId) -> Option<&DocumentNodeDefinition> { + let metadata = self.node_metadata(&node_id, network_path)?; + resolve_document_node_type(metadata.persistent_metadata.reference.as_ref()?) + } + + pub fn input_from_connector(&self, input_connector: &InputConnector, network_path: &[NodeId]) -> Option<&NodeInput> { + let Some(network) = self.nested_network(network_path) else { + log::error!("Could not get network in input_from_connector"); + return None; + }; + match input_connector { + InputConnector::Node { node_id, input_index } => { + let Some(node) = network.nodes.get(node_id) else { + log::error!("Could not get node {node_id} in input_from_connector"); + return None; + }; + node.inputs.get(*input_index) + } + InputConnector::Export(export_index) => network.exports.get(*export_index), + } + } + + /// Try and get the [`Type`] for any [`InputConnector`] based on the `self.resolved_types`. + fn node_type_from_compiled(&mut self, input_connector: &InputConnector, network_path: &[NodeId]) -> Option<(Type, TypeSource)> { + let (node_id, input_index) = match *input_connector { + InputConnector::Node { node_id, input_index } => (node_id, input_index), + InputConnector::Export(export_index) => { + let Some((encapsulating_node_id, encapsulating_node_id_path)) = network_path.split_last() else { + // The outermost network export defaults to an ArtboardGroupTable. + return Some((concrete!(graphene_std::ArtboardGroupTable), TypeSource::OuterMostExportDefault)); + }; + + let output_type = self.output_type(encapsulating_node_id, export_index, encapsulating_node_id_path); + return Some(output_type); + } + }; + let Some(node) = self.document_node(&node_id, network_path) else { + log::error!("Could not get node {node_id} in input_type"); + return None; + }; + // If the input_connector is a NodeInput::Value, return the type of the tagged value. + if let Some(value) = node.inputs.get(input_index).and_then(|input| input.as_value()) { + return Some((value.ty(), TypeSource::TaggedValue)); + } + let node_id_path = [network_path, &[node_id]].concat(); + match &node.implementation { + DocumentNodeImplementation::Network(_nested_network) => { + // Attempt to resolve where this import is within the nested network (it may be connected to the node or directly to an export) + let outwards_wires = self.outward_wires(&node_id_path); + let inputs_using_import = outwards_wires.and_then(|outwards_wires| outwards_wires.get(&OutputConnector::Import(input_index))); + let first_input = inputs_using_import.and_then(|input| input.first()).copied(); + + if inputs_using_import.is_some_and(|inputs| inputs.len() > 1) { + warn!("Found multiple inputs using an import. Using the type of the first one."); + } + + if let Some(input_connector) = first_input { + self.node_type_from_compiled(&input_connector, &node_id_path) + } + // Nothing is connected to the import + else { + None + } + } + DocumentNodeImplementation::ProtoNode(_) => { + // If a node has manual composition, then offset the input index by 1 since the proto node also includes the type of the input passed through manual composition. + let manual_composition_offset = if node.manual_composition.is_some() { 1 } else { 0 }; + self.resolved_types + .types + .get(node_id_path.as_slice()) + .and_then(|node_types| node_types.inputs.get(input_index + manual_composition_offset).cloned()) + .map(|node_types| (node_types, TypeSource::Compiled)) + } + DocumentNodeImplementation::Extract => None, + } + } + + /// Guess the type from the node based on a document node default or a random protonode definition. + fn guess_type_from_node(&mut self, network_path: &mut Vec, node_id: NodeId, input_index: usize) -> (Type, TypeSource) { + // Try and get the default value from the document node definition + if let Some(value) = self + .get_node_definition(network_path, node_id) + .and_then(|definition| definition.node_template.document_node.inputs.get(input_index)) + .and_then(|input| input.as_value()) + { + return (value.ty(), TypeSource::DocumentNodeDefault); + } + + let Some(node) = self.document_node(&node_id, network_path) else { + return (concrete!(()), TypeSource::Error("node id {node_id:?} not in network {network_path:?}")); + }; + + let node_id_path = [network_path.as_slice(), &[node_id]].concat(); + match &node.implementation { + DocumentNodeImplementation::ProtoNode(protonode) => { + let Some(node_types) = random_protonode_implementation(protonode) else { + return (concrete!(()), TypeSource::Error("could not resolve protonode")); + }; + + let skip_footprint = if node.manual_composition.is_some() { 1 } else { 0 }; + + let Some(input_type) = std::iter::once(node_types.call_argument.clone()).chain(node_types.inputs.clone()).nth(input_index + skip_footprint) else { + log::error!("Could not get type"); + return (concrete!(()), TypeSource::Error("could not get the protonode's input")); + }; + + (input_type, TypeSource::RandomProtonodeImplementation) + } + DocumentNodeImplementation::Network(_network) => { + // Attempt to resolve where this import is within the nested network + let outwards_wires = self.outward_wires(&node_id_path); + let inputs_using_import = outwards_wires.and_then(|outwards_wires| outwards_wires.get(&OutputConnector::Import(input_index))); + let first_input = inputs_using_import.and_then(|input| input.first()).copied(); + + if let Some(InputConnector::Node { + node_id: child_id, + input_index: child_input_index, + }) = first_input + { + network_path.push(node_id); + let result = self.guess_type_from_node(network_path, child_id, child_input_index); + network_path.pop(); + return result; + } + + // Input is disconnected + (concrete!(()), TypeSource::Error("disconnected network input")) + } + _ => (concrete!(()), TypeSource::Error("implementation is not network or protonode")), + } + } + + /// Get the [`Type`] for any InputConnector + pub fn input_type(&mut self, input_connector: &InputConnector, network_path: &[NodeId]) -> (Type, TypeSource) { + if let Some(result) = self.node_type_from_compiled(input_connector, network_path) { + return result; + } + + // Resolve types from proto nodes in node_registry + let Some(node_id) = input_connector.node_id() else { + return (concrete!(()), TypeSource::Error("input connector is not a node")); + }; + + // TODO: Once there is type inference (#1621), replace this workaround approach when disconnecting node inputs with NodeInput::Node(ToDefaultNode), + // TODO: which would be a new node that implements the Default trait (i.e. `Default::default()`) + self.guess_type_from_node(&mut network_path.to_vec(), node_id, input_connector.input_index()) + } + + pub fn valid_input_types(&mut self, input_connector: &InputConnector, network_path: &[NodeId]) -> Vec { + let InputConnector::Node { node_id, input_index } = input_connector else { + // An export can have any type connected to it + return vec![graph_craft::generic!(T)]; + }; + let Some(implementation) = self.implementation(node_id, network_path) else { + log::error!("Could not get node implementation in valid_input_types"); + return Vec::new(); + }; + match implementation { + DocumentNodeImplementation::Network(_) => { + let nested_path = [network_path, &[*node_id]].concat(); + let Some(outward_wires) = self.outward_wires(&nested_path) else { + log::error!("Could not get outward wires in valid_input_types"); + return Vec::new(); + }; + let Some(inputs_from_import) = outward_wires.get(&OutputConnector::Import(*input_index)) else { + log::error!("Could not get inputs from import in valid_input_types"); + return Vec::new(); + }; + + let intersection: HashSet = inputs_from_import + .clone() + .iter() + .map(|input_connector| self.valid_input_types(input_connector, &nested_path)) + .map(|vec| vec.into_iter().collect::>()) + .fold(None, |acc: Option>, set| match acc { + Some(acc_set) => Some(acc_set.intersection(&set).cloned().collect()), + None => Some(set), + }) + .unwrap_or_default(); + + intersection.into_iter().collect::>() + } + DocumentNodeImplementation::ProtoNode(proto_node_identifier) => { + let Some(implementations) = NODE_REGISTRY.get(proto_node_identifier) else { + log::error!("Protonode {proto_node_identifier:?} not found in registry"); + return Vec::new(); + }; + let number_of_inputs = self.number_of_inputs(node_id, network_path); + implementations + .iter() + .filter_map(|(node_io, _)| { + let valid_implementation = (0..number_of_inputs).filter(|iterator_index| iterator_index != input_index).all(|iterator_index| { + let input_type = self.input_type(&InputConnector::node(*node_id, iterator_index), network_path).0; + // Value inputs are stored as concrete, so they are compared to the nested type. Node inputs are stored as fn, so they are compared to the entire type. + // For example a node input of (Footprint) -> VectorData would not be compatible with () -> VectorData + node_io.inputs[iterator_index].clone().nested_type() == &input_type || node_io.inputs[iterator_index] == input_type + }); + if valid_implementation { node_io.inputs.get(*input_index).cloned() } else { None } + }) + .collect::>() + } + DocumentNodeImplementation::Extract => { + log::error!("Input types for extract node not supported"); + Vec::new() + } + } + } + + /// Retrieves the output types for a given document node and its exports. + /// + /// This function traverses the node and its nested network structure (if applicable) to determine + /// the types of all outputs, including the primary output and any additional exports. + /// + /// # Arguments + /// + /// * `node` - A reference to the `DocumentNode` for which to determine output types. + /// * `resolved_types` - A reference to `ResolvedDocumentNodeTypes` containing pre-resolved type information. + /// * `node_id_path` - A slice of `NodeId`s representing the path to the current node in the document graph. + /// + /// # Returns + /// + /// A `Vec>` where: + /// - The first element is the primary output type of the node. + /// - Subsequent elements are types of additional exports (if the node is a network). + /// - `None` values indicate that a type couldn't be resolved for a particular output. + /// + /// # Behavior + /// + /// 1. Retrieves the primary output type from `resolved_types`. + /// 2. If the node is a network: + /// - Iterates through its exports (skipping the first/primary export). + /// - For each export, traverses the network until reaching a protonode or terminal condition. + /// - Determines the output type based on the final node/value encountered. + /// 3. Collects and returns all resolved types. + /// + /// # Note + /// + /// This function assumes that export indices and node IDs always exist within their respective + /// collections. It will panic if these assumptions are violated. + /// + pub fn output_type(&self, node_id: &NodeId, output_index: usize, network_path: &[NodeId]) -> (Type, TypeSource) { + let Some(implementation) = self.implementation(node_id, network_path) else { + log::error!("Could not get output type for node {node_id} output index {output_index}. This node is no longer supported, and needs to be upgraded."); + return (concrete!(()), TypeSource::Error("Could not get implementation")); + }; + + // If the node is not a protonode, get types by traversing across exports until a proto node is reached. + match &implementation { + graph_craft::document::DocumentNodeImplementation::Network(internal_network) => { + let Some(export) = internal_network.exports.get(output_index) else { + return (concrete!(()), TypeSource::Error("Could not get export index")); + }; + match export { + NodeInput::Node { + node_id: nested_node_id, + output_index, + .. + } => self.output_type(nested_node_id, *output_index, &[network_path, &[*node_id]].concat()), + NodeInput::Value { tagged_value, .. } => (tagged_value.ty(), TypeSource::TaggedValue), + NodeInput::Network { .. } => { + // let mut encapsulating_path = network_path.to_vec(); + // let encapsulating_node = encapsulating_path.pop().expect("No imports exist in document network"); + // self.input_type(&InputConnector::node(encapsulating_node, *import_index), network_path) + (concrete!(()), TypeSource::Error("Could not type from network")) + } + NodeInput::Scope(_) => todo!(), + NodeInput::Inline(_) => todo!(), + NodeInput::Reflection(_) => todo!(), + } + } + graph_craft::document::DocumentNodeImplementation::ProtoNode(protonode) => { + let node_id_path = &[network_path, &[*node_id]].concat(); + self.resolved_types + .types + .get(node_id_path) + .map(|ty| (ty.output.clone(), TypeSource::Compiled)) + .or_else(|| { + let node_types = random_protonode_implementation(protonode)?; + Some((node_types.return_value.clone(), TypeSource::RandomProtonodeImplementation)) + }) + .unwrap_or((concrete!(()), TypeSource::Error("Could not get protonode implementation"))) + } + graph_craft::document::DocumentNodeImplementation::Extract => (concrete!(()), TypeSource::Error("extract node")), + } + } + + pub fn position(&mut self, node_id: &NodeId, network_path: &[NodeId]) -> Option { + let top_left_position = self + .node_click_targets(node_id, network_path) + .and_then(|click_targets| click_targets.node_click_target.bounding_box()) + .map(|mut bounding_box| { + if !self.is_layer(node_id, network_path) { + bounding_box[0] -= DVec2::new(0., 12.); + } + (bounding_box[0] / 24.).as_ivec2() + }); + top_left_position.map(|position| { + if self.is_layer(node_id, network_path) { + position + IVec2::new(self.chain_width(node_id, network_path) as i32, 0) + } else { + position + } + }) + } + + pub fn frontend_imports(&mut self, network_path: &[NodeId]) -> Option> { + self.import_export_ports(network_path).cloned().map(|import_export_ports| { + import_export_ports + .output_ports + .iter() + .filter_map(|(import_index, click_target)| { + // Get import name from parent node metadata input, which must match the number of imports. + // Empty string means to use type, or "Import + index" if type can't be determined + + let mut import_metadata = None; + + if !network_path.is_empty() { + let mut encapsulating_path = network_path.to_vec(); + let encapsulating_node_id = encapsulating_path.pop().unwrap(); + + let (input_type, type_source) = self.input_type(&InputConnector::node(encapsulating_node_id, *import_index), &encapsulating_path); + let data_type = FrontendGraphDataType::displayed_type(&input_type, &type_source); + + let (name, description) = self.displayed_input_name_and_description(&encapsulating_node_id, *import_index, &encapsulating_path); + + let connected_to = self + .outward_wires(network_path) + .and_then(|outward_wires| outward_wires.get(&OutputConnector::Import(*import_index))) + .cloned() + .unwrap_or_else(|| { + log::error!("Could not get OutputConnector::Import({import_index}) in outward wires"); + Vec::new() + }); + + import_metadata = Some(( + FrontendGraphOutput { + data_type, + name, + description, + resolved_type: format!("{:?}", input_type), + connected_to, + }, + click_target, + )); + } + import_metadata + }) + .filter_map(|(import_index, output_port)| output_port.bounding_box().map(|bounding_box| (import_index, bounding_box[0].x as i32, bounding_box[0].y as i32))) + .collect::>() + }) + } + + pub fn frontend_exports(&mut self, network_path: &[NodeId]) -> Option> { + self.import_export_ports(network_path).cloned().map(|import_export_ports| { + import_export_ports + .input_ports + .iter() + .map(|(export_index, click_target)| { + let export_type = self.input_type(&InputConnector::Export(*export_index), network_path); + let data_type = FrontendGraphDataType::displayed_type(&export_type.0, &TypeSource::TaggedValue); + + let connected_to = self.upstream_output_connector(&InputConnector::Export(*export_index), network_path); + + // Get export name from parent node metadata input, which must match the number of exports. + // Empty string means to use type, or "Export + index" if type is empty determined + let export_name = if network_path.is_empty() { + "Canvas".to_string() + } else { + self.encapsulating_node_metadata(network_path) + .and_then(|encapsulating_metadata| encapsulating_metadata.persistent_metadata.output_names.get(*export_index).cloned()) + .unwrap_or_default() + }; + + let export_name = if !export_name.is_empty() { + export_name + } else if *export_type.0.nested_type() != concrete!(()) { + export_type.0.nested_type().to_string() + } else { + format!("Export {}", *export_index + 1) + }; + + ( + FrontendGraphInput { + data_type, + name: export_name, + description: String::new(), + resolved_type: format!("{:?}", export_type.0), + valid_types: self.valid_input_types(&InputConnector::Export(*export_index), network_path).iter().map(|ty| ty.to_string()).collect(), + connected_to, + }, + click_target, + ) + }) + .filter_map(|(export_metadata, output_port)| output_port.bounding_box().map(|bounding_box| (export_metadata, bounding_box[0].x as i32, bounding_box[0].y as i32))) + .collect::>() + }) + } + + pub fn frontend_import_export_modify(&mut self, get_ports: F, network_path: &[NodeId]) -> Vec<(i32, i32)> + where + F: FnOnce(&ModifyImportExportClickTarget) -> Vec<&(usize, ClickTarget)>, + { + self.modify_import_export(network_path) + .map(|modify_import_export_click_target| { + get_ports(modify_import_export_click_target) + .iter() + .filter_map(|(_, click_target)| click_target.bounding_box().map(|bounding_box| (bounding_box[0].x as i32, bounding_box[0].y as i32))) + .collect() + }) + .unwrap_or_default() + } + + pub fn height_from_click_target(&mut self, node_id: &NodeId, network_path: &[NodeId]) -> Option { + let mut node_height: Option = self + .node_click_targets(node_id, network_path) + .and_then(|click_targets: &DocumentNodeClickTargets| click_targets.node_click_target.bounding_box()) + .map(|bounding_box| ((bounding_box[1].y - bounding_box[0].y) / 24.) as u32); + if !self.is_layer(node_id, network_path) { + node_height = node_height.map(|height| height + 1); + } + node_height + } + + // All chain nodes and branches from the chain which are sole dependents of the layer + pub fn upstream_nodes_below_layer(&mut self, node_id: &NodeId, network_path: &[NodeId]) -> HashSet { + // Every upstream node below layer must be a sole dependent + let mut upstream_nodes_below_layer = HashSet::new(); + + let mut potential_upstream_nodes = HashSet::new(); + for chain_node in self + .upstream_flow_back_from_nodes(vec![*node_id], network_path, FlowType::HorizontalFlow) + .skip(1) + .take_while(|node_id| self.is_chain(node_id, network_path)) + .collect::>() + { + upstream_nodes_below_layer.insert(chain_node); + let Some(chain_node) = self.document_node(&chain_node, network_path) else { + log::error!("Could not get node {node_id} in upstream_nodes_below_layer"); + continue; + }; + potential_upstream_nodes.extend(chain_node.inputs.iter().filter(|input| input.is_exposed()).skip(1).filter_map(|node_input| node_input.as_node())) + } + + // Get the node feeding into the left input of the chain + let mut current_node_id = *node_id; + loop { + let Some(current_node) = self.document_node(¤t_node_id, network_path) else { + log::error!("Could not get node {node_id} in upstream_nodes_below_layer"); + break; + }; + if let Some(primary_node_id) = current_node + .inputs + .iter() + .filter(|input| input.is_exposed()) + .nth(if self.is_layer(¤t_node_id, network_path) { 1 } else { 0 }) + .and_then(|left_input| left_input.as_node()) + { + if self.is_chain(&primary_node_id, network_path) { + current_node_id = primary_node_id; + } else { + potential_upstream_nodes.insert(primary_node_id); + break; + } + } else { + break; + } + } + + for potential_upstream_node in potential_upstream_nodes { + // The upstream chain cannot be added if there is some node upstream from an input that is not a sole dependent + let mut upstream_chain_can_be_added = true; + // Collect a vec of nodes that are sole dependents while iterating + let mut sole_dependents = HashSet::new(); + + for upstream_node_from_input in self + .upstream_flow_back_from_nodes(vec![potential_upstream_node], network_path, FlowType::UpstreamFlow) + .collect::>() + { + let number_of_outputs = self.number_of_outputs(&upstream_node_from_input, network_path); + + // A node is a sole dependent if all outputs are sole dependents, and there are no dead ends + let mut all_outputs_are_sole_dependents = true; + let mut dead_ends = 0; + + for output_index in 0..number_of_outputs { + let downstream_connections = { + let Some(outward_wires) = self.outward_wires(network_path) else { + log::error!("Could not get outward wires in upstream_nodes_below_layer"); + continue; + }; + outward_wires.get(&OutputConnector::node(upstream_node_from_input, output_index)).cloned() + }; + let Some(downstream_connections) = downstream_connections else { + log::error!("Could not get outward wires in upstream_nodes_below_layer"); + continue; + }; + let mut current_output_is_sole_dependent = true; + let mut stack = downstream_connections; + while let Some(current_downstream_connection) = stack.pop() { + // Iterate downstream. If a sole dependent or chain_node_id is reached, then stop the iteration. If the exports is eventually reached, then it is not a sole dependent + match ¤t_downstream_connection { + InputConnector::Node { + node_id: downstream_node_id, + input_index, + } => { + // Stop iterating once the downstream node is the left input to the chain or a sole dependent + if !(sole_dependents.contains(downstream_node_id) || downstream_node_id == node_id && *input_index == 1) { + // Continue iterating downstream for the downstream node + let number_of_outputs = self.number_of_outputs(downstream_node_id, network_path); + let Some(outward_wires) = self.outward_wires(network_path) else { + log::error!("Could not get outward wires in upstream_nodes_below_layer"); + continue; + }; + let mut has_downstream_connections = false; + for output_index in 0..number_of_outputs { + let Some(downstream_connections) = outward_wires.get(&OutputConnector::node(*downstream_node_id, output_index)) else { + log::error!("Could not get outward wires in upstream_nodes_below_layer"); + continue; + }; + if !downstream_connections.is_empty() { + has_downstream_connections = true; + } + stack.extend(downstream_connections.clone()); + } + if !has_downstream_connections { + dead_ends += 1; + } + } + } + InputConnector::Export(_) => current_output_is_sole_dependent = false, + } + } + if !current_output_is_sole_dependent || dead_ends != 0 { + all_outputs_are_sole_dependents = false; + break; + } + } + if all_outputs_are_sole_dependents && dead_ends == 0 { + sole_dependents.insert(upstream_node_from_input); + } else { + upstream_chain_can_be_added = false; + break; + } + } + + if upstream_chain_can_be_added { + upstream_nodes_below_layer.extend(sole_dependents) + } + } + upstream_nodes_below_layer + } + + pub fn previewing(&self, network_path: &[NodeId]) -> Previewing { + let Some(network_metadata) = self.network_metadata(network_path) else { + log::error!("Could not get nested network_metadata in previewing"); + return Previewing::No; + }; + network_metadata.persistent_metadata.previewing + } + + /// Returns the root node (the node that the solid line is connect to), or None if no nodes are connected to the output + pub fn root_node(&self, network_path: &[NodeId]) -> Option { + let Some(network) = self.nested_network(network_path) else { + log::error!("Could not get network in root_node"); + return None; + }; + let Some(network_metadata) = self.network_metadata(network_path) else { + log::error!("Could not get nested network_metadata in root_node"); + return None; + }; + match &network_metadata.persistent_metadata.previewing { + Previewing::Yes { root_node_to_restore } => *root_node_to_restore, + Previewing::No => network.exports.first().and_then(|export| { + if let NodeInput::Node { node_id, output_index, .. } = export { + Some(RootNode { + node_id: *node_id, + output_index: *output_index, + }) + } else { + None + } + }), + } + } + + pub fn reference(&self, node_id: &NodeId, network_path: &[NodeId]) -> Option<&Option> { + let Some(node_metadata) = self.node_metadata(node_id, network_path) else { + log::error!("Could not get reference for node: {:?}", node_id); + return None; + }; + Some(&node_metadata.persistent_metadata.reference) + } + + pub fn implementation(&self, node_id: &NodeId, network_path: &[NodeId]) -> Option<&DocumentNodeImplementation> { + let Some(node) = self.document_node(node_id, network_path) else { + log::error!("Could not get implementation"); + return None; + }; + Some(&node.implementation) + } + + pub fn input_data(&self, node_id: &NodeId, index: usize, key: &str, network_path: &[NodeId]) -> Option<&Value> { + let metadata = self + .node_metadata(node_id, network_path) + .and_then(|node_metadata| node_metadata.persistent_metadata.input_metadata.get(index))?; + metadata.persistent_metadata.input_data.get(key) + } + pub fn persistent_input_metadata(&self, node_id: &NodeId, index: usize, network_path: &[NodeId]) -> Option<&InputPersistentMetadata> { + let metadata = self + .node_metadata(node_id, network_path) + .and_then(|node_metadata| node_metadata.persistent_metadata.input_metadata.get(index))?; + Some(&metadata.persistent_metadata) + } + + fn transient_input_metadata(&self, node_id: &NodeId, index: usize, network_path: &[NodeId]) -> Option<&InputTransientMetadata> { + let metadata = self + .node_metadata(node_id, network_path) + .and_then(|node_metadata| node_metadata.persistent_metadata.input_metadata.get(index))?; + Some(&metadata.transient_metadata) + } + + /// Returns the input name to display in the properties panel. If the name is empty then the type is used. + pub fn displayed_input_name_and_description(&mut self, node_id: &NodeId, input_index: usize, network_path: &[NodeId]) -> (String, String) { + let Some(input_metadata) = self.persistent_input_metadata(node_id, input_index, network_path) else { + log::warn!("input metadata not found in displayed_input_name_and_description"); + return (String::new(), String::new()); + }; + let description = input_metadata.input_description.to_string(); + let name = if input_metadata.input_name.is_empty() { + self.input_type(&InputConnector::node(*node_id, input_index), network_path).0.nested_type().to_string() + } else { + input_metadata.input_name.to_string() + }; + (name, description) + } + + /// Returns the display name of the node. If the display name is empty, it will return "Untitled Node" or "Untitled Layer" depending on the node type. + pub fn display_name(&self, node_id: &NodeId, network_path: &[NodeId]) -> String { + let is_layer = self + .node_metadata(node_id, network_path) + .expect("Could not get persistent node metadata in untitled_layer_label") + .persistent_metadata + .is_layer(); + + let Some(reference) = self.reference(node_id, network_path) else { + log::error!("Could not get reference in untitled_layer_label"); + return "".to_string(); + }; + + let display_name = if let Some(node_metadata) = self.node_metadata(node_id, network_path) { + node_metadata.persistent_metadata.display_name.clone() + } else { + log::error!("Could not get node_metadata in display_name"); + String::new() + }; + + if display_name.is_empty() { + if is_layer { + "Untitled Layer".to_string() + } else { + reference.clone().unwrap_or("Untitled Node".to_string()) + } + } else { + display_name + } + } + + /// Returns the description of the node, or an empty string if it is not set. + pub fn description(&self, node_id: &NodeId, network_path: &[NodeId]) -> String { + self.get_node_definition(network_path, *node_id) + .map(|node_definition| node_definition.description.to_string()) + .filter(|description| description != "TODO") + .unwrap_or_default() + } + + pub fn is_locked(&self, node_id: &NodeId, network_path: &[NodeId]) -> bool { + let Some(node_metadata) = self.node_metadata(node_id, network_path) else { + log::error!("Could not get persistent node metadata in is_locked for node {node_id}"); + return false; + }; + node_metadata.persistent_metadata.locked + } + + pub fn is_pinned(&self, node_id: &NodeId, network_path: &[NodeId]) -> bool { + let Some(node_metadata) = self.node_metadata(node_id, network_path) else { + log::error!("Could not get persistent node metadata in is_pinned for node {node_id}"); + return false; + }; + node_metadata.persistent_metadata.pinned + } + + pub fn is_visible(&self, node_id: &NodeId, network_path: &[NodeId]) -> bool { + let Some(node) = self.document_node(node_id, network_path) else { + log::error!("Could not get node in is_visible"); + return false; + }; + node.visible + } + + pub fn is_layer(&self, node_id: &NodeId, network_path: &[NodeId]) -> bool { + let Some(node_metadata) = self.node_metadata(node_id, network_path) else { + log::error!("Could not get nested node_metadata in is_layer"); + return false; + }; + node_metadata.persistent_metadata.is_layer() + } + + pub fn has_primary_output(&self, node_id: &NodeId, network_path: &[NodeId]) -> bool { + let Some(node_metadata) = self.node_metadata(node_id, network_path) else { + log::error!("Could not get node_metadata in has_primary_output"); + return false; + }; + node_metadata.persistent_metadata.has_primary_output + } + + pub fn is_absolute(&self, node_id: &NodeId, network_path: &[NodeId]) -> bool { + let Some(node_metadata) = self.node_metadata(node_id, network_path) else { + log::error!("Could not get node_metadata in is_absolute"); + return false; + }; + match &node_metadata.persistent_metadata.node_type_metadata { + NodeTypePersistentMetadata::Layer(layer_metadata) => matches!(layer_metadata.position, LayerPosition::Absolute(_)), + NodeTypePersistentMetadata::Node(node_metadata) => matches!(node_metadata.position, NodePosition::Absolute(_)), + } + } + + pub fn is_chain(&self, node_id: &NodeId, network_path: &[NodeId]) -> bool { + let Some(node_metadata) = self.node_metadata(node_id, network_path) else { + log::error!("Could not get node_metadata in is_chain"); + return false; + }; + match &node_metadata.persistent_metadata.node_type_metadata { + NodeTypePersistentMetadata::Node(node_metadata) => matches!(node_metadata.position, NodePosition::Chain), + _ => false, + } + } + + pub fn is_stack(&self, node_id: &NodeId, network_path: &[NodeId]) -> bool { + let Some(node_metadata) = self.node_metadata(node_id, network_path) else { + log::error!("Could not get node_metadata in is_stack"); + return false; + }; + match &node_metadata.persistent_metadata.node_type_metadata { + NodeTypePersistentMetadata::Layer(layer_metadata) => matches!(layer_metadata.position, LayerPosition::Stack(_)), + _ => false, + } + } + + pub fn is_artboard(&self, node_id: &NodeId, network_path: &[NodeId]) -> bool { + self.reference(node_id, network_path) + .is_some_and(|reference| *reference == Some("Artboard".to_string()) && self.connected_to_output(node_id, &[])) + } + + pub fn all_artboards(&self) -> HashSet { + self.document_network_metadata() + .persistent_metadata + .node_metadata + .iter() + .filter_map(|(node_id, node_metadata)| { + if node_metadata + .persistent_metadata + .reference + .as_ref() + .is_some_and(|reference| reference == "Artboard" && self.connected_to_output(node_id, &[]) && self.is_layer(node_id, &[])) + { + Some(LayerNodeIdentifier::new(*node_id, self, &[])) + } else { + None + } + }) + .collect() + } + + /// Folders sorted from most nested to least nested + pub fn folders_sorted_by_most_nested(&self, network_path: &[NodeId]) -> Vec { + if !network_path.is_empty() { + log::error!("Currently can only get deepest common ancestor in the document network"); + return Vec::new(); + } + let Some(selected_nodes) = self.selected_nodes_in_nested_network(network_path) else { + log::error!("Could not get selected nodes in deepest_common_ancestor"); + return Vec::new(); + }; + let mut folders: Vec<_> = selected_nodes + .selected_layers(self.document_metadata()) + .filter(|layer| layer.has_children(self.document_metadata())) + .collect(); + folders.sort_by_cached_key(|a| std::cmp::Reverse(a.ancestors(self.document_metadata()).count())); + folders + } + + /// Calculates the document bounds in document space + pub fn document_bounds_document_space(&self, include_artboards: bool) -> Option<[DVec2; 2]> { + self.document_metadata + .all_layers() + .filter(|layer| include_artboards || !self.is_artboard(&layer.to_node(), &[])) + .filter_map(|layer| { + if !self.is_artboard(&layer.to_node(), &[]) { + if let Some(artboard_node_identifier) = layer + .ancestors(self.document_metadata()) + .find(|ancestor| *ancestor != LayerNodeIdentifier::ROOT_PARENT && self.is_artboard(&ancestor.to_node(), &[])) + { + let artboard = self.document_node(&artboard_node_identifier.to_node(), &[]); + let clip_input = artboard.unwrap().inputs.get(5).unwrap(); + if let NodeInput::Value { tagged_value, .. } = clip_input { + if tagged_value.to_primitive_string() == "true" { + return Some(Quad::clip( + self.document_metadata.bounding_box_document(layer).unwrap_or_default(), + self.document_metadata.bounding_box_document(artboard_node_identifier).unwrap_or_default(), + )); + } + } + } + } + self.document_metadata.bounding_box_document(layer) + }) + .reduce(Quad::combine_bounds) + } + + /// Calculates the selected layer bounds in document space + pub fn selected_bounds_document_space(&self, include_artboards: bool, network_path: &[NodeId]) -> Option<[DVec2; 2]> { + let Some(selected_nodes) = self.selected_nodes_in_nested_network(network_path) else { + log::error!("Could not get selected nodes in shallowest_unique_layers"); + return None; + }; + selected_nodes + .selected_layers(&self.document_metadata) + .filter(|&layer| include_artboards || !self.is_artboard(&layer.to_node(), &[])) + .filter_map(|layer| self.document_metadata.bounding_box_document(layer)) + .reduce(Quad::combine_bounds) + } + + /// Layers excluding ones that are children of other layers in the list. + // TODO: Cache this + pub fn shallowest_unique_layers(&self, network_path: &[NodeId]) -> impl Iterator + use<> { + let mut sorted_layers = if let Some(selected_nodes) = self.selected_nodes_in_nested_network(network_path) { + selected_nodes + .selected_layers(self.document_metadata()) + .map(|layer| { + let mut layer_path = layer.ancestors(&self.document_metadata).collect::>(); + layer_path.reverse(); + layer_path + }) + .collect::>() + } else { + log::error!("Could not get selected nodes in shallowest_unique_layers"); + Vec::new() + }; + + // Sorting here creates groups of similar UUID paths + sorted_layers.sort(); + sorted_layers.dedup_by(|a, b| a.starts_with(b)); + sorted_layers.into_iter().map(|mut path| { + let layer = path.pop().expect("Path should not be empty"); + assert!( + layer != LayerNodeIdentifier::ROOT_PARENT, + "The root parent cannot be selected, so it cannot be a shallowest selected layer" + ); + layer + }) + } + + pub fn shallowest_unique_layers_sorted(&self, network_path: &[NodeId]) -> Vec { + let all_layers_to_group = self.shallowest_unique_layers(network_path).collect::>(); + // Ensure nodes are grouped in the correct order + let mut all_layers_to_group_sorted = Vec::new(); + for descendant in LayerNodeIdentifier::ROOT_PARENT.descendants(self.document_metadata()) { + if all_layers_to_group.contains(&descendant) { + all_layers_to_group_sorted.push(descendant); + }; + } + all_layers_to_group_sorted + } + + /// Ancestor that is shared by all layers and that is deepest (more nested). Default may be the root. Skips selected non-folder, non-artboard layers + pub fn deepest_common_ancestor(&self, selected_nodes: &SelectedNodes, network_path: &[NodeId], include_self: bool) -> Option { + if !network_path.is_empty() { + log::error!("Currently can only get deepest common ancestor in the document network"); + return None; + } + selected_nodes + .selected_layers(&self.document_metadata) + .map(|layer| { + let mut layer_path = layer.ancestors(&self.document_metadata).collect::>(); + layer_path.reverse(); + if !include_self || !self.is_artboard(&layer.to_node(), network_path) { + layer_path.pop(); + } + + layer_path + }) + .reduce(|mut a, b| { + a.truncate(a.iter().zip(b.iter()).position(|(&a, &b)| a != b).unwrap_or_else(|| a.len().min(b.len()))); + a + }) + .and_then(|layer| layer.last().copied()) + } + + /// Gives an iterator to all nodes connected to the given nodes by all inputs (primary or primary + secondary depending on `only_follow_primary` choice), traversing backwards upstream starting from the given node's inputs. + pub fn upstream_flow_back_from_nodes<'a>(&'a self, mut node_ids: Vec, network_path: &'a [NodeId], mut flow_type: FlowType) -> impl Iterator + 'a { + let (Some(network), Some(network_metadata)) = (self.nested_network(network_path), self.network_metadata(network_path)) else { + log::error!("Could not get network or network_metadata in upstream_flow_back_from_nodes"); + return FlowIter { + stack: Vec::new(), + network: &self.network, + network_metadata: &self.network_metadata, + flow_type: FlowType::UpstreamFlow, + }; + }; + if matches!(flow_type, FlowType::LayerChildrenUpstreamFlow) { + node_ids = node_ids + .iter() + .filter_map(move |node_id| { + if self.is_layer(node_id, network_path) { + network.nodes.get(node_id).and_then(|node| node.inputs.get(1)).and_then(|input| input.as_node()) + } else { + Some(*node_id) + } + }) + .collect::>(); + flow_type = FlowType::UpstreamFlow; + }; + FlowIter { + stack: node_ids, + network, + network_metadata, + flow_type, + } + } + + pub fn upstream_output_connector(&self, input_connector: &InputConnector, network_path: &[NodeId]) -> Option { + let input = self.input_from_connector(input_connector, network_path); + input.and_then(|input| match input { + NodeInput::Node { node_id, output_index, .. } => Some(OutputConnector::node(*node_id, *output_index)), + NodeInput::Network { import_index, .. } => Some(OutputConnector::Import(*import_index)), + _ => None, + }) + } + + /// In the network `X -> Y -> Z`, `is_node_upstream_of_another_by_primary_flow(Z, X)` returns true. + pub fn is_node_upstream_of_another_by_horizontal_flow(&self, node: NodeId, network_path: &[NodeId], potentially_upstream_node: NodeId) -> bool { + self.upstream_flow_back_from_nodes(vec![node], network_path, FlowType::HorizontalFlow) + .any(|id| id == potentially_upstream_node) + } + + #[cfg(not(target_arch = "wasm32"))] + fn text_width(&self, node_id: &NodeId, network_path: &[NodeId]) -> Option { + warn!("Failed to find width of {node_id:#?} in network_path {network_path:?} due to non-wasm arch"); + Some(0.) + } + + #[cfg(target_arch = "wasm32")] + fn text_width(&self, node_id: &NodeId, network_path: &[NodeId]) -> Option { + let document = web_sys::window().unwrap().document().unwrap(); + let div = match document.create_element("div") { + Ok(div) => div, + Err(err) => { + log::error!("Error creating div: {:?}", err); + return None; + } + }; + + // Set the div's style to make it offscreen and single line + match div.set_attribute("style", "position: absolute; top: -9999px; left: -9999px; white-space: nowrap;") { + Err(err) => { + log::error!("Error setting attribute: {:?}", err); + return None; + } + _ => {} + }; + + let name = self.display_name(node_id, network_path); + + div.set_text_content(Some(&name)); + + // Append the div to the document body + match document.body().unwrap().append_child(&div) { + Err(err) => { + log::error!("Error setting adding child to document {:?}", err); + return None; + } + _ => {} + }; + + // Measure the width + let text_width = div.get_bounding_client_rect().width(); + + // Remove the div from the document + match document.body().unwrap().remove_child(&div) { + Err(_) => log::error!("Could not remove child when rendering text"), + _ => {} + }; + + Some(text_width) + } + + pub fn from_old_network(old_network: OldNodeNetwork) -> Self { + let mut node_network = NodeNetwork::default(); + let mut network_metadata = NodeNetworkMetadata::default(); + let mut stack = vec![(Vec::new(), old_network)]; + while let Some((network_path, old_network)) = stack.pop() { + let Some(nested_network) = node_network.nested_network_mut(&network_path) else { + log::error!("Could not get nested network in from_old_network"); + continue; + }; + nested_network.exports = old_network.exports; + nested_network.scope_injections = old_network.scope_injections.into_iter().collect(); + let Some(nested_network_metadata) = network_metadata.nested_metadata_mut(&network_path) else { + log::error!("Could not get nested network in from_old_network"); + continue; + }; + nested_network_metadata.persistent_metadata.previewing = Previewing::No; + for (node_id, old_node) in old_network.nodes { + let mut node = DocumentNode::default(); + let mut node_metadata = DocumentNodeMetadata::default(); + + node.inputs = old_node.inputs; + node.manual_composition = old_node.manual_composition; + node.visible = old_node.visible; + node.skip_deduplication = old_node.skip_deduplication; + node.original_location = old_node.original_location; + node_metadata.persistent_metadata.display_name = old_node.alias; + node_metadata.persistent_metadata.reference = if old_node.name.is_empty() { None } else { Some(old_node.name) }; + node_metadata.persistent_metadata.has_primary_output = old_node.has_primary_output; + node_metadata.persistent_metadata.locked = old_node.locked; + node_metadata.persistent_metadata.node_type_metadata = if old_node.is_layer { + NodeTypePersistentMetadata::Layer(LayerPersistentMetadata { + position: LayerPosition::Absolute(old_node.metadata.position), + owned_nodes: TransientMetadata::Unloaded, + }) + } else { + NodeTypePersistentMetadata::Node(NodePersistentMetadata { + position: NodePosition::Absolute(old_node.metadata.position), + }) + }; + + match old_node.implementation { + OldDocumentNodeImplementation::ProtoNode(protonode) => { + node.implementation = DocumentNodeImplementation::ProtoNode(protonode); + } + OldDocumentNodeImplementation::Network(old_network) => { + node.implementation = DocumentNodeImplementation::Network(NodeNetwork::default()); + node_metadata.persistent_metadata.network_metadata = Some(NodeNetworkMetadata::default()); + let mut nested_path = network_path.clone(); + nested_path.push(node_id); + stack.push((nested_path, old_network)); + } + OldDocumentNodeImplementation::Extract => { + node.implementation = DocumentNodeImplementation::Extract; + } + } + + nested_network.nodes.insert(node_id, node); + nested_network_metadata.persistent_metadata.node_metadata.insert(node_id, node_metadata); + } + } + Self { + network: node_network, + network_metadata, + document_metadata: DocumentMetadata::default(), + resolved_types: ResolvedDocumentNodeTypes::default(), + transaction_status: TransactionStatus::Finished, + } + } +} + +/// Gets the type for a random protonode implementation (used if there is no type from the compiled network) +fn random_protonode_implementation(protonode: &graph_craft::ProtoNodeIdentifier) -> Option<&graphene_std::NodeIOTypes> { + let mut protonode = protonode.clone(); + // TODO: Remove + if let Some((path, _generics)) = protonode.name.split_once('<') { + protonode = path.to_string().to_string().into(); + } + let Some(node_io_hashmap) = NODE_REGISTRY.get(&protonode) else { + log::error!("Could not get hashmap for proto node: {protonode:?}"); + return None; + }; + + let node_types = node_io_hashmap.keys().min_by_key(|node_io_types| { + let mut hasher = DefaultHasher::new(); + node_io_types.hash(&mut hasher); + hasher.finish() + }); + + if node_types.is_none() { + log::error!("Could not get node_types from hashmap"); + }; + node_types +} + +// Private mutable getters for use within the network interface +impl NodeNetworkInterface { + fn network_mut(&mut self, network_path: &[NodeId]) -> Option<&mut NodeNetwork> { + self.network.nested_network_mut(network_path) + } + + fn network_metadata_mut(&mut self, network_path: &[NodeId]) -> Option<&mut NodeNetworkMetadata> { + self.network_metadata.nested_metadata_mut(network_path) + } + + fn node_metadata_mut(&mut self, node_id: &NodeId, network_path: &[NodeId]) -> Option<&mut DocumentNodeMetadata> { + let Some(network_metadata) = self.network_metadata_mut(network_path) else { + log::error!("Could not get nested network_metadata"); + return None; + }; + let Some(node_metadata) = network_metadata.persistent_metadata.node_metadata.get_mut(node_id) else { + log::error!("Could not get nested node_metadata for node {node_id} in network {network_path:?}"); + return None; + }; + Some(node_metadata) + } + + /// Mutably get the network which the encapsulating node of the currently viewed network is part of. Will always be None in the document network. + fn encapsulating_network_metadata_mut(&mut self, network_path: &[NodeId]) -> Option<&mut NodeNetworkMetadata> { + let mut encapsulating_path = network_path.to_vec(); + encapsulating_path.pop()?; + let Some(parent_metadata) = self.network_metadata_mut(&encapsulating_path) else { + log::error!("Could not get parent network in encapsulating_node_metadata"); + return None; + }; + Some(parent_metadata) + } + + // /// Mutably get the node which encapsulates the currently viewed network. Will always be None in the document network. + // fn encapsulating_node_mut(&mut self, network_path: &[NodeId]) -> Option<&mut DocumentNode> { + // let mut encapsulating_path = network_path.to_vec(); + // let encapsulating_node_id = encapsulating_path.pop()?; + // let Some(parent_network) = self.network_mut(&encapsulating_path) else { + // log::error!("Could not get parent network in encapsulating_node_mut"); + // return None; + // }; + // let Some(encapsulating_node) = parent_network.nodes.mut(&encapsulating_node_id) else { + // log::error!("Could not get encapsulating node in encapsulating_node_mut"); + // return None; + // }; + // Some(encapsulating_node) + // } + + /// Get the node metadata for the node which encapsulates the currently viewed network. Will always be None in the document network. + fn encapsulating_node_metadata_mut(&mut self, network_path: &[NodeId]) -> Option<&mut DocumentNodeMetadata> { + let mut encapsulating_path = network_path.to_vec(); + let encapsulating_node_id = encapsulating_path.pop()?; + let Some(parent_metadata) = self.network_metadata_mut(&encapsulating_path) else { + log::error!("Could not get parent network in encapsulating_node_metadata"); + return None; + }; + let Some(encapsulating_node_metadata) = parent_metadata.persistent_metadata.node_metadata.get_mut(&encapsulating_node_id) else { + log::error!("Could not get encapsulating node metadata in encapsulating_node_metadata"); + return None; + }; + Some(encapsulating_node_metadata) + } +} + +// Public mutable getters for data that involves transient network metadata +// Mutable methods never recalculate the transient metadata, they only unload it. Loading metadata should only be done by the getter. +impl NodeNetworkInterface { + pub fn start_transaction(&mut self) { + self.transaction_status = TransactionStatus::Started; + } + + pub fn transaction_modified(&mut self) { + if self.transaction_status == TransactionStatus::Started { + self.transaction_status = TransactionStatus::Modified; + } + } + + pub fn finish_transaction(&mut self) { + self.transaction_status = TransactionStatus::Finished; + } + + /// Mutably get the selected nodes for the network at the network_path. Every time they are mutated, the transient metadata for the top of the stack gets unloaded. + pub fn selected_nodes_mut(&mut self, network_path: &[NodeId]) -> Option<&mut SelectedNodes> { + let (last_selection_state, prev_state, is_selection_empty) = { + let network_metadata = self.network_metadata(network_path)?; + let history = &network_metadata.persistent_metadata.selection_undo_history; + let current = history.back().cloned().unwrap_or_default(); + let previous = history.iter().rev().nth(1).cloned(); + let empty = current.selected_layers_except_artboards(self).next().is_none(); + (current, previous, empty) + }; + self.unload_stack_dependents(network_path); + + let Some(network_metadata) = self.network_metadata_mut(network_path) else { + log::error!("Could not get nested network_metadata in selected_nodes"); + return None; + }; + + // Initialize default value if selection_undo_history is empty + if network_metadata.persistent_metadata.selection_undo_history.is_empty() { + network_metadata.persistent_metadata.selection_undo_history.push_back(SelectedNodes::default()); + } + + // Update history only if selection is non-empty/does not contain only artboards + if !is_selection_empty && prev_state.as_ref() != Some(&last_selection_state) { + network_metadata.persistent_metadata.selection_undo_history.push_back(last_selection_state); + network_metadata.persistent_metadata.selection_redo_history.clear(); + + if network_metadata.persistent_metadata.selection_undo_history.len() > crate::consts::MAX_UNDO_HISTORY_LEN { + network_metadata.persistent_metadata.selection_undo_history.pop_front(); + } + } + + network_metadata.persistent_metadata.selection_undo_history.back_mut() + } + + pub fn selection_step_back(&mut self, network_path: &[NodeId]) { + let Some(network_metadata) = self.network_metadata_mut(network_path) else { + log::error!("Could not get nested network_metadata in selection_step_back"); + return; + }; + + if let Some(selection_state) = network_metadata.persistent_metadata.selection_undo_history.pop_back() { + network_metadata.persistent_metadata.selection_redo_history.push_front(selection_state); + } + } + + pub fn selection_step_forward(&mut self, network_path: &[NodeId]) { + let Some(network_metadata) = self.network_metadata_mut(network_path) else { + log::error!("Could not get nested network_metadata in selection_step_forward"); + return; + }; + + if let Some(selection_state) = network_metadata.persistent_metadata.selection_redo_history.pop_front() { + network_metadata.persistent_metadata.selection_undo_history.push_back(selection_state); + } + } + + fn stack_dependents(&mut self, network_path: &[NodeId]) -> Option<&HashMap> { + self.try_load_stack_dependents(network_path); + self.try_get_stack_dependents(network_path) + } + + fn try_load_stack_dependents(&mut self, network_path: &[NodeId]) { + let Some(network_metadata) = self.network_metadata(network_path) else { + log::error!("Could not get nested network_metadata in stack_dependents"); + return; + }; + + if !network_metadata.transient_metadata.stack_dependents.is_loaded() { + self.load_stack_dependents(network_path); + } + } + + fn try_get_stack_dependents(&self, network_path: &[NodeId]) -> Option<&HashMap> { + let Some(network_metadata) = self.network_metadata(network_path) else { + log::error!("Could not get nested network_metadata in try_get_stack_dependents"); + return None; + }; + let TransientMetadata::Loaded(stack_dependents) = &network_metadata.transient_metadata.stack_dependents else { + log::error!("could not load stack_dependents"); + return None; + }; + Some(stack_dependents) + } + + // This function always has to be in sync with the selected nodes. + fn load_stack_dependents(&mut self, network_path: &[NodeId]) { + let Some(selected_nodes) = self.selected_nodes_in_nested_network(network_path) else { + log::error!("Could not get selected nodes in load_stack_dependents"); + return; + }; + + let mut selected_layers = selected_nodes.selected_nodes().filter(|node_id| self.is_layer(node_id, network_path)).cloned().collect::>(); + + // Deselect all layers that are upstream of other selected layers + let mut removed_layers = Vec::new(); + for layer in selected_layers.clone() { + if removed_layers.contains(&layer) { + continue; + } + for upstream_node in self.upstream_flow_back_from_nodes(vec![layer], network_path, FlowType::UpstreamFlow).skip(1) { + if selected_layers.remove(&upstream_node) { + removed_layers.push(upstream_node) + } + } + } + + // Get a unique list of the top of each stack for each layer + let mut stack_tops = HashSet::new(); + + for layer in &selected_layers { + let mut current_node = *layer; + loop { + if self.is_layer(¤t_node, network_path) && self.is_absolute(¤t_node, network_path) { + stack_tops.insert(current_node); + break; + }; + let Some(outward_wires) = self.outward_wires(network_path) else { + log::error!("Cannot load outward wires in load_stack_dependents"); + return; + }; + let Some(layer_outward_wires) = outward_wires.get(&OutputConnector::node(current_node, 0)) else { + log::error!("Could not get outward_wires for layer {current_node}"); + break; + }; + match layer_outward_wires.first() { + Some(downstream_input) => { + let Some(downstream_node) = downstream_input.node_id() else { + log::error!("Node connected to export should be absolute"); + break; + }; + current_node = downstream_node + } + None => break, + } + } + } + + let mut stack_dependents = HashMap::new(); + let mut owned_sole_dependents = HashSet::new(); + // Loop through all layers below the stack_tops, and set sole dependents upstream from that layer to be owned by that layer. Ensure LayerOwner is kept in sync. + for stack_top in &stack_tops { + for upstream_stack_layer in self + .upstream_flow_back_from_nodes(vec![*stack_top], network_path, FlowType::PrimaryFlow) + .take_while(|upstream_node| self.is_layer(upstream_node, network_path)) + .collect::>() + { + for upstream_layer in self.upstream_flow_back_from_nodes(vec![upstream_stack_layer], network_path, FlowType::UpstreamFlow).collect::>() { + if !self.is_layer(&upstream_layer, network_path) { + continue; + } + let mut new_owned_nodes = HashSet::new(); + for layer_sole_dependent in &self.upstream_nodes_below_layer(&upstream_layer, network_path) { + stack_dependents.insert(*layer_sole_dependent, LayerOwner::Layer(upstream_layer)); + owned_sole_dependents.insert(*layer_sole_dependent); + new_owned_nodes.insert(*layer_sole_dependent); + } + let Some(layer_node) = self.node_metadata_mut(&upstream_layer, network_path) else { + log::error!("Could not get layer node in load_stack_dependents"); + continue; + }; + let NodeTypePersistentMetadata::Layer(LayerPersistentMetadata { owned_nodes, .. }) = &mut layer_node.persistent_metadata.node_type_metadata else { + log::error!("upstream layer should be a layer"); + return; + }; + *owned_nodes = TransientMetadata::Loaded(new_owned_nodes); + } + } + } + + // Set any sole dependents of the stack top that are not dependents of a layer in the stack to LayerOwner::None. These nodes will be pushed as blocks when a layer is shifted. + for stack_top in &stack_tops { + let mut sole_dependents = HashSet::new(); + let mut not_sole_dependents = HashSet::new(); + sole_dependents.insert(*stack_top); + for upstream_node in self.upstream_flow_back_from_nodes(vec![*stack_top], network_path, FlowType::UpstreamFlow).collect::>() { + let mut stack = vec![upstream_node]; + let mut is_sole_dependent = true; + while let Some(current_node) = stack.pop() { + if not_sole_dependents.contains(¤t_node) { + is_sole_dependent = false; + break; + } + if !sole_dependents.contains(¤t_node) { + let mut has_outward_wire = false; + for output_index in 0..self.number_of_outputs(¤t_node, network_path) { + let Some(outward_wires) = self.outward_wires(network_path) else { + log::error!("Cannot load outward wires in load_stack_dependents"); + continue; + }; + let Some(outward_wires) = outward_wires.get(&OutputConnector::node(current_node, output_index)) else { + log::error!("Cannot load outward wires in load_stack_dependents"); + continue; + }; + for downstream_input in outward_wires { + has_outward_wire = true; + match downstream_input { + InputConnector::Node { node_id, .. } => stack.push(*node_id), + InputConnector::Export(_) => is_sole_dependent = false, + } + } + } + if !has_outward_wire { + is_sole_dependent = false; + } + } + if !is_sole_dependent { + break; + } + } + + if is_sole_dependent { + sole_dependents.insert(upstream_node); + } else { + not_sole_dependents.insert(upstream_node); + } + } + + for sole_dependent in sole_dependents { + if !owned_sole_dependents.contains(&sole_dependent) { + stack_dependents.insert(sole_dependent, LayerOwner::None(0)); + } + } + } + + let Some(network_metadata) = self.network_metadata_mut(network_path) else { + log::error!("Could not get current network in load_export_ports"); + return; + }; + + network_metadata.transient_metadata.stack_dependents = TransientMetadata::Loaded(stack_dependents); + } + + pub fn unload_stack_dependents(&mut self, network_path: &[NodeId]) { + let Some(network_metadata) = self.network_metadata_mut(network_path) else { + log::error!("Could not get nested network_metadata in unload_stack_dependents"); + return; + }; + network_metadata.transient_metadata.stack_dependents.unload(); + } + + /// Resets all the offsets for nodes with no LayerOwner when the drag ends + pub fn unload_stack_dependents_y_offset(&mut self, network_path: &[NodeId]) { + let Some(network_metadata) = self.network_metadata_mut(network_path) else { + log::error!("Could not get nested network_metadata in unload_stack_dependents_y_offset"); + return; + }; + + if let TransientMetadata::Loaded(stack_dependents) = &mut network_metadata.transient_metadata.stack_dependents { + for layer_owner in stack_dependents.values_mut() { + if let LayerOwner::None(offset) = layer_owner { + *offset = 0; + } + } + } + } + + pub fn import_export_ports(&mut self, network_path: &[NodeId]) -> Option<&Ports> { + let Some(network_metadata) = self.network_metadata(network_path) else { + log::error!("Could not get nested network_metadata in export_ports"); + return None; + }; + if !network_metadata.transient_metadata.import_export_ports.is_loaded() { + self.load_import_export_ports(network_path); + } + + let Some(network_metadata) = self.network_metadata(network_path) else { + log::error!("Could not get nested network_metadata in export_ports"); + return None; + }; + let TransientMetadata::Loaded(ports) = &network_metadata.transient_metadata.import_export_ports else { + log::error!("could not load import ports"); + return None; + }; + Some(ports) + } + + pub fn load_import_export_ports(&mut self, network_path: &[NodeId]) { + //let point = network_metadata.persistent_metadata.navigation_metadata.node_graph_to_viewport.inverse().transform_point2(); + let Some(all_nodes_bounding_box) = self.all_nodes_bounding_box(network_path).cloned() else { + log::error!("Could not get all nodes bounding box in load_export_ports"); + return; + }; + let Some(rounded_network_edge_distance) = self.rounded_network_edge_distance(network_path).cloned() else { + log::error!("Could not get rounded_network_edge_distance in load_export_ports"); + return; + }; + let Some(network_metadata) = self.network_metadata(network_path) else { + log::error!("Could not get nested network_metadata in load_export_ports"); + return; + }; + let Some(network) = self.nested_network(network_path) else { + log::error!("Could not get current network in load_export_ports"); + return; + }; + + let mut import_export_ports = Ports::new(); + + let viewport_top_right = network_metadata + .persistent_metadata + .navigation_metadata + .node_graph_to_viewport + .inverse() + .transform_point2(rounded_network_edge_distance.exports_to_edge_distance); + let offset_from_top_right = if network + .exports + .first() + .is_some_and(|export| export.as_node().is_some_and(|export_node| self.is_layer(&export_node, network_path))) + { + DVec2::new(2. * GRID_SIZE as f64, -2. * GRID_SIZE as f64) + } else { + DVec2::new(4. * GRID_SIZE as f64, 0.) + }; + + let bounding_box_top_right = DVec2::new((all_nodes_bounding_box[1].x / 24. + 0.5).floor() * 24., (all_nodes_bounding_box[0].y / 24. + 0.5).floor() * 24.) + offset_from_top_right; + let export_top_right = DVec2::new(viewport_top_right.x.max(bounding_box_top_right.x), viewport_top_right.y.min(bounding_box_top_right.y)); + for input_index in 0..network.exports.len() { + import_export_ports.insert_input_port_at_center(input_index, export_top_right + DVec2::new(0., input_index as f64 * 24.)); + } + + let viewport_top_left = network_metadata + .persistent_metadata + .navigation_metadata + .node_graph_to_viewport + .inverse() + .transform_point2(rounded_network_edge_distance.imports_to_edge_distance); + + let offset_from_top_left = if network + .exports + .first() + .is_some_and(|export| export.as_node().is_some_and(|export_node| self.is_layer(&export_node, network_path))) + { + DVec2::new(-4. * GRID_SIZE as f64, -2. * GRID_SIZE as f64) + } else { + DVec2::new(-4. * GRID_SIZE as f64, 0.) + }; + + let bounding_box_top_left = DVec2::new((all_nodes_bounding_box[0].x / 24. + 0.5).floor() * 24., (all_nodes_bounding_box[0].y / 24. + 0.5).floor() * 24.) + offset_from_top_left; + let import_top_left = DVec2::new(viewport_top_left.x.min(bounding_box_top_left.x), viewport_top_left.y.min(bounding_box_top_left.y)); + for output_index in 0..self.number_of_displayed_imports(network_path) { + import_export_ports.insert_output_port_at_center(output_index, import_top_left + DVec2::new(0., output_index as f64 * 24.)); + } + let Some(network_metadata) = self.network_metadata_mut(network_path) else { + log::error!("Could not get current network in load_export_ports"); + return; + }; + + network_metadata.transient_metadata.import_export_ports = TransientMetadata::Loaded(import_export_ports); + } + + fn unload_import_export_ports(&mut self, network_path: &[NodeId]) { + let Some(network_metadata) = self.network_metadata_mut(network_path) else { + log::error!("Could not get nested network_metadata in unload_export_ports"); + return; + }; + network_metadata.transient_metadata.import_export_ports.unload(); + + // Always unload all wires connected to them as well + let number_of_imports = self.number_of_imports(network_path); + let Some(outward_wires) = self.outward_wires(network_path) else { + log::error!("Could not get outward wires in remove_import"); + return; + }; + let mut input_connectors = Vec::new(); + for import_index in 0..number_of_imports { + let Some(outward_wires_for_import) = outward_wires.get(&OutputConnector::Import(import_index)).cloned() else { + log::error!("Could not get outward wires for import in remove_import"); + return; + }; + input_connectors.extend(outward_wires_for_import); + } + let Some(network) = self.nested_network(network_path) else { + return; + }; + for export_index in 0..network.exports.len() { + input_connectors.push(InputConnector::Export(export_index)); + } + for input in &input_connectors { + self.unload_wire(input, network_path); + } + } + + pub fn modify_import_export(&mut self, network_path: &[NodeId]) -> Option<&ModifyImportExportClickTarget> { + let Some(network_metadata) = self.network_metadata(network_path) else { + log::error!("Could not get nested network_metadata in modify_import_export"); + return None; + }; + if !network_metadata.transient_metadata.modify_import_export.is_loaded() { + self.load_modify_import_export(network_path); + } + let Some(network_metadata) = self.network_metadata(network_path) else { + log::error!("Could not get nested network_metadata in modify_import_export"); + return None; + }; + let TransientMetadata::Loaded(click_targets) = &network_metadata.transient_metadata.modify_import_export else { + log::error!("could not load modify import export ports"); + return None; + }; + Some(click_targets) + } + + pub fn load_modify_import_export(&mut self, network_path: &[NodeId]) { + let Some(all_nodes_bounding_box) = self.all_nodes_bounding_box(network_path).cloned() else { + log::error!("Could not get all nodes bounding box in load_export_ports"); + return; + }; + let Some(rounded_network_edge_distance) = self.rounded_network_edge_distance(network_path).cloned() else { + log::error!("Could not get rounded_network_edge_distance in load_export_ports"); + return; + }; + let Some(network_metadata) = self.network_metadata(network_path) else { + log::error!("Could not get nested network_metadata in load_export_ports"); + return; + }; + let Some(network) = self.nested_network(network_path) else { + log::error!("Could not get current network in load_export_ports"); + return; + }; + + let mut reorder_imports_exports = Ports::new(); + let mut add_import_export = Ports::new(); + let mut remove_imports_exports = Ports::new(); + + if !network_path.is_empty() { + let viewport_top_right = network_metadata + .persistent_metadata + .navigation_metadata + .node_graph_to_viewport + .inverse() + .transform_point2(rounded_network_edge_distance.exports_to_edge_distance); + let offset_from_top_right = if network + .exports + .first() + .is_some_and(|export| export.as_node().is_some_and(|export_node| self.is_layer(&export_node, network_path))) + { + DVec2::new(2. * GRID_SIZE as f64, -2. * GRID_SIZE as f64) + } else { + DVec2::new(4. * GRID_SIZE as f64, 0.) + }; + + let bounding_box_top_right = DVec2::new((all_nodes_bounding_box[1].x / 24. + 0.5).floor() * 24., (all_nodes_bounding_box[0].y / 24. + 0.5).floor() * 24.) + offset_from_top_right; + let export_top_right: DVec2 = DVec2::new(viewport_top_right.x.max(bounding_box_top_right.x), viewport_top_right.y.min(bounding_box_top_right.y)); + let add_export_center = export_top_right + DVec2::new(0., network.exports.len() as f64 * 24.); + let add_export = ClickTarget::new_with_subpath( + Subpath::new_rounded_rect(add_export_center - DVec2::new(12., 12.), add_export_center + DVec2::new(12., 12.), [3.; 4]), + 0., + ); + add_import_export.insert_custom_input_port(0, add_export); + + let viewport_top_left = network_metadata + .persistent_metadata + .navigation_metadata + .node_graph_to_viewport + .inverse() + .transform_point2(rounded_network_edge_distance.imports_to_edge_distance); + + let offset_from_top_left = if network + .exports + .first() + .is_some_and(|export| export.as_node().is_some_and(|export_node| self.is_layer(&export_node, network_path))) + { + DVec2::new(-4. * GRID_SIZE as f64, -2. * GRID_SIZE as f64) + } else { + DVec2::new(-4. * GRID_SIZE as f64, 0.) + }; + + let bounding_box_top_left = DVec2::new((all_nodes_bounding_box[0].x / 24. + 0.5).floor() * 24., (all_nodes_bounding_box[0].y / 24. + 0.5).floor() * 24.) + offset_from_top_left; + let import_top_left = DVec2::new(viewport_top_left.x.min(bounding_box_top_left.x), viewport_top_left.y.min(bounding_box_top_left.y)); + let add_import_center = import_top_left + DVec2::new(0., self.number_of_displayed_imports(network_path) as f64 * 24.); + let add_import = ClickTarget::new_with_subpath( + Subpath::new_rounded_rect(add_import_center - DVec2::new(12., 12.), add_import_center + DVec2::new(12., 12.), [3.; 4]), + 0., + ); + add_import_export.insert_custom_output_port(0, add_import); + + let Some(import_exports) = self.import_export_ports(network_path) else { + log::error!("Could not get import_export_ports in load_modify_import_export"); + return; + }; + + for (import_index, import_click_target) in import_exports.output_ports() { + let Some(import_bounding_box) = import_click_target.bounding_box() else { + log::error!("Could not get export bounding box in load_modify_import_export"); + continue; + }; + let reorder_import_center = (import_bounding_box[0] + import_bounding_box[1]) / 2. + DVec2::new(-12., 0.); + let remove_import_center = reorder_import_center + DVec2::new(-12., 0.); + + let reorder_import = ClickTarget::new_with_subpath(Subpath::new_rect(reorder_import_center - DVec2::new(3., 4.), reorder_import_center + DVec2::new(3., 4.)), 0.); + let remove_import = ClickTarget::new_with_subpath(Subpath::new_rect(remove_import_center - DVec2::new(8., 8.), remove_import_center + DVec2::new(8., 8.)), 0.); + + reorder_imports_exports.insert_custom_output_port(*import_index, reorder_import); + remove_imports_exports.insert_custom_output_port(*import_index, remove_import); + } + + for (export_index, export_click_target) in import_exports.input_ports() { + let Some(export_bounding_box) = export_click_target.bounding_box() else { + log::error!("Could not get export bounding box in load_modify_import_export"); + continue; + }; + let reorder_export_center = (export_bounding_box[0] + export_bounding_box[1]) / 2. + DVec2::new(12., 0.); + let remove_export_center = reorder_export_center + DVec2::new(12., 0.); + + let reorder_export = ClickTarget::new_with_subpath(Subpath::new_rect(reorder_export_center - DVec2::new(3., 4.), reorder_export_center + DVec2::new(3., 4.)), 0.); + let remove_export = ClickTarget::new_with_subpath(Subpath::new_rect(remove_export_center - DVec2::new(8., 8.), remove_export_center + DVec2::new(8., 8.)), 0.); + + reorder_imports_exports.insert_custom_input_port(*export_index, reorder_export); + remove_imports_exports.insert_custom_input_port(*export_index, remove_export); + } + } + + let Some(network_metadata) = self.network_metadata_mut(network_path) else { + log::error!("Could not get current network in load_modify_import_export"); + return; + }; + + network_metadata.transient_metadata.modify_import_export = TransientMetadata::Loaded(ModifyImportExportClickTarget { + add_import_export, + remove_imports_exports, + reorder_imports_exports, + }); + } + + fn unload_modify_import_export(&mut self, network_path: &[NodeId]) { + let Some(network_metadata) = self.network_metadata_mut(network_path) else { + log::error!("Could not get nested network_metadata in unload_export_ports"); + return; + }; + network_metadata.transient_metadata.modify_import_export.unload(); + } + + pub fn rounded_network_edge_distance(&mut self, network_path: &[NodeId]) -> Option<&NetworkEdgeDistance> { + let Some(network_metadata) = self.network_metadata(network_path) else { + log::error!("Could not get nested network_metadata in rounded_network_edge_distance"); + return None; + }; + if !network_metadata.transient_metadata.rounded_network_edge_distance.is_loaded() { + self.load_rounded_network_edge_distance(network_path); + } + let Some(network_metadata) = self.network_metadata(network_path) else { + log::error!("Could not get nested network_metadata in rounded_network_edge_distance"); + return None; + }; + let TransientMetadata::Loaded(rounded_network_edge_distance) = &network_metadata.transient_metadata.rounded_network_edge_distance else { + log::error!("could not load import rounded_network_edge_distance"); + return None; + }; + Some(rounded_network_edge_distance) + } + + fn load_rounded_network_edge_distance(&mut self, network_path: &[NodeId]) { + let Some(network_metadata) = self.network_metadata_mut(network_path) else { + log::error!("Could not get nested network in set_grid_aligned_edges"); + return; + }; + // When setting the edges to be grid aligned, update the pixel offset to ensure the next pan starts from the snapped import/export position + let node_graph_to_viewport = network_metadata.persistent_metadata.navigation_metadata.node_graph_to_viewport; + // TODO: Eventually replace node graph top right with the footprint when trying to get the network edge distance + let node_graph_top_right = network_metadata.persistent_metadata.navigation_metadata.node_graph_top_right; + let target_exports_distance = node_graph_to_viewport.inverse().transform_point2(DVec2::new( + node_graph_top_right.x - EXPORTS_TO_RIGHT_EDGE_PIXEL_GAP as f64, + node_graph_top_right.y + EXPORTS_TO_TOP_EDGE_PIXEL_GAP as f64, + )); + + let target_imports_distance = node_graph_to_viewport + .inverse() + .transform_point2(DVec2::new(IMPORTS_TO_LEFT_EDGE_PIXEL_GAP as f64, IMPORTS_TO_TOP_EDGE_PIXEL_GAP as f64)); + + let rounded_exports_distance = DVec2::new((target_exports_distance.x / 24. + 0.5).floor() * 24., (target_exports_distance.y / 24. + 0.5).floor() * 24.); + let rounded_imports_distance = DVec2::new((target_imports_distance.x / 24. + 0.5).floor() * 24., (target_imports_distance.y / 24. + 0.5).floor() * 24.); + + let rounded_viewport_exports_distance = node_graph_to_viewport.transform_point2(rounded_exports_distance); + let rounded_viewport_imports_distance = node_graph_to_viewport.transform_point2(rounded_imports_distance); + + let network_edge_distance = NetworkEdgeDistance { + exports_to_edge_distance: rounded_viewport_exports_distance, + imports_to_edge_distance: rounded_viewport_imports_distance, + }; + let Some(network_metadata) = self.network_metadata_mut(network_path) else { + log::error!("Could not get current network in load_export_ports"); + return; + }; + network_metadata.transient_metadata.rounded_network_edge_distance = TransientMetadata::Loaded(network_edge_distance); + } + + fn unload_rounded_network_edge_distance(&mut self, network_path: &[NodeId]) { + let Some(network_metadata) = self.network_metadata_mut(network_path) else { + log::error!("Could not get nested network_metadata in unload_export_ports"); + return; + }; + network_metadata.transient_metadata.rounded_network_edge_distance.unload(); + } + + fn owned_nodes(&self, node_id: &NodeId, network_path: &[NodeId]) -> Option<&HashSet> { + let layer_node = self.node_metadata(node_id, network_path)?; + let NodeTypePersistentMetadata::Layer(LayerPersistentMetadata { owned_nodes, .. }) = &layer_node.persistent_metadata.node_type_metadata else { + return None; + }; + let TransientMetadata::Loaded(owned_nodes) = owned_nodes else { + return None; + }; + Some(owned_nodes) + } + + pub fn all_nodes_bounding_box(&mut self, network_path: &[NodeId]) -> Option<&[DVec2; 2]> { + let Some(network_metadata) = self.network_metadata(network_path) else { + log::error!("Could not get nested network_metadata in all_nodes_bounding_box"); + return None; + }; + + if !network_metadata.transient_metadata.all_nodes_bounding_box.is_loaded() { + self.load_all_nodes_bounding_box(network_path); + } + + let network_metadata = self.network_metadata(network_path)?; + + let TransientMetadata::Loaded(bounding_box) = &network_metadata.transient_metadata.all_nodes_bounding_box else { + log::error!("could not load all nodes bounding box"); + return None; + }; + + Some(bounding_box) + } + + pub fn load_all_nodes_bounding_box(&mut self, network_path: &[NodeId]) { + let Some(network_metadata) = self.network_metadata(network_path) else { + log::error!("Could not get nested network_metadata in load_all_nodes_bounding_box"); + return; + }; + let nodes = network_metadata.persistent_metadata.node_metadata.keys().copied().collect::>(); + + let all_nodes_bounding_box = nodes + .iter() + .filter_map(|node_id| { + self.node_click_targets(node_id, network_path) + .and_then(|transient_node_metadata| transient_node_metadata.node_click_target.bounding_box()) + }) + .reduce(Quad::combine_bounds) + .unwrap_or([DVec2::new(0., 0.), DVec2::new(0., 0.)]); + + let Some(network_metadata) = self.network_metadata_mut(network_path) else { return }; + network_metadata.transient_metadata.all_nodes_bounding_box = TransientMetadata::Loaded(all_nodes_bounding_box); + } + + pub fn unload_all_nodes_bounding_box(&mut self, network_path: &[NodeId]) { + let Some(network_metadata) = self.network_metadata_mut(network_path) else { + log::error!("Could not get nested network_metadata in unload_all_nodes_bounding_box"); + return; + }; + network_metadata.transient_metadata.all_nodes_bounding_box.unload(); + self.unload_import_export_ports(network_path); + } + + pub fn outward_wires(&mut self, network_path: &[NodeId]) -> Option<&HashMap>> { + let Some(network_metadata) = self.network_metadata(network_path) else { + log::error!("Could not get nested network_metadata in outward_wires"); + return None; + }; + + if !network_metadata.transient_metadata.outward_wires.is_loaded() { + self.load_outward_wires(network_path); + } + + let network_metadata = self.network_metadata(network_path)?; + + let TransientMetadata::Loaded(outward_wires) = &network_metadata.transient_metadata.outward_wires else { + log::error!("could not load outward wires"); + return None; + }; + + Some(outward_wires) + } + + fn load_outward_wires(&mut self, network_path: &[NodeId]) { + let mut outward_wires = HashMap::new(); + let Some(network) = self.nested_network(network_path) else { + log::error!("Could not get nested network in load_outward_wires"); + return; + }; + // Initialize all output connectors for nodes + for (node_id, _) in network.nodes.iter() { + let number_of_outputs = self.number_of_outputs(node_id, network_path); + for output_index in 0..number_of_outputs { + outward_wires.insert(OutputConnector::node(*node_id, output_index), Vec::new()); + } + } + // Initialize output connectors for the import node + for import_index in 0..self.number_of_imports(network_path) { + outward_wires.insert(OutputConnector::Import(import_index), Vec::new()); + } + // Collect wires between all nodes and the Imports + for (current_node_id, node) in network.nodes.iter() { + for (input_index, input) in node.inputs.iter().enumerate() { + if let NodeInput::Node { node_id, output_index, .. } = input { + // If this errors then there is an input to a node that does not exist + let outward_wires_entry = outward_wires.get_mut(&OutputConnector::node(*node_id, *output_index)).unwrap_or_else(|| { + panic!( + "Output connector {:?} should be initialized for each node output from a node", + OutputConnector::node(*node_id, *output_index) + ) + }); + outward_wires_entry.push(InputConnector::node(*current_node_id, input_index)); + } else if let NodeInput::Network { import_index, .. } = input { + let outward_wires_entry = outward_wires + .get_mut(&OutputConnector::Import(*import_index)) + .unwrap_or_else(|| panic!("Output connector {:?} should be initialized for each import from a node", OutputConnector::Import(*import_index))); + outward_wires_entry.push(InputConnector::node(*current_node_id, input_index)); + } + } + } + for (export_index, export) in network.exports.iter().enumerate() { + if let NodeInput::Node { node_id, output_index, .. } = export { + let outward_wires_entry = outward_wires.get_mut(&OutputConnector::node(*node_id, *output_index)).unwrap_or_else(|| { + panic!( + "Output connector {:?} should be initialized for each node input from exports", + OutputConnector::node(*node_id, *output_index) + ) + }); + outward_wires_entry.push(InputConnector::Export(export_index)); + } else if let NodeInput::Network { import_index, .. } = export { + let outward_wires_entry = outward_wires + .get_mut(&OutputConnector::Import(*import_index)) + .unwrap_or_else(|| panic!("Output connector {:?} should be initialized between imports and exports", OutputConnector::Import(*import_index))); + outward_wires_entry.push(InputConnector::Export(export_index)); + } + } + + let Some(network_metadata) = self.network_metadata_mut(network_path) else { return }; + + network_metadata.transient_metadata.outward_wires = TransientMetadata::Loaded(outward_wires); + } + + fn unload_outward_wires(&mut self, network_path: &[NodeId]) { + let Some(network_metadata) = self.network_metadata_mut(network_path) else { + log::error!("Could not get nested network_metadata in unload_outward_wires"); + return; + }; + network_metadata.transient_metadata.outward_wires.unload(); + } + + pub fn layer_width(&mut self, node_id: &NodeId, network_path: &[NodeId]) -> Option { + let Some(node_metadata) = self.node_metadata(node_id, network_path) else { + log::error!("Could not get nested node_metadata in layer_width"); + return None; + }; + if !node_metadata.persistent_metadata.is_layer() { + log::error!("Cannot get layer width for non layer node {node_id} in network {network_path:?}"); + return None; + } + + let layer_width_loaded = if let NodeTypeTransientMetadata::Layer(layer_metadata) = &node_metadata.transient_metadata.node_type_metadata { + layer_metadata.layer_width.is_loaded() + } else { + false + }; + if !layer_width_loaded { + self.load_layer_width(node_id, network_path); + } + + let node_metadata = self.node_metadata(node_id, network_path)?; + let NodeTypeTransientMetadata::Layer(layer_metadata) = &node_metadata.transient_metadata.node_type_metadata else { + log::error!("Transient metadata should be layer metadata when getting layer width"); + return None; + }; + let TransientMetadata::Loaded(layer_width) = layer_metadata.layer_width else { + log::error!("Transient metadata was not loaded when getting layer width"); + return None; + }; + + Some(layer_width) + } + + pub fn load_layer_width(&mut self, node_id: &NodeId, network_path: &[NodeId]) { + let left_thumbnail_padding = GRID_SIZE as f64 / 2.; + let thumbnail_width = 3. * GRID_SIZE as f64; + let gap_width = 8.; + let text_width = self.text_width(node_id, network_path).unwrap_or_else(|| { + log::error!("Could not get text width for node {node_id}"); + 0. + }); + + let grip_padding = 4.; + let grip_width = 8.; + let icon_overhang_width = GRID_SIZE as f64 / 2.; + + let layer_width_pixels = left_thumbnail_padding + thumbnail_width + gap_width + text_width + grip_padding + grip_width + icon_overhang_width; + let layer_width = ((layer_width_pixels / 24.).ceil() as u32).max(8); + + let Some(node_metadata) = self.node_metadata_mut(node_id, network_path) else { + log::error!("Could not get nested node_metadata in load_layer_width"); + return; + }; + + // Ensure layer width is not loaded for a non layer node + if node_metadata.persistent_metadata.is_layer() { + if let NodeTypeTransientMetadata::Layer(layer_metadata) = &mut node_metadata.transient_metadata.node_type_metadata { + layer_metadata.layer_width = TransientMetadata::Loaded(layer_width); + } else { + // Set the entire transient node type metadata to be a layer, in case it was previously a node + node_metadata.transient_metadata.node_type_metadata = NodeTypeTransientMetadata::Layer(LayerTransientMetadata { + layer_width: TransientMetadata::Loaded(layer_width), + }); + } + } else { + log::warn!("Tried loading layer width for non layer node"); + } + } + + /// Unloads layer width if the node is a layer + pub fn try_unload_layer_width(&mut self, node_id: &NodeId, network_path: &[NodeId]) { + let is_layer = self.is_layer(node_id, network_path); + + let Some(node_metadata) = self.node_metadata_mut(node_id, network_path) else { + return; + }; + + // If the node is a layer, then the width and click targets need to be recalculated + if is_layer { + if let NodeTypeTransientMetadata::Layer(layer_metadata) = &mut node_metadata.transient_metadata.node_type_metadata { + layer_metadata.layer_width.unload(); + } + } + } + + pub fn get_input_center(&mut self, input: &InputConnector, network_path: &[NodeId]) -> Option { + let (ports, index) = match input { + InputConnector::Node { node_id, input_index } => { + let node_click_target = self.node_click_targets(node_id, network_path)?; + (&node_click_target.port_click_targets, input_index) + } + InputConnector::Export(export_index) => { + let ports = self.import_export_ports(network_path)?; + (ports, export_index) + } + }; + ports + .input_ports + .iter() + .find_map(|(input_index, click_target)| if index == input_index { click_target.bounding_box_center() } else { None }) + } + + pub fn get_output_center(&mut self, output: &OutputConnector, network_path: &[NodeId]) -> Option { + let (ports, index) = match output { + OutputConnector::Node { node_id, output_index } => { + let node_click_target = self.node_click_targets(node_id, network_path)?; + (&node_click_target.port_click_targets, output_index) + } + OutputConnector::Import(import_index) => { + let ports = self.import_export_ports(network_path)?; + (ports, import_index) + } + }; + ports + .output_ports + .iter() + .find_map(|(input_index, click_target)| if index == input_index { click_target.bounding_box_center() } else { None }) + } + + pub fn newly_loaded_input_wire(&mut self, input: &InputConnector, graph_wire_style: GraphWireStyle, network_path: &[NodeId]) -> Option { + if !self.wire_is_loaded(input, network_path) { + self.load_wire(input, graph_wire_style, network_path); + } else { + return None; + } + + let wire = match input { + InputConnector::Node { node_id, input_index } => { + let input_metadata = self.transient_input_metadata(node_id, *input_index, network_path)?; + let TransientMetadata::Loaded(wire) = &input_metadata.wire else { + log::error!("Could not load wire for input: {:?}", input); + return None; + }; + wire.clone() + } + InputConnector::Export(export_index) => { + let network_metadata = self.network_metadata(network_path)?; + let Some(TransientMetadata::Loaded(wire)) = network_metadata.transient_metadata.wires.get(*export_index) else { + log::error!("Could not load wire for input: {:?}", input); + return None; + }; + wire.clone() + } + }; + Some(wire) + } + + pub fn wire_is_loaded(&mut self, input: &InputConnector, network_path: &[NodeId]) -> bool { + match input { + InputConnector::Node { node_id, input_index } => { + let Some(input_metadata) = self.transient_input_metadata(node_id, *input_index, network_path) else { + log::error!("Input metadata should always exist for input"); + return false; + }; + input_metadata.wire.is_loaded() + } + InputConnector::Export(export_index) => { + let Some(network_metadata) = self.network_metadata(network_path) else { + return false; + }; + match network_metadata.transient_metadata.wires.get(*export_index) { + Some(wire) => wire.is_loaded(), + None => false, + } + } + } + } + + fn load_wire(&mut self, input: &InputConnector, graph_wire_style: GraphWireStyle, network_path: &[NodeId]) { + let dashed = match self.previewing(network_path) { + Previewing::Yes { .. } => match input { + InputConnector::Node { .. } => false, + InputConnector::Export(export_index) => *export_index == 0, + }, + Previewing::No => false, + }; + let Some(wire) = self.wire_path_from_input(input, graph_wire_style, dashed, network_path) else { + return; + }; + match input { + InputConnector::Node { node_id, input_index } => { + let Some(node_metadata) = self.node_metadata_mut(node_id, network_path) else { return }; + let Some(input_metadata) = node_metadata.persistent_metadata.input_metadata.get_mut(*input_index) else { + log::error!("Node metadata must exist on node: {input:?}"); + return; + }; + let wire_update = WirePathUpdate { + id: *node_id, + input_index: *input_index, + wire_path_update: Some(wire), + }; + input_metadata.transient_metadata.wire = TransientMetadata::Loaded(wire_update); + } + InputConnector::Export(export_index) => { + let Some(network_metadata) = self.network_metadata_mut(network_path) else { return }; + if *export_index >= network_metadata.transient_metadata.wires.len() { + network_metadata.transient_metadata.wires.resize(export_index + 1, TransientMetadata::Unloaded); + } + let Some(input_metadata) = network_metadata.transient_metadata.wires.get_mut(*export_index) else { + return; + }; + let wire_update = WirePathUpdate { + id: NodeId(u64::MAX), + input_index: *export_index, + wire_path_update: Some(wire), + }; + *input_metadata = TransientMetadata::Loaded(wire_update); + } + } + } + + pub fn all_input_connectors(&self, network_path: &[NodeId]) -> Vec { + let mut input_connectors = Vec::new(); + let Some(network) = self.nested_network(network_path) else { + log::error!("Could not get nested network in all_input_connectors"); + return Vec::new(); + }; + for export_index in 0..network.exports.len() { + input_connectors.push(InputConnector::Export(export_index)); + } + for (node_id, node) in &network.nodes { + for input_index in 0..node.inputs.len() { + input_connectors.push(InputConnector::node(*node_id, input_index)); + } + } + input_connectors + } + + pub fn node_graph_input_connectors(&self, network_path: &[NodeId]) -> Vec { + self.all_input_connectors(network_path) + .into_iter() + .filter(|input| self.input_from_connector(input, network_path).is_some_and(|input| input.is_exposed())) + .collect() + } + + /// Maps to the frontend representation of a wire start. Includes disconnected value wire inputs. + pub fn node_graph_wire_inputs(&self, network_path: &[NodeId]) -> Vec<(NodeId, usize)> { + self.node_graph_input_connectors(network_path) + .iter() + .map(|input| match input { + InputConnector::Node { node_id, input_index } => (*node_id, *input_index), + InputConnector::Export(export_index) => (NodeId(u64::MAX), *export_index), + }) + .chain(std::iter::once((NodeId(u64::MAX), usize::MAX))) + .collect() + } + + fn unload_wires_for_node(&mut self, node_id: &NodeId, network_path: &[NodeId]) { + let number_of_outputs = self.number_of_outputs(node_id, network_path); + let Some(outward_wires) = self.outward_wires(network_path) else { + log::error!("Could not get outward wires in reorder_export"); + return; + }; + let mut input_connectors = Vec::new(); + for output_index in 0..number_of_outputs { + let Some(inputs) = outward_wires.get(&OutputConnector::node(*node_id, output_index)) else { + continue; + }; + input_connectors.extend(inputs.clone()) + } + for input_index in 0..self.number_of_inputs(node_id, network_path) { + input_connectors.push(InputConnector::node(*node_id, input_index)); + } + for input in input_connectors { + self.unload_wire(&input, network_path); + } + } + + pub fn unload_wire(&mut self, input: &InputConnector, network_path: &[NodeId]) { + match input { + InputConnector::Node { node_id, input_index } => { + let Some(node_metadata) = self.node_metadata_mut(node_id, network_path) else { + return; + }; + let Some(input_metadata) = node_metadata.persistent_metadata.input_metadata.get_mut(*input_index) else { + log::error!("Node metadata must exist on node: {input:?}"); + return; + }; + input_metadata.transient_metadata.wire = TransientMetadata::Unloaded; + } + InputConnector::Export(export_index) => { + let Some(network_metadata) = self.network_metadata_mut(network_path) else { + return; + }; + if *export_index >= network_metadata.transient_metadata.wires.len() { + network_metadata.transient_metadata.wires.resize(export_index + 1, TransientMetadata::Unloaded); + } + let Some(input_metadata) = network_metadata.transient_metadata.wires.get_mut(*export_index) else { + return; + }; + *input_metadata = TransientMetadata::Unloaded; + } + } + } + + /// When previewing, there may be a second path to the root node. + pub fn wire_to_root(&mut self, graph_wire_style: GraphWireStyle, network_path: &[NodeId]) -> Option { + let input = InputConnector::Export(0); + let current_export = self.upstream_output_connector(&input, network_path)?; + + let root_node = match self.previewing(network_path) { + Previewing::Yes { root_node_to_restore } => root_node_to_restore, + Previewing::No => None, + }?; + + if Some(root_node.node_id) == current_export.node_id() { + return None; + } + let Some(input_position) = self.get_input_center(&input, network_path) else { + log::error!("Could not get dom rect for wire end in root node: {:?}", input); + return None; + }; + let upstream_output = OutputConnector::node(root_node.node_id, root_node.output_index); + let Some(output_position) = self.get_output_center(&upstream_output, network_path) else { + log::error!("Could not get dom rect for wire start in root node: {:?}", upstream_output); + return None; + }; + let vertical_end = input.node_id().is_some_and(|node_id| self.is_layer(&node_id, network_path) && input.input_index() == 0); + let vertical_start: bool = upstream_output.node_id().is_some_and(|node_id| self.is_layer(&node_id, network_path)); + let thick = vertical_end && vertical_start; + let vector_wire = build_vector_wire(output_position, input_position, vertical_start, vertical_end, graph_wire_style); + + let mut path_string = String::new(); + let _ = vector_wire.subpath_to_svg(&mut path_string, DAffine2::IDENTITY); + let data_type = FrontendGraphDataType::from_type(&self.input_type(&input, network_path).0); + let wire_path_update = Some(WirePath { + path_string, + data_type, + thick, + dashed: false, + }); + + Some(WirePathUpdate { + id: NodeId(u64::MAX), + input_index: usize::MAX, + wire_path_update, + }) + } + + /// Returns the vector subpath and a boolean of whether the wire should be thick. + pub fn vector_wire_from_input(&mut self, input: &InputConnector, wire_style: GraphWireStyle, network_path: &[NodeId]) -> Option<(Subpath, bool)> { + let Some(input_position) = self.get_input_center(input, network_path) else { + log::error!("Could not get dom rect for wire end: {:?}", input); + return None; + }; + // An upstream output could not be found, so the wire does not exist, but it should still be loaded as as empty vector + let Some(upstream_output) = self.upstream_output_connector(input, network_path) else { + return Some((Subpath::from_anchors(std::iter::empty(), false), false)); + }; + let Some(output_position) = self.get_output_center(&upstream_output, network_path) else { + log::error!("Could not get dom rect for wire start: {:?}", upstream_output); + return None; + }; + let vertical_end = input.node_id().is_some_and(|node_id| self.is_layer(&node_id, network_path) && input.input_index() == 0); + let vertical_start = upstream_output.node_id().is_some_and(|node_id| self.is_layer(&node_id, network_path)); + let thick = vertical_end && vertical_start; + Some((build_vector_wire(output_position, input_position, vertical_start, vertical_end, wire_style), thick)) + } + + pub fn wire_path_from_input(&mut self, input: &InputConnector, graph_wire_style: GraphWireStyle, dashed: bool, network_path: &[NodeId]) -> Option { + let (vector_wire, thick) = self.vector_wire_from_input(input, graph_wire_style, network_path)?; + let mut path_string = String::new(); + let _ = vector_wire.subpath_to_svg(&mut path_string, DAffine2::IDENTITY); + let data_type = FrontendGraphDataType::from_type(&self.input_type(input, network_path).0); + Some(WirePath { + path_string, + data_type, + thick, + dashed, + }) + } + + pub fn node_click_targets(&mut self, node_id: &NodeId, network_path: &[NodeId]) -> Option<&DocumentNodeClickTargets> { + self.try_load_node_click_targets(node_id, network_path); + self.try_get_node_click_targets(node_id, network_path) + } + + fn try_load_node_click_targets(&mut self, node_id: &NodeId, network_path: &[NodeId]) { + let Some(node_metadata) = self.node_metadata(node_id, network_path) else { + log::error!("Could not get nested node_metadata in node_click_targets"); + return; + }; + if !node_metadata.transient_metadata.click_targets.is_loaded() { + self.load_node_click_targets(node_id, network_path) + }; + } + + fn try_get_node_click_targets(&self, node_id: &NodeId, network_path: &[NodeId]) -> Option<&DocumentNodeClickTargets> { + let node_metadata = self.node_metadata(node_id, network_path)?; + let TransientMetadata::Loaded(click_target) = &node_metadata.transient_metadata.click_targets else { + log::error!("Could not load node type metadata when getting click targets"); + return None; + }; + Some(click_target) + } + + pub fn load_node_click_targets(&mut self, node_id: &NodeId, network_path: &[NodeId]) { + let Some(node_position) = self.position_from_downstream_node(node_id, network_path) else { + log::error!("Could not get node position in load_node_click_targets for node {node_id}"); + return; + }; + let Some(node_metadata) = self.node_metadata(node_id, network_path) else { + log::error!("Could not get nested node_metadata in load_node_click_targets"); + return; + }; + let Some(document_node) = self.document_node(node_id, network_path) else { + log::error!("Could not get document node in load_node_click_targets"); + return; + }; + + let node_top_left = node_position.as_dvec2() * 24.; + let mut port_click_targets = Ports::new(); + let document_node_click_targets = if !node_metadata.persistent_metadata.is_layer() { + // Create input/output click targets + let mut input_row_count = 0; + for (input_index, input) in document_node.inputs.iter().enumerate() { + if input.is_exposed() { + port_click_targets.insert_node_input(input_index, input_row_count, node_top_left); + } + // Primary input row is always displayed, even if the input is not exposed + if input_index == 0 || input.is_exposed() { + input_row_count += 1; + } + } + + let number_of_outputs = match &document_node.implementation { + DocumentNodeImplementation::Network(network) => network.exports.len(), + _ => 1, + }; + // If the node does not have a primary output, shift all ports down a row + let mut output_row_count = if !node_metadata.persistent_metadata.has_primary_output { 1 } else { 0 }; + for output_index in 0..number_of_outputs { + port_click_targets.insert_node_output(output_index, output_row_count, node_top_left); + output_row_count += 1; + } + + let height = input_row_count.max(output_row_count).max(1) as u32 * crate::consts::GRID_SIZE; + let width = 5 * crate::consts::GRID_SIZE; + let node_click_target_top_left = node_top_left + DVec2::new(0., 12.); + let node_click_target_bottom_right = node_click_target_top_left + DVec2::new(width as f64, height as f64); + + let radius = 3.; + let subpath = bezier_rs::Subpath::new_rounded_rect(node_click_target_top_left, node_click_target_bottom_right, [radius; 4]); + let node_click_target = ClickTarget::new_with_subpath(subpath, 0.); + + DocumentNodeClickTargets { + node_click_target, + port_click_targets, + node_type_metadata: NodeTypeClickTargets::Node, + } + } else { + // Layer inputs + port_click_targets.insert_layer_input(0, node_top_left); + if document_node.inputs.iter().filter(|input| input.is_exposed()).count() > 1 { + port_click_targets.insert_layer_input(1, node_top_left); + } + port_click_targets.insert_layer_output(node_top_left); + + let layer_width_cells = self.layer_width(node_id, network_path).unwrap_or_else(|| { + log::error!("Could not get layer width in load_node_click_targets"); + 0 + }); + let width = layer_width_cells * crate::consts::GRID_SIZE; + let height = 2 * crate::consts::GRID_SIZE; + + // Update visibility button click target + let visibility_offset = node_top_left + DVec2::new(width as f64, 24.); + let subpath = Subpath::new_rounded_rect(DVec2::new(-12., -12.) + visibility_offset, DVec2::new(12., 12.) + visibility_offset, [3.; 4]); + let visibility_click_target = ClickTarget::new_with_subpath(subpath, 0.); + + // Update grip button click target, which is positioned to the left of the left most icon + let grip_offset_right_edge = node_top_left + DVec2::new(width as f64 - (GRID_SIZE as f64) / 2., 24.); + let subpath = Subpath::new_rounded_rect(DVec2::new(-8., -12.) + grip_offset_right_edge, DVec2::new(0., 12.) + grip_offset_right_edge, [0.; 4]); + let grip_click_target = ClickTarget::new_with_subpath(subpath, 0.); + + // Create layer click target, which is contains the layer and the chain background + let chain_width_grid_spaces = self.chain_width(node_id, network_path); + + let node_bottom_right = node_top_left + DVec2::new(width as f64, height as f64); + let chain_top_left = node_top_left - DVec2::new((chain_width_grid_spaces * crate::consts::GRID_SIZE) as f64, 0.); + let radius = 10.; + let subpath = bezier_rs::Subpath::new_rounded_rect(chain_top_left, node_bottom_right, [radius; 4]); + let node_click_target = ClickTarget::new_with_subpath(subpath, 0.); + + DocumentNodeClickTargets { + node_click_target, + port_click_targets, + node_type_metadata: NodeTypeClickTargets::Layer(LayerClickTargets { + visibility_click_target, + grip_click_target, + }), + } + }; + + let Some(node_metadata) = self.node_metadata_mut(node_id, network_path) else { + log::error!("Could not get nested node_metadata in load_node_click_targets"); + return; + }; + node_metadata.transient_metadata.click_targets = TransientMetadata::Loaded(document_node_click_targets); + } + + pub fn node_bounding_box(&mut self, node_id: &NodeId, network_path: &[NodeId]) -> Option<[DVec2; 2]> { + self.node_click_targets(node_id, network_path) + .and_then(|transient_node_metadata| transient_node_metadata.node_click_target.bounding_box()) + } + + pub fn try_get_node_bounding_box(&self, node_id: &NodeId, network_path: &[NodeId]) -> Option<[DVec2; 2]> { + self.try_get_node_click_targets(node_id, network_path) + .and_then(|transient_node_metadata| transient_node_metadata.node_click_target.bounding_box()) + } + + pub fn try_load_all_node_click_targets(&mut self, network_path: &[NodeId]) { + let Some(network) = self.nested_network(network_path) else { + log::error!("Could not get network in load_all_node_click_targets"); + return; + }; + for node_id in network.nodes.keys().cloned().collect::>() { + self.try_load_node_click_targets(&node_id, network_path); + } + } + + /// Get the top left position in node graph coordinates for a node by recursively iterating downstream through cached positions, which means the iteration can be broken once a known position is reached. + pub fn position_from_downstream_node(&mut self, node_id: &NodeId, network_path: &[NodeId]) -> Option { + let Some(node_metadata) = self.node_metadata(node_id, network_path) else { + log::error!("Could not get nested node_metadata in position_from_downstream_node"); + return None; + }; + match &node_metadata.persistent_metadata.node_type_metadata { + NodeTypePersistentMetadata::Layer(layer_metadata) => { + match layer_metadata.position { + LayerPosition::Absolute(position) => Some(position), + LayerPosition::Stack(y_offset) => { + let Some(downstream_node_connectors) = self + .outward_wires(network_path) + .and_then(|outward_wires| outward_wires.get(&OutputConnector::node(*node_id, 0))) + .cloned() + else { + log::error!("Could not get downstream node in position_from_downstream_node"); + return None; + }; + let downstream_connector = downstream_node_connectors + .iter() + .find_map(|input_connector| input_connector.node_id().map(|node_id| (node_id, input_connector.input_index()))); + + let Some((downstream_node_id, _)) = downstream_connector else { + log::error!("Could not get downstream node input connector for node {node_id}"); + return None; + }; + // Get the height of the node to ensure nodes do not overlap + let Some(downstream_node_height) = self.height_from_click_target(&downstream_node_id, network_path) else { + log::error!("Could not get click target height in position_from_downstream_node"); + return None; + }; + self.position(&downstream_node_id, network_path) + .map(|position| position + IVec2::new(0, 1 + downstream_node_height as i32 + y_offset as i32)) + } + } + } + NodeTypePersistentMetadata::Node(node_metadata) => { + match node_metadata.position { + NodePosition::Absolute(position) => Some(position), + NodePosition::Chain => { + // Iterate through primary flow to find the first Layer + let mut current_node_id = *node_id; + let mut node_distance_from_layer = 1; + loop { + // TODO: Use root node to restore if previewing + let Some(downstream_node_connectors) = self + .outward_wires(network_path) + .and_then(|outward_wires| outward_wires.get(&OutputConnector::node(current_node_id, 0))) + .cloned() + else { + log::error!("Could not get downstream node for node {node_id} with Position::Chain"); + return None; + }; + let Some(downstream_node_id) = downstream_node_connectors.iter().find_map(|input_connector| { + if let InputConnector::Node { node_id, input_index } = input_connector { + let downstream_input_index = if self.is_layer(node_id, network_path) { 1 } else { 0 }; + if *input_index == downstream_input_index { Some(node_id) } else { None } + } else { + None + } + }) else { + log::error!("Could not get downstream node input connector with input index 1 for node with Position::Chain"); + return None; + }; + let Some(downstream_node_metadata) = self.network_metadata(network_path)?.persistent_metadata.node_metadata.get(downstream_node_id) else { + log::error!("Downstream node metadata not found in node_metadata for node with Position::Chain"); + return None; + }; + if downstream_node_metadata.persistent_metadata.is_layer() { + // Get the position of the layer + let layer_position = self.position(downstream_node_id, network_path)?; + return Some(layer_position + IVec2::new(-node_distance_from_layer * 7, 0)); + } + node_distance_from_layer += 1; + current_node_id = *downstream_node_id; + } + } + } + } + } + } + + pub fn unload_node_click_targets(&mut self, node_id: &NodeId, network_path: &[NodeId]) { + let Some(node_metadata) = self.node_metadata_mut(node_id, network_path) else { + log::error!("Could not get nested node_metadata in unload_node_click_target"); + return; + }; + node_metadata.transient_metadata.click_targets.unload(); + self.unload_wires_for_node(node_id, network_path); + } + + pub fn unload_upstream_node_click_targets(&mut self, node_ids: Vec, network_path: &[NodeId]) { + let upstream_nodes = self.upstream_flow_back_from_nodes(node_ids, network_path, FlowType::UpstreamFlow).collect::>(); + + for upstream_id in &upstream_nodes { + self.unload_node_click_targets(upstream_id, network_path); + } + } + + pub fn unload_all_nodes_click_targets(&mut self, network_path: &[NodeId]) { + let Some(network) = self.nested_network(network_path) else { + log::error!("Could not get nested network in unload_all_nodes_click_targets"); + return; + }; + let upstream_nodes = network.nodes.keys().cloned().collect::>(); + + for upstream_id in &upstream_nodes { + self.unload_node_click_targets(upstream_id, network_path); + } + } +} + +// Helper functions for mutable getters +impl NodeNetworkInterface { + pub fn upstream_chain_nodes(&mut self, network_path: &[NodeId]) -> Vec { + let Some(selected_nodes) = self.selected_nodes_in_nested_network(network_path) else { + log::error!("Could not get selected nodes in upstream_chain_nodes"); + return Vec::new(); + }; + let mut all_selected_nodes = selected_nodes.selected_nodes().cloned().collect::>(); + for selected_node_id in selected_nodes.selected_nodes() { + if self.is_layer(selected_node_id, network_path) { + let unique_upstream_chain = self + .upstream_flow_back_from_nodes(vec![*selected_node_id], network_path, FlowType::HorizontalFlow) + .skip(1) + .take_while(|node_id| self.is_chain(node_id, network_path)) + .filter(|upstream_node| all_selected_nodes.iter().all(|new_selected_node| new_selected_node != upstream_node)) + .collect::>(); + all_selected_nodes.extend(unique_upstream_chain); + } + } + all_selected_nodes + } + + pub fn collect_frontend_click_targets(&mut self, network_path: &[NodeId]) -> FrontendClickTargets { + let mut all_node_click_targets = Vec::new(); + let mut port_click_targets = Vec::new(); + let mut icon_click_targets = Vec::new(); + let Some(network_metadata) = self.network_metadata(network_path) else { + log::error!("Could not get nested network_metadata in collect_frontend_click_targets"); + return FrontendClickTargets::default(); + }; + network_metadata.persistent_metadata.node_metadata.keys().copied().collect::>().into_iter().for_each(|node_id| { + if let (Some(import_export_click_targets), Some(node_click_targets)) = (self.import_export_ports(network_path).cloned(), self.node_click_targets(&node_id, network_path)) { + let mut node_path = String::new(); + + if let ClickTargetType::Subpath(subpath) = node_click_targets.node_click_target.target_type() { + let _ = subpath.subpath_to_svg(&mut node_path, DAffine2::IDENTITY); + } + all_node_click_targets.push((node_id, node_path)); + for port in node_click_targets.port_click_targets.click_targets().chain(import_export_click_targets.click_targets()) { + if let ClickTargetType::Subpath(subpath) = port.target_type() { + let mut port_path = String::new(); + let _ = subpath.subpath_to_svg(&mut port_path, DAffine2::IDENTITY); + port_click_targets.push(port_path); + } + } + if let NodeTypeClickTargets::Layer(layer_metadata) = &node_click_targets.node_type_metadata { + if let ClickTargetType::Subpath(subpath) = layer_metadata.visibility_click_target.target_type() { + let mut port_path = String::new(); + let _ = subpath.subpath_to_svg(&mut port_path, DAffine2::IDENTITY); + icon_click_targets.push(port_path); + } + + if let ClickTargetType::Subpath(subpath) = layer_metadata.grip_click_target.target_type() { + let mut port_path = String::new(); + let _ = subpath.subpath_to_svg(&mut port_path, DAffine2::IDENTITY); + icon_click_targets.push(port_path); + } + } + } + }); + let mut layer_click_targets = Vec::new(); + let mut node_click_targets = Vec::new(); + all_node_click_targets.into_iter().for_each(|(node_id, path)| { + if self.is_layer(&node_id, network_path) { + layer_click_targets.push(path); + } else { + node_click_targets.push(path); + } + }); + + let bounds = self.all_nodes_bounding_box(network_path).cloned().unwrap_or([DVec2::ZERO, DVec2::ZERO]); + let rect = bezier_rs::Subpath::::new_rect(bounds[0], bounds[1]); + let mut all_nodes_bounding_box = String::new(); + let _ = rect.subpath_to_svg(&mut all_nodes_bounding_box, DAffine2::IDENTITY); + + let Some(rounded_network_edge_distance) = self.rounded_network_edge_distance(network_path).cloned() else { + log::error!("Could not get rounded_network_edge_distance in collect_frontend_click_targets"); + return FrontendClickTargets::default(); + }; + let Some(network_metadata) = self.network_metadata(network_path) else { + log::error!("Could not get nested network_metadata in collect_frontend_click_targets"); + return FrontendClickTargets::default(); + }; + let import_exports_viewport_top_left = rounded_network_edge_distance.imports_to_edge_distance; + let import_exports_viewport_bottom_right = rounded_network_edge_distance.exports_to_edge_distance; + + let node_graph_top_left = network_metadata + .persistent_metadata + .navigation_metadata + .node_graph_to_viewport + .inverse() + .transform_point2(import_exports_viewport_top_left); + let node_graph_bottom_right = network_metadata + .persistent_metadata + .navigation_metadata + .node_graph_to_viewport + .inverse() + .transform_point2(import_exports_viewport_bottom_right); + + let import_exports_target = bezier_rs::Subpath::::new_rect(node_graph_top_left, node_graph_bottom_right); + let mut import_exports_bounding_box = String::new(); + let _ = import_exports_target.subpath_to_svg(&mut import_exports_bounding_box, DAffine2::IDENTITY); + + let mut modify_import_export = Vec::new(); + if let Some(modify_import_export_click_targets) = self.modify_import_export(network_path) { + for click_target in modify_import_export_click_targets + .add_import_export + .click_targets() + .chain(modify_import_export_click_targets.remove_imports_exports.click_targets()) + .chain(modify_import_export_click_targets.reorder_imports_exports.click_targets()) + { + if let ClickTargetType::Subpath(subpath) = click_target.target_type() { + let mut remove_string = String::new(); + let _ = subpath.subpath_to_svg(&mut remove_string, DAffine2::IDENTITY); + modify_import_export.push(remove_string); + } + } + } + FrontendClickTargets { + node_click_targets, + layer_click_targets, + port_click_targets, + icon_click_targets, + all_nodes_bounding_box, + import_exports_bounding_box, + modify_import_export, + } + } + + pub fn set_document_to_viewport_transform(&mut self, transform: DAffine2) { + self.document_metadata.document_to_viewport = transform; + } + + pub fn is_eligible_to_be_layer(&mut self, node_id: &NodeId, network_path: &[NodeId]) -> bool { + let Some(node) = self.document_node(node_id, network_path) else { + log::error!("Could not get node {node_id} in is_eligible_to_be_layer"); + return false; + }; + let input_count = node.inputs.iter().take(2).filter(|input| input.is_exposed()).count(); + let parameters_hidden = node.inputs.iter().skip(2).all(|input| !input.is_exposed()); + let output_count = self.number_of_outputs(node_id, network_path); + + self.node_metadata(node_id, network_path) + .is_some_and(|node_metadata| node_metadata.persistent_metadata.has_primary_output) + && output_count == 1 + && (input_count <= 2) + && parameters_hidden + } + + pub fn node_graph_ptz(&self, network_path: &[NodeId]) -> Option<&PTZ> { + let Some(network_metadata) = self.network_metadata(network_path) else { + log::error!("Could not get nested network_metadata in node_graph_ptz_mut"); + return None; + }; + Some(&network_metadata.persistent_metadata.navigation_metadata.node_graph_ptz) + } + + pub fn node_graph_ptz_mut(&mut self, network_path: &[NodeId]) -> Option<&mut PTZ> { + let Some(network_metadata) = self.network_metadata_mut(network_path) else { + log::error!("Could not get nested network_metadata in node_graph_ptz_mut"); + return None; + }; + Some(&mut network_metadata.persistent_metadata.navigation_metadata.node_graph_ptz) + } + + // TODO: Optimize getting click target intersections from click by using a spacial data structure like a quadtree instead of linear search + /// Click target getter methods + pub fn node_from_click(&mut self, click: DVec2, network_path: &[NodeId]) -> Option { + let Some(network_metadata) = self.network_metadata(network_path) else { + log::error!("Could not get nested network_metadata in node_from_click"); + return None; + }; + let Some(network) = self.nested_network(network_path) else { + log::error!("Could not get nested network in node_from_click"); + return None; + }; + + let point = network_metadata.persistent_metadata.navigation_metadata.node_graph_to_viewport.inverse().transform_point2(click); + let nodes = network.nodes.keys().copied().collect::>(); + let clicked_nodes = nodes + .iter() + .filter(|node_id| { + self.node_click_targets(node_id, network_path) + .is_some_and(|transient_node_metadata| transient_node_metadata.node_click_target.intersect_point_no_stroke(point)) + }) + .cloned() + .collect::>(); + // Since nodes are placed on top of layer chains, find the first non layer node that was clicked, and if there way no non layer nodes clicked, then find the first layer node that was clicked + clicked_nodes + .iter() + .find_map(|node_id| { + let Some(node_metadata) = self.network_metadata(network_path)?.persistent_metadata.node_metadata.get(node_id) else { + log::error!("Could not get node_metadata for node {node_id}"); + return None; + }; + if !node_metadata.persistent_metadata.is_layer() { Some(*node_id) } else { None } + }) + .or_else(|| clicked_nodes.into_iter().next()) + } + + pub fn layer_click_target_from_click(&mut self, click: DVec2, click_target_type: LayerClickTargetTypes, network_path: &[NodeId]) -> Option { + let Some(network_metadata) = self.network_metadata(network_path) else { + log::error!("Could not get nested network_metadata in visibility_from_click"); + return None; + }; + let Some(network) = self.nested_network(network_path) else { + log::error!("Could not get nested network in visibility_from_click"); + return None; + }; + + let point = network_metadata.persistent_metadata.navigation_metadata.node_graph_to_viewport.inverse().transform_point2(click); + let node_ids: Vec<_> = network.nodes.keys().copied().collect(); + + node_ids + .iter() + .filter_map(|node_id| { + self.node_click_targets(node_id, network_path).and_then(|transient_node_metadata| { + if let NodeTypeClickTargets::Layer(layer) = &transient_node_metadata.node_type_metadata { + match click_target_type { + LayerClickTargetTypes::Visibility => layer.visibility_click_target.intersect_point_no_stroke(point).then_some(*node_id), + LayerClickTargetTypes::Grip => layer.grip_click_target.intersect_point_no_stroke(point).then_some(*node_id), + } + } else { + None + } + }) + }) + .next() + } + + pub fn input_connector_from_click(&mut self, click: DVec2, network_path: &[NodeId]) -> Option { + let Some(network_metadata) = self.network_metadata(network_path) else { + log::error!("Could not get nested network_metadata in input_connector_from_click"); + return None; + }; + let Some(network) = self.nested_network(network_path) else { + log::error!("Could not get nested network in input_connector_from_click"); + return None; + }; + + let point = network_metadata.persistent_metadata.navigation_metadata.node_graph_to_viewport.inverse().transform_point2(click); + network + .nodes + .keys() + .copied() + .collect::>() + .iter() + .filter_map(|node_id| { + self.node_click_targets(node_id, network_path) + .and_then(|transient_node_metadata| { + transient_node_metadata + .port_click_targets + .clicked_input_port_from_point(point) + .map(|port| InputConnector::node(*node_id, port)) + }) + .or_else(|| { + self.import_export_ports(network_path) + .and_then(|import_export_ports| import_export_ports.clicked_input_port_from_point(point).map(InputConnector::Export)) + }) + }) + .next() + } + + pub fn output_connector_from_click(&mut self, click: DVec2, network_path: &[NodeId]) -> Option { + let Some(network_metadata) = self.network_metadata(network_path) else { + log::error!("Could not get nested network_metadata in output_connector_from_click"); + return None; + }; + let Some(network) = self.nested_network(network_path) else { + log::error!("Could not get nested network in output_connector_from_click"); + return None; + }; + + let point = network_metadata.persistent_metadata.navigation_metadata.node_graph_to_viewport.inverse().transform_point2(click); + let nodes = network.nodes.keys().copied().collect::>(); + nodes + .iter() + .filter_map(|node_id| { + self.node_click_targets(node_id, network_path) + .and_then(|transient_node_metadata| { + transient_node_metadata + .port_click_targets + .clicked_output_port_from_point(point) + .map(|output_index| OutputConnector::node(*node_id, output_index)) + }) + .or_else(|| { + self.import_export_ports(network_path) + .and_then(|import_export_ports| import_export_ports.clicked_output_port_from_point(point).map(OutputConnector::Import)) + }) + }) + .next() + } + + pub fn input_position(&mut self, input_connector: &InputConnector, network_path: &[NodeId]) -> Option { + match input_connector { + InputConnector::Node { node_id, input_index } => { + // Get the displayed index from the input index + let Some(node) = self.document_node(node_id, network_path) else { + log::error!("Could not get node in input_position"); + return None; + }; + let mut displayed_index = 0; + for i in 0..*input_index { + if node.inputs[i].is_exposed() { + displayed_index += 1; + } + } + self.node_click_targets(node_id, network_path) + .and_then(|transient_node_metadata| transient_node_metadata.port_click_targets.input_port_position(displayed_index)) + } + InputConnector::Export(export_index) => self + .import_export_ports(network_path) + .and_then(|import_export_ports| import_export_ports.input_port_position(*export_index)), + } + } + + pub fn output_position(&mut self, output_connector: &OutputConnector, network_path: &[NodeId]) -> Option { + match output_connector { + OutputConnector::Node { node_id, output_index } => self + .node_click_targets(node_id, network_path) + .and_then(|transient_node_metadata| transient_node_metadata.port_click_targets.output_port_position(*output_index)), + OutputConnector::Import(import_index) => self + .import_export_ports(network_path) + .and_then(|import_export_ports| import_export_ports.output_port_position(*import_index)), + } + } + + /// Get the combined bounding box of the click targets of the selected nodes in the node graph in viewport space + pub fn selected_nodes_bounding_box_viewport(&mut self, network_path: &[NodeId]) -> Option<[DVec2; 2]> { + // Always get the bounding box for nodes in the currently viewed network + let Some(network_metadata) = self.network_metadata(network_path) else { + log::error!("Could not get nested network_metadata in selected_nodes_bounding_box_viewport"); + return None; + }; + let node_graph_to_viewport = network_metadata.persistent_metadata.navigation_metadata.node_graph_to_viewport; + self.selected_nodes_bounding_box(network_path) + .map(|[a, b]| [node_graph_to_viewport.transform_point2(a), node_graph_to_viewport.transform_point2(b)]) + } + + /// Get the combined bounding box of the click targets of the selected nodes in the node graph in layer space + pub fn selected_nodes_bounding_box(&mut self, network_path: &[NodeId]) -> Option<[DVec2; 2]> { + let Some(selected_nodes) = self.selected_nodes_in_nested_network(network_path) else { + log::error!("Could not get selected nodes in selected_nodes_bounding_box_viewport"); + return None; + }; + selected_nodes + .selected_nodes() + .cloned() + .collect::>() + .iter() + .filter_map(|node_id| { + self.node_click_targets(node_id, network_path) + .and_then(|transient_node_metadata| transient_node_metadata.node_click_target.bounding_box()) + }) + .reduce(graphene_std::renderer::Quad::combine_bounds) + } + + /// Gets the bounding box in viewport coordinates for each node in the node graph + pub fn graph_bounds_viewport_space(&mut self, network_path: &[NodeId]) -> Option<[DVec2; 2]> { + let bounds = *self.all_nodes_bounding_box(network_path)?; + let Some(network_metadata) = self.network_metadata(network_path) else { + log::error!("Could not get nested network_metadata in graph_bounds_viewport_space"); + return None; + }; + + let bounding_box_subpath = bezier_rs::Subpath::::new_rect(bounds[0], bounds[1]); + bounding_box_subpath.bounding_box_with_transform(network_metadata.persistent_metadata.navigation_metadata.node_graph_to_viewport) + } + + pub fn collect_layer_widths(&mut self, network_path: &[NodeId]) -> (HashMap, HashMap, HashMap) { + let Some(network_metadata) = self.network_metadata(network_path) else { + log::error!("Could not get nested network_metadata in collect_layer_widths"); + return (HashMap::new(), HashMap::new(), HashMap::new()); + }; + let nodes = network_metadata + .persistent_metadata + .node_metadata + .iter() + .filter_map(|(node_id, _)| if self.is_layer(node_id, network_path) { Some(*node_id) } else { None }) + .collect::>(); + let layer_widths = nodes + .iter() + .filter_map(|node_id| self.layer_width(node_id, network_path).map(|layer_width| (*node_id, layer_width))) + .collect::>(); + let chain_widths = nodes.iter().map(|node_id| (*node_id, self.chain_width(node_id, network_path))).collect::>(); + let has_left_input_wire = nodes + .iter() + .map(|node_id| { + ( + *node_id, + !self + .upstream_flow_back_from_nodes(vec![*node_id], network_path, FlowType::HorizontalFlow) + .skip(1) + .all(|node_id| self.is_chain(&node_id, network_path)), + ) + }) + .collect::>(); + + (layer_widths, chain_widths, has_left_input_wire) + } + + pub fn compute_modified_vector(&self, layer: LayerNodeIdentifier) -> Option { + let graph_layer = graph_modification_utils::NodeGraphLayer::new(layer, self); + + if let Some(vector_data) = graph_layer.upstream_node_id_from_name("Path").and_then(|node| self.document_metadata.vector_modify.get(&node)) { + let mut modified = vector_data.clone(); + if let Some(TaggedValue::VectorModification(modification)) = graph_layer.find_input("Path", 1) { + modification.apply(&mut modified); + } + return Some(modified); + } + + self.document_metadata + .click_targets + .get(&layer) + .map(|click| click.iter().map(ClickTarget::target_type)) + .map(|target_types| VectorData::from_target_types(target_types, true)) + } + + /// Loads the structure of layer nodes from a node graph. + pub fn load_structure(&mut self) { + self.document_metadata.structure = HashMap::from_iter([(LayerNodeIdentifier::ROOT_PARENT, NodeRelations::default())]); + + // Only load structure if there is a root node + let Some(root_node) = self.root_node(&[]) else { return }; + + let Some(first_root_layer) = self + .upstream_flow_back_from_nodes(vec![root_node.node_id], &[], FlowType::PrimaryFlow) + .find_map(|node_id| if self.is_layer(&node_id, &[]) { Some(LayerNodeIdentifier::new(node_id, self, &[])) } else { None }) + else { + return; + }; + // Should refer to output node + let mut awaiting_horizontal_flow = vec![(first_root_layer.to_node(), first_root_layer)]; + let mut awaiting_primary_flow = vec![]; + + while let Some((horizontal_root_node_id, mut parent_layer_node)) = awaiting_horizontal_flow.pop() { + let horizontal_flow_iter = self.upstream_flow_back_from_nodes(vec![horizontal_root_node_id], &[], FlowType::HorizontalFlow); + let mut children = Vec::new(); + + // Special handling for the root layer, since it should not be skipped + if horizontal_root_node_id == first_root_layer.to_node() { + for current_node_id in horizontal_flow_iter { + if self.is_layer(¤t_node_id, &[]) { + let current_layer_node = LayerNodeIdentifier::new(current_node_id, self, &[]); + if !self.document_metadata.structure.contains_key(¤t_layer_node) { + if current_node_id == first_root_layer.to_node() { + awaiting_primary_flow.push((current_node_id, LayerNodeIdentifier::ROOT_PARENT)); + children.push((LayerNodeIdentifier::ROOT_PARENT, current_layer_node)); + } else { + awaiting_primary_flow.push((current_node_id, parent_layer_node)); + children.push((parent_layer_node, current_layer_node)); + } + parent_layer_node = current_layer_node; + } + } + } + } else { + // Skip the horizontal_root_node_id node + for current_node_id in horizontal_flow_iter.skip(1) { + if self.is_layer(¤t_node_id, &[]) { + let current_layer_node = LayerNodeIdentifier::new(current_node_id, self, &[]); + if !self.document_metadata.structure.contains_key(¤t_layer_node) { + awaiting_primary_flow.push((current_node_id, parent_layer_node)); + children.push((parent_layer_node, current_layer_node)); + parent_layer_node = current_layer_node; + } + } + } + } + + for (parent, child) in children { + parent.push_child(&mut self.document_metadata, child); + } + + while let Some((primary_root_node_id, parent_layer_node)) = awaiting_primary_flow.pop() { + let primary_flow_iter = self.upstream_flow_back_from_nodes(vec![primary_root_node_id], &[], FlowType::PrimaryFlow); + // Skip the primary_root_node_id node + let mut children = Vec::new(); + for current_node_id in primary_flow_iter.skip(1) { + if self.is_layer(¤t_node_id, &[]) { + // Create a new layer for the top of each stack, and add it as a child to the previous parent + let current_layer_node = LayerNodeIdentifier::new(current_node_id, self, &[]); + if !self.document_metadata.structure.contains_key(¤t_layer_node) { + children.push(current_layer_node); + + // The layer nodes for the horizontal flow is itself + awaiting_horizontal_flow.push((current_node_id, current_layer_node)); + } + } + } + for child in children { + parent_layer_node.push_child(&mut self.document_metadata, child); + } + } + } + + let nodes: HashSet = self.document_network().nodes.keys().cloned().collect::>(); + + self.document_metadata.upstream_footprints.retain(|node, _| nodes.contains(node)); + self.document_metadata.local_transforms.retain(|node, _| nodes.contains(node)); + self.document_metadata.vector_modify.retain(|node, _| nodes.contains(node)); + self.document_metadata.click_targets.retain(|layer, _| self.document_metadata.structure.contains_key(layer)); + } + + /// Update the cached transforms of the layers + pub fn update_transforms(&mut self, upstream_footprints: HashMap, local_transforms: HashMap) { + self.document_metadata.upstream_footprints = upstream_footprints; + self.document_metadata.local_transforms = local_transforms; + } + + /// Update the cached click targets of the layers + pub fn update_click_targets(&mut self, new_click_targets: HashMap>) { + self.document_metadata.click_targets = new_click_targets; + } + + /// Update the cached clip targets of the layers + pub fn update_clip_targets(&mut self, new_clip_targets: HashSet) { + self.document_metadata.clip_targets = new_clip_targets; + } + + /// Update the vector modify of the layers + pub fn update_vector_modify(&mut self, new_vector_modify: HashMap) { + self.document_metadata.vector_modify = new_vector_modify; + } +} + +// Public mutable methods +impl NodeNetworkInterface { + pub fn copy_all_navigation_metadata(&mut self, other_interface: &NodeNetworkInterface) { + let mut stack = vec![vec![]]; + while let Some(path) = stack.pop() { + let Some(self_network_metadata) = self.network_metadata_mut(&path) else { + continue; + }; + if let Some(other_network_metadata) = other_interface.network_metadata(&path) { + self_network_metadata.persistent_metadata.navigation_metadata = other_network_metadata.persistent_metadata.navigation_metadata.clone(); + } + + stack.extend(self_network_metadata.persistent_metadata.node_metadata.keys().map(|node_id| { + let mut current_path = path.clone(); + current_path.push(*node_id); + current_path + })); + } + } + + pub fn set_reference(&mut self, node_id: &NodeId, network_path: &[NodeId], reference: Option) { + let Some(node_metadata) = self.node_metadata_mut(node_id, network_path) else { + log::error!("Could not get node_metadata in set_reference"); + return; + }; + node_metadata.persistent_metadata.reference = reference; + } + + pub fn set_transform(&mut self, transform: DAffine2, network_path: &[NodeId]) { + let Some(network_metadata) = self.network_metadata_mut(network_path) else { + log::error!("Could not get nested network in set_transform"); + return; + }; + network_metadata.persistent_metadata.navigation_metadata.node_graph_to_viewport = transform; + self.unload_import_export_ports(network_path); + self.unload_modify_import_export(network_path); + } + + // This should be run whenever the pan ends, a zoom occurs, or the network is opened + pub fn set_grid_aligned_edges(&mut self, node_graph_top_right: DVec2, network_path: &[NodeId]) { + let Some(network_metadata) = self.network_metadata_mut(network_path) else { + log::error!("Could not get nested network_metadata in set_grid_aligned_edges"); + return; + }; + network_metadata.persistent_metadata.navigation_metadata.node_graph_top_right = node_graph_top_right; + self.unload_rounded_network_edge_distance(network_path); + self.unload_import_export_ports(network_path); + self.unload_modify_import_export(network_path); + } + + pub fn vector_modify(&mut self, node_id: &NodeId, modification_type: VectorModificationType) { + let Some(node) = self.network_mut(&[]).unwrap().nodes.get_mut(node_id) else { + log::error!("Could not get node in vector_modification"); + return; + }; + { + let mut value = node.inputs.get_mut(1).and_then(|input| input.as_value_mut()); + let Some(TaggedValue::VectorModification(modification)) = value.as_deref_mut() else { + panic!("Path node does not have modification input"); + }; + + modification.modify(&modification_type); + } + self.transaction_modified(); + } + + /// Inserts a new export at insert index. If the insert index is -1 it is inserted at the end. The output_name is used by the encapsulating node. + pub fn add_export(&mut self, default_value: TaggedValue, insert_index: isize, output_name: &str, network_path: &[NodeId]) { + let Some(network) = self.network_mut(network_path) else { + log::error!("Could not get nested network in add_export"); + return; + }; + + let input = NodeInput::value(default_value, true); + if insert_index == -1 { + network.exports.push(input); + } else { + network.exports.insert(insert_index as usize, input); + } + + self.transaction_modified(); + + let mut encapsulating_path = network_path.to_vec(); + // Set the parent node (if it exists) to be a non layer if it is no longer eligible to be a layer + if let Some(parent_id) = encapsulating_path.pop() { + if !self.is_eligible_to_be_layer(&parent_id, &encapsulating_path) && self.is_layer(&parent_id, &encapsulating_path) { + self.set_to_node_or_layer(&parent_id, &encapsulating_path, false); + } + }; + + // There will not be an encapsulating node if the network is the document network + if let Some(encapsulating_node_metadata) = self.encapsulating_node_metadata_mut(network_path) { + if insert_index == -1 { + encapsulating_node_metadata.persistent_metadata.output_names.push(output_name.to_string()); + } else { + encapsulating_node_metadata.persistent_metadata.output_names.insert(insert_index as usize, output_name.to_string()); + } + // Clear the reference to the nodes definition + encapsulating_node_metadata.persistent_metadata.reference = None; + }; + + // Update the export ports and outward wires for the current network + self.unload_import_export_ports(network_path); + self.unload_modify_import_export(network_path); + self.unload_outward_wires(network_path); + + // Update the outward wires and bounding box for all nodes in the encapsulating network + if let Some(encapsulating_network_metadata) = self.encapsulating_network_metadata_mut(network_path) { + encapsulating_network_metadata.transient_metadata.outward_wires.unload(); + encapsulating_network_metadata.transient_metadata.all_nodes_bounding_box.unload(); + } + + // Update the click targets for the encapsulating node, if it exists. There is no encapsulating node if the network is the document network + let mut path = network_path.to_vec(); + if let Some(encapsulating_node) = path.pop() { + self.unload_node_click_targets(&encapsulating_node, &path); + } + + // If the export is inserted as the first input or second input, and the parent network is the document_network, then it may have affected the document metadata structure + if network_path.len() == 1 && (insert_index == 0 || insert_index == 1) { + self.load_structure(); + } + } + + /// Inserts a new input at insert index. If the insert index is -1 it is inserted at the end. The output_name is used by the encapsulating node. + pub fn add_import(&mut self, default_value: TaggedValue, exposed: bool, insert_index: isize, input_name: &str, input_description: &str, network_path: &[NodeId]) { + let mut encapsulating_network_path = network_path.to_vec(); + let Some(node_id) = encapsulating_network_path.pop() else { + log::error!("Cannot add import for document network"); + return; + }; + + let Some(network) = self.network_mut(&encapsulating_network_path) else { + log::error!("Could not get nested network in insert_input"); + return; + }; + let Some(node) = network.nodes.get_mut(&node_id) else { + log::error!("Could not get node in insert_input"); + return; + }; + + let input = NodeInput::value(default_value, exposed); + if insert_index == -1 { + node.inputs.push(input); + } else { + node.inputs.insert(insert_index as usize, input); + } + + self.transaction_modified(); + + // Set the node to be a non layer if it is no longer eligible to be a layer + if !self.is_eligible_to_be_layer(&node_id, &encapsulating_network_path) && self.is_layer(&node_id, &encapsulating_network_path) { + self.set_to_node_or_layer(&node_id, &encapsulating_network_path, false); + } + + let Some(node_metadata) = self.node_metadata_mut(&node_id, &encapsulating_network_path) else { + log::error!("Could not get node_metadata in insert_input"); + return; + }; + let new_input = (input_name, input_description).into(); + if insert_index == -1 { + node_metadata.persistent_metadata.input_metadata.push(new_input); + } else { + node_metadata.persistent_metadata.input_metadata.insert(insert_index as usize, new_input); + } + + // Clear the reference to the nodes definition + node_metadata.persistent_metadata.reference = None; + + // Update the metadata for the encapsulating node + self.unload_node_click_targets(&node_id, &encapsulating_network_path); + self.unload_all_nodes_bounding_box(&encapsulating_network_path); + if encapsulating_network_path.is_empty() && (insert_index == 0 || insert_index == 1) { + self.load_structure(); + } + + // Unload the metadata for the nested network + self.unload_outward_wires(network_path); + self.unload_import_export_ports(network_path); + self.unload_modify_import_export(network_path); + } + + // First disconnects the export, then removes it + pub fn remove_export(&mut self, export_index: usize, network_path: &[NodeId]) { + let mut encapsulating_network_path = network_path.to_vec(); + let Some(parent_id) = encapsulating_network_path.pop() else { + log::error!("Cannot remove export for document network"); + return; + }; + + // Disconnect the removed export, and handle connections to the node which had its output removed + self.disconnect_input(&InputConnector::Export(export_index), network_path); + let number_of_outputs = self.number_of_outputs(&parent_id, &encapsulating_network_path); + for shifted_export in export_index..number_of_outputs { + let Some(encapsulating_outward_wires) = self.outward_wires(&encapsulating_network_path) else { + log::error!("Could not get outward wires in remove_export"); + return; + }; + let Some(downstream_connections_for_shifted_export) = encapsulating_outward_wires.get(&OutputConnector::node(parent_id, shifted_export)).cloned() else { + log::error!("Could not get downstream connections for shifted export in remove_export"); + return; + }; + for downstream_connection in downstream_connections_for_shifted_export { + self.disconnect_input(&downstream_connection, &encapsulating_network_path); + if shifted_export != export_index { + self.create_wire(&OutputConnector::node(parent_id, shifted_export - 1), &downstream_connection, &encapsulating_network_path); + } + } + } + + let Some(network) = self.network_mut(network_path) else { + log::error!("Could not get nested network in add_export"); + return; + }; + network.exports.remove(export_index); + + self.transaction_modified(); + + let Some(encapsulating_node_metadata) = self.node_metadata_mut(&parent_id, &encapsulating_network_path) else { + log::error!("Could not get encapsulating node metadata in remove_export"); + return; + }; + encapsulating_node_metadata.persistent_metadata.output_names.remove(export_index); + encapsulating_node_metadata.persistent_metadata.reference = None; + + // Update the metadata for the encapsulating node + self.unload_outward_wires(&encapsulating_network_path); + self.unload_node_click_targets(&parent_id, &encapsulating_network_path); + self.unload_all_nodes_bounding_box(&encapsulating_network_path); + if !self.is_eligible_to_be_layer(&parent_id, &encapsulating_network_path) && self.is_layer(&parent_id, &encapsulating_network_path) { + self.set_to_node_or_layer(&parent_id, &encapsulating_network_path, false); + } + if encapsulating_network_path.is_empty() { + self.load_structure(); + } + + // Unload the metadata for the nested network + self.unload_outward_wires(network_path); + self.unload_import_export_ports(network_path); + self.unload_modify_import_export(network_path); + } + + // First disconnects the import, then removes it + pub fn remove_import(&mut self, import_index: usize, network_path: &[NodeId]) { + let mut encapsulating_network_path = network_path.to_vec(); + let Some(parent_id) = encapsulating_network_path.pop() else { + log::error!("Cannot remove export for document network"); + return; + }; + + let number_of_inputs = self.number_of_inputs(&parent_id, &encapsulating_network_path); + let Some(outward_wires) = self.outward_wires(network_path) else { + log::error!("Could not get outward wires in remove_import"); + return; + }; + let Some(outward_wires_for_import) = outward_wires.get(&OutputConnector::Import(import_index)).cloned() else { + log::error!("Could not get outward wires for import in remove_import"); + return; + }; + let mut new_import_mapping = Vec::new(); + for i in (import_index + 1)..number_of_inputs { + let Some(outward_wires_for_import) = outward_wires.get(&OutputConnector::Import(i)).cloned() else { + log::error!("Could not get outward wires for import in remove_import"); + return; + }; + for upstream_input_wire in outward_wires_for_import { + new_import_mapping.push((OutputConnector::Import(i - 1), upstream_input_wire)); + } + } + + // Disconnect all upstream connections + for outward_wire in outward_wires_for_import { + self.disconnect_input(&outward_wire, network_path); + } + // Shift inputs connected to to imports at a higher index down one + for (output_connector, input_wire) in new_import_mapping { + self.create_wire(&output_connector, &input_wire, network_path); + } + + let Some(network) = self.network_mut(&encapsulating_network_path) else { + log::error!("Could not get parent node in remove_import"); + return; + }; + let Some(node) = network.nodes.get_mut(&parent_id) else { + log::error!("Could not get node in remove_import"); + return; + }; + + node.inputs.remove(import_index); + + self.transaction_modified(); + + // There will not be an encapsulating node if the network is the document network + let Some(encapsulating_node_metadata) = self.node_metadata_mut(&parent_id, &encapsulating_network_path) else { + log::error!("Could not get encapsulating node metadata in remove_export"); + return; + }; + encapsulating_node_metadata.persistent_metadata.input_metadata.remove(import_index); + encapsulating_node_metadata.persistent_metadata.reference = None; + + // Update the metadata for the encapsulating node + self.unload_outward_wires(&encapsulating_network_path); + self.unload_node_click_targets(&parent_id, &encapsulating_network_path); + self.unload_all_nodes_bounding_box(&encapsulating_network_path); + if !self.is_eligible_to_be_layer(&parent_id, &encapsulating_network_path) && self.is_layer(&parent_id, &encapsulating_network_path) { + self.set_to_node_or_layer(&parent_id, &encapsulating_network_path, false); + } + if encapsulating_network_path.is_empty() { + self.load_structure(); + } + + // Unload the metadata for the nested network + self.unload_outward_wires(network_path); + self.unload_import_export_ports(network_path); + self.unload_modify_import_export(network_path); + } + + /// The end index is before the export is removed, so moving to the end is the length of the current exports + pub fn reorder_export(&mut self, start_index: usize, mut end_index: usize, network_path: &[NodeId]) { + let mut encapsulating_network_path = network_path.to_vec(); + let Some(parent_id) = encapsulating_network_path.pop() else { + log::error!("Could not reorder export for document network"); + return; + }; + + let Some(network) = self.network_mut(network_path) else { + log::error!("Could not get nested network in reorder_export"); + return; + }; + if end_index > start_index { + end_index -= 1; + } + let export = network.exports.remove(start_index); + network.exports.insert(end_index, export); + + self.transaction_modified(); + + let Some(encapsulating_node_metadata) = self.node_metadata_mut(&parent_id, &encapsulating_network_path) else { + log::error!("Could not get encapsulating network_metadata in reorder_export"); + return; + }; + + let name = encapsulating_node_metadata.persistent_metadata.output_names.remove(start_index); + encapsulating_node_metadata.persistent_metadata.output_names.insert(end_index, name); + encapsulating_node_metadata.persistent_metadata.reference = None; + + // Update the metadata for the encapsulating network + self.unload_outward_wires(&encapsulating_network_path); + self.unload_stack_dependents(&encapsulating_network_path); + + // Node input at the start index is now at the end index + let Some(move_to_end_index) = self + .outward_wires(&encapsulating_network_path) + .and_then(|outward_wires| outward_wires.get(&OutputConnector::node(parent_id, start_index))) + .cloned() + else { + log::error!("Could not get outward wires in reorder_export"); + return; + }; + // Node inputs above the start index should be shifted down one + let last_output_index = self.number_of_outputs(&parent_id, &encapsulating_network_path) - 1; + for shift_output_down in (start_index + 1)..=last_output_index { + let Some(outward_wires) = self + .outward_wires(&encapsulating_network_path) + .and_then(|outward_wires| outward_wires.get(&OutputConnector::node(parent_id, shift_output_down))) + .cloned() + else { + log::error!("Could not get outward wires in reorder_export"); + return; + }; + for downstream_connection in &outward_wires { + self.disconnect_input(downstream_connection, &encapsulating_network_path); + self.create_wire(&OutputConnector::node(parent_id, shift_output_down - 1), downstream_connection, &encapsulating_network_path); + } + } + // Node inputs at or above the end index should be shifted up one + for shift_output_up in (end_index..last_output_index).rev() { + let Some(outward_wires) = self + .outward_wires(&encapsulating_network_path) + .and_then(|outward_wires| outward_wires.get(&OutputConnector::node(parent_id, shift_output_up))) + .cloned() + else { + log::error!("Could not get outward wires in reorder_export"); + return; + }; + for downstream_connection in &outward_wires { + self.disconnect_input(downstream_connection, &encapsulating_network_path); + self.create_wire(&OutputConnector::node(parent_id, shift_output_up + 1), downstream_connection, &encapsulating_network_path); + } + } + + // Move the connections to the moved export after all other ones have been shifted + for downstream_connection in &move_to_end_index { + self.disconnect_input(downstream_connection, &encapsulating_network_path); + self.create_wire(&OutputConnector::node(parent_id, end_index), downstream_connection, &encapsulating_network_path); + } + + // Update the metadata for the current network + self.unload_outward_wires(network_path); + self.unload_import_export_ports(network_path); + self.unload_modify_import_export(network_path); + self.unload_stack_dependents(network_path); + } + + /// The end index is before the import is removed, so moving to the end is the length of the current imports + pub fn reorder_import(&mut self, start_index: usize, mut end_index: usize, network_path: &[NodeId]) { + let mut encapsulating_network_path = network_path.to_vec(); + let Some(parent_id) = encapsulating_network_path.pop() else { + log::error!("Could not reorder import for document network"); + return; + }; + + let Some(encapsulating_network) = self.network_mut(&encapsulating_network_path) else { + log::error!("Could not get nested network in reorder_import"); + return; + }; + let Some(encapsulating_node) = encapsulating_network.nodes.get_mut(&parent_id) else { + log::error!("Could not get encapsulating node in reorder_import"); + return; + }; + + if end_index > start_index { + end_index -= 1; + } + let import = encapsulating_node.inputs.remove(start_index); + encapsulating_node.inputs.insert(end_index, import); + + self.transaction_modified(); + + let Some(encapsulating_node_metadata) = self.node_metadata_mut(&parent_id, &encapsulating_network_path) else { + log::error!("Could not get encapsulating network_metadata in reorder_import"); + return; + }; + + let properties_row = encapsulating_node_metadata.persistent_metadata.input_metadata.remove(start_index); + encapsulating_node_metadata.persistent_metadata.input_metadata.insert(end_index, properties_row); + encapsulating_node_metadata.persistent_metadata.reference = None; + + // Update the metadata for the outer network + self.unload_outward_wires(&encapsulating_network_path); + self.unload_stack_dependents(&encapsulating_network_path); + + // Node input at the start index is now at the end index + let Some(move_to_end_index) = self + .outward_wires(network_path) + .and_then(|outward_wires| outward_wires.get(&OutputConnector::Import(start_index))) + .cloned() + else { + log::error!("Could not get outward wires in reorder_import"); + return; + }; + // Node inputs above the start index should be shifted down one + let last_import_index = self.number_of_imports(network_path) - 1; + for shift_output_down in (start_index + 1)..=last_import_index { + let Some(outward_wires) = self + .outward_wires(network_path) + .and_then(|outward_wires| outward_wires.get(&OutputConnector::Import(shift_output_down))) + .cloned() + else { + log::error!("Could not get outward wires in reorder_import"); + return; + }; + for downstream_connection in &outward_wires { + self.disconnect_input(downstream_connection, network_path); + self.create_wire(&OutputConnector::Import(shift_output_down - 1), downstream_connection, network_path); + } + } + // Node inputs at or above the end index should be shifted up one + for shift_output_up in (end_index..last_import_index).rev() { + let Some(outward_wires) = self + .outward_wires(network_path) + .and_then(|outward_wires| outward_wires.get(&OutputConnector::Import(shift_output_up))) + .cloned() + else { + log::error!("Could not get outward wires in reorder_import"); + return; + }; + for downstream_connection in &outward_wires { + self.disconnect_input(downstream_connection, network_path); + self.create_wire(&OutputConnector::Import(shift_output_up + 1), downstream_connection, network_path); + } + } + + // Move the connections to the moved export after all other ones have been shifted + for downstream_connection in &move_to_end_index { + self.disconnect_input(downstream_connection, network_path); + self.create_wire(&OutputConnector::Import(end_index), downstream_connection, network_path); + } + + // Update the metadata for the current network + self.unload_outward_wires(network_path); + self.unload_import_export_ports(network_path); + self.unload_modify_import_export(network_path); + self.unload_stack_dependents(network_path); + } + + /// Replaces the implementation and corresponding metadata. + pub fn replace_implementation(&mut self, node_id: &NodeId, network_path: &[NodeId], new_template: &mut NodeTemplate) { + let Some(network) = self.network_mut(network_path) else { + log::error!("Could not get nested network in set_implementation"); + return; + }; + let Some(node) = network.nodes.get_mut(node_id) else { + log::error!("Could not get node in set_implementation"); + return; + }; + let new_implementation = std::mem::take(&mut new_template.document_node.implementation); + let _ = std::mem::replace(&mut node.implementation, new_implementation); + let Some(metadata) = self.node_metadata_mut(node_id, network_path) else { + log::error!("Could not get metadata in set_implementation"); + return; + }; + let new_metadata = std::mem::take(&mut new_template.persistent_node_metadata.network_metadata); + let _ = std::mem::replace(&mut metadata.persistent_metadata.network_metadata, new_metadata); + } + + /// Replaces the inputs and corresponding metadata. + pub fn replace_inputs(&mut self, node_id: &NodeId, network_path: &[NodeId], new_template: &mut NodeTemplate) -> Option> { + let Some(network) = self.network_mut(network_path) else { + log::error!("Could not get nested network in set_implementation"); + return None; + }; + let Some(node) = network.nodes.get_mut(node_id) else { + log::error!("Could not get node in set_implementation"); + return None; + }; + let new_inputs = std::mem::take(&mut new_template.document_node.inputs); + let old_inputs = std::mem::replace(&mut node.inputs, new_inputs); + let Some(metadata) = self.node_metadata_mut(node_id, network_path) else { + log::error!("Could not get metadata in set_implementation"); + return None; + }; + let new_metadata = std::mem::take(&mut new_template.persistent_node_metadata.input_metadata); + let _ = std::mem::replace(&mut metadata.persistent_metadata.input_metadata, new_metadata); + Some(old_inputs) + } + + /// Used when opening an old document to add the persistent metadata for each input if it doesnt exist, which is where the name/description are saved. + pub fn validate_input_metadata(&mut self, node_id: &NodeId, node: &DocumentNode, network_path: &[NodeId]) { + let number_of_inputs = node.inputs.len(); + let Some(metadata) = self.node_metadata_mut(node_id, network_path) else { return }; + for added_input_index in metadata.persistent_metadata.input_metadata.len()..number_of_inputs { + let reference = metadata.persistent_metadata.reference.as_ref(); + let definition = reference.and_then(|reference| resolve_document_node_type(reference)); + let input_metadata = definition + .and_then(|definition| definition.node_template.persistent_node_metadata.input_metadata.get(added_input_index)) + .cloned(); + metadata.persistent_metadata.input_metadata.push(input_metadata.unwrap_or_default()); + } + } + + /// Used to ensure the display name is the reference name in case it is empty. + pub fn validate_display_name_metadata(&mut self, node_id: &NodeId, network_path: &[NodeId]) { + let Some(metadata) = self.node_metadata_mut(node_id, network_path) else { return }; + if metadata.persistent_metadata.display_name.is_empty() { + if let Some(reference) = metadata.persistent_metadata.reference.clone() { + // Keep the name for merge nodes as empty + if reference != "Merge" { + metadata.persistent_metadata.display_name = reference; + } + } + } + } + + /// Keep metadata in sync with the new implementation if this is used by anything other than the upgrade scripts + pub fn replace_reference_name(&mut self, node_id: &NodeId, network_path: &[NodeId], reference_name: String) { + let Some(node_metadata) = self.node_metadata_mut(node_id, network_path) else { + log::error!("Could not get node metadata in replace_reference_name"); + return; + }; + node_metadata.persistent_metadata.reference = Some(reference_name); + } + + /// Keep metadata in sync with the new implementation if this is used by anything other than the upgrade scripts + pub fn set_manual_compostion(&mut self, node_id: &NodeId, network_path: &[NodeId], manual_composition: Option) { + let Some(network) = self.network_mut(network_path) else { + log::error!("Could not get nested network in set_implementation"); + return; + }; + let Some(node) = network.nodes.get_mut(node_id) else { + log::error!("Could not get node in set_implementation"); + return; + }; + node.manual_composition = manual_composition; + } + + pub fn set_input(&mut self, input_connector: &InputConnector, new_input: NodeInput, network_path: &[NodeId]) { + if matches!(input_connector, InputConnector::Export(_)) && matches!(new_input, NodeInput::Network { .. }) { + // TODO: Add support for flattening NodeInput::Network exports in flatten_with_fns https://github.com/GraphiteEditor/Graphite/issues/1762 + log::error!("Cannot connect a network to an export, see https://github.com/GraphiteEditor/Graphite/issues/1762"); + return; + } + let Some(previous_input) = self.input_from_connector(input_connector, network_path).cloned() else { + log::error!("Could not get previous input in set_input"); + return; + }; + + // When changing a NodeInput::Node to a NodeInput::Node, the input should first be disconnected to ensure proper side effects + if (matches!(previous_input, NodeInput::Node { .. }) && matches!(new_input, NodeInput::Node { .. })) { + self.disconnect_input(input_connector, network_path); + self.set_input(input_connector, new_input, network_path); + return; + } + + // If the previous input is connected to a chain node, then set all upstream chain nodes to absolute position + if let NodeInput::Node { node_id: previous_upstream_id, .. } = &previous_input { + if self.is_chain(previous_upstream_id, network_path) { + self.set_upstream_chain_to_absolute(previous_upstream_id, network_path); + } + } + if let NodeInput::Node { node_id: new_upstream_id, .. } = &new_input { + // If the new input is connected to a chain node, then break its chain + if self.is_chain(new_upstream_id, network_path) { + self.set_upstream_chain_to_absolute(new_upstream_id, network_path); + } + } + + let previous_metadata = match &previous_input { + NodeInput::Node { node_id, .. } => self.position(node_id, network_path).map(|position| (*node_id, position)), + _ => None, + }; + + let Some(network) = self.network_mut(network_path) else { + log::error!("Could not get nested network in set_input"); + return; + }; + + let old_input = match input_connector { + InputConnector::Node { node_id, input_index } => { + let Some(node) = network.nodes.get_mut(node_id) else { + log::error!("Could not get node in set_input"); + return; + }; + let Some(input) = node.inputs.get_mut(*input_index) else { + log::error!("Could not get input in set_input"); + return; + }; + std::mem::replace(input, new_input.clone()) + } + InputConnector::Export(export_index) => { + let Some(export) = network.exports.get_mut(*export_index) else { + log::error!("Could not get export in set_input"); + return; + }; + std::mem::replace(export, new_input.clone()) + } + }; + + if old_input == new_input { + return; + }; + + // Ensure the network is not cyclic + if !network.is_acyclic() { + self.set_input(input_connector, old_input, network_path); + return; + } + + self.transaction_modified(); + + // Ensure layer is toggled to non layer if it is no longer eligible to be a layer + if let InputConnector::Node { node_id, .. } = &input_connector { + if !self.is_eligible_to_be_layer(node_id, network_path) && self.is_layer(node_id, network_path) { + self.set_to_node_or_layer(node_id, network_path, false); + } + } + + // Side effects + match (&old_input, &new_input) { + // If a node input is exposed or hidden reload the click targets and update the bounding box for all nodes + (NodeInput::Value { exposed: new_exposed, .. }, NodeInput::Value { exposed: old_exposed, .. }) => { + if let InputConnector::Node { node_id, .. } = input_connector { + if new_exposed != old_exposed { + self.unload_upstream_node_click_targets(vec![*node_id], network_path); + self.unload_all_nodes_bounding_box(network_path); + } + } + } + (_, NodeInput::Node { node_id: upstream_node_id, .. }) => { + // Load structure if the change is to the document network and to the first or second + if network_path.is_empty() { + if matches!(input_connector, InputConnector::Export(0)) { + self.load_structure(); + } else if let InputConnector::Node { node_id, input_index } = &input_connector { + // If the connection is made to the first or second input of a node connected to the output, then load the structure + if self.connected_to_output(node_id, network_path) && (*input_index == 0 || *input_index == 1) { + self.load_structure(); + } + } + } + self.unload_outward_wires(network_path); + // Layout system + let Some(current_node_position) = self.position(upstream_node_id, network_path) else { + log::error!("Could not get current node position in set_input for node {upstream_node_id}"); + return; + }; + let Some(node_metadata) = self.node_metadata(upstream_node_id, network_path) else { + log::error!("Could not get node_metadata in set_input"); + return; + }; + match &node_metadata.persistent_metadata.node_type_metadata { + NodeTypePersistentMetadata::Layer(_) => { + match &input_connector { + InputConnector::Export(_) => { + // If a layer is connected to the exports, it should be set to absolute position without being moved. + self.set_absolute_position(upstream_node_id, current_node_position, network_path) + } + InputConnector::Node { + node_id: downstream_node_id, + input_index, + } => { + // If a layer has a single connection to the bottom of another layer, it should be set to stack positioning + let Some(downstream_node_metadata) = self.node_metadata(downstream_node_id, network_path) else { + log::error!("Could not get downstream node_metadata in set_input"); + return; + }; + match &downstream_node_metadata.persistent_metadata.node_type_metadata { + NodeTypePersistentMetadata::Layer(_) => { + // If the layer feeds into the bottom input of layer, and has no other outputs, set its position to stack at its previous y position + let multiple_outward_wires = self + .outward_wires(network_path) + .and_then(|all_outward_wires| all_outward_wires.get(&OutputConnector::node(*upstream_node_id, 0))) + .is_some_and(|outward_wires| outward_wires.len() > 1); + if *input_index == 0 && !multiple_outward_wires { + self.set_stack_position_calculated_offset(upstream_node_id, downstream_node_id, network_path); + } else { + self.set_absolute_position(upstream_node_id, current_node_position, network_path); + } + } + NodeTypePersistentMetadata::Node(_) => { + // If the layer feeds into a node, set its y offset to 0 + self.set_absolute_position(upstream_node_id, current_node_position, network_path); + } + } + } + } + } + NodeTypePersistentMetadata::Node(_) => {} + } + self.unload_upstream_node_click_targets(vec![*upstream_node_id], network_path); + self.unload_stack_dependents(network_path); + self.try_set_upstream_to_chain(input_connector, network_path); + } + // If a connection is made to the imports + (NodeInput::Value { .. } | NodeInput::Scope { .. } | NodeInput::Inline { .. }, NodeInput::Network { .. }) => { + self.unload_outward_wires(network_path); + self.unload_wire(input_connector, network_path); + } + // If a connection to the imports is disconnected + (NodeInput::Network { .. }, NodeInput::Value { .. } | NodeInput::Scope { .. } | NodeInput::Inline { .. }) => { + self.unload_outward_wires(network_path); + self.unload_wire(input_connector, network_path); + } + // If a node is disconnected. + (NodeInput::Node { .. }, NodeInput::Value { .. } | NodeInput::Scope { .. } | NodeInput::Inline { .. }) => { + self.unload_outward_wires(network_path); + self.unload_wire(input_connector, network_path); + + if let Some((old_upstream_node_id, previous_position)) = previous_metadata { + let old_upstream_node_is_layer = self.is_layer(&old_upstream_node_id, network_path); + let Some(outward_wires) = self + .outward_wires(network_path) + .and_then(|outward_wires| outward_wires.get(&OutputConnector::node(old_upstream_node_id, 0))) + else { + log::error!("Could not get outward wires in set_input"); + return; + }; + // If it is a layer and is connected to a single layer, set its position to stack at its previous y position + if old_upstream_node_is_layer && outward_wires.len() == 1 && outward_wires[0].input_index() == 0 { + if let Some(downstream_node_id) = outward_wires[0].node_id() { + if self.is_layer(&downstream_node_id, network_path) { + self.set_stack_position_calculated_offset(&old_upstream_node_id, &downstream_node_id, network_path); + self.unload_upstream_node_click_targets(vec![old_upstream_node_id], network_path); + } + } + } + // If it is a node and is eligible to be in a chain, then set it to chain positioning + else if !old_upstream_node_is_layer { + self.try_set_node_to_chain(&old_upstream_node_id, network_path); + } + // If a node was previously connected, and it is no longer connected to any nodes, then set its position to absolute at its previous position + else { + self.set_absolute_position(&old_upstream_node_id, previous_position, network_path); + } + } + // Load structure if the change is to the document network and to the first or second + if network_path.is_empty() { + if matches!(input_connector, InputConnector::Export(0)) { + self.load_structure(); + } else if let InputConnector::Node { node_id, input_index } = &input_connector { + // If the connection is made to the first or second input of a node connected to the output, then load the structure + if self.connected_to_output(node_id, network_path) && (*input_index == 0 || *input_index == 1) { + self.load_structure(); + } + } + } + self.unload_stack_dependents(network_path); + } + _ => {} + } + } + + /// Ensure network metadata, positions, and other metadata is kept in sync + pub fn disconnect_input(&mut self, input_connector: &InputConnector, network_path: &[NodeId]) { + let Some(current_input) = self.input_from_connector(input_connector, network_path).cloned() else { + log::error!("Could not get current input in disconnect_input"); + return; + }; + // Do not disconnect an already disconnected input + if matches!(current_input, NodeInput::Value { .. }) { + return; + } + + if let NodeInput::Node { + node_id: upstream_node_id, + output_index, + .. + } = ¤t_input + { + // If the node upstream from the disconnected input is a chain, then break the chain by setting it to absolute positioning + if self.is_chain(upstream_node_id, network_path) { + self.set_upstream_chain_to_absolute(upstream_node_id, network_path); + } + // If the node upstream from the disconnected input has an outward wire to the bottom of a layer, set it back to stack positioning + if self.is_layer(upstream_node_id, network_path) { + let Some(outward_wires) = self + .outward_wires(network_path) + .and_then(|outward_wires| outward_wires.get(&OutputConnector::node(*upstream_node_id, *output_index))) + else { + log::error!("Could not get outward wires in disconnect_input"); + return; + }; + let mut other_outward_wires = outward_wires.iter().filter(|outward_wire| *outward_wire != input_connector); + if let Some(other_outward_wire) = other_outward_wires.next().cloned() { + if other_outward_wires.next().is_none() { + if let InputConnector::Node { + node_id: downstream_node_id, + input_index, + } = other_outward_wire + { + if self.is_layer(&downstream_node_id, network_path) && input_index == 0 { + self.set_stack_position_calculated_offset(upstream_node_id, &downstream_node_id, network_path); + } + } + } + } + } + } + + let tagged_value = TaggedValue::from_type_or_none(&self.input_type(input_connector, network_path).0); + + let value_input = NodeInput::value(tagged_value, true); + + self.set_input(input_connector, value_input, network_path); + } + + pub fn create_wire(&mut self, output_connector: &OutputConnector, input_connector: &InputConnector, network_path: &[NodeId]) { + let input = match output_connector { + OutputConnector::Node { node_id, output_index } => NodeInput::node(*node_id, *output_index), + OutputConnector::Import(import_index) => NodeInput::Network { + import_type: graph_craft::generic!(T), + import_index: *import_index, + }, + }; + + self.set_input(input_connector, input, network_path); + } + + /// Used to insert a group of nodes into the network + pub fn insert_node_group(&mut self, nodes: Vec<(NodeId, NodeTemplate)>, new_ids: HashMap, network_path: &[NodeId]) { + for (old_node_id, mut node_template) in nodes { + // Get the new node template + node_template = self.map_ids(node_template, &old_node_id, &new_ids, network_path); + // Insert node into network + let node_id = *new_ids.get(&old_node_id).unwrap(); + let Some(network) = self.network_mut(network_path) else { + log::error!("Network not found in insert_node"); + return; + }; + + network.nodes.insert(node_id, node_template.document_node); + self.transaction_modified(); + + let Some(network_metadata) = self.network_metadata_mut(network_path) else { + log::error!("Network not found in insert_node"); + return; + }; + let node_metadata = DocumentNodeMetadata { + persistent_metadata: node_template.persistent_node_metadata, + transient_metadata: DocumentNodeTransientMetadata::default(), + }; + network_metadata.persistent_metadata.node_metadata.insert(node_id, node_metadata); + } + for new_node_id in new_ids.values() { + self.unload_node_click_targets(new_node_id, network_path); + } + self.unload_all_nodes_bounding_box(network_path); + self.unload_outward_wires(network_path); + } + + /// Used to insert a node template with no node/network inputs into the network and returns the a NodeTemplate with information from the previous node, if it existed. + pub fn insert_node(&mut self, node_id: NodeId, node_template: NodeTemplate, network_path: &[NodeId]) -> Option { + let has_node_or_network_input = node_template + .document_node + .inputs + .iter() + .all(|input| !(matches!(input, NodeInput::Node { .. }) || matches!(input, NodeInput::Network { .. }))); + assert!(has_node_or_network_input, "Cannot insert node with node or network inputs. Use insert_node_group instead"); + let Some(network) = self.network_mut(network_path) else { + log::error!("Network not found in insert_node"); + return None; + }; + + let previous_node = network.nodes.insert(node_id, node_template.document_node); + self.transaction_modified(); + + let Some(network_metadata) = self.network_metadata_mut(network_path) else { + log::error!("Network not found in insert_node"); + return None; + }; + let node_metadata = DocumentNodeMetadata { + persistent_metadata: node_template.persistent_node_metadata, + transient_metadata: DocumentNodeTransientMetadata::default(), + }; + let previous_metadata = network_metadata.persistent_metadata.node_metadata.insert(node_id, node_metadata); + + self.unload_all_nodes_bounding_box(network_path); + self.unload_node_click_targets(&node_id, network_path); + + previous_node.zip(previous_metadata).map(|(document_node, node_metadata)| NodeTemplate { + document_node, + persistent_node_metadata: node_metadata.persistent_metadata, + }) + } + + /// Deletes all nodes in `node_ids` and any sole dependents in the horizontal chain if the node to delete is a layer node. + pub fn delete_nodes(&mut self, nodes_to_delete: Vec, delete_children: bool, network_path: &[NodeId]) { + let Some(outward_wires) = self.outward_wires(network_path).cloned() else { + log::error!("Could not get outward wires in delete_nodes"); + return; + }; + + let mut delete_nodes = HashSet::new(); + for node_id in &nodes_to_delete { + delete_nodes.insert(*node_id); + + if !delete_children { + continue; + }; + + for upstream_id in self.upstream_flow_back_from_nodes(vec![*node_id], network_path, FlowType::LayerChildrenUpstreamFlow) { + // This does a downstream traversal starting from the current node, and ending at either a node in the `delete_nodes` set or the output. + // If the traversal find as child node of a node in the `delete_nodes` set, then it is a sole dependent. If the output node is eventually reached, then it is not a sole dependent. + let mut stack = vec![OutputConnector::node(upstream_id, 0)]; + let mut can_delete = true; + while let Some(current_node) = stack.pop() { + let current_node_id = current_node.node_id().expect("The current node in the delete stack cannot be the export"); + let Some(downstream_nodes) = outward_wires.get(¤t_node) else { continue }; + for downstream_node in downstream_nodes { + if let InputConnector::Node { node_id: downstream_id, .. } = downstream_node { + if !delete_nodes.contains(downstream_id) { + can_delete = false; + break; + } + // Continue traversing over the downstream sibling, if the current node is a sibling to a node that will be deleted and it is a layer + else { + for deleted_node_id in &nodes_to_delete { + let Some(downstream_node) = self.document_node(deleted_node_id, network_path) else { continue }; + let Some(input) = downstream_node.inputs.first() else { continue }; + + if let NodeInput::Node { node_id, .. } = input { + if *node_id == current_node_id { + stack.push(OutputConnector::node(*deleted_node_id, 0)); + } + } + } + } + } + // If the traversal reaches the export, then the current node is not a sole dependent + else { + can_delete = false; + } + } + } + if can_delete { + delete_nodes.insert(upstream_id); + } + } + } + + for delete_node_id in &delete_nodes { + let upstream_chain_nodes = self + .upstream_flow_back_from_nodes(vec![*delete_node_id], network_path, FlowType::PrimaryFlow) + .skip(1) + .take_while(|upstream_node| self.is_chain(upstream_node, network_path)) + .collect::>(); + + if !self.remove_references_from_network(delete_node_id, network_path) { + log::error!("could not remove references from network"); + continue; + } + + for input_index in 0..self.number_of_displayed_inputs(delete_node_id, network_path) { + self.disconnect_input(&InputConnector::node(*delete_node_id, input_index), network_path); + } + + let Some(network) = self.network_mut(network_path) else { + log::error!("Could not get nested network in delete_nodes"); + continue; + }; + + network.nodes.remove(delete_node_id); + self.transaction_modified(); + + let Some(network_metadata) = self.network_metadata_mut(network_path) else { + log::error!("Could not get nested network_metadata in delete_nodes"); + continue; + }; + network_metadata.persistent_metadata.node_metadata.remove(delete_node_id); + for previous_chain_node in upstream_chain_nodes { + self.set_chain_position(&previous_chain_node, network_path); + } + } + self.unload_all_nodes_bounding_box(network_path); + // Instead of unloaded all node click targets, just unload the nodes upstream from the deleted nodes. unload_upstream_node_click_targets will not work since the nodes have been deleted. + self.unload_all_nodes_click_targets(network_path); + let Some(selected_nodes) = self.selected_nodes_mut(network_path) else { + log::error!("Could not get selected nodes in NodeGraphMessage::DeleteNodes"); + return; + }; + selected_nodes.retain_selected_nodes(|node_id| !nodes_to_delete.contains(node_id)); + } + + /// Removes all references to the node with the given id from the network, and reconnects the input to the node below. + pub fn remove_references_from_network(&mut self, node_id: &NodeId, network_path: &[NodeId]) -> bool { + // TODO: Add more logic to support retaining preview when removing references. Since there are so many edge cases/possible crashes, for now the preview is ended. + self.stop_previewing(network_path); + + // Check whether the being-deleted node's first (primary) input is a node + let reconnect_to_input = self.document_node(node_id, network_path).and_then(|node| { + node.inputs + .iter() + .find(|input| input.is_exposed()) + .filter(|input| matches!(input, NodeInput::Node { .. } | NodeInput::Network { .. })) + .cloned() + }); + // Get all upstream references + let number_of_outputs = self.number_of_outputs(node_id, network_path); + let Some(all_outward_wires) = self.outward_wires(network_path) else { + log::error!("Could not get outward wires in remove_references_from_network"); + return false; + }; + let mut downstream_inputs_to_disconnect = Vec::new(); + for output_index in 0..number_of_outputs { + if let Some(outward_wires) = all_outward_wires.get(&OutputConnector::node(*node_id, output_index)) { + downstream_inputs_to_disconnect.extend(outward_wires.clone()); + } + } + + let mut reconnect_node = None; + + for downstream_input in &downstream_inputs_to_disconnect { + self.disconnect_input(downstream_input, network_path); + // Prevent reconnecting export to import until https://github.com/GraphiteEditor/Graphite/issues/1762 is solved + if !(matches!(reconnect_to_input, Some(NodeInput::Network { .. })) && matches!(downstream_input, InputConnector::Export(_))) { + if let Some(reconnect_input) = &reconnect_to_input { + reconnect_node = reconnect_input.as_node().and_then(|node_id| if self.is_stack(&node_id, network_path) { Some(node_id) } else { None }); + self.disconnect_input(&InputConnector::node(*node_id, 0), network_path); + self.set_input(downstream_input, reconnect_input.clone(), network_path); + } + } + } + + // Shift the reconnected node up to collapse space + if let Some(reconnect_node) = &reconnect_node { + let Some(reconnected_node_position) = self.position(reconnect_node, network_path) else { + log::error!("Could not get reconnected node position in remove_references_from_network"); + return false; + }; + let Some(disconnected_node_position) = self.position(node_id, network_path) else { + log::error!("Could not get disconnected node position in remove_references_from_network"); + return false; + }; + let max_shift_distance = reconnected_node_position.y - disconnected_node_position.y; + + let upstream_nodes = self.upstream_flow_back_from_nodes(vec![*reconnect_node], network_path, FlowType::PrimaryFlow).collect::>(); + + // Select the reconnect node to move to ensure the shifting works correctly + let Some(selected_nodes) = self.selected_nodes_mut(network_path) else { + log::error!("Could not get selected nodes in remove_references_from_network"); + return false; + }; + + let old_selected_nodes = selected_nodes.replace_with(upstream_nodes); + + // Shift up until there is either a collision or the disconnected node position is reached + let mut current_shift_distance = 0; + while self.check_collision_with_stack_dependents(reconnect_node, -1, network_path).is_empty() && max_shift_distance > current_shift_distance { + self.shift_selected_nodes(Direction::Up, false, network_path); + current_shift_distance += 1; + } + + let _ = self.selected_nodes_mut(network_path).unwrap().replace_with(old_selected_nodes); + } + + true + } + + pub fn start_previewing_without_restore(&mut self, network_path: &[NodeId]) { + // Some logic will have to be performed to prevent the graph positions from being completely changed when the export changes to some previewed node + let Some(network_metadata) = self.network_metadata_mut(network_path) else { + log::error!("Could not get nested network_metadata in start_previewing_without_restore"); + return; + }; + network_metadata.persistent_metadata.previewing = Previewing::Yes { root_node_to_restore: None }; + } + + fn stop_previewing(&mut self, network_path: &[NodeId]) { + if let Previewing::Yes { + root_node_to_restore: Some(root_node_to_restore), + } = self.previewing(network_path) + { + self.set_input( + &InputConnector::Export(0), + NodeInput::node(root_node_to_restore.node_id, root_node_to_restore.output_index), + network_path, + ); + } + let Some(network_metadata) = self.network_metadata_mut(network_path) else { + log::error!("Could not get nested network_metadata in stop_previewing"); + return; + }; + network_metadata.persistent_metadata.previewing = Previewing::No; + } + + // /// Sets the root node only if a node is being previewed + // pub fn update_root_node(&mut self, node_id: NodeId, output_index: usize) { + // if let Previewing::Yes { root_node_to_restore } = self.previewing { + // // Only continue previewing if the new root node is not the same as the primary export. If it is the same, end the preview + // if let Some(root_node_to_restore) = root_node_to_restore { + // if root_node_to_restore.id != node_id { + // self.start_previewing(node_id, output_index); + // } else { + // self.stop_preview(); + // } + // } else { + // self.stop_preview(); + // } + // } + // } + + pub fn set_display_name(&mut self, node_id: &NodeId, display_name: String, network_path: &[NodeId]) { + let Some(node_metadata) = self.node_metadata_mut(node_id, network_path) else { + log::error!("Could not get node {node_id} in set_visibility"); + return; + }; + + if node_metadata.persistent_metadata.display_name == display_name { + return; + } + + node_metadata.persistent_metadata.display_name.clone_from(&display_name); + + // Keep the alias in sync with the `ToArtboard` name input + if node_metadata.persistent_metadata.reference.as_ref().is_some_and(|reference| reference == "Artboard") { + let Some(nested_network) = self.network_mut(network_path) else { + return; + }; + let Some(artboard_node) = nested_network.nodes.get_mut(node_id) else { + return; + }; + let DocumentNodeImplementation::Network(network) = &mut artboard_node.implementation else { + return; + }; + // Keep this in sync with the definition + let Some(to_artboard) = network.nodes.get_mut(&NodeId(0)) else { + return; + }; + + let label_index = 1; + let label = if !display_name.is_empty() { display_name } else { "Artboard".to_string() }; + let label_input = NodeInput::value(TaggedValue::String(label), false); + to_artboard.inputs[label_index] = label_input; + } + + self.transaction_modified(); + self.try_unload_layer_width(node_id, network_path); + self.unload_node_click_targets(node_id, network_path); + } + + pub fn set_import_export_name(&mut self, mut name: String, index: ImportOrExport, network_path: &[NodeId]) { + let Some(encapsulating_node) = self.encapsulating_node_metadata_mut(network_path) else { + log::error!("Could not get encapsulating network in set_import_export_name"); + return; + }; + + let name_changed = match index { + ImportOrExport::Import(import_index) => { + let Some(input_properties) = encapsulating_node.persistent_metadata.input_metadata.get_mut(import_index) else { + log::error!("Could not get input properties in set_import_export_name"); + return; + }; + // Only return false if the previous value is the same as the current value + std::mem::swap(&mut input_properties.persistent_metadata.input_name, &mut name); + input_properties.persistent_metadata.input_name != name + } + ImportOrExport::Export(export_index) => { + let Some(export_name) = encapsulating_node.persistent_metadata.output_names.get_mut(export_index) else { + log::error!("Could not get export_name in set_import_export_name"); + return; + }; + std::mem::swap(export_name, &mut name); + *export_name != name + } + }; + if name_changed { + self.transaction_modified(); + } + } + + pub fn set_pinned(&mut self, node_id: &NodeId, network_path: &[NodeId], pinned: bool) { + let Some(node_metadata) = self.node_metadata_mut(node_id, network_path) else { + log::error!("Could not get node {node_id} in set_pinned"); + return; + }; + + node_metadata.persistent_metadata.pinned = pinned; + self.transaction_modified(); + } + + pub fn set_visibility(&mut self, node_id: &NodeId, network_path: &[NodeId], is_visible: bool) { + let Some(network) = self.network_mut(network_path) else { + return; + }; + let Some(node) = network.nodes.get_mut(node_id) else { + log::error!("Could not get node {node_id} in set_visibility"); + return; + }; + + node.visible = is_visible; + self.transaction_modified(); + } + + pub fn set_locked(&mut self, node_id: &NodeId, network_path: &[NodeId], locked: bool) { + let Some(node_metadata) = self.node_metadata_mut(node_id, network_path) else { + log::error!("Could not get node {node_id} in set_visibility"); + return; + }; + + node_metadata.persistent_metadata.locked = locked; + self.transaction_modified(); + } + + pub fn set_to_node_or_layer(&mut self, node_id: &NodeId, network_path: &[NodeId], is_layer: bool) { + // If a layer is set to a node, set upstream nodes to absolute position, and upstream siblings to absolute position + let child_id = { self.upstream_flow_back_from_nodes(vec![*node_id], network_path, FlowType::HorizontalFlow).nth(1) }; + let upstream_sibling_id = { self.upstream_flow_back_from_nodes(vec![*node_id], network_path, FlowType::PrimaryFlow).nth(1) }; + match (self.is_layer(node_id, network_path), is_layer) { + (true, false) => { + if let Some(child_id) = child_id { + self.set_upstream_chain_to_absolute(&child_id, network_path); + } + if let Some(upstream_sibling_id) = upstream_sibling_id { + let Some(upstream_sibling_position) = self.position(&upstream_sibling_id, network_path) else { + log::error!("Could not get upstream sibling position in set_to_node_or_layer"); + return; + }; + self.set_absolute_position(&upstream_sibling_id, upstream_sibling_position, network_path); + } + } + (false, true) => { + // If a node is set to a layer + if let Some(upstream_sibling_id) = upstream_sibling_id { + // If the upstream sibling layer has a single output, then set it to stack position + if self.is_layer(&upstream_sibling_id, network_path) + && self + .outward_wires(network_path) + .and_then(|outward_wires| outward_wires.get(&OutputConnector::node(upstream_sibling_id, 0))) + .is_some_and(|outward_wires| outward_wires.len() == 1) + { + self.set_stack_position_calculated_offset(&upstream_sibling_id, node_id, network_path); + } else { + self.set_upstream_chain_to_absolute(&upstream_sibling_id, network_path); + } + } + } + _ => return, + }; + + let Some(position) = self.position(node_id, network_path) else { + log::error!("Could not get position in set_to_node_or_layer"); + return; + }; + + let single_downstream_layer_position = self + .outward_wires(network_path) + .and_then(|outward_wires| { + outward_wires + .get(&OutputConnector::node(*node_id, 0)) + .and_then(|outward_wires| (outward_wires.len() == 1).then(|| outward_wires[0])) + .and_then(|downstream_connector| if downstream_connector.input_index() == 0 { downstream_connector.node_id() } else { None }) + }) + .filter(|downstream_node_id| self.is_layer(downstream_node_id, network_path)) + .and_then(|downstream_layer| self.position(&downstream_layer, network_path)); + + let Some(node_metadata) = self.node_metadata_mut(node_id, network_path) else { + log::error!("Could not get node_metadata for node {node_id}"); + return; + }; + + // First set the position to absolute + node_metadata.persistent_metadata.node_type_metadata = if is_layer { + NodeTypePersistentMetadata::Layer(LayerPersistentMetadata { + position: LayerPosition::Absolute(position), + owned_nodes: TransientMetadata::Unloaded, + }) + } else { + NodeTypePersistentMetadata::Node(NodePersistentMetadata { + position: NodePosition::Absolute(position), + }) + }; + + // Try build the chain + if is_layer { + self.try_set_upstream_to_chain(&InputConnector::node(*node_id, 1), network_path); + } else { + self.try_set_node_to_chain(node_id, network_path); + } + + let Some(node_metadata) = self.node_metadata_mut(node_id, network_path) else { + log::error!("Could not get node_metadata for node {node_id}"); + return; + }; + // Set the position to stack if necessary + if let Some(downstream_position) = is_layer.then_some(single_downstream_layer_position).flatten() { + node_metadata.persistent_metadata.node_type_metadata = NodeTypePersistentMetadata::Layer(LayerPersistentMetadata { + position: LayerPosition::Stack((position.y - downstream_position.y - 3).max(0) as u32), + owned_nodes: TransientMetadata::Unloaded, + }) + } + + if is_layer { + node_metadata.transient_metadata.node_type_metadata = NodeTypeTransientMetadata::Layer(LayerTransientMetadata::default()); + } else { + node_metadata.transient_metadata.node_type_metadata = NodeTypeTransientMetadata::Node; + } + + self.transaction_modified(); + self.unload_stack_dependents(network_path); + self.unload_upstream_node_click_targets(vec![*node_id], network_path); + self.unload_all_nodes_bounding_box(network_path); + self.unload_import_export_ports(network_path); + self.unload_modify_import_export(network_path); + self.load_structure(); + } + + pub fn toggle_preview(&mut self, toggle_id: NodeId, network_path: &[NodeId]) { + let Some(network) = self.nested_network(network_path) else { + return; + }; + // If new_export is None then disconnect + let mut new_export = None; + let mut new_previewing_state = Previewing::No; + if let Some(export) = network.exports.first() { + // If there currently an export + if let NodeInput::Node { node_id, output_index, .. } = export { + let previous_export_id = *node_id; + let previous_output_index = *output_index; + + // The export is clicked + if *node_id == toggle_id { + // If the current export is clicked and is being previewed end the preview and set either export back to root node or disconnect + if let Previewing::Yes { root_node_to_restore } = self.previewing(network_path) { + new_export = root_node_to_restore.map(|root_node| root_node.to_connector()); + new_previewing_state = Previewing::No; + } + // The export is clicked and there is no preview + else { + new_previewing_state = Previewing::Yes { + root_node_to_restore: Some(RootNode { + node_id: previous_export_id, + output_index: previous_output_index, + }), + }; + } + } + // The export is not clicked + else { + new_export = Some(OutputConnector::node(toggle_id, 0)); + + // There is currently a dashed line being drawn + if let Previewing::Yes { root_node_to_restore } = self.previewing(network_path) { + // There is also a solid line being drawn + if let Some(root_node_to_restore) = root_node_to_restore { + // If the node with the solid line is clicked, then start previewing that node without restore + if root_node_to_restore.node_id == toggle_id { + new_export = Some(OutputConnector::node(toggle_id, 0)); + new_previewing_state = Previewing::Yes { root_node_to_restore: None }; + } else { + // Root node to restore does not change + new_previewing_state = Previewing::Yes { + root_node_to_restore: Some(root_node_to_restore), + }; + } + } + // There is a dashed line without a solid line. + else { + new_previewing_state = Previewing::Yes { root_node_to_restore: None }; + } + } + // Not previewing, there is no dashed line being drawn + else { + new_export = Some(OutputConnector::node(toggle_id, 0)); + new_previewing_state = Previewing::Yes { + root_node_to_restore: Some(RootNode { + node_id: previous_export_id, + output_index: previous_output_index, + }), + }; + } + } + } + // The primary export is disconnected + else { + // Set node as export and cancel any preview + new_export = Some(OutputConnector::node(toggle_id, 0)); + self.start_previewing_without_restore(network_path); + } + } + match new_export { + Some(new_export) => { + self.create_wire(&new_export, &InputConnector::Export(0), network_path); + } + None => { + self.disconnect_input(&InputConnector::Export(0), network_path); + } + } + let Some(network_metadata) = self.network_metadata_mut(network_path) else { + return; + }; + network_metadata.persistent_metadata.previewing = new_previewing_state; + } + + /// Sets the position of a node to an absolute position + fn set_absolute_position(&mut self, node_id: &NodeId, position: IVec2, network_path: &[NodeId]) { + let Some(node_metadata) = self.node_metadata_mut(node_id, network_path) else { + log::error!("Could not get node_metadata for node {node_id}"); + return; + }; + + if let NodeTypePersistentMetadata::Node(node_metadata) = &mut node_metadata.persistent_metadata.node_type_metadata { + if node_metadata.position == NodePosition::Absolute(position) { + return; + } + node_metadata.position = NodePosition::Absolute(position); + self.transaction_modified(); + } else if let NodeTypePersistentMetadata::Layer(layer_metadata) = &mut node_metadata.persistent_metadata.node_type_metadata { + if layer_metadata.position == LayerPosition::Absolute(position) { + return; + } + layer_metadata.position = LayerPosition::Absolute(position); + self.transaction_modified(); + } + } + + /// Sets the position of a layer to a stack position + pub fn set_stack_position(&mut self, node_id: &NodeId, y_offset: u32, network_path: &[NodeId]) { + let Some(node_metadata) = self.node_metadata_mut(node_id, network_path) else { + log::error!("Could not get node_metadata for node {node_id}"); + return; + }; + match &mut node_metadata.persistent_metadata.node_type_metadata { + NodeTypePersistentMetadata::Layer(layer_metadata) => { + if layer_metadata.position == LayerPosition::Stack(y_offset) { + return; + } + layer_metadata.position = LayerPosition::Stack(y_offset); + self.transaction_modified(); + } + _ => { + log::error!("Could not set stack position for non layer node {node_id}"); + } + } + self.unload_upstream_node_click_targets(vec![*node_id], network_path); + } + + /// Sets the position of a node to a stack position without changing its y offset + pub fn set_stack_position_calculated_offset(&mut self, node_id: &NodeId, downstream_layer: &NodeId, network_path: &[NodeId]) { + let Some(node_position) = self.position(node_id, network_path) else { + log::error!("Could not get node position for node {node_id}"); + return; + }; + let Some(downstream_position) = self.position(downstream_layer, network_path) else { + log::error!("Could not get downstream position for node {downstream_layer}"); + return; + }; + + self.set_stack_position(node_id, (node_position.y - downstream_position.y - 3).max(0) as u32, network_path); + } + + /// Sets the position of a node to a chain position + pub fn set_chain_position(&mut self, node_id: &NodeId, network_path: &[NodeId]) { + let Some(node_metadata) = self.node_metadata_mut(node_id, network_path) else { + log::error!("Could not get node_metadata for node {node_id}"); + return; + }; + // Set any absolute nodes to chain positioning + if let NodeTypePersistentMetadata::Node(NodePersistentMetadata { position }) = &mut node_metadata.persistent_metadata.node_type_metadata { + if *position == NodePosition::Chain { + return; + } + *position = NodePosition::Chain; + self.transaction_modified(); + } + // If there is an upstream layer then stop breaking the chain + else { + log::error!("Could not set chain position for layer node {node_id}"); + } + self.unload_upstream_node_click_targets(vec![*node_id], network_path); + // Reload click target of the layer which encapsulate the chain + if let Some(downstream_layer) = self.downstream_layer(node_id, network_path) { + self.unload_node_click_targets(&downstream_layer.to_node(), network_path); + } + self.unload_all_nodes_bounding_box(network_path); + } + + fn valid_upstream_chain_nodes(&mut self, input_connector: &InputConnector, network_path: &[NodeId]) -> Vec { + let InputConnector::Node { + node_id: input_connector_node_id, + input_index, + } = input_connector + else { + return Vec::new(); + }; + let mut set_position_to_chain = Vec::new(); + if self.is_layer(input_connector_node_id, network_path) && *input_index == 1 || self.is_chain(input_connector_node_id, network_path) && *input_index == 0 { + let mut downstream_id = *input_connector_node_id; + for upstream_node in self + .upstream_flow_back_from_nodes(vec![*input_connector_node_id], network_path, FlowType::HorizontalFlow) + .skip(1) + .collect::>() + { + if self.is_layer(&upstream_node, network_path) { + break; + } + if !self.has_primary_output(&upstream_node, network_path) { + break; + } + let Some(outward_wires) = self.outward_wires(network_path).and_then(|outward_wires| outward_wires.get(&OutputConnector::node(upstream_node, 0))) else { + log::error!("Could not get outward wires in try_set_upstream_to_chain"); + break; + }; + if outward_wires.len() != 1 { + break; + } + let downstream_position = self.position(&downstream_id, network_path); + let upstream_node_position = self.position(&upstream_node, network_path); + if let (Some(input_connector_position), Some(new_upstream_node_position)) = (downstream_position, upstream_node_position) { + if input_connector_position.y == new_upstream_node_position.y + && new_upstream_node_position.x >= input_connector_position.x - 9 + && new_upstream_node_position.x <= input_connector_position.x + { + set_position_to_chain.push(upstream_node); + } else { + break; + } + } else { + break; + } + downstream_id = upstream_node; + } + } + set_position_to_chain + } + + /// Input connector is the input to the layer + pub fn try_set_upstream_to_chain(&mut self, input_connector: &InputConnector, network_path: &[NodeId]) { + // If the new input is to a non layer node on the same y position as the input connector, or the input connector is the side input of a layer, then set it to chain position + + let valid_upstream_chain_nodes = self.valid_upstream_chain_nodes(input_connector, network_path); + + for node_id in &valid_upstream_chain_nodes { + self.set_chain_position(node_id, network_path); + } + // Reload click target of the layer which used to encapsulate the node + if !valid_upstream_chain_nodes.is_empty() { + let mut downstream_layer = Some(input_connector.node_id().unwrap()); + while let Some(downstream_layer_id) = downstream_layer { + if downstream_layer_id == input_connector.node_id().unwrap() || !self.is_layer(&downstream_layer_id, network_path) { + let Some(outward_wires) = self.outward_wires(network_path) else { + log::error!("Could not get outward wires in try_set_upstream_to_chain"); + downstream_layer = None; + break; + }; + downstream_layer = outward_wires + .get(&OutputConnector::node(downstream_layer_id, 0)) + .and_then(|outward_wires| if outward_wires.len() == 1 { outward_wires[0].node_id() } else { None }); + } else { + break; + } + } + if let Some(downstream_layer) = downstream_layer { + self.unload_node_click_targets(&downstream_layer, network_path); + } + } + } + + fn try_set_node_to_chain(&mut self, node_id: &NodeId, network_path: &[NodeId]) { + if let Some(outward_wires) = self + .outward_wires(network_path) + .and_then(|outward_wires| outward_wires.get(&OutputConnector::node(*node_id, 0))) + .cloned() + { + if outward_wires.len() == 1 { + self.try_set_upstream_to_chain(&outward_wires[0], network_path) + } + } + } + + pub fn force_set_upstream_to_chain(&mut self, node_id: &NodeId, network_path: &[NodeId]) { + for upstream_id in self.upstream_flow_back_from_nodes(vec![*node_id], network_path, FlowType::HorizontalFlow).collect::>().iter() { + if !self.is_layer(upstream_id, network_path) + && self.has_primary_output(node_id, network_path) + && self + .outward_wires(network_path) + .is_some_and(|outward_wires| outward_wires.get(&OutputConnector::node(*upstream_id, 0)).is_some_and(|outward_wires| outward_wires.len() == 1)) + { + self.set_chain_position(upstream_id, network_path); + } + // If there is an upstream layer then stop breaking the chain + else { + break; + } + } + } + + /// node_id is the first chain node, not the layer + fn set_upstream_chain_to_absolute(&mut self, node_id: &NodeId, network_path: &[NodeId]) { + let Some(downstream_layer) = self.downstream_layer(node_id, network_path) else { + log::error!("Could not get downstream layer in set_upstream_chain_to_absolute"); + return; + }; + for upstream_id in self.upstream_flow_back_from_nodes(vec![*node_id], network_path, FlowType::HorizontalFlow).collect::>().iter() { + let Some(previous_position) = self.position(upstream_id, network_path) else { + log::error!("Could not get position in set_upstream_chain_to_absolute"); + return; + }; + // Set any chain nodes to absolute positioning + if self.is_chain(upstream_id, network_path) { + self.set_absolute_position(upstream_id, previous_position, network_path); + // Reload click target of the layer which used to encapsulate the chain + self.unload_node_click_targets(&downstream_layer.to_node(), network_path); + } + // If there is an upstream layer then stop breaking the chain + else { + break; + } + } + } + + pub fn nodes_sorted_top_to_bottom<'a>(&mut self, node_ids: impl Iterator, network_path: &[NodeId]) -> Option> { + let mut node_ids_with_position = node_ids + .filter_map(|&node_id| { + let Some(position) = self.position(&node_id, network_path) else { + log::error!("Could not get position for node {node_id} in shift_selected_nodes"); + return None; + }; + Some((node_id, position.y)) + }) + .collect::>(); + + node_ids_with_position.sort_unstable_by(|a, b| a.1.cmp(&b.1)); + Some(node_ids_with_position.into_iter().map(|(node_id, _)| node_id).collect::>()) + } + + /// Used when moving layer by the layer panel, does not run any pushing logic. Moves all sole dependents of the layer as well. + /// Ensure that the layer is absolute position. + pub fn shift_absolute_node_position(&mut self, layer: &NodeId, shift: IVec2, network_path: &[NodeId]) { + if shift == IVec2::ZERO { + return; + } + let mut nodes_to_shift = self.upstream_nodes_below_layer(layer, network_path); + nodes_to_shift.insert(*layer); + + for node_id in nodes_to_shift { + let Some(node_to_shift_metadata) = self.node_metadata_mut(&node_id, network_path) else { + log::error!("Could not get node metadata for node {node_id} in set_layer_position"); + continue; + }; + match &mut node_to_shift_metadata.persistent_metadata.node_type_metadata { + NodeTypePersistentMetadata::Layer(layer_metadata) => { + if let LayerPosition::Absolute(layer_position) = &mut layer_metadata.position { + *layer_position += shift; + } + } + NodeTypePersistentMetadata::Node(node_metadata) => { + if let NodePosition::Absolute(node_position) = &mut node_metadata.position { + *node_position += shift; + } + } + } + } + self.transaction_modified(); + self.unload_upstream_node_click_targets(vec![*layer], network_path); + } + + pub fn shift_selected_nodes(&mut self, direction: Direction, shift_without_push: bool, network_path: &[NodeId]) { + let Some(mut node_ids) = self + .selected_nodes_in_nested_network(network_path) + .map(|selected_nodes| selected_nodes.selected_nodes().cloned().collect::>()) + else { + log::error!("Could not get selected nodes in shift_selected_nodes"); + return; + }; + if !shift_without_push { + for node_id in node_ids.clone() { + if self.is_layer(&node_id, network_path) { + if let Some(owned_nodes) = self.owned_nodes(&node_id, network_path) { + for owned_node in owned_nodes { + node_ids.remove(owned_node); + } + }; + } + } + } + + for selected_node in &node_ids.clone() { + // Deselect chain nodes upstream from a selected layer + if self.is_chain(selected_node, network_path) + && self + .downstream_layer(selected_node, network_path) + .is_some_and(|downstream_layer| node_ids.contains(&downstream_layer.to_node())) + { + node_ids.remove(selected_node); + } + } + + // If shifting up without a push, cancel the shift if there is a stack node that cannot move up + if direction == Direction::Up && shift_without_push { + for node_id in &node_ids { + let Some(node_metadata) = self.node_metadata(node_id, network_path) else { + log::error!("Could not get node metadata for node {node_id} in shift_selected_nodes"); + return; + }; + if let NodeTypePersistentMetadata::Layer(layer_metadata) = &node_metadata.persistent_metadata.node_type_metadata { + if let LayerPosition::Stack(offset) = layer_metadata.position { + // If the upstream layer is selected, then skip + let Some(outward_wires) = self.outward_wires(network_path).and_then(|outward_wires| outward_wires.get(&OutputConnector::node(*node_id, 0))) else { + log::error!("Could not get outward wires in shift_selected_nodes"); + return; + }; + if let Some(upstream_node) = outward_wires.first() { + if node_ids.contains(&upstream_node.node_id().expect("Stack layer should have downstream layer")) { + continue; + } + } + // Offset cannot be negative, so cancel the shift + if offset == 0 { + return; + } + } + } + } + } + + let Some(mut sorted_node_ids) = self.nodes_sorted_top_to_bottom(node_ids.iter(), network_path) else { + return; + }; + + if sorted_node_ids.len() != node_ids.len() { + log::error!("Could not get position for all nodes in shift_selected_nodes"); + return; + } + + // If shifting down, then the lowest node (greatest y value) should be shifted first + if direction == Direction::Down { + sorted_node_ids.reverse(); + } + + // Ensure the top of each stack is only shifted left/right once (this is only for performance) + let mut shifted_absolute_layers = Vec::new(); + + let mut shifted_nodes = HashSet::new(); + + let shift_sign = if direction == Direction::Left || direction == Direction::Up { -1 } else { 1 }; + + for node_id in &sorted_node_ids { + match direction { + Direction::Left | Direction::Right => { + // If the node is a non layer, then directly shift it + if !self.is_layer(node_id, network_path) { + self.try_shift_node(node_id, IVec2::new(shift_sign, 0), &mut shifted_nodes, network_path); + } else { + // Get the downstream absolute layer (inclusive) + let mut downstream_absolute_layer = *node_id; + loop { + if self.is_absolute(&downstream_absolute_layer, network_path) { + break; + } + let Some(downstream_node) = self + .outward_wires(network_path) + .and_then(|outward_wires| outward_wires.get(&OutputConnector::node(downstream_absolute_layer, 0))) + .and_then(|downstream_nodes| downstream_nodes.first()) + .and_then(|downstream_node| downstream_node.node_id()) + else { + log::error!("Could not get downstream node when deselecting stack layer in shift_selected_nodes"); + break; + }; + downstream_absolute_layer = downstream_node; + } + + // Shift the upstream nodes below the stack layers only once + if !shifted_absolute_layers.contains(&downstream_absolute_layer) { + shifted_absolute_layers.push(downstream_absolute_layer); + + self.try_shift_node(&downstream_absolute_layer, IVec2::new(shift_sign, 0), &mut shifted_nodes, network_path); + + if !shift_without_push { + for stack_nodes in self + .upstream_flow_back_from_nodes(vec![downstream_absolute_layer], network_path, FlowType::PrimaryFlow) + .take_while(|layer| self.is_layer(layer, network_path)) + .collect::>() + { + for sole_dependent in &self.upstream_nodes_below_layer(&stack_nodes, network_path) { + if self.is_absolute(sole_dependent, network_path) { + self.try_shift_node(sole_dependent, IVec2::new(shift_sign, 0), &mut shifted_nodes, network_path); + } + } + } + } + } + } + } + Direction::Up | Direction::Down => { + if !shift_without_push && self.is_layer(node_id, network_path) { + self.shift_node_or_parent(node_id, shift_sign, &mut shifted_nodes, network_path); + } else if !shifted_nodes.contains(node_id) { + shifted_nodes.insert(*node_id); + self.shift_node(node_id, IVec2::new(0, shift_sign), network_path); + + let Some(network_metadata) = self.network_metadata_mut(network_path) else { + log::error!("Could not get nested network_metadata in export_ports"); + continue; + }; + if let TransientMetadata::Loaded(stack_dependents) = &mut network_metadata.transient_metadata.stack_dependents { + if let Some(LayerOwner::None(offset)) = stack_dependents.get_mut(node_id) { + *offset += shift_sign; + self.transaction_modified(); + }; + }; + + // Shift the upstream layer so that it stays in the same place + if self.is_layer(node_id, network_path) { + let upstream_layer = { + self.upstream_flow_back_from_nodes(vec![*node_id], network_path, FlowType::PrimaryFlow) + .nth(1) + .filter(|upstream_node| self.is_stack(upstream_node, network_path)) + }; + if let Some(upstream_layer) = upstream_layer { + self.shift_node(&upstream_layer, IVec2::new(0, -shift_sign), network_path); + } + } + } + } + } + } + + let Some(stack_dependents) = self + .stack_dependents(network_path) + .map(|stack_dependents| stack_dependents.iter().map(|(node_id, owner)| (*node_id, owner.clone())).collect::>()) + else { + log::error!("Could not load stack dependents in shift_selected_nodes"); + return; + }; + + let mut stack_dependents_with_position = stack_dependents + .iter() + .filter_map(|(node_id, owner)| { + let LayerOwner::None(offset) = owner else { + return None; + }; + if *offset == 0 { + return None; + } + if self.selected_nodes_in_nested_network(network_path).is_some_and(|selected_nodes| { + selected_nodes + .selected_nodes() + .any(|selected_node| selected_node == node_id || self.owned_nodes(node_id, network_path).is_some_and(|owned_nodes| owned_nodes.contains(selected_node))) + }) { + return None; + }; + let Some(position) = self.position(node_id, network_path) else { + log::error!("Could not get position for node {node_id} in shift_selected_nodes"); + return None; + }; + Some((*node_id, *offset, position.y)) + }) + .collect::>(); + + stack_dependents_with_position.sort_unstable_by(|a, b| { + a.1.signum().cmp(&b.1.signum()).then_with(|| { + // If the node has a positive offset, then it is shifted up, so shift the top nodes first + if a.1.signum() == 1 { a.2.cmp(&b.2) } else { b.2.cmp(&a.2) } + }) + }); + + // Try shift every node that is offset from its original position + for &(ref node_id, mut offset, _) in stack_dependents_with_position.iter() { + while offset != 0 { + if self.check_collision_with_stack_dependents(node_id, -offset.signum(), network_path).is_empty() { + self.vertical_shift_with_push(node_id, -offset.signum(), &mut HashSet::new(), network_path); + offset += -offset.signum(); + } else { + break; + } + } + } + } + + fn try_shift_node(&mut self, node_id: &NodeId, shift: IVec2, shifted_nodes: &mut HashSet, network_path: &[NodeId]) { + if !shifted_nodes.contains(node_id) { + self.shift_node(node_id, shift, network_path); + shifted_nodes.insert(*node_id); + } + } + + fn vertical_shift_with_push(&mut self, node_id: &NodeId, shift_sign: i32, shifted_nodes: &mut HashSet, network_path: &[NodeId]) { + // Do not shift a node more than once + if shifted_nodes.contains(node_id) { + return; + } + shifted_nodes.insert(*node_id); + + let nodes_to_shift = self.check_collision_with_stack_dependents(node_id, shift_sign, network_path); + + for node_to_shift in nodes_to_shift { + self.shift_node_or_parent(&node_to_shift.0, shift_sign, shifted_nodes, network_path); + } + + self.shift_node(node_id, IVec2::new(0, shift_sign), network_path); + + let Some(network_metadata) = self.network_metadata_mut(network_path) else { + log::error!("Could not get nested network_metadata in export_ports"); + return; + }; + let TransientMetadata::Loaded(stack_dependents) = &mut network_metadata.transient_metadata.stack_dependents else { + log::error!("Stack dependents should be loaded in vertical_shift_with_push"); + return; + }; + + let mut default_layer_owner = LayerOwner::None(0); + let layer_owner = stack_dependents.get_mut(node_id).unwrap_or_else(|| { + log::error!("Could not get layer owner in vertical_shift_with_push for node {node_id}"); + &mut default_layer_owner + }); + + match layer_owner { + LayerOwner::None(offset) => { + *offset += shift_sign; + self.transaction_modified(); + } + LayerOwner::Layer(_) => { + log::error!("Node being shifted with a push should not be owned"); + } + } + + // Shift the upstream layer so that it stays in the same place + if self.is_layer(node_id, network_path) { + let upstream_layer = { + self.upstream_flow_back_from_nodes(vec![*node_id], network_path, FlowType::PrimaryFlow) + .nth(1) + .filter(|upstream_node| self.is_stack(upstream_node, network_path)) + }; + if let Some(upstream_layer) = upstream_layer { + self.shift_node(&upstream_layer, IVec2::new(0, -shift_sign), network_path); + } + } + + // Shift the nodes that are owned by the layer (if any) + if let Some(owned_nodes) = self.owned_nodes(node_id, network_path).cloned() { + for owned_node in owned_nodes { + if self.is_absolute(&owned_node, network_path) { + self.try_shift_node(&owned_node, IVec2::new(0, shift_sign), shifted_nodes, network_path); + } + } + } + } + + fn check_collision_with_stack_dependents(&mut self, node_id: &NodeId, shift_sign: i32, network_path: &[NodeId]) -> Vec<(NodeId, LayerOwner)> { + self.try_load_all_node_click_targets(network_path); + self.try_load_stack_dependents(network_path); + let Some(stack_dependents) = self.try_get_stack_dependents(network_path) else { + log::error!("Could not load stack dependents in shift_selected_nodes"); + return Vec::new(); + }; + // Check collisions and for all owned nodes and recursively shift them + let mut nodes_to_shift = Vec::new(); + + let default_hashset = HashSet::new(); + let owned_nodes = self.owned_nodes(node_id, network_path).unwrap_or(&default_hashset); + + for current_node in owned_nodes.iter().chain(std::iter::once(node_id)) { + for node_to_check_collision in stack_dependents { + // Do not check collision between any of the owned nodes or the shifted node + if owned_nodes.contains(node_to_check_collision.0) || node_to_check_collision.0 == node_id { + continue; + } + + if node_to_check_collision.0 == current_node { + continue; + } + let Some(mut current_node_bounding_box) = self.try_get_node_bounding_box(current_node, network_path) else { + log::error!("Could not get bounding box for node {node_id} in shift_selected_nodes"); + continue; + }; + + let Some(node_bounding_box) = self.try_get_node_bounding_box(node_to_check_collision.0, network_path) else { + log::error!("Could not get bounding box for node {node_to_check_collision:?} in shift_selected_nodes"); + continue; + }; + // If the nodes do not intersect horizontally, then there is no collision + if current_node_bounding_box[1].x < node_bounding_box[0].x || current_node_bounding_box[0].x > node_bounding_box[1].x { + continue; + } + // Do not check collision if the nodes are currently intersecting + if current_node_bounding_box[1].y >= node_bounding_box[0].y - 0.1 && current_node_bounding_box[0].y <= node_bounding_box[1].y + 0.1 { + continue; + } + + current_node_bounding_box[1].y += GRID_SIZE as f64 * shift_sign as f64; + current_node_bounding_box[0].y += GRID_SIZE as f64 * shift_sign as f64; + + let collision = current_node_bounding_box[1].y >= node_bounding_box[0].y - 0.1 && current_node_bounding_box[0].y <= node_bounding_box[1].y + 0.1; + if collision { + nodes_to_shift.push((*node_to_check_collision.0, node_to_check_collision.1.clone())); + } + } + } + nodes_to_shift + } + + fn shift_node_or_parent(&mut self, node_id: &NodeId, shift_sign: i32, shifted_nodes: &mut HashSet, network_path: &[NodeId]) { + let Some(stack_dependents) = self.stack_dependents(network_path) else { + log::error!("Could not load stack dependents in shift_selected_nodes"); + return; + }; + let Some(layer_owner) = stack_dependents.get(node_id) else { + log::error!("Could not get layer owner in shift_node_or_parent for node {node_id}"); + return; + }; + match layer_owner { + LayerOwner::Layer(layer_owner) => { + let layer_owner = *layer_owner; + self.shift_node_or_parent(&layer_owner, shift_sign, shifted_nodes, network_path) + } + LayerOwner::None(_) => self.vertical_shift_with_push(node_id, shift_sign, shifted_nodes, network_path), + } + } + + /// Shifts a node by a certain offset without the auto layout system. If the node is a layer in a stack, the y_offset is shifted. If the node is a node in a chain, its position gets set to absolute. + // TODO: Check for unnecessary unloading of click targets + pub fn shift_node(&mut self, node_id: &NodeId, shift: IVec2, network_path: &[NodeId]) { + let Some(node_metadata) = self.node_metadata_mut(node_id, network_path) else { + log::error!("Could not get node_metadata for node {node_id}"); + return; + }; + if let NodeTypePersistentMetadata::Layer(layer_metadata) = &mut node_metadata.persistent_metadata.node_type_metadata { + if let LayerPosition::Absolute(layer_position) = &mut layer_metadata.position { + *layer_position += shift; + self.transaction_modified(); + } else if let LayerPosition::Stack(y_offset) = &mut layer_metadata.position { + let shifted_y_offset = *y_offset as i32 + shift.y; + + // A layer can only be shifted to a positive y_offset + if shifted_y_offset < 0 { + log::error!( + "Space should be made above the layer before shifting it up. Layer {node_id} current y_offset: {y_offset} shift: {}", + shift.y + ); + } + if shift.x != 0 { + log::error!("Stack layer {node_id} cannot be shifted horizontally."); + } + + let new_y_offset = shifted_y_offset.max(0) as u32; + if *y_offset == new_y_offset { + return; + } + *y_offset = new_y_offset; + self.transaction_modified(); + } + // Unload click targets for all upstream nodes, since they may have been derived from the node that was shifted + self.unload_upstream_node_click_targets(vec![*node_id], network_path); + } else if let NodeTypePersistentMetadata::Node(node_metadata) = &mut node_metadata.persistent_metadata.node_type_metadata { + if let NodePosition::Absolute(node_metadata) = &mut node_metadata.position { + *node_metadata += shift; + self.transaction_modified(); + // Unload click targets for all upstream nodes, since they may have been derived from the node that was shifted + self.unload_upstream_node_click_targets(vec![*node_id], network_path); + self.try_set_node_to_chain(node_id, network_path); + } else if let NodePosition::Chain = node_metadata.position { + self.set_upstream_chain_to_absolute(node_id, network_path); + self.shift_node(node_id, shift, network_path); + } + } + // Unload click targets for all upstream nodes, since they may have been derived from the node that was shifted + self.unload_upstream_node_click_targets(vec![*node_id], network_path); + self.unload_all_nodes_bounding_box(network_path); + } + + // TODO: Run the auto layout system to make space for the new nodes + /// Disconnect the layers primary output and the input to the last non layer node feeding into it through primary flow, reconnects, then moves the layer to the new layer and stack index + pub fn move_layer_to_stack(&mut self, layer: LayerNodeIdentifier, mut parent: LayerNodeIdentifier, mut insert_index: usize, network_path: &[NodeId]) { + // Prevent moving an artboard anywhere but to the ROOT_PARENT child stack + if self.is_artboard(&layer.to_node(), network_path) && parent != LayerNodeIdentifier::ROOT_PARENT { + log::error!("Artboard can only be moved to the root parent stack"); + return; + } + + // A layer is considered to be the height of that layer plus the height to the upstream layer sibling + // If a non artboard layer is attempted to be connected to the exports, and there is already an artboard connected, then connect the layer to the artboard. + if let Some(first_layer) = LayerNodeIdentifier::ROOT_PARENT.children(&self.document_metadata).next() { + if parent == LayerNodeIdentifier::ROOT_PARENT + && self.reference(&layer.to_node(), network_path).is_none_or(|reference| *reference != Some("Artboard".to_string())) + && self.is_artboard(&first_layer.to_node(), network_path) + { + parent = first_layer; + insert_index = 0; + } + } + + let Some(layer_to_move_position) = self.position(&layer.to_node(), network_path) else { + log::error!("Could not get layer_to_move_position in move_layer_to_stack"); + return; + }; + + let mut lowest_upstream_node_height = 0; + for upstream_node in self + .upstream_flow_back_from_nodes(vec![layer.to_node()], network_path, FlowType::LayerChildrenUpstreamFlow) + .collect::>() + { + let Some(upstream_node_position) = self.position(&upstream_node, network_path) else { + log::error!("Could not get upstream node position in move_layer_to_stack"); + return; + }; + lowest_upstream_node_height = lowest_upstream_node_height.max((upstream_node_position.y - layer_to_move_position.y).max(0) as u32); + } + + // If the moved layer is a child of the new parent, then get its index after the disconnect + if let Some(moved_layer_previous_index) = parent.children(&self.document_metadata).position(|child| child == layer) { + // Adjust the insert index if the layer's previous index is less than the insert index + if moved_layer_previous_index < insert_index { + insert_index -= 1; + } + } + + // Disconnect layer to move + self.remove_references_from_network(&layer.to_node(), network_path); + + let post_node = ModifyInputsContext::get_post_node_with_index(self, parent, insert_index); + + // Get the previous input to the post node before inserting the layer + let Some(post_node_input) = self.input_from_connector(&post_node, network_path).cloned() else { + log::error!("Could not get previous input in move_layer_to_stack for parent {parent:?} and insert_index {insert_index}"); + return; + }; + + let Some(previous_layer_position) = self.position(&layer.to_node(), network_path) else { + log::error!("Could not get previous layer position in move_layer_to_stack"); + return; + }; + + let after_move_post_layer_position = if let Some(post_node_id) = post_node.node_id() { + self.position(&post_node_id, network_path) + } else { + Some(IVec2::new(8, -3)) + }; + + let Some(after_move_post_layer_position) = after_move_post_layer_position else { + log::error!("Could not get post node position in move_layer_to_stack"); + return; + }; + + // Get the height of the downstream node if inserting into a stack + let mut downstream_height = 0; + let inserting_into_stack = + !(post_node.input_index() == 1 || matches!(post_node, InputConnector::Export(_)) || !post_node.node_id().is_some_and(|post_node_id| self.is_layer(&post_node_id, network_path))); + if inserting_into_stack { + if let Some(downstream_node) = post_node.node_id() { + let Some(downstream_node_position) = self.position(&downstream_node, network_path) else { + log::error!("Could not get downstream node position in move_layer_to_stack"); + return; + }; + let mut lowest_y_position = downstream_node_position.y + 3; + + for bottom_position in self.upstream_nodes_below_layer(&downstream_node, network_path).iter().filter_map(|node_id| { + let is_layer = self.is_layer(node_id, network_path); + self.position(node_id, network_path).map(|position| position.y + if is_layer { 3 } else { 2 }) + }) { + lowest_y_position = lowest_y_position.max(bottom_position); + } + downstream_height = lowest_y_position - (downstream_node_position.y + 3); + } + } + + let mut highest_y_position = layer_to_move_position.y; + let mut lowest_y_position = layer_to_move_position.y; + + for (bottom_position, top_position) in self.upstream_nodes_below_layer(&layer.to_node(), network_path).iter().filter_map(|node_id| { + let is_layer = self.is_layer(node_id, network_path); + let bottom_position = self.position(node_id, network_path).map(|position| position.y + if is_layer { 3 } else { 2 }); + let top_position = self.position(node_id, network_path).map(|position| if is_layer { position.y - 1 } else { position.y }); + bottom_position.zip(top_position) + }) { + highest_y_position = highest_y_position.min(top_position); + lowest_y_position = lowest_y_position.max(bottom_position); + } + let height_above_layer = layer_to_move_position.y - highest_y_position + downstream_height; + let height_below_layer = lowest_y_position - layer_to_move_position.y - 3; + + // If there is an upstream node in the new location for the layer, create space for the moved layer by shifting the upstream node down + if let Some(upstream_node_id) = post_node_input.as_node() { + // Select the layer to move to ensure the shifting works correctly + let Some(selected_nodes) = self.selected_nodes_mut(network_path) else { + log::error!("Could not get selected nodes in move_layer_to_stack"); + return; + }; + let old_selected_nodes = selected_nodes.replace_with(vec![upstream_node_id]); + + // Create the minimum amount space for the moved layer + for _ in 0..3 { + self.vertical_shift_with_push(&upstream_node_id, 1, &mut HashSet::new(), network_path); + } + + let Some(stack_position) = self.position(&upstream_node_id, network_path) else { + log::error!("Could not get stack position in move_layer_to_stack"); + return; + }; + + let current_gap = stack_position.y - (after_move_post_layer_position.y + 2); + let target_gap = 1 + height_above_layer + 2 + height_below_layer + 1; + + for _ in 0..(target_gap - current_gap).max(0) { + self.vertical_shift_with_push(&upstream_node_id, 1, &mut HashSet::new(), network_path); + } + + let _ = self.selected_nodes_mut(network_path).unwrap().replace_with(old_selected_nodes); + } + + // If inserting into a stack with a parent, ensure the parent stack has enough space for the child stack + if parent != LayerNodeIdentifier::ROOT_PARENT { + if let Some(upstream_sibling) = parent.next_sibling(&self.document_metadata) { + let Some(parent_position) = self.position(&parent.to_node(), network_path) else { + log::error!("Could not get parent position in move_layer_to_stack"); + return; + }; + let last_child = parent.last_child(&self.document_metadata).unwrap_or(parent); + + let Some(mut last_child_position) = self.position(&last_child.to_node(), network_path) else { + log::error!("Could not get last child position in move_layer_to_stack"); + return; + }; + + if self.is_layer(&last_child.to_node(), network_path) { + last_child_position.y += 3; + } else { + last_child_position.y += 2; + } + + // If inserting below the current last child, then the last child is layer to move + if post_node.node_id() == Some(last_child.to_node()) { + last_child_position += height_above_layer + 3 + height_below_layer; + } + + let Some(upstream_sibling_position) = self.position(&upstream_sibling.to_node(), network_path) else { + log::error!("Could not get upstream sibling position in move_layer_to_stack"); + return; + }; + + let target_gap = last_child_position.y - parent_position.y + 3; + let current_gap = upstream_sibling_position.y - parent_position.y; + + let upstream_nodes = self + .upstream_flow_back_from_nodes(vec![upstream_sibling.to_node()], network_path, FlowType::UpstreamFlow) + .collect::>(); + let Some(selected_nodes) = self.selected_nodes_mut(network_path) else { + log::error!("Could not get selected nodes in move_layer_to_stack"); + return; + }; + let old_selected_nodes = selected_nodes.replace_with(upstream_nodes); + + for _ in 0..(target_gap - current_gap).max(0) { + self.shift_selected_nodes(Direction::Down, true, network_path); + } + + let _ = self.selected_nodes_mut(network_path).unwrap().replace_with(old_selected_nodes); + } + } + + // Connect the layer to a parent layer/node at the top of the stack, or a non layer node midway down the stack + if !inserting_into_stack { + match post_node_input { + // Create a new stack + NodeInput::Value { .. } | NodeInput::Scope(_) | NodeInput::Inline(_) | NodeInput::Reflection(_) => { + self.create_wire(&OutputConnector::node(layer.to_node(), 0), &post_node, network_path); + + let final_layer_position = after_move_post_layer_position + IVec2::new(-8, 3); + let shift = final_layer_position - previous_layer_position; + self.shift_absolute_node_position(&layer.to_node(), shift, network_path); + } + // Move to the top of a stack. + NodeInput::Node { node_id, .. } => { + let Some(stack_top_position) = self.position(&node_id, network_path) else { + log::error!("Could not get stack x position in move_layer_to_stack"); + return; + }; + + let final_layer_position = IVec2::new(stack_top_position.x, after_move_post_layer_position.y + 3 + height_above_layer); + let shift = final_layer_position - previous_layer_position; + self.shift_absolute_node_position(&layer.to_node(), shift, network_path); + self.insert_node_between(&layer.to_node(), &post_node, 0, network_path); + } + NodeInput::Network { .. } => { + log::error!("Cannot move post node to parent which connects to the imports") + } + } + } else { + match post_node_input { + // Move to the bottom of the stack + NodeInput::Value { .. } | NodeInput::Scope(_) | NodeInput::Inline(_) | NodeInput::Reflection(_) => { + let offset = after_move_post_layer_position - previous_layer_position + IVec2::new(0, 3 + height_above_layer); + self.shift_absolute_node_position(&layer.to_node(), offset, network_path); + self.create_wire(&OutputConnector::node(layer.to_node(), 0), &post_node, network_path); + } + // Insert into the stack + NodeInput::Node { .. } => { + let final_layer_position = after_move_post_layer_position + IVec2::new(0, 3 + height_above_layer); + let shift = final_layer_position - previous_layer_position; + self.shift_absolute_node_position(&layer.to_node(), shift, network_path); + self.insert_node_between(&layer.to_node(), &post_node, 0, network_path); + } + NodeInput::Network { .. } => { + log::error!("Cannot move post node to parent which connects to the imports") + } + } + } + self.unload_upstream_node_click_targets(vec![layer.to_node()], network_path); + } + + // Insert a node onto a wire. Ensure insert_node_input_index is an exposed input + pub fn insert_node_between(&mut self, node_id: &NodeId, input_connector: &InputConnector, insert_node_input_index: usize, network_path: &[NodeId]) { + if self.number_of_displayed_inputs(node_id, network_path) == 0 { + log::error!("Cannot insert a node onto a wire with no exposed inputs"); + return; + } + + let Some(upstream_output) = self.upstream_output_connector(input_connector, network_path) else { + log::error!("Could not get upstream output in insert_node_between"); + return; + }; + + // Disconnect the previous input + self.disconnect_input(input_connector, network_path); + + // Connect the input connector to the new node + self.create_wire(&OutputConnector::node(*node_id, 0), input_connector, network_path); + + // Connect the new node to the previous node + self.create_wire(&upstream_output, &InputConnector::node(*node_id, insert_node_input_index), network_path); + } + + // Moves a node and to the start of a layer chain (feeding into the secondary input of the layer) + pub fn move_node_to_chain_start(&mut self, node_id: &NodeId, parent: LayerNodeIdentifier, network_path: &[NodeId]) { + let Some(current_input) = self.input_from_connector(&InputConnector::node(parent.to_node(), 1), network_path) else { + log::error!("Could not get input for node {node_id}"); + return; + }; + if matches!(current_input, NodeInput::Value { .. }) { + self.create_wire(&OutputConnector::node(*node_id, 0), &InputConnector::node(parent.to_node(), 1), network_path); + self.set_chain_position(node_id, network_path); + } else { + // TODO: Implement a more robust horizontal shift system when inserting a node into a chain. + // This should be done by breaking the chain and shifting the sole dependents for each node upstream of the insertion. + // Before inserting the node, shift the layer right 7 units so that all sole dependents are also shifted + // let input_connector = InputConnector::node(parent.to_node(), 0); + // let old_upstream = self.upstream_output_connector(&input_connector, network_path); + // This also needs to disconnect from the downstream layer + // self.disconnect_input(&input_connector, network_path); + // let Some(selected_nodes) = self.selected_nodes_mut(network_path) else { + // log::error!("Could not get selected nodes in move_layer_to_stack"); + // return; + // }; + // let old_selected_nodes = selected_nodes.replace_with(vec![parent.to_node()]); + + // for _ in 0..7 { + // self.shift_selected_nodes(Direction::Left, false, network_path); + // } + // // Grip drag it back to the right + // for _ in 0..7 { + // self.shift_selected_nodes(Direction::Right, true, network_path); + // } + // let _ = self.selected_nodes_mut(network_path).unwrap().replace_with(old_selected_nodes); + // if let Some(old_upstream) = old_upstream { + // self.create_wire(&old_upstream, &input_connector, network_path); + // } + + // Insert the node in the gap and set the upstream to a chain + self.insert_node_between(node_id, &InputConnector::node(parent.to_node(), 1), 0, network_path); + self.force_set_upstream_to_chain(node_id, network_path); + } + } +} + +#[derive(PartialEq)] +pub enum FlowType { + /// Iterate over all upstream nodes (inclusive) from every input (the primary and all secondary). + UpstreamFlow, + /// Iterate over nodes (inclusive) connected to the primary input. + PrimaryFlow, + /// Iterate over the secondary input (inclusive) for layer nodes and primary input for non layer nodes. + HorizontalFlow, + /// Same as horizontal flow, but only iterates over connections to primary outputs + HorizontalPrimaryOutputFlow, + /// Upstream flow starting from the either the node (inclusive) or secondary input of the layer (not inclusive). + LayerChildrenUpstreamFlow, +} +/// Iterate over upstream nodes. The behavior changes based on the `flow_type` that's set. +/// - [`FlowType::UpstreamFlow`]: iterates over all upstream nodes from every input (the primary and all secondary). +/// - [`FlowType::PrimaryFlow`]: iterates along the horizontal inputs of nodes, so in the case of a node chain `a -> b -> c`, this would yield `c, b, a` if we started from `c`. +/// - [`FlowType::HorizontalFlow`]: iterates over the secondary input for layer nodes and primary input for non layer nodes. +/// - [`FlowType::LayerChildrenUpstreamFlow`]: iterates over all upstream nodes from the secondary input of the node. +struct FlowIter<'a> { + stack: Vec, + network: &'a NodeNetwork, + network_metadata: &'a NodeNetworkMetadata, + flow_type: FlowType, +} +impl Iterator for FlowIter<'_> { + type Item = NodeId; + fn next(&mut self) -> Option { + loop { + let node_id = self.stack.pop()?; + + if let (Some(document_node), Some(node_metadata)) = (self.network.nodes.get(&node_id), self.network_metadata.persistent_metadata.node_metadata.get(&node_id)) { + let skip = if matches!(self.flow_type, FlowType::HorizontalFlow | FlowType::HorizontalPrimaryOutputFlow) && node_metadata.persistent_metadata.is_layer() { + 1 + } else { + 0 + }; + let take = if self.flow_type == FlowType::UpstreamFlow { usize::MAX } else { 1 }; + let inputs = document_node.inputs.iter().skip(skip).take(take); + + let node_ids = inputs.filter_map(|input| match input { + NodeInput::Node { output_index, .. } if self.flow_type == FlowType::HorizontalPrimaryOutputFlow && *output_index != 0 => None, + NodeInput::Node { node_id, .. } => Some(node_id), + _ => None, + }); + + self.stack.extend(node_ids); + + return Some(node_id); + } + } + } +} + +// TODO: Refactor to be Unknown, Compiled(Type) for NodeInput::Node, or Value(Type) for NodeInput::Value +/// Represents the source of a resolved type (for debugging). +/// There will be two valid types list. One for the current valid types that will not cause a node graph error, +/// based on the other inputs to that node and returned during compilation. THe other list will be all potential +/// Valid types, based on the protonode implementation/downstream users. +#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize, specta::Type)] +pub enum TypeSource { + Compiled, + RandomProtonodeImplementation, + DocumentNodeDefault, + TaggedValue, + OuterMostExportDefault, + + Error(&'static str), +} + +impl Default for TypeSource { + fn default() -> Self { + Self::Error("no source") + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize, specta::Type)] +pub enum ImportOrExport { + Import(usize), + Export(usize), +} + +/// Represents an input connector with index based on the [`DocumentNode::inputs`] index, not the visible input index +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, serde::Serialize, serde::Deserialize, specta::Type)] +pub enum InputConnector { + #[serde(rename = "node")] + Node { + #[serde(rename = "nodeId")] + node_id: NodeId, + #[serde(rename = "inputIndex")] + input_index: usize, + }, + #[serde(rename = "export")] + Export(usize), +} + +impl Default for InputConnector { + fn default() -> Self { + InputConnector::Export(0) + } +} + +impl InputConnector { + pub fn node(node_id: NodeId, input_index: usize) -> Self { + InputConnector::Node { node_id, input_index } + } + + pub fn input_index(&self) -> usize { + match self { + InputConnector::Node { input_index, .. } => *input_index, + InputConnector::Export(input_index) => *input_index, + } + } + + pub fn node_id(&self) -> Option { + match self { + InputConnector::Node { node_id, .. } => Some(*node_id), + _ => None, + } + } +} + +/// Represents an output connector +#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq, serde::Serialize, serde::Deserialize, specta::Type)] +pub enum OutputConnector { + #[serde(rename = "node")] + Node { + #[serde(rename = "nodeId")] + node_id: NodeId, + #[serde(rename = "outputIndex")] + output_index: usize, + }, + #[serde(rename = "import")] + Import(usize), +} + +impl Default for OutputConnector { + fn default() -> Self { + OutputConnector::Import(0) + } +} + +impl OutputConnector { + pub fn node(node_id: NodeId, output_index: usize) -> Self { + OutputConnector::Node { node_id, output_index } + } + + pub fn index(&self) -> usize { + match self { + OutputConnector::Node { output_index, .. } => *output_index, + OutputConnector::Import(output_index) => *output_index, + } + } + + pub fn node_id(&self) -> Option { + match self { + OutputConnector::Node { node_id, .. } => Some(*node_id), + _ => None, + } + } + + pub fn from_input(input: &NodeInput) -> Option { + match input { + NodeInput::Network { import_index, .. } => Some(Self::Import(*import_index)), + NodeInput::Node { node_id, output_index, .. } => Some(Self::node(*node_id, *output_index)), + _ => None, + } + } +} + +#[derive(Debug, Clone)] +pub struct Ports { + input_ports: Vec<(usize, ClickTarget)>, + output_ports: Vec<(usize, ClickTarget)>, +} + +impl Default for Ports { + fn default() -> Self { + Self::new() + } +} + +impl Ports { + pub fn new() -> Ports { + Ports { + input_ports: Vec::new(), + output_ports: Vec::new(), + } + } + + pub fn click_targets(&self) -> impl Iterator { + self.input_ports + .iter() + .map(|(_, click_target)| click_target) + .chain(self.output_ports.iter().map(|(_, click_target)| click_target)) + } + + pub fn input_ports(&self) -> impl Iterator { + self.input_ports.iter() + } + + pub fn output_ports(&self) -> impl Iterator { + self.output_ports.iter() + } + + fn insert_input_port_at_center(&mut self, input_index: usize, center: DVec2) { + let subpath = Subpath::new_ellipse(center - DVec2::new(8., 8.), center + DVec2::new(8., 8.)); + self.insert_custom_input_port(input_index, ClickTarget::new_with_subpath(subpath, 0.)); + } + + fn insert_custom_input_port(&mut self, input_index: usize, click_target: ClickTarget) { + self.input_ports.push((input_index, click_target)); + } + + fn insert_output_port_at_center(&mut self, output_index: usize, center: DVec2) { + let subpath = Subpath::new_ellipse(center - DVec2::new(8., 8.), center + DVec2::new(8., 8.)); + self.insert_custom_output_port(output_index, ClickTarget::new_with_subpath(subpath, 0.)); + } + + fn insert_custom_output_port(&mut self, output_index: usize, click_target: ClickTarget) { + self.output_ports.push((output_index, click_target)); + } + + fn insert_node_input(&mut self, input_index: usize, row_index: usize, node_top_left: DVec2) { + // The center of the click target is always 24 px down from the top left corner of the node + let center = node_top_left + DVec2::new(0., 24. + 24. * row_index as f64); + self.insert_input_port_at_center(input_index, center); + } + + fn insert_node_output(&mut self, output_index: usize, row_index: usize, node_top_left: DVec2) { + // The center of the click target is always 24 px down from the top left corner of the node + let center = node_top_left + DVec2::new(5. * 24., 24. + 24. * row_index as f64); + self.insert_output_port_at_center(output_index, center); + } + + fn insert_layer_input(&mut self, input_index: usize, node_top_left: DVec2) { + let center = if input_index == 0 { + node_top_left + DVec2::new(2. * 24., 24. * 2. + 8.) + } else { + node_top_left + DVec2::new(0., 24. * 1.) + }; + self.insert_input_port_at_center(input_index, center); + } + + fn insert_layer_output(&mut self, node_top_left: DVec2) { + // The center of the click target is always 24 px down from the top left corner of the node + let center = node_top_left + DVec2::new(2. * 24., -8.); + self.insert_output_port_at_center(0, center); + } + + pub fn clicked_input_port_from_point(&self, point: DVec2) -> Option { + self.input_ports.iter().find_map(|(port, click_target)| click_target.intersect_point_no_stroke(point).then_some(*port)) + } + + pub fn clicked_output_port_from_point(&self, point: DVec2) -> Option { + self.output_ports.iter().find_map(|(port, click_target)| click_target.intersect_point_no_stroke(point).then_some(*port)) + } + + pub fn input_port_position(&self, index: usize) -> Option { + self.input_ports + .get(index) + .and_then(|(_, click_target)| click_target.bounding_box().map(|bounds| bounds[0] + DVec2::new(8., 8.))) + } + + pub fn output_port_position(&self, index: usize) -> Option { + self.output_ports + .get(index) + .and_then(|(_, click_target)| click_target.bounding_box().map(|bounds| bounds[0] + DVec2::new(8., 8.))) + } +} + +#[derive(PartialEq, Debug, Clone, Copy, Hash, Default, serde::Serialize, serde::Deserialize)] +pub struct RootNode { + pub node_id: NodeId, + pub output_index: usize, +} + +impl RootNode { + pub fn to_connector(&self) -> OutputConnector { + OutputConnector::Node { + node_id: self.node_id, + output_index: self.output_index, + } + } +} + +#[derive(PartialEq, Debug, Clone, Copy, Hash, Default, serde::Serialize, serde::Deserialize)] +pub enum Previewing { + /// If there is a node to restore the connection to the export for, then it is stored in the option. + /// Otherwise, nothing gets restored and the primary export is disconnected. + Yes { root_node_to_restore: Option }, + #[default] + No, +} + +/// All fields in NetworkMetadata should automatically be updated by using the network interface API. If a field is none then it should be calculated based on the network state. +#[derive(Debug, Default, serde::Serialize, serde::Deserialize)] +pub struct NodeNetworkMetadata { + pub persistent_metadata: NodeNetworkPersistentMetadata, + #[serde(skip)] + pub transient_metadata: NodeNetworkTransientMetadata, +} + +impl Clone for NodeNetworkMetadata { + fn clone(&self) -> Self { + NodeNetworkMetadata { + persistent_metadata: self.persistent_metadata.clone(), + transient_metadata: Default::default(), + } + } +} + +impl PartialEq for NodeNetworkMetadata { + fn eq(&self, other: &Self) -> bool { + self.persistent_metadata == other.persistent_metadata + } +} + +impl NodeNetworkMetadata { + pub fn nested_metadata(&self, nested_path: &[NodeId]) -> Option<&Self> { + let mut network_metadata = Some(self); + + for segment in nested_path { + network_metadata = network_metadata + .and_then(|network| network.persistent_metadata.node_metadata.get(segment)) + .and_then(|node| node.persistent_metadata.network_metadata.as_ref()); + } + network_metadata + } + + /// Get the mutable nested network given by the path of node ids + pub fn nested_metadata_mut(&mut self, nested_path: &[NodeId]) -> Option<&mut Self> { + let mut network_metadata = Some(self); + + for segment in nested_path { + network_metadata = network_metadata + .and_then(|network: &mut NodeNetworkMetadata| network.persistent_metadata.node_metadata.get_mut(segment)) + .and_then(|node| node.persistent_metadata.network_metadata.as_mut()); + } + network_metadata + } +} + +#[derive(Debug, Clone, Default, PartialEq, serde::Serialize, serde::Deserialize)] +pub struct NodeNetworkPersistentMetadata { + /// Node metadata must exist for every document node in the network + #[serde(serialize_with = "graphene_std::vector::serialize_hashmap", deserialize_with = "graphene_std::vector::deserialize_hashmap")] + pub node_metadata: HashMap, + /// Cached metadata for each node, which is calculated when adding a node to node_metadata + /// Indicates whether the network is currently rendered with a particular node that is previewed, and if so, which connection should be restored when the preview ends. + pub previewing: Previewing, + // Stores the transform and navigation state for the network + pub navigation_metadata: NavigationMetadata, + /// Stack of selection snapshots for previous history states. + // TODO: Use `#[serde(skip)]` here instead? @TrueDoctor claims this isn't valid but hasn't satisfactorily explained how it differs from the situation where `#[serde(default)]` fills in the default value. From brief testing, skip seems to work without issue. + #[serde(default)] + pub selection_undo_history: VecDeque, + /// Stack of selection snapshots for future history states. + // TODO: Use `#[serde(skip)]` here instead? See above. + #[serde(default)] + pub selection_redo_history: VecDeque, +} + +/// This is the same as Option, but more clear in the context of having cached metadata either being loaded or unloaded +#[derive(Debug, Default, Clone)] +pub enum TransientMetadata { + Loaded(T), + #[default] + Unloaded, +} + +impl TransientMetadata { + /// Set the current transient metadata to unloaded + pub fn unload(&mut self) { + *self = TransientMetadata::Unloaded; + } + + pub fn is_loaded(&self) -> bool { + matches!(self, TransientMetadata::Loaded(_)) + } +} + +/// If some network calculation is too slow to compute for every usage, cache the data here +#[derive(Debug, Default, Clone)] +pub struct NodeNetworkTransientMetadata { + pub selected_nodes: SelectedNodes, + /// Sole dependents of the top of the stacks of all selected nodes. Used to determine which nodes are checked for collision when shifting. + /// The LayerOwner is used to determine whether the collided node should be shifted, or the layer that owns it. + pub stack_dependents: TransientMetadata>, + /// Cache for the bounding box around all nodes in node graph space. + pub all_nodes_bounding_box: TransientMetadata<[DVec2; 2]>, + /// Cache bounding box for all "groups of nodes", which will be used to prevent overlapping nodes + // node_group_bounding_box: Vec<(Subpath, Vec)>, + /// Cache for all outward wire connections + pub outward_wires: TransientMetadata>>, + /// All export connector click targets + pub import_export_ports: TransientMetadata, + /// Click targets for adding, removing, and moving import/export ports + pub modify_import_export: TransientMetadata, + // Distance to the edges of the network, where the import/export ports are displayed. Rounded to nearest grid space when the panning ends. + pub rounded_network_edge_distance: TransientMetadata, + // Wires from the exports + pub wires: Vec>, +} + +#[derive(Debug, Clone)] +pub struct ModifyImportExportClickTarget { + // Plus icon that appears below all imports/exports, except in the document network + pub add_import_export: Ports, + // Subtract icon that appears when hovering over an import/export + pub remove_imports_exports: Ports, + // Grip drag icon that appears when hovering over an import/export + pub reorder_imports_exports: Ports, +} + +#[derive(Debug, Clone)] +pub struct NetworkEdgeDistance { + /// The viewport pixel distance between the left edge of the node graph and the exports. + pub exports_to_edge_distance: DVec2, + /// The viewport pixel distance between the left edge of the node graph and the imports. + pub imports_to_edge_distance: DVec2, +} + +#[derive(Debug, Clone)] +pub enum LayerOwner { + // Used to get the layer that should be shifted when there is a collision. + Layer(NodeId), + // The vertical offset of a node from the start of its shift. Should be reset when the drag ends. + None(i32), +} + +/// Utility function for providing a default boolean value to serde. +#[inline(always)] +fn return_true() -> bool { + true +} + +#[derive(Debug, Default, serde::Serialize, serde::Deserialize)] +pub struct DocumentNodeMetadata { + #[serde(deserialize_with = "deserialize_node_persistent_metadata")] + pub persistent_metadata: DocumentNodePersistentMetadata, + #[serde(skip)] + pub transient_metadata: DocumentNodeTransientMetadata, +} + +impl Clone for DocumentNodeMetadata { + fn clone(&self) -> Self { + DocumentNodeMetadata { + persistent_metadata: self.persistent_metadata.clone(), + transient_metadata: Default::default(), + } + } +} + +impl PartialEq for DocumentNodeMetadata { + fn eq(&self, other: &Self) -> bool { + self.persistent_metadata == other.persistent_metadata + } +} + +#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)] +pub struct NumberInputSettings { + pub unit: Option, + pub min: Option, + pub max: Option, + pub step: Option, + pub mode: NumberInputMode, + pub range_min: Option, + pub range_max: Option, + pub is_integer: bool, + pub blank_assist: bool, +} + +impl Default for NumberInputSettings { + fn default() -> Self { + NumberInputSettings { + unit: None, + min: None, + max: None, + step: None, + mode: NumberInputMode::default(), + range_min: None, + range_max: None, + is_integer: false, + blank_assist: true, + } + } +} + +#[derive(Debug, Default, Clone, serde::Serialize, serde::Deserialize)] +pub struct Vec2InputSettings { + pub x: String, + pub y: String, + pub unit: String, + pub min: Option, +} + +#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)] +pub enum WidgetOverride { + None, + Hidden, + String(String), + Number(NumberInputSettings), + Vec2(Vec2InputSettings), + Custom(String), +} + +// TODO: Custom deserialization/serialization to ensure number of properties row matches number of node inputs +#[derive(Debug, Clone, Default, PartialEq, serde::Serialize, serde::Deserialize)] +pub struct InputPersistentMetadata { + /// A general datastore than can store key value pairs of any types for any input + /// Each instance of the input node needs to store its own data, since it can lose the reference to its + /// node definition if the node signature is modified by the user. For example adding/removing/renaming an import/export of a network node. + pub input_data: HashMap, + // An input can override a widget, which would otherwise be automatically generated from the type + // The string is the identifier to the widget override function stored in INPUT_OVERRIDES + pub widget_override: Option, + /// An empty input name means to use the type as the name. + pub input_name: String, + /// Displayed as the tooltip. + pub input_description: String, +} + +impl InputPersistentMetadata { + pub fn with_name(mut self, input_name: &str) -> Self { + self.input_name = input_name.to_string(); + self + } + pub fn with_override(mut self, widget_override: WidgetOverride) -> Self { + match widget_override { + // Uses the default widget for the type + WidgetOverride::None => { + self.widget_override = None; + } + WidgetOverride::Hidden => { + self.widget_override = Some("hidden".to_string()); + } + WidgetOverride::String(string_properties) => { + self.input_data.insert("string_properties".to_string(), Value::String(string_properties)); + self.widget_override = Some("string".to_string()); + } + WidgetOverride::Number(mut number_properties) => { + if let Some(unit) = number_properties.unit.take() { + self.input_data.insert("unit".to_string(), json!(unit)); + } + if let Some(min) = number_properties.min.take() { + self.input_data.insert("min".to_string(), json!(min)); + } + if let Some(max) = number_properties.max.take() { + self.input_data.insert("max".to_string(), json!(max)); + } + if let Some(step) = number_properties.step.take() { + self.input_data.insert("step".to_string(), json!(step)); + } + if let Some(range_min) = number_properties.range_min.take() { + self.input_data.insert("range_min".to_string(), json!(range_min)); + } + if let Some(range_max) = number_properties.range_max.take() { + self.input_data.insert("range_max".to_string(), json!(range_max)); + } + self.input_data.insert("mode".to_string(), json!(number_properties.mode)); + self.input_data.insert("is_integer".to_string(), Value::Bool(number_properties.is_integer)); + self.input_data.insert("blank_assist".to_string(), Value::Bool(number_properties.blank_assist)); + self.widget_override = Some("number".to_string()); + } + WidgetOverride::Vec2(vec2_properties) => { + self.input_data.insert("x".to_string(), json!(vec2_properties.x)); + self.input_data.insert("y".to_string(), json!(vec2_properties.y)); + self.input_data.insert("unit".to_string(), json!(vec2_properties.unit)); + if let Some(min) = vec2_properties.min { + self.input_data.insert("min".to_string(), json!(min)); + } + self.widget_override = Some("vec2".to_string()); + } + WidgetOverride::Custom(lambda_name) => { + self.widget_override = Some(lambda_name); + } + }; + self + } + + pub fn with_description(mut self, tooltip: &str) -> Self { + self.input_description = tooltip.to_string(); + self + } +} + +#[derive(Debug, Clone, Default)] +struct InputTransientMetadata { + wire: TransientMetadata, + // downstream_protonode: populated for all inputs after each compile + // types: populated for each protonode after each +} + +// TODO: Eventually remove this migration document upgrade code +fn migrate_output_names<'de, D: serde::Deserializer<'de>>(deserializer: D) -> Result, D::Error> { + use serde::Deserialize; + + const REPLACEMENTS: [(&str, &str); 4] = [ + ("VectorData", "Instances"), + ("GraphicGroup", "Instances"), + ("ImageFrame", "Instances"), + ("Instances", "Instances"), + ]; + + let mut names = Vec::::deserialize(deserializer)?; + + for name in names.iter_mut() { + for (old, new) in REPLACEMENTS.iter() { + if name == old { + *name = new.to_string(); + } + } + } + + Ok(names) +} + +/// Persistent metadata for each node in the network, which must be included when creating, serializing, and deserializing saving a node. +#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)] +pub struct DocumentNodePersistentMetadata { + /// The name of the node definition, as originally set by [`DocumentNodeDefinition`], used to display in the UI and to display the appropriate properties if no display name is set. + // TODO: Used during serialization/deserialization to prevent storing implementation or inputs (and possible other fields) if they are the same as the definition. + // TODO: The reference is removed once the node is modified, since the node now stores its own implementation and inputs. + // TODO: Implement node versioning so that references to old nodes can be updated to the new node definition. + pub reference: Option, + /// A name chosen by the user for this instance of the node. Empty indicates no given name, in which case the reference name is displayed to the user in italics. + #[serde(default)] + pub display_name: String, + /// Stores metadata to override the properties in the properties panel for each input. These can either be generated automatically based on the type, or with a custom function. + /// Must match the length of node inputs + pub input_metadata: Vec, + #[serde(deserialize_with = "migrate_output_names")] + pub output_names: Vec, + /// Indicates to the UI if a primary output should be drawn for this node. + /// True for most nodes, but the Split Channels node is an example of a node that has multiple secondary outputs but no primary output. + #[serde(default = "return_true")] + pub has_primary_output: bool, + /// Represents the lock icon for locking/unlocking the node in the graph UI. When locked, a node cannot be moved in the graph UI. + #[serde(default)] + pub locked: bool, + /// Indicates that the node will be shown in the Properties panel when it would otherwise be empty, letting a user easily edit its properties by just deselecting everything. + #[serde(default)] + pub pinned: bool, + /// Metadata that is specific to either nodes or layers, which are chosen states for displaying as a left-to-right node or bottom-to-top layer. + /// All fields in NodeTypePersistentMetadata should automatically be updated by using the network interface API + pub node_type_metadata: NodeTypePersistentMetadata, + /// This should always be Some for nodes with a [`DocumentNodeImplementation::Network`], and none for [`DocumentNodeImplementation::ProtoNode`] + pub network_metadata: Option, +} + +impl Default for DocumentNodePersistentMetadata { + fn default() -> Self { + DocumentNodePersistentMetadata { + reference: None, + display_name: String::new(), + input_metadata: Vec::new(), + output_names: Vec::new(), + has_primary_output: true, + pinned: false, + locked: false, + node_type_metadata: NodeTypePersistentMetadata::default(), + network_metadata: None, + } + } +} + +impl DocumentNodePersistentMetadata { + pub fn is_layer(&self) -> bool { + matches!(self.node_type_metadata, NodeTypePersistentMetadata::Layer(_)) + } +} + +#[derive(Debug, Default, serde::Serialize, serde::Deserialize)] +pub struct InputMetadata { + pub persistent_metadata: InputPersistentMetadata, + #[serde(skip)] + transient_metadata: InputTransientMetadata, +} + +impl Clone for InputMetadata { + fn clone(&self) -> Self { + InputMetadata { + persistent_metadata: self.persistent_metadata.clone(), + transient_metadata: Default::default(), + } + } +} + +impl PartialEq for InputMetadata { + fn eq(&self, other: &Self) -> bool { + self.persistent_metadata == other.persistent_metadata + } +} + +impl From<(&str, &str)> for InputMetadata { + fn from(input_name_and_description: (&str, &str)) -> Self { + InputMetadata { + persistent_metadata: InputPersistentMetadata::default() + .with_name(input_name_and_description.0) + .with_description(input_name_and_description.1), + ..Default::default() + } + } +} + +impl InputMetadata { + pub fn with_name_description_override(input_name: &str, tooltip: &str, widget_override: WidgetOverride) -> Self { + InputMetadata { + persistent_metadata: InputPersistentMetadata::default().with_name(input_name).with_description(tooltip).with_override(widget_override), + ..Default::default() + } + } +} + +/// Persistent metadata for each node in the network, which must be included when creating, serializing, and deserializing saving a node. +#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)] +pub struct DocumentNodePersistentMetadataInputNames { + pub reference: Option, + #[serde(default)] + pub display_name: String, + pub input_names: Vec, + pub output_names: Vec, + #[serde(default = "return_true")] + pub has_primary_output: bool, + #[serde(default)] + pub locked: bool, + #[serde(default)] + pub pinned: bool, + pub node_type_metadata: NodeTypePersistentMetadata, + pub network_metadata: Option, +} + +impl From for DocumentNodePersistentMetadata { + fn from(old: DocumentNodePersistentMetadataInputNames) -> Self { + DocumentNodePersistentMetadata { + input_metadata: Vec::new(), + ..old.into() + } + } +} + +#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)] +pub struct DocumentNodePersistentMetadataPropertiesRow { + pub reference: Option, + #[serde(default)] + pub display_name: String, + pub input_properties: Vec, + #[serde(deserialize_with = "migrate_output_names")] + pub output_names: Vec, + #[serde(default = "return_true")] + pub has_primary_output: bool, + #[serde(default)] + pub locked: bool, + #[serde(default)] + pub pinned: bool, + pub node_type_metadata: NodeTypePersistentMetadata, + pub network_metadata: Option, +} + +#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)] +pub struct PropertiesRow { + pub input_data: HashMap, + pub widget_override: Option, + #[serde(skip)] + pub input_name: String, + #[serde(skip)] + pub input_description: String, +} + +impl From for DocumentNodePersistentMetadata { + fn from(old: DocumentNodePersistentMetadataPropertiesRow) -> Self { + let mut input_metadata = Vec::new(); + for properties_row in old.input_properties { + input_metadata.push(InputMetadata { + persistent_metadata: InputPersistentMetadata { + input_data: properties_row.input_data, + widget_override: properties_row.widget_override, + input_name: properties_row.input_name, + input_description: properties_row.input_description, + }, + ..Default::default() + }) + } + DocumentNodePersistentMetadata { + reference: old.reference, + display_name: old.display_name, + input_metadata: Vec::new(), + output_names: old.output_names, + has_primary_output: old.has_primary_output, + locked: old.locked, + pinned: old.pinned, + node_type_metadata: old.node_type_metadata, + network_metadata: old.network_metadata, + } + } +} + +#[derive(serde::Serialize, serde::Deserialize)] +enum NodePersistentMetadataVersions { + DocumentNodePersistentMetadataPropertiesRow(DocumentNodePersistentMetadataPropertiesRow), + NodePersistentMetadataInputNames(DocumentNodePersistentMetadataInputNames), + NodePersistentMetadata(DocumentNodePersistentMetadata), +} + +fn deserialize_node_persistent_metadata<'de, D>(deserializer: D) -> Result +where + D: serde::Deserializer<'de>, +{ + use serde::Deserialize; + + let value = Value::deserialize(deserializer)?; + if let Ok(document) = serde_json::from_value::(value.clone()) { + return Ok(document); + }; + if let Ok(document) = serde_json::from_value::(value.clone()) { + return Ok(document.into()); + }; + match serde_json::from_value::(value.clone()) { + Ok(document) => Ok(document.into()), + Err(e) => Err(serde::de::Error::custom(e)), + } +} + +#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)] +pub enum NodeTypePersistentMetadata { + Layer(LayerPersistentMetadata), + Node(NodePersistentMetadata), +} + +impl Default for NodeTypePersistentMetadata { + fn default() -> Self { + NodeTypePersistentMetadata::node(IVec2::ZERO) + } +} + +impl NodeTypePersistentMetadata { + pub fn node(position: IVec2) -> NodeTypePersistentMetadata { + NodeTypePersistentMetadata::Node(NodePersistentMetadata { + position: NodePosition::Absolute(position), + }) + } + pub fn layer(position: IVec2) -> NodeTypePersistentMetadata { + NodeTypePersistentMetadata::Layer(LayerPersistentMetadata { + position: LayerPosition::Absolute(position), + owned_nodes: TransientMetadata::default(), + }) + } +} + +/// All fields in LayerMetadata should automatically be updated by using the network interface API +#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)] +pub struct LayerPersistentMetadata { + // TODO: Store click target for the preview button, which will appear when the node is a selected/(hovered?) layer node + // preview_click_target: Option, + /// Stores the position of a layer node, which can either be Absolute or Stack + pub position: LayerPosition, + /// All nodes that should be moved when the layer is moved. + #[serde(skip)] + pub owned_nodes: TransientMetadata>, +} + +impl PartialEq for LayerPersistentMetadata { + fn eq(&self, other: &Self) -> bool { + self.position == other.position + } +} + +#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)] +pub struct NodePersistentMetadata { + /// Stores the position of a non layer node, which can either be Absolute or Chain + position: NodePosition, +} + +impl NodePersistentMetadata { + pub fn new(position: NodePosition) -> Self { + Self { position } + } +} + +/// A layer can either be position as Absolute or in a Stack +#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)] +pub enum LayerPosition { + // Position of the node in grid spaces + Absolute(IVec2), + // A layer is in a Stack when it feeds into the bottom input of a layer. The Y position stores the vertical distance between the layer and its upstream sibling/parent. + Stack(u32), +} + +/// A node can either be position as Absolute or in a Chain +#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)] +pub enum NodePosition { + // Position of the node in grid spaces + Absolute(IVec2), + // In a chain the position is based on the number of nodes to the first layer node + Chain, +} + +/// Cached metadata that should be calculated when creating a node, and should be recalculated when modifying a node property that affects one of the cached fields. +#[derive(Debug, Default, Clone)] +pub struct DocumentNodeTransientMetadata { + // The click targets are stored as a single struct since it is very rare for only one to be updated, and recomputing all click targets in one function is more efficient than storing them separately. + pub click_targets: TransientMetadata, + // Metadata that is specific to either nodes or layers, which are chosen states for displaying as a left-to-right node or bottom-to-top layer. + pub node_type_metadata: NodeTypeTransientMetadata, +} + +#[derive(Debug, Clone)] +pub struct DocumentNodeClickTargets { + /// In order to keep the displayed position of the node in sync with the click target, the displayed position of a node is derived from the top left of the click target + /// Ensure node_click_target is kept in sync when modifying a node property that changes its size. Currently this is alias, inputs, is_layer, and metadata + pub node_click_target: ClickTarget, + /// Stores all port click targets in node graph space. + pub port_click_targets: Ports, + // Click targets that are specific to either nodes or layers, which are chosen states for displaying as a left-to-right node or bottom-to-top layer. + pub node_type_metadata: NodeTypeClickTargets, +} + +#[derive(Debug, Default, Clone)] +pub enum NodeTypeTransientMetadata { + Layer(LayerTransientMetadata), + #[default] + Node, // No transient data is stored exclusively for nodes +} + +#[derive(Debug, Default, Clone)] +pub struct LayerTransientMetadata { + // Stores the width in grid cell units for layer nodes from the left edge of the thumbnail (+12px padding since thumbnail ends between grid spaces) to the left end of the node + /// This is necessary since calculating the layer width through web_sys is very slow + pub layer_width: TransientMetadata, + // Should not be a performance concern to calculate when needed with chain_width. + // Stores the width in grid cell units for layer nodes from the left edge of the thumbnail to the end of the chain + // chain_width: u32, +} + +#[derive(Debug, Clone)] +pub enum NodeTypeClickTargets { + Layer(LayerClickTargets), + Node, // No transient click targets are stored exclusively for nodes +} + +/// All fields in TransientLayerMetadata should automatically be updated by using the network interface API +#[derive(Debug, Clone)] +pub struct LayerClickTargets { + /// Cache for all visibility buttons. Should be automatically updated when update_click_target is called + pub visibility_click_target: ClickTarget, + /// Cache for the grip icon, which is next to the visibility button. + pub grip_click_target: ClickTarget, + // TODO: Store click target for the preview button, which will appear when the node is a selected/(hovered?) layer node + // preview_click_target: ClickTarget, +} + +pub enum LayerClickTargetTypes { + Visibility, + Grip, + // Preview, +} + +#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)] +pub struct NavigationMetadata { + /// The current pan, and zoom state of the viewport's view of the node graph. + /// Ensure `DocumentMessage::UpdateDocumentTransform` is called when the pan, zoom, or transform changes. + pub node_graph_ptz: PTZ, + // TODO: Remove and replace with calculate_offset_transform from the node_graph_ptz. This will be difficult since it requires both the navigation message handler and the IPP + /// Transform from node graph space to viewport space. + pub node_graph_to_viewport: DAffine2, + /// Top right of the node graph in viewport space + #[serde(default)] + pub node_graph_top_right: DVec2, +} + +impl Default for NavigationMetadata { + fn default() -> NavigationMetadata { + // Default PTZ and transform + NavigationMetadata { + node_graph_ptz: PTZ::default(), + node_graph_to_viewport: DAffine2::IDENTITY, + // TODO: Eventually replace with footprint + node_graph_top_right: DVec2::ZERO, + } + } +} + +// PartialEq required by message handlers +/// All persistent editor and Graphene data for a node. Used to serialize and deserialize a node, pass it through the editor, and create definitions. +#[derive(Debug, Clone, Default, PartialEq, serde::Serialize, serde::Deserialize)] +pub struct NodeTemplate { + pub document_node: DocumentNode, + pub persistent_node_metadata: DocumentNodePersistentMetadata, +} + +#[derive(Clone, Copy, Debug, Default, PartialEq, serde::Serialize, serde::Deserialize)] +pub enum TransactionStatus { + Started, + Modified, + #[default] + Finished, +} diff --git a/editor/src/messages/portfolio/document/utility_types/nodes.rs b/editor/src/messages/portfolio/document/utility_types/nodes.rs new file mode 100644 index 0000000000000000000000000000000000000000..d81f1693d70ec23fa61092f93e61ebda0e10c7e0 --- /dev/null +++ b/editor/src/messages/portfolio/document/utility_types/nodes.rs @@ -0,0 +1,156 @@ +use super::document_metadata::{DocumentMetadata, LayerNodeIdentifier}; +use super::network_interface::NodeNetworkInterface; +use graph_craft::document::{NodeId, NodeNetwork}; +use serde::ser::SerializeStruct; + +#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, PartialEq, Eq, specta::Type)] +pub struct RawBuffer(Vec); + +impl From<&[u64]> for RawBuffer { + fn from(iter: &[u64]) -> Self { + let v_from_raw: Vec = iter.iter().flat_map(|x| x.to_ne_bytes()).collect(); + Self(v_from_raw) + } +} +#[derive(Debug, Clone, serde::Deserialize, PartialEq, Eq, specta::Type)] +pub struct JsRawBuffer(Vec); + +impl From for JsRawBuffer { + fn from(buffer: RawBuffer) -> Self { + Self(buffer.0) + } +} +impl serde::Serialize for JsRawBuffer { + fn serialize(&self, serializer: S) -> Result { + let mut buffer = serializer.serialize_struct("Buffer", 2)?; + buffer.serialize_field("pointer", &(self.0.as_ptr() as usize))?; + buffer.serialize_field("length", &(self.0.len()))?; + buffer.end() + } +} + +#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, PartialEq, Eq, specta::Type)] +pub struct LayerPanelEntry { + pub id: NodeId, + pub alias: String, + pub tooltip: String, + #[serde(rename = "inSelectedNetwork")] + pub in_selected_network: bool, + #[serde(rename = "childrenAllowed")] + pub children_allowed: bool, + #[serde(rename = "childrenPresent")] + pub children_present: bool, + pub expanded: bool, + pub depth: usize, + pub visible: bool, + #[serde(rename = "parentsVisible")] + pub parents_visible: bool, + pub unlocked: bool, + #[serde(rename = "parentsUnlocked")] + pub parents_unlocked: bool, + #[serde(rename = "parentId")] + pub parent_id: Option, + pub selected: bool, + #[serde(rename = "ancestorOfSelected")] + pub ancestor_of_selected: bool, + #[serde(rename = "descendantOfSelected")] + pub descendant_of_selected: bool, + pub clipped: bool, + pub clippable: bool, +} + +#[derive(Debug, Clone, Default, serde::Serialize, serde::Deserialize, PartialEq, Eq, specta::Type)] +pub struct SelectedNodes(pub Vec); + +impl SelectedNodes { + pub fn layer_visible(&self, layer: LayerNodeIdentifier, network_interface: &NodeNetworkInterface) -> bool { + layer.ancestors(network_interface.document_metadata()).all(|layer| { + if layer != LayerNodeIdentifier::ROOT_PARENT { + network_interface.is_visible(&layer.to_node(), &[]) + } else { + true + } + }) + } + + pub fn selected_visible_layers<'a>(&'a self, network_interface: &'a NodeNetworkInterface) -> impl Iterator + 'a { + self.selected_layers(network_interface.document_metadata()) + .filter(move |&layer| self.layer_visible(layer, network_interface)) + } + + pub fn layer_locked(&self, layer: LayerNodeIdentifier, network_interface: &NodeNetworkInterface) -> bool { + layer.ancestors(network_interface.document_metadata()).any(|layer| { + if layer != LayerNodeIdentifier::ROOT_PARENT { + network_interface.is_locked(&layer.to_node(), &[]) + } else { + false + } + }) + } + + pub fn selected_unlocked_layers<'a>(&'a self, network_interface: &'a NodeNetworkInterface) -> impl Iterator + 'a { + self.selected_layers(network_interface.document_metadata()) + .filter(move |&layer| !self.layer_locked(layer, network_interface)) + } + + pub fn selected_visible_and_unlocked_layers<'a>(&'a self, network_interface: &'a NodeNetworkInterface) -> impl Iterator + 'a { + self.selected_layers(network_interface.document_metadata()) + .filter(move |&layer| self.layer_visible(layer, network_interface) && !self.layer_locked(layer, network_interface)) + } + + pub fn selected_layers<'a>(&'a self, metadata: &'a DocumentMetadata) -> impl Iterator + 'a { + metadata.all_layers().filter(|layer| self.0.contains(&layer.to_node())) + } + + pub fn selected_layers_except_artboards<'a>(&'a self, network_interface: &'a NodeNetworkInterface) -> impl Iterator + 'a { + self.selected_layers(network_interface.document_metadata()) + .filter(move |&layer| !network_interface.is_artboard(&layer.to_node(), &[])) + } + + pub fn selected_layers_contains(&self, layer: LayerNodeIdentifier, metadata: &DocumentMetadata) -> bool { + self.selected_layers(metadata).any(|selected| selected == layer) + } + + pub fn selected_nodes(&self) -> impl Iterator + '_ { + self.0.iter() + } + + pub fn selected_nodes_ref(&self) -> &Vec { + &self.0 + } + + pub fn network_has_selected_nodes(&self, network: &NodeNetwork) -> bool { + self.0.iter().any(|node_id| network.nodes.contains_key(node_id)) + } + + pub fn has_selected_nodes(&self) -> bool { + !self.0.is_empty() + } + + pub fn retain_selected_nodes(&mut self, f: impl FnMut(&NodeId) -> bool) { + self.0.retain(f); + } + + pub fn set_selected_nodes(&mut self, new: Vec) { + self.0 = new; + } + + pub fn add_selected_nodes(&mut self, new: Vec) { + self.0.extend(new); + } + + pub fn clear_selected_nodes(&mut self) { + self.0 = Vec::new(); + } + + pub fn replace_with(&mut self, new: Vec) -> Vec { + std::mem::replace(&mut self.0, new) + } + + pub fn filtered_selected_nodes(&self, node_ids: std::collections::HashSet) -> SelectedNodes { + SelectedNodes(self.0.iter().filter(|node_id| node_ids.contains(node_id)).cloned().collect()) + } +} + +#[derive(Debug, Clone, Default, serde::Serialize, serde::Deserialize, PartialEq, Eq, specta::Type)] +pub struct CollapsedLayers(pub Vec); diff --git a/editor/src/messages/portfolio/document/utility_types/transformation.rs b/editor/src/messages/portfolio/document/utility_types/transformation.rs new file mode 100644 index 0000000000000000000000000000000000000000..e0149939a511cfb169c34526988de82375ce0c41 --- /dev/null +++ b/editor/src/messages/portfolio/document/utility_types/transformation.rs @@ -0,0 +1,799 @@ +use super::network_interface::NodeNetworkInterface; +use crate::consts::{ROTATE_INCREMENT, SCALE_INCREMENT}; +use crate::messages::portfolio::document::graph_operation::transform_utils; +use crate::messages::portfolio::document::graph_operation::utility_types::{ModifyInputsContext, TransformIn}; +use crate::messages::portfolio::document::utility_types::document_metadata::{DocumentMetadata, LayerNodeIdentifier}; +use crate::messages::prelude::*; +use crate::messages::tool::common_functionality::graph_modification_utils; +use crate::messages::tool::common_functionality::shape_editor::ShapeState; +use crate::messages::tool::utility_types::ToolType; +use glam::{DAffine2, DMat2, DVec2}; +use graphene_std::renderer::Quad; +use graphene_std::vector::{HandleExt, HandleId, ManipulatorPointId, PointId, VectorModificationType}; +use std::collections::{HashMap, VecDeque}; +use std::f64::consts::PI; + +#[derive(Debug, PartialEq, Clone, Copy)] +struct AnchorPoint { + initial: DVec2, + current: DVec2, +} + +#[derive(Debug, PartialEq, Clone, Copy)] +struct HandlePoint { + initial: DVec2, + relative: DVec2, + anchor: PointId, + mirror: Option<(HandleId, DVec2)>, +} + +#[derive(Debug, PartialEq, Clone)] +pub struct InitialPoints { + anchors: HashMap, + handles: HashMap, +} + +#[derive(Debug, PartialEq, Clone)] +pub enum OriginalTransforms { + Layer(HashMap), + Path(HashMap), +} +impl Default for OriginalTransforms { + fn default() -> Self { + OriginalTransforms::Path(HashMap::new()) + } +} +impl OriginalTransforms { + pub fn clear(&mut self) { + match self { + OriginalTransforms::Layer(layer_map) => layer_map.clear(), + OriginalTransforms::Path(path_map) => path_map.clear(), + } + } + + /// Gets the transform from the most downstream transform node + fn get_layer_transform(layer: LayerNodeIdentifier, network_interface: &NodeNetworkInterface) -> Option { + let transform_node_id = ModifyInputsContext::locate_node_in_layer_chain("Transform", layer, network_interface)?; + + let document_node = network_interface.document_network().nodes.get(&transform_node_id)?; + Some(transform_utils::get_current_transform(&document_node.inputs)) + } + + pub fn update<'a>(&mut self, selected: &'a [LayerNodeIdentifier], network_interface: &NodeNetworkInterface, shape_editor: Option<&'a ShapeState>) { + match self { + OriginalTransforms::Layer(layer_map) => { + layer_map.retain(|layer, _| selected.contains(layer)); + for &layer in selected { + if layer == LayerNodeIdentifier::ROOT_PARENT { + continue; + } + + layer_map.entry(layer).or_insert_with(|| Self::get_layer_transform(layer, network_interface).unwrap_or_default()); + } + } + OriginalTransforms::Path(path_map) => { + let Some(shape_editor) = shape_editor else { + warn!("No shape editor structure found, which only happens in select tool, which cannot reach this point as we check for ToolType"); + return; + }; + for &layer in selected { + if path_map.contains_key(&layer) { + continue; + } + let Some(vector_data) = network_interface.compute_modified_vector(layer) else { + continue; + }; + let Some(selected_points) = shape_editor.selected_points_in_layer(layer) else { + continue; + }; + let Some(selected_segments) = shape_editor.selected_segments_in_layer(layer) else { + continue; + }; + + let mut selected_points = selected_points.clone(); + + for (segment_id, _, start, end) in vector_data.segment_bezier_iter() { + if selected_segments.contains(&segment_id) { + selected_points.insert(ManipulatorPointId::Anchor(start)); + selected_points.insert(ManipulatorPointId::Anchor(end)); + } + } + + // Anchors also move their handles + let anchor_ids = selected_points.iter().filter_map(|point| point.as_anchor()); + let anchors = anchor_ids.filter_map(|id| vector_data.point_domain.position_from_id(id).map(|pos| (id, AnchorPoint { initial: pos, current: pos }))); + let anchors = anchors.collect(); + + let selected_handles = selected_points.iter().filter_map(|point| point.as_handle()); + let anchor_ids = selected_points.iter().filter_map(|point| point.as_anchor()); + let connected_handles = anchor_ids.flat_map(|point| vector_data.all_connected(point)); + let all_handles = selected_handles.chain(connected_handles); + + let handles = all_handles + .filter_map(|id| { + let anchor = id.to_manipulator_point().get_anchor(&vector_data)?; + let initial = id.to_manipulator_point().get_position(&vector_data)?; + let relative = vector_data.point_domain.position_from_id(anchor)?; + let other_handle = vector_data + .other_colinear_handle(id) + .filter(|other| !selected_points.contains(&other.to_manipulator_point()) && !selected_points.contains(&ManipulatorPointId::Anchor(anchor))); + let mirror = other_handle.and_then(|id| Some((id, id.to_manipulator_point().get_position(&vector_data)?))); + + Some((id, HandlePoint { initial, relative, anchor, mirror })) + }) + .collect(); + + path_map.insert(layer, InitialPoints { anchors, handles }); + } + } + } + } +} + +#[derive(Default, Debug, Clone, PartialEq, Eq, Copy)] +pub enum Axis { + #[default] + Both, + X, + Y, +} + +impl Axis { + pub fn contrainted_to_axis(self, target: Axis, local: bool) -> (Self, bool) { + if self != target { + return (target, false); + } + + if local { (Axis::Both, false) } else { (self, true) } + } +} + +#[derive(Default, Debug, Clone, PartialEq, Copy)] +pub struct Translation { + pub dragged_distance: DVec2, + pub typed_distance: Option, + pub constraint: Axis, +} + +impl Translation { + pub fn to_dvec(self, transform: DAffine2, increment_mode: bool) -> DVec2 { + let displacement = if let Some(value) = self.typed_distance { + match self.constraint { + Axis::X => transform.transform_vector2(DVec2::new(value, 0.)), + Axis::Y => transform.transform_vector2(DVec2::new(0., value)), + Axis::Both => self.dragged_distance, + } + } else { + match self.constraint { + Axis::Both => self.dragged_distance, + Axis::X => DVec2::new(self.dragged_distance.x, 0.), + Axis::Y => DVec2::new(0., self.dragged_distance.y), + } + }; + let displacement = transform.inverse().transform_vector2(displacement); + if increment_mode { displacement.round() } else { displacement } + } + + #[must_use] + pub fn increment_amount(self, delta: DVec2) -> Self { + Self { + dragged_distance: self.dragged_distance + delta, + typed_distance: None, + constraint: self.constraint, + } + } + pub fn set_amount(self, change: DVec2) -> Self { + Self { + dragged_distance: change, + typed_distance: None, + constraint: self.constraint, + } + } + + pub fn negate(self) -> Self { + let dragged_distance = -self.dragged_distance; + Self { dragged_distance, ..self } + } + + pub fn with_constraint(self, target: Axis, local: bool) -> (Self, bool) { + let (constraint, local) = self.constraint.contrainted_to_axis(target, local); + (Self { constraint, ..self }, local) + } +} + +#[derive(Default, Debug, Clone, PartialEq, Copy)] +pub struct Rotation { + pub dragged_angle: f64, + pub typed_angle: Option, +} + +impl Rotation { + pub fn to_f64(self, increment_mode: bool) -> f64 { + if let Some(value) = self.typed_angle { + value.to_radians() + } else if increment_mode { + let increment_resolution = ROTATE_INCREMENT.to_radians(); + (self.dragged_angle / increment_resolution).round() * increment_resolution + } else { + self.dragged_angle + } + } + + #[must_use] + pub fn increment_amount(self, delta: f64) -> Self { + Self { + dragged_angle: self.dragged_angle + delta, + typed_angle: None, + } + } + pub fn set_amount(self, angle: f64) -> Self { + Self { + dragged_angle: angle, + typed_angle: None, + } + } + + pub fn negate(self) -> Self { + let dragged_angle = -self.dragged_angle; + Self { dragged_angle, ..self } + } +} + +#[derive(Debug, Clone, PartialEq, Copy)] +pub struct Scale { + pub dragged_factor: f64, + pub typed_factor: Option, + pub constraint: Axis, +} + +impl Default for Scale { + fn default() -> Self { + Self { + dragged_factor: 1., + typed_factor: None, + constraint: Axis::default(), + } + } +} + +impl Scale { + pub fn to_f64(self, increment: bool) -> f64 { + let factor = if let Some(value) = self.typed_factor { value } else { self.dragged_factor }; + if increment { (factor / SCALE_INCREMENT).round() * SCALE_INCREMENT } else { factor } + } + + pub fn to_dvec(self, increment_mode: bool) -> DVec2 { + let factor = self.to_f64(increment_mode); + + match self.constraint { + Axis::Both => DVec2::splat(factor), + Axis::X => DVec2::new(factor, 1.), + Axis::Y => DVec2::new(1., factor), + } + } + + pub fn negate(self) -> Self { + let dragged_factor = -self.dragged_factor; + Self { dragged_factor, ..self } + } + + #[must_use] + pub fn increment_amount(self, delta: f64) -> Self { + Self { + dragged_factor: (self.dragged_factor + delta), + typed_factor: None, + constraint: self.constraint, + } + } + + pub fn set_amount(self, change: f64) -> Self { + Self { + dragged_factor: 1. + change, + typed_factor: None, + constraint: self.constraint, + } + } + + pub fn with_constraint(self, target: Axis, local: bool) -> (Self, bool) { + let (constraint, local) = self.constraint.contrainted_to_axis(target, local); + (Self { constraint, ..self }, local) + } +} + +#[derive(Default, Debug, Clone, PartialEq, Copy)] +pub enum TransformOperation { + #[default] + None, + Grabbing(Translation), + Rotating(Rotation), + Scaling(Scale), +} + +#[derive(Debug, Clone, PartialEq, Copy, serde::Serialize, serde::Deserialize)] +pub enum TransformType { + Grab, + Rotate, + Scale, +} + +impl TransformType { + pub fn equivalent_to(&self, operation: TransformOperation) -> bool { + matches!( + (operation, self), + (TransformOperation::Scaling(_), TransformType::Scale) | (TransformOperation::Grabbing(_), TransformType::Grab) | (TransformOperation::Rotating(_), TransformType::Rotate) + ) + } +} + +impl TransformOperation { + #[allow(clippy::too_many_arguments)] + pub fn apply_transform_operation(&self, selected: &mut Selected, increment_mode: bool, local: bool, quad: Quad, transform: DAffine2, pivot: DVec2, local_transform: DAffine2) { + let local_axis_transform_angle = (quad.top_left() - quad.top_right()).to_angle(); + if self != &TransformOperation::None { + let transformation = match self { + TransformOperation::Grabbing(translation) => { + let translate = DAffine2::from_translation(transform.transform_vector2(translation.to_dvec(local_transform, increment_mode))); + if local { + let resolved_angle = if local_axis_transform_angle > 0. { + local_axis_transform_angle + } else { + local_axis_transform_angle - PI + }; + DAffine2::from_angle(resolved_angle) * translate * DAffine2::from_angle(-resolved_angle) + } else { + translate + } + } + TransformOperation::Rotating(rotation) => DAffine2::from_angle(rotation.to_f64(increment_mode)), + TransformOperation::Scaling(scale) => { + if local { + DAffine2::from_angle(local_axis_transform_angle) * DAffine2::from_scale(scale.to_dvec(increment_mode)) * DAffine2::from_angle(-local_axis_transform_angle) + } else { + DAffine2::from_scale(scale.to_dvec(increment_mode)) + } + } + TransformOperation::None => unreachable!(), + }; + + selected.update_transforms(transformation, Some(pivot), Some(*self)); + self.hints(selected.responses, local); + } + } + + pub fn axis_constraint(&self) -> Axis { + match self { + TransformOperation::Grabbing(grabbing) => grabbing.constraint, + TransformOperation::Scaling(scaling) => scaling.constraint, + _ => Axis::Both, + } + } + + pub fn can_begin_typing(&self) -> bool { + self.is_constraint_to_axis() || !matches!(self, TransformOperation::Grabbing(_)) + } + + #[allow(clippy::too_many_arguments)] + pub fn constrain_axis(&mut self, axis: Axis, selected: &mut Selected, increment_mode: bool, mut local: bool, quad: Quad, transform: DAffine2, pivot: DVec2, local_transform: DAffine2) -> bool { + (*self, local) = match self { + TransformOperation::Grabbing(translation) => { + let (translation, local) = translation.with_constraint(axis, local); + (TransformOperation::Grabbing(translation), local) + } + TransformOperation::Scaling(scale) => { + let (scale, local) = scale.with_constraint(axis, local); + (TransformOperation::Scaling(scale), local) + } + _ => (*self, false), + }; + self.apply_transform_operation(selected, increment_mode, local, quad, transform, pivot, local_transform); + local + } + + #[allow(clippy::too_many_arguments)] + pub fn grs_typed(&mut self, typed: Option, selected: &mut Selected, increment_mode: bool, local: bool, quad: Quad, transform: DAffine2, pivot: DVec2, local_transform: DAffine2) { + match self { + TransformOperation::None => (), + TransformOperation::Grabbing(translation) => translation.typed_distance = typed, + TransformOperation::Rotating(rotation) => rotation.typed_angle = typed, + TransformOperation::Scaling(scale) => scale.typed_factor = typed, + }; + + self.apply_transform_operation(selected, increment_mode, local, quad, transform, pivot, local_transform); + } + + pub fn hints(&self, responses: &mut VecDeque, local: bool) { + use crate::messages::input_mapper::utility_types::input_keyboard::{Key, MouseMotion}; + use crate::messages::tool::utility_types::{HintData, HintGroup, HintInfo}; + + let mut input_hints = Vec::new(); + let clear_constraint = "Clear Constraint"; + match self.axis_constraint() { + Axis::Both => { + input_hints.push(HintInfo::keys([Key::KeyX], "X-Axis Constraint")); + input_hints.push(HintInfo::keys([Key::KeyY], "Y-Axis Constraint")); + } + Axis::X => { + let x_label = if local { clear_constraint } else { "Local X-Axis Constraint" }; + input_hints.push(HintInfo::keys([Key::KeyX], x_label)); + input_hints.push(HintInfo::keys([Key::KeyY], "Y-Axis Constraint")); + if !local { + input_hints.push(HintInfo::keys([Key::KeyX, Key::KeyX], clear_constraint)); + } + } + Axis::Y => { + let y_label = if local { clear_constraint } else { "Local Y-Axis Constraint" }; + input_hints.push(HintInfo::keys([Key::KeyX], "X-Axis Constraint")); + input_hints.push(HintInfo::keys([Key::KeyY], y_label)); + if !local { + input_hints.push(HintInfo::keys([Key::KeyY, Key::KeyY], clear_constraint)); + } + } + } + + let grs_hint_group = match self { + TransformOperation::None => unreachable!(), + TransformOperation::Scaling(_) => HintGroup(vec![HintInfo::multi_keys([[Key::KeyG], [Key::KeyR]], "Grab/Rotate Selected")]), + TransformOperation::Grabbing(_) => HintGroup(vec![HintInfo::multi_keys([[Key::KeyR], [Key::KeyS]], "Rotate/Scale Selected")]), + TransformOperation::Rotating(_) => HintGroup(vec![HintInfo::multi_keys([[Key::KeyG], [Key::KeyS]], "Grab/Scale Selected")]), + }; + + let confirm_and_cancel_group = HintGroup(vec![ + HintInfo::mouse(MouseMotion::Lmb, ""), + HintInfo::keys([Key::Enter], "Confirm").prepend_slash(), + HintInfo::mouse(MouseMotion::Rmb, ""), + HintInfo::keys([Key::Escape], "Cancel").prepend_slash(), + ]); + let mut hint_groups = vec![confirm_and_cancel_group, grs_hint_group]; + if !self.is_typing() { + let modifiers = vec![ + HintInfo::keys([Key::Shift], "Slow"), + HintInfo::keys([Key::Control], if matches!(self, TransformOperation::Rotating(_)) { "15° Increments" } else { "Increments" }), + ]; + hint_groups.push(HintGroup(modifiers)); + } + if !matches!(self, TransformOperation::Rotating(_)) { + hint_groups.push(HintGroup(input_hints)); + } + let mut typing_hints = vec![HintInfo::keys([Key::Minus], "Negate Direction")]; + if self.can_begin_typing() { + typing_hints.push(HintInfo::keys([Key::NumKeys], "Enter Number")); + if self.is_typing() { + typing_hints.push(HintInfo::keys([Key::Backspace], "Delete Digit")); + } + } + hint_groups.push(HintGroup(typing_hints)); + + let hint_data = HintData(hint_groups); + responses.add(FrontendMessage::UpdateInputHints { hint_data }); + } + + pub fn is_constraint_to_axis(&self) -> bool { + self.axis_constraint() != Axis::Both + } + + pub fn is_typing(&self) -> bool { + match self { + TransformOperation::None => false, + TransformOperation::Grabbing(translation) => translation.typed_distance.is_some(), + TransformOperation::Rotating(rotation) => rotation.typed_angle.is_some(), + TransformOperation::Scaling(scale) => scale.typed_factor.is_some(), + } + } + + #[allow(clippy::too_many_arguments)] + pub fn negate(&mut self, selected: &mut Selected, increment_mode: bool, local: bool, quad: Quad, transform: DAffine2, pivot: DVec2, local_transform: DAffine2) { + if *self != TransformOperation::None { + *self = match self { + TransformOperation::Scaling(scale) => TransformOperation::Scaling(scale.negate()), + TransformOperation::Rotating(rotation) => TransformOperation::Rotating(rotation.negate()), + TransformOperation::Grabbing(translation) => TransformOperation::Grabbing(translation.negate()), + _ => *self, + }; + self.apply_transform_operation(selected, increment_mode, local, quad, transform, pivot, local_transform); + } + } +} + +pub struct Selected<'a> { + pub selected: &'a [LayerNodeIdentifier], + pub responses: &'a mut VecDeque, + pub network_interface: &'a NodeNetworkInterface, + pub original_transforms: &'a mut OriginalTransforms, + pub pivot: &'a mut DVec2, + pub shape_editor: Option<&'a ShapeState>, + pub tool_type: &'a ToolType, + // Only for the Pen tool + pub pen_handle: Option<&'a mut DVec2>, +} + +impl<'a> Selected<'a> { + #[allow(clippy::too_many_arguments)] + pub fn new( + original_transforms: &'a mut OriginalTransforms, + pivot: &'a mut DVec2, + selected: &'a [LayerNodeIdentifier], + responses: &'a mut VecDeque, + network_interface: &'a NodeNetworkInterface, + shape_editor: Option<&'a ShapeState>, + tool_type: &'a ToolType, + pen_handle: Option<&'a mut DVec2>, + ) -> Self { + // If user is using the Select tool then use the original layer transforms + if (*tool_type == ToolType::Select) && (*original_transforms == OriginalTransforms::Path(HashMap::new())) { + *original_transforms = OriginalTransforms::Layer(HashMap::new()); + } + + original_transforms.update(selected, network_interface, shape_editor); + + Self { + selected, + responses, + network_interface, + original_transforms, + pivot, + shape_editor, + tool_type, + pen_handle, + } + } + + pub fn mean_average_of_pivots(&mut self) -> DVec2 { + let xy_summation = self + .selected + .iter() + .map(|&layer| graph_modification_utils::get_viewport_pivot(layer, self.network_interface)) + .reduce(|a, b| a + b) + .unwrap_or_default(); + + xy_summation / self.selected.len() as f64 + } + + pub fn center_of_aabb(&mut self) -> DVec2 { + let [min, max] = self + .selected + .iter() + .filter_map(|&layer| self.network_interface.document_metadata().bounding_box_viewport(layer)) + .reduce(Quad::combine_bounds) + .unwrap_or_default(); + (min + max) / 2. + } + + pub fn bounding_box(&mut self) -> Quad { + let metadata = self.network_interface.document_metadata(); + + let mut transform = self + .network_interface + .selected_nodes() + .selected_visible_and_unlocked_layers(self.network_interface) + .find(|layer| !self.network_interface.is_artboard(&layer.to_node(), &[])) + .map(|layer| metadata.transform_to_viewport(layer)) + .unwrap_or(DAffine2::IDENTITY); + + if transform.matrix2.determinant().abs() <= f64::EPSILON { + transform.matrix2 += DMat2::IDENTITY * 1e-4; // TODO: Is this the cleanest way to handle this? + } + + let bounds = self + .selected + .iter() + .filter_map(|&layer| metadata.bounding_box_with_transform(layer, transform.inverse() * metadata.transform_to_viewport(layer))) + .reduce(Quad::combine_bounds) + .unwrap_or_default(); + + transform * Quad::from_box(bounds) + } + + fn transform_layer(document_metadata: &DocumentMetadata, layer: LayerNodeIdentifier, original_transform: Option<&DAffine2>, transformation: DAffine2, responses: &mut VecDeque) { + let Some(&original_transform) = original_transform else { return }; + let to = document_metadata.downstream_transform_to_viewport(layer); + let new = to.inverse() * transformation * to * original_transform; + responses.add(GraphOperationMessage::TransformSet { + layer, + transform: new, + transform_in: TransformIn::Local, + skip_rerender: false, + }); + } + + fn transform_path( + document_metadata: &DocumentMetadata, + layer: LayerNodeIdentifier, + initial_points: &mut InitialPoints, + transformation: DAffine2, + responses: &mut VecDeque, + transform_operation: Option, + ) { + let viewspace = document_metadata.transform_to_viewport(layer); + let layerspace_rotation = viewspace.inverse() * transformation; + + for (&point, anchor) in initial_points.anchors.iter_mut() { + let new_pos_viewport = layerspace_rotation.transform_point2(viewspace.transform_point2(anchor.initial)); + let delta = new_pos_viewport - anchor.current; + anchor.current += delta; + let modification_type = VectorModificationType::ApplyPointDelta { point, delta }; + responses.add(GraphOperationMessage::Vector { layer, modification_type }); + } + + if transform_operation.is_some_and(|transform_operation| matches!(transform_operation, TransformOperation::Scaling(_))) && (initial_points.anchors.len() == 2) { + return; + } + + for (&id, handle) in initial_points.handles.iter() { + let new_pos_viewport = layerspace_rotation.transform_point2(viewspace.transform_point2(handle.initial)); + let relative = initial_points.anchors.get(&handle.anchor).map_or(handle.relative, |anchor| anchor.current); + let modification_type = id.set_relative_position(new_pos_viewport - relative); + responses.add(GraphOperationMessage::Vector { layer, modification_type }); + + if let Some((id, initial)) = handle.mirror { + // When the handle is scaled to zero, don't update the mirror handle + if (new_pos_viewport - relative).length_squared() > f64::EPSILON { + let direction = viewspace.transform_vector2(new_pos_viewport - relative).try_normalize(); + let length = viewspace.transform_vector2(initial - relative).length(); + let new_relative = direction.map_or(initial - relative, |direction| viewspace.inverse().transform_vector2(-direction * length)); + let modification_type = id.set_relative_position(new_relative); + responses.add(GraphOperationMessage::Vector { layer, modification_type }); + } + } + } + } + + pub fn apply_transform_pen(&mut self, transformation: DAffine2) { + if let Some(pen_handle) = &self.pen_handle { + let final_position = transformation.transform_point2(**pen_handle); + self.responses.add(PenToolMessage::FinalPosition { final_position }); + } + } + + pub fn apply_transformation(&mut self, transformation: DAffine2, transform_operation: Option) { + if self.selected.is_empty() { + return; + } + + // TODO: Cache the result of `shallowest_unique_layers` to avoid this heavy computation every frame of movement, see https://github.com/GraphiteEditor/Graphite/pull/481 + for layer in self.network_interface.shallowest_unique_layers(&[]) { + match &mut self.original_transforms { + OriginalTransforms::Layer(layer_transforms) => Self::transform_layer(self.network_interface.document_metadata(), layer, layer_transforms.get(&layer), transformation, self.responses), + OriginalTransforms::Path(path_transforms) => { + if let Some(initial_points) = path_transforms.get_mut(&layer) { + Self::transform_path(self.network_interface.document_metadata(), layer, initial_points, transformation, self.responses, transform_operation) + } + } + } + } + } + + pub fn update_transforms(&mut self, delta: DAffine2, pivot: Option, transform_operation: Option) { + let pivot = DAffine2::from_translation(pivot.unwrap_or(*self.pivot)); + let transformation = pivot * delta * pivot.inverse(); + match self.tool_type { + ToolType::Pen => self.apply_transform_pen(transformation), + _ => self.apply_transformation(transformation, transform_operation), + } + } + + pub fn revert_operation(&mut self) { + for layer in self.selected.iter().copied() { + let original_transform = &self.original_transforms; + match original_transform { + OriginalTransforms::Layer(hash) => { + let Some(matrix) = hash.get(&layer) else { continue }; + self.responses.add(GraphOperationMessage::TransformSet { + layer, + transform: *matrix, + transform_in: TransformIn::Local, + skip_rerender: false, + }); + } + OriginalTransforms::Path(path) => { + for (&layer, points) in path { + for (&point, &anchor) in &points.anchors { + let delta = anchor.initial - anchor.current; + let modification_type = VectorModificationType::ApplyPointDelta { point, delta }; + self.responses.add(GraphOperationMessage::Vector { layer, modification_type }); + } + + for (&point, &handle) in &points.handles { + let modification_type = point.set_relative_position(handle.initial - handle.relative); + self.responses.add(GraphOperationMessage::Vector { layer, modification_type }); + + if let Some((id, initial)) = handle.mirror { + let modification_type = id.set_relative_position(initial - handle.relative); + self.responses.add(GraphOperationMessage::Vector { layer, modification_type }); + } + } + } + } + } + } + } +} + +#[derive(Debug, Clone, PartialEq, Eq, Default)] +pub struct Typing { + pub digits: Vec, + pub string: String, + pub contains_decimal: bool, + pub negative: bool, +} + +const DECIMAL_POINT: u8 = 10; + +impl Typing { + pub fn type_number(&mut self, number: u8) -> Option { + self.digits.push(number); + self.string.push((b'0' + number) as char); + + self.evaluate() + } + + pub fn type_backspace(&mut self) -> Option { + if self.digits.is_empty() { + return None; + } + + match self.digits.pop() { + Some(DECIMAL_POINT) => self.contains_decimal = false, + Some(_) => (), + None => self.negative = false, + } + self.string.pop(); + self.evaluate() + } + + pub fn type_decimal_point(&mut self) -> Option { + if !self.contains_decimal { + self.contains_decimal = true; + self.digits.push(DECIMAL_POINT); + self.string.push('.'); + } + + self.evaluate() + } + + pub fn type_negate(&mut self) -> Option { + self.negative = !self.negative; + if self.negative { + self.string.insert(0, '-'); + } else { + self.string.remove(0); + } + + self.evaluate() + } + + pub fn evaluate(&self) -> Option { + if self.digits.is_empty() { + return None; + } + + let mut result = 0_f64; + let mut running_decimal_place = 0_i32; + + for digit in &self.digits { + if *digit == DECIMAL_POINT { + if running_decimal_place == 0 { + running_decimal_place = 1; + } + } else if running_decimal_place == 0 { + result *= 10.; + result += *digit as f64; + } else { + result += *digit as f64 * 0.1_f64.powi(running_decimal_place); + running_decimal_place += 1; + } + } + + if self.negative { + result = -result; + } + + Some(result) + } + + pub fn clear(&mut self) { + self.digits.clear(); + self.string.clear(); + self.contains_decimal = false; + self.negative = false; + } +} diff --git a/editor/src/messages/portfolio/document/utility_types/wires.rs b/editor/src/messages/portfolio/document/utility_types/wires.rs new file mode 100644 index 0000000000000000000000000000000000000000..9f85c8267027bce1beb19c87cfb09b1fa4f4d534 --- /dev/null +++ b/editor/src/messages/portfolio/document/utility_types/wires.rs @@ -0,0 +1,589 @@ +use crate::messages::portfolio::document::node_graph::utility_types::FrontendGraphDataType; +use bezier_rs::{ManipulatorGroup, Subpath}; +use glam::{DVec2, IVec2}; +use graphene_std::uuid::NodeId; +use graphene_std::vector::PointId; + +#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize, specta::Type)] +pub struct WirePath { + #[serde(rename = "pathString")] + pub path_string: String, + #[serde(rename = "dataType")] + pub data_type: FrontendGraphDataType, + pub thick: bool, + pub dashed: bool, +} + +#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize, specta::Type)] +pub struct WirePathUpdate { + pub id: NodeId, + #[serde(rename = "inputIndex")] + pub input_index: usize, + // If none, then remove the wire from the map + #[serde(rename = "wirePathUpdate")] + pub wire_path_update: Option, +} + +#[derive(Copy, Clone, Debug, PartialEq, Default, serde::Serialize, serde::Deserialize, specta::Type)] +pub enum GraphWireStyle { + #[default] + Direct = 0, + GridAligned = 1, +} + +impl std::fmt::Display for GraphWireStyle { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + GraphWireStyle::GridAligned => write!(f, "Grid-Aligned"), + GraphWireStyle::Direct => write!(f, "Direct"), + } + } +} + +impl GraphWireStyle { + pub fn tooltip_description(&self) -> &'static str { + match self { + GraphWireStyle::GridAligned => "Wires follow the grid, running in straight lines between nodes", + GraphWireStyle::Direct => "Wires bend to run at an angle directly between nodes", + } + } + + pub fn is_direct(&self) -> bool { + *self == GraphWireStyle::Direct + } +} + +pub fn build_vector_wire(output_position: DVec2, input_position: DVec2, vertical_out: bool, vertical_in: bool, graph_wire_style: GraphWireStyle) -> Subpath { + let grid_spacing = 24.; + match graph_wire_style { + GraphWireStyle::Direct => { + let horizontal_gap = (output_position.x - input_position.x).abs(); + let vertical_gap = (output_position.y - input_position.y).abs(); + + let curve_length = grid_spacing; + let curve_falloff_rate = curve_length * std::f64::consts::TAU; + + let horizontal_curve_amount = -(2_f64.powf((-10. * horizontal_gap) / curve_falloff_rate)) + 1.; + let vertical_curve_amount = -(2_f64.powf((-10. * vertical_gap) / curve_falloff_rate)) + 1.; + let horizontal_curve = horizontal_curve_amount * curve_length; + let vertical_curve = vertical_curve_amount * curve_length; + + let locations = [ + output_position, + DVec2::new( + if vertical_out { output_position.x } else { output_position.x + horizontal_curve }, + if vertical_out { output_position.y - vertical_curve } else { output_position.y }, + ), + DVec2::new( + if vertical_in { input_position.x } else { input_position.x - horizontal_curve }, + if vertical_in { input_position.y + vertical_curve } else { input_position.y }, + ), + DVec2::new(input_position.x, input_position.y), + ]; + + let smoothing = 0.5; + let delta01 = DVec2::new((locations[1].x - locations[0].x) * smoothing, (locations[1].y - locations[0].y) * smoothing); + let delta23 = DVec2::new((locations[3].x - locations[2].x) * smoothing, (locations[3].y - locations[2].y) * smoothing); + + Subpath::new( + vec![ + ManipulatorGroup { + anchor: locations[0], + in_handle: None, + out_handle: None, + id: PointId::generate(), + }, + ManipulatorGroup { + anchor: locations[1], + in_handle: None, + out_handle: Some(locations[1] + delta01), + id: PointId::generate(), + }, + ManipulatorGroup { + anchor: locations[2], + in_handle: Some(locations[2] - delta23), + out_handle: None, + id: PointId::generate(), + }, + ManipulatorGroup { + anchor: locations[3], + in_handle: None, + out_handle: None, + id: PointId::generate(), + }, + ], + false, + ) + } + GraphWireStyle::GridAligned => { + let locations = straight_wire_paths(output_position, input_position, vertical_out, vertical_in); + straight_wire_subpath(locations) + } + } +} + +fn straight_wire_paths(output_position: DVec2, input_position: DVec2, vertical_out: bool, vertical_in: bool) -> Vec { + let grid_spacing = 24; + let line_width = 2; + + let in_x = input_position.x as i32; + let in_y = input_position.y as i32; + let out_x = output_position.x as i32; + let out_y = output_position.y as i32; + + let mid_x = (in_x + out_x) / 2 + (((in_x + out_x) / 2) % grid_spacing); + let mid_y = (in_y + out_y) / 2 + (((in_y + out_y) / 2) % grid_spacing); + let mid_y_alternate = (in_y + in_y) / 2 - (((in_y + in_y) / 2) % grid_spacing); + + let x1 = out_x; + let x2 = out_x + grid_spacing; + let x3 = in_x - 2 * grid_spacing; + let x4 = in_x; + let x5 = in_x - 2 * grid_spacing + line_width; + let x6 = out_x + grid_spacing + line_width; + let x7 = out_x + 2 * grid_spacing + line_width; + let x8 = in_x + line_width; + let x9 = out_x + 2 * grid_spacing; + let x10 = mid_x + line_width; + let x11 = out_x - grid_spacing; + let x12 = out_x - 4 * grid_spacing; + let x13 = mid_x; + let x14 = in_x + grid_spacing; + let x15 = in_x - 4 * grid_spacing; + let x16 = in_x + 8 * grid_spacing; + let x17 = mid_x - 2 * line_width; + let x18 = out_x + grid_spacing - 2 * line_width; + let x19 = out_x - 2 * line_width; + let x20 = mid_x - line_width; + + let y1 = out_y; + let y2 = out_y - grid_spacing; + let y3 = in_y; + let y4 = out_y - grid_spacing + 5 * line_width + 1; + let y5 = in_y - 2 * grid_spacing; + let y6 = out_y + 4 * line_width; + let y7 = out_y + 5 * line_width; + let y8 = out_y - 2 * grid_spacing + 5 * line_width + 1; + let y9 = out_y + 6 * line_width; + let y10 = in_y + 2 * grid_spacing; + let y111 = in_y + grid_spacing + 6 * line_width + 1; + let y12 = in_y + grid_spacing - 5 * line_width + 1; + let y13 = in_y - grid_spacing; + let y14 = in_y + grid_spacing; + let y15 = mid_y; + let y16 = mid_y_alternate; + + let wire1 = vec![IVec2::new(x1, y1), IVec2::new(x1, y4), IVec2::new(x5, y4), IVec2::new(x5, y3), IVec2::new(x4, y3)]; + + let wire2 = vec![IVec2::new(x1, y1), IVec2::new(x1, y16), IVec2::new(x3, y16), IVec2::new(x3, y3), IVec2::new(x4, y3)]; + + let wire3 = vec![ + IVec2::new(x1, y1), + IVec2::new(x1, y4), + IVec2::new(x12, y4), + IVec2::new(x12, y10), + IVec2::new(x3, y10), + IVec2::new(x3, y3), + IVec2::new(x4, y3), + ]; + + let wire4 = vec![ + IVec2::new(x1, y1), + IVec2::new(x1, y4), + IVec2::new(x13, y4), + IVec2::new(x13, y10), + IVec2::new(x3, y10), + IVec2::new(x3, y3), + IVec2::new(x4, y3), + ]; + + if out_y == in_y && out_x > in_x && (vertical_out || !vertical_in) { + return vec![IVec2::new(x1, y1), IVec2::new(x2, y1), IVec2::new(x2, y2), IVec2::new(x3, y2), IVec2::new(x3, y3), IVec2::new(x4, y3)]; + } + + // `outConnector` point and `inConnector` point lying on the same horizontal grid line and `outConnector` point lies to the right of `inConnector` point + if out_y == in_y && out_x > in_x && (vertical_out || !vertical_in) { + return vec![IVec2::new(x1, y1), IVec2::new(x2, y1), IVec2::new(x2, y2), IVec2::new(x3, y2), IVec2::new(x3, y3), IVec2::new(x4, y3)]; + }; + + // Handle straight lines + if out_y == in_y || (out_x == in_x && vertical_out) { + return vec![IVec2::new(x1, y1), IVec2::new(x4, y3)]; + }; + + // Handle standard right-angle paths + // Start vertical, then horizontal + + // `outConnector` point lies to the left of `inConnector` point + if vertical_out && in_x > out_x { + // `outConnector` point lies above `inConnector` point + if out_y < in_y { + // `outConnector` point lies on the vertical grid line 4 units to the left of `inConnector` point point + if -4 * grid_spacing <= out_x - in_x && out_x - in_x < -3 * grid_spacing { + return wire1; + }; + + // `outConnector` point lying on vertical grid lines 3 and 2 units to the left of `inConnector` point + if -3 * grid_spacing <= out_x - in_x && out_x - in_x <= -grid_spacing { + if -2 * grid_spacing <= out_y - in_y && out_y - in_y <= -grid_spacing { + return vec![IVec2::new(x1, y1), IVec2::new(x1, y2), IVec2::new(x2, y2), IVec2::new(x2, y3), IVec2::new(x4, y3)]; + }; + + if -grid_spacing <= out_y - in_y && out_y - in_y <= 0 { + return vec![IVec2::new(x1, y1), IVec2::new(x1, y4), IVec2::new(x6, y4), IVec2::new(x6, y3), IVec2::new(x4, y3)]; + }; + + return vec![ + IVec2::new(x1, y1), + IVec2::new(x1, y4), + IVec2::new(x7, y4), + IVec2::new(x7, y5), + IVec2::new(x3, y5), + IVec2::new(x3, y3), + IVec2::new(x4, y3), + ]; + } + + // `outConnector` point lying on vertical grid line 1 units to the left of `inConnector` point + if -grid_spacing < out_x - in_x && out_x - in_x <= 0 { + // `outConnector` point lying on horizontal grid line 1 unit above `inConnector` point + if -2 * grid_spacing <= out_y - in_y && out_y - in_y <= -grid_spacing { + return vec![IVec2::new(x1, y6), IVec2::new(x2, y6), IVec2::new(x8, y3)]; + }; + + // `outConnector` point lying on the same horizontal grid line as `inConnector` point + if -grid_spacing <= out_y - in_y && out_y - in_y <= 0 { + return vec![IVec2::new(x1, y7), IVec2::new(x4, y3)]; + }; + + return vec![ + IVec2::new(x1, y1), + IVec2::new(x1, y2), + IVec2::new(x9, y2), + IVec2::new(x9, y5), + IVec2::new(x3, y5), + IVec2::new(x3, y3), + IVec2::new(x4, y3), + ]; + } + + return vec![IVec2::new(x1, y1), IVec2::new(x1, y4), IVec2::new(x10, y4), IVec2::new(x10, y3), IVec2::new(x4, y3)]; + } + + // `outConnector` point lies below `inConnector` point + // `outConnector` point lying on vertical grid line 1 unit to the left of `inConnector` point + if -grid_spacing <= out_x - in_x && out_x - in_x <= 0 { + // `outConnector` point lying on the horizontal grid lines 1 and 2 units below the `inConnector` point + if 0 <= out_y - in_y && out_y - in_y <= 2 * grid_spacing { + return vec![IVec2::new(x1, y6), IVec2::new(x11, y6), IVec2::new(x11, y3), IVec2::new(x4, y3)]; + }; + + return wire2; + } + + return vec![IVec2::new(x1, y1), IVec2::new(x1, y3), IVec2::new(x4, y3)]; + } + + // `outConnector` point lies to the right of `inConnector` point + if vertical_out && in_x <= out_x { + // `outConnector` point lying on any horizontal grid line above `inConnector` point + if out_y < in_y { + // `outConnector` point lying on horizontal grid line 1 unit above `inConnector` point + if -2 * grid_spacing < out_y - in_y && out_y - in_y <= -grid_spacing { + return wire1; + }; + + // `outConnector` point lying on the same horizontal grid line as `inConnector` point + if -grid_spacing < out_y - in_y && out_y - in_y <= 0 { + return vec![IVec2::new(x1, y1), IVec2::new(x1, y8), IVec2::new(x5, y8), IVec2::new(x5, y3), IVec2::new(x4, y3)]; + }; + + // `outConnector` point lying on vertical grid lines 1 and 2 units to the right of `inConnector` point + if grid_spacing <= out_x - in_x && out_x - in_x <= 3 * grid_spacing { + return vec![ + IVec2::new(x1, y1), + IVec2::new(x1, y4), + IVec2::new(x9, y4), + IVec2::new(x9, y5), + IVec2::new(x3, y5), + IVec2::new(x3, y3), + IVec2::new(x4, y3), + ]; + } + + return vec![ + IVec2::new(x1, y1), + IVec2::new(x1, y4), + IVec2::new(x10, y4), + IVec2::new(x10, y5), + IVec2::new(x5, y5), + IVec2::new(x5, y3), + IVec2::new(x4, y3), + ]; + } + + // `outConnector` point lies below `inConnector` point + if out_y - in_y <= grid_spacing { + // `outConnector` point lies on the horizontal grid line 1 unit below the `inConnector` Point + if 0 <= out_x - in_x && out_x - in_x <= 13 * grid_spacing { + return vec![IVec2::new(x1, y9), IVec2::new(x3, y9), IVec2::new(x3, y3), IVec2::new(x4, y3)]; + }; + + if 13 < out_x - in_x && out_x - in_x <= 18 * grid_spacing { + return wire3; + }; + + return wire4; + } + + // `outConnector` point lies on the horizontal grid line 2 units below `outConnector` point + if grid_spacing <= out_y - in_y && out_y - in_y <= 2 * grid_spacing { + if 0 <= out_x - in_x && out_x - in_x <= 13 * grid_spacing { + return vec![IVec2::new(x1, y7), IVec2::new(x5, y7), IVec2::new(x5, y3), IVec2::new(x4, y3)]; + }; + + if 13 < out_x - in_x && out_x - in_x <= 18 * grid_spacing { + return wire3; + }; + + return wire4; + } + + // 0 to 4 units below the `outConnector` Point + if out_y - in_y <= 4 * grid_spacing { + return wire1; + }; + + return wire2; + } + + // Start horizontal, then vertical + if vertical_in { + // when `outConnector` lies below `inConnector` + if out_y > in_y { + // `out_x` lies to the left of `in_x` + if out_x < in_x { + return vec![IVec2::new(x1, y1), IVec2::new(x4, y1), IVec2::new(x4, y3)]; + }; + + // `out_x` lies to the right of `in_x` + if out_y - in_y <= grid_spacing { + // `outConnector` point directly below `inConnector` point + if 0 <= out_x - in_x && out_x - in_x <= grid_spacing { + return vec![IVec2::new(x1, y1), IVec2::new(x14, y1), IVec2::new(x14, y2), IVec2::new(x4, y2), IVec2::new(x4, y3)]; + }; + + // `outConnector` point lies below `inConnector` point and strictly to the right of `inConnector` point + return vec![IVec2::new(x1, y1), IVec2::new(x2, y1), IVec2::new(x2, y111), IVec2::new(x4, y111), IVec2::new(x4, y3)]; + } + + return vec![IVec2::new(x1, y1), IVec2::new(x2, y1), IVec2::new(x2, y2), IVec2::new(x4, y2), IVec2::new(x4, y3)]; + } + + // `out_y` lies on or above the `in_y` point + if -6 * grid_spacing < in_x - out_x && in_x - out_x < 4 * grid_spacing { + // edge case: `outConnector` point lying on vertical grid lines ranging from 4 units to left to 5 units to right of `inConnector` point + if -grid_spacing < in_x - out_x && in_x - out_x < 4 * grid_spacing { + return vec![ + IVec2::new(x1, y1), + IVec2::new(x2, y1), + IVec2::new(x2, y2), + IVec2::new(x15, y2), + IVec2::new(x15, y12), + IVec2::new(x4, y12), + IVec2::new(x4, y3), + ]; + } + + return vec![IVec2::new(x1, y1), IVec2::new(x16, y1), IVec2::new(x16, y12), IVec2::new(x4, y12), IVec2::new(x4, y3)]; + } + + // left of edge case: `outConnector` point lying on vertical grid lines more than 4 units to left of `inConnector` point + if 4 * grid_spacing < in_x - out_x { + return vec![IVec2::new(x1, y1), IVec2::new(x17, y1), IVec2::new(x17, y12), IVec2::new(x4, y12), IVec2::new(x4, y3)]; + }; + + // right of edge case: `outConnector` point lying on the vertical grid lines more than 5 units to right of `inConnector` point + if 6 * grid_spacing > in_x - out_x { + return vec![IVec2::new(x1, y1), IVec2::new(x18, y1), IVec2::new(x18, y12), IVec2::new(x4, y12), IVec2::new(x4, y3)]; + }; + } + + // Both horizontal - use horizontal middle point + // When `inConnector` point is one of the two closest diagonally opposite points + if 0 <= in_x - out_x && in_x - out_x <= grid_spacing && in_y - out_y >= -grid_spacing && in_y - out_y <= grid_spacing { + return vec![IVec2::new(x19, y1), IVec2::new(x19, y3), IVec2::new(x4, y3)]; + } + + // When `inConnector` point lies on the horizontal line 1 unit above and below the `outConnector` point + if -grid_spacing <= out_y - in_y && out_y - in_y <= grid_spacing && out_x > in_x { + // Horizontal line above `out_y` + if in_y < out_y { + return vec![IVec2::new(x1, y1), IVec2::new(x2, y1), IVec2::new(x2, y13), IVec2::new(x3, y13), IVec2::new(x3, y3), IVec2::new(x4, y3)]; + }; + + // Horizontal line below `out_y` + return vec![IVec2::new(x1, y1), IVec2::new(x2, y1), IVec2::new(x2, y14), IVec2::new(x3, y14), IVec2::new(x3, y3), IVec2::new(x4, y3)]; + } + + // `outConnector` point to the right of `inConnector` point + if out_x > in_x - grid_spacing { + return vec![ + IVec2::new(x1, y1), + IVec2::new(x18, y1), + IVec2::new(x18, y15), + IVec2::new(x5, y15), + IVec2::new(x5, y3), + IVec2::new(x4, y3), + ]; + }; + + // When `inConnector` point lies on the vertical grid line two units to the right of `outConnector` point + if grid_spacing <= in_x - out_x && in_x - out_x <= 2 * grid_spacing { + return vec![IVec2::new(x1, y1), IVec2::new(x18, y1), IVec2::new(x18, y3), IVec2::new(x4, y3)]; + }; + + vec![IVec2::new(x1, y1), IVec2::new(x20, y1), IVec2::new(x20, y3), IVec2::new(x4, y3)] +} + +fn straight_wire_subpath(locations: Vec) -> Subpath { + if locations.is_empty() { + return Subpath::new(Vec::new(), false); + } + + if locations.len() == 2 { + return Subpath::new( + vec![ + ManipulatorGroup { + anchor: locations[0].into(), + in_handle: None, + out_handle: None, + id: PointId::generate(), + }, + ManipulatorGroup { + anchor: locations[1].into(), + in_handle: None, + out_handle: None, + id: PointId::generate(), + }, + ], + false, + ); + } + + let corner_radius = 10; + + // Create path with rounded corners + let mut path = vec![ManipulatorGroup { + anchor: locations[0].into(), + in_handle: None, + out_handle: None, + id: PointId::generate(), + }]; + + for i in 1..(locations.len() - 1) { + let prev = locations[i - 1]; + let curr = locations[i]; + let next = locations[i + 1]; + + let corner_start = IVec2::new( + curr.x + + if curr.x == prev.x { + 0 + } else if prev.x > curr.x { + corner_radius + } else { + -corner_radius + }, + curr.y + + if curr.y == prev.y { + 0 + } else if prev.y > curr.y { + corner_radius + } else { + -corner_radius + }, + ); + + let corner_start_mid = IVec2::new( + curr.x + + if curr.x == prev.x { + 0 + } else if prev.x > curr.x { + corner_radius / 2 + } else { + -corner_radius / 2 + }, + curr.y + + if curr.y == prev.y { + 0 + } else { + match prev.y > curr.y { + true => corner_radius / 2, + false => -corner_radius / 2, + } + }, + ); + + let corner_end = IVec2::new( + curr.x + + if curr.x == next.x { + 0 + } else if next.x > curr.x { + corner_radius + } else { + -corner_radius + }, + curr.y + + if curr.y == next.y { + 0 + } else if next.y > curr.y { + corner_radius + } else { + -corner_radius + }, + ); + + let corner_end_mid = IVec2::new( + curr.x + + if curr.x == next.x { + 0 + } else if next.x > curr.x { + corner_radius / 2 + } else { + -corner_radius / 2 + }, + curr.y + + if curr.y == next.y { + 0 + } else if next.y > curr.y { + 10 / 2 + } else { + -corner_radius / 2 + }, + ); + + path.extend(vec![ + ManipulatorGroup { + anchor: corner_start.into(), + in_handle: None, + out_handle: Some(corner_start_mid.into()), + id: PointId::generate(), + }, + ManipulatorGroup { + anchor: corner_end.into(), + in_handle: Some(corner_end_mid.into()), + out_handle: None, + id: PointId::generate(), + }, + ]) + } + + path.push(ManipulatorGroup { + anchor: (*locations.last().unwrap()).into(), + in_handle: None, + out_handle: None, + id: PointId::generate(), + }); + Subpath::new(path, false) +} diff --git a/editor/src/messages/portfolio/document_migration.rs b/editor/src/messages/portfolio/document_migration.rs new file mode 100644 index 0000000000000000000000000000000000000000..7df0b38398fcd19affe322e8b5d2f336347554f3 --- /dev/null +++ b/editor/src/messages/portfolio/document_migration.rs @@ -0,0 +1,682 @@ +// TODO: Eventually remove this document upgrade code +// This file contains lots of hacky code for upgrading old documents to the new format + +use crate::messages::portfolio::document::node_graph::document_node_definitions::resolve_document_node_type; +use crate::messages::portfolio::document::utility_types::document_metadata::LayerNodeIdentifier; +use crate::messages::portfolio::document::utility_types::network_interface::{InputConnector, NodeTemplate, OutputConnector}; +use crate::messages::prelude::DocumentMessageHandler; +use bezier_rs::Subpath; +use glam::IVec2; +use graph_craft::document::{DocumentNodeImplementation, NodeInput, value::TaggedValue}; +use graphene_std::text::TypesettingConfig; +use graphene_std::uuid::NodeId; +use graphene_std::vector::style::{PaintOrder, StrokeAlign}; +use graphene_std::vector::{VectorData, VectorDataTable}; +use std::collections::HashMap; + +const TEXT_REPLACEMENTS: &[(&str, &str)] = &[ + ("graphene_core::vector::vector_nodes::SamplePointsNode", "graphene_core::vector::SamplePolylineNode"), + ("graphene_core::vector::vector_nodes::SubpathSegmentLengthsNode", "graphene_core::vector::SubpathSegmentLengthsNode"), +]; + +const REPLACEMENTS: &[(&str, &str)] = &[ + ("graphene_core::AddArtboardNode", "graphene_core::graphic_element::AppendArtboardNode"), + ("graphene_core::ConstructArtboardNode", "graphene_core::graphic_element::ToArtboardNode"), + ("graphene_core::ToGraphicElementNode", "graphene_core::graphic_element::ToElementNode"), + ("graphene_core::ToGraphicGroupNode", "graphene_core::graphic_element::ToGroupNode"), + // math_nodes + ("graphene_core::ops::MathNode", "graphene_math_nodes::MathNode"), + ("graphene_core::ops::AddNode", "graphene_math_nodes::AddNode"), + ("graphene_core::ops::SubtractNode", "graphene_math_nodes::SubtractNode"), + ("graphene_core::ops::MultiplyNode", "graphene_math_nodes::MultiplyNode"), + ("graphene_core::ops::DivideNode", "graphene_math_nodes::DivideNode"), + ("graphene_core::ops::ModuloNode", "graphene_math_nodes::ModuloNode"), + ("graphene_core::ops::ExponentNode", "graphene_math_nodes::ExponentNode"), + ("graphene_core::ops::RootNode", "graphene_math_nodes::RootNode"), + ("graphene_core::ops::LogarithmNode", "graphene_math_nodes::LogarithmNode"), + ("graphene_core::ops::SineNode", "graphene_math_nodes::SineNode"), + ("graphene_core::ops::CosineNode", "graphene_math_nodes::CosineNode"), + ("graphene_core::ops::TangentNode", "graphene_math_nodes::TangentNode"), + ("graphene_core::ops::SineInverseNode", "graphene_math_nodes::SineInverseNode"), + ("graphene_core::ops::CosineInverseNode", "graphene_math_nodes::CosineInverseNode"), + ("graphene_core::ops::TangentInverseNode", "graphene_math_nodes::TangentInverseNode"), + ("graphene_core::ops::RandomNode", "graphene_math_nodes::RandomNode"), + ("graphene_core::ops::ToU32Node", "graphene_math_nodes::ToU32Node"), + ("graphene_core::ops::ToU64Node", "graphene_math_nodes::ToU64Node"), + ("graphene_core::ops::ToF64Node", "graphene_math_nodes::ToF64Node"), + ("graphene_core::ops::RoundNode", "graphene_math_nodes::RoundNode"), + ("graphene_core::ops::FloorNode", "graphene_math_nodes::FloorNode"), + ("graphene_core::ops::CeilingNode", "graphene_math_nodes::CeilingNode"), + ("graphene_core::ops::MinNode", "graphene_math_nodes::MinNode"), + ("graphene_core::ops::MaxNode", "graphene_math_nodes::MaxNode"), + ("graphene_core::ops::ClampNode", "graphene_math_nodes::ClampNode"), + ("graphene_core::ops::EqualsNode", "graphene_math_nodes::EqualsNode"), + ("graphene_core::ops::NotEqualsNode", "graphene_math_nodes::NotEqualsNode"), + ("graphene_core::ops::LessThanNode", "graphene_math_nodes::LessThanNode"), + ("graphene_core::ops::GreaterThanNode", "graphene_math_nodes::GreaterThanNode"), + ("graphene_core::ops::LogicalOrNode", "graphene_math_nodes::LogicalOrNode"), + ("graphene_core::ops::LogicalAndNode", "graphene_math_nodes::LogicalAndNode"), + ("graphene_core::ops::LogicalNotNode", "graphene_math_nodes::LogicalNotNode"), + ("graphene_core::ops::BoolValueNode", "graphene_math_nodes::BoolValueNode"), + ("graphene_core::ops::NumberValueNode", "graphene_math_nodes::NumberValueNode"), + ("graphene_core::ops::PercentageValueNode", "graphene_math_nodes::PercentageValueNode"), + ("graphene_core::ops::CoordinateValueNode", "graphene_math_nodes::CoordinateValueNode"), + ("graphene_core::ops::ConstructVector2", "graphene_math_nodes::CoordinateValueNode"), + ("graphene_core::ops::Vector2ValueNode", "graphene_math_nodes::CoordinateValueNode"), + ("graphene_core::ops::ColorValueNode", "graphene_math_nodes::ColorValueNode"), + ("graphene_core::ops::GradientValueNode", "graphene_math_nodes::GradientValueNode"), + ("graphene_core::ops::StringValueNode", "graphene_math_nodes::StringValueNode"), + ("graphene_core::ops::DotProductNode", "graphene_math_nodes::DotProductNode"), + // debug + ("graphene_core::ops::SizeOfNode", "graphene_core::debug::SizeOfNode"), + ("graphene_core::ops::SomeNode", "graphene_core::debug::SomeNode"), + ("graphene_core::ops::UnwrapNode", "graphene_core::debug::UnwrapNode"), + ("graphene_core::ops::CloneNode", "graphene_core::debug::CloneNode"), + // ??? + ("graphene_core::ops::ExtractXyNode", "graphene_core::extract_xy::ExtractXyNode"), + ("graphene_core::logic::LogicAndNode", "graphene_core::ops::LogicAndNode"), + ("graphene_core::logic::LogicNotNode", "graphene_core::ops::LogicNotNode"), + ("graphene_core::logic::LogicOrNode", "graphene_core::ops::LogicOrNode"), + ("graphene_core::raster::BlendModeNode", "graphene_core::blending_nodes::BlendModeNode"), + ("graphene_core::raster::OpacityNode", "graphene_core::blending_nodes::OpacityNode"), + ("graphene_core::raster::BlendingNode", "graphene_core::blending_nodes::BlendingNode"), + ("graphene_core::vector::GenerateHandlesNode", "graphene_core::vector::AutoTangentsNode"), + ("graphene_core::vector::RemoveHandlesNode", "graphene_core::vector::AutoTangentsNode"), + // raster::adjustments + ("graphene_core::raster::adjustments::LuminanceNode", "graphene_raster_nodes::adjustments::LuminanceNode"), + ("graphene_core::raster::LuminanceNode", "graphene_raster_nodes::adjustments::LuminanceNode"), + ("graphene_core::raster::adjustments::ExtractChannelNode", "graphene_raster_nodes::adjustments::ExtractChannelNode"), + ("graphene_core::raster::ExtractChannelNode", "graphene_raster_nodes::adjustments::ExtractChannelNode"), + ("graphene_core::raster::adjustments::MakeOpaqueNode", "graphene_raster_nodes::adjustments::MakeOpaqueNode"), + ("graphene_core::raster::ExtractOpaqueNode", "graphene_raster_nodes::adjustments::MakeOpaqueNode"), + ( + "graphene_core::raster::adjustments::BrightnessContrastNode", + "graphene_raster_nodes::adjustments::BrightnessContrastNode", + ), + ("graphene_core::raster::adjustments::LevelsNode", "graphene_raster_nodes::adjustments::LevelsNode"), + ("graphene_core::raster::LevelsNode", "graphene_raster_nodes::adjustments::LevelsNode"), + ("graphene_core::raster::adjustments::BlackAndWhiteNode", "graphene_raster_nodes::adjustments::BlackAndWhiteNode"), + ("graphene_core::raster::BlackAndWhiteNode", "graphene_raster_nodes::adjustments::BlackAndWhiteNode"), + ("graphene_core::raster::adjustments::HueSaturationNode", "graphene_raster_nodes::adjustments::HueSaturationNode"), + ("graphene_core::raster::HueSaturationNode", "graphene_raster_nodes::adjustments::HueSaturationNode"), + ("graphene_core::raster::adjustments::InvertNode", "graphene_raster_nodes::adjustments::InvertNode"), + ("graphene_core::raster::InvertNode", "graphene_raster_nodes::adjustments::InvertNode"), + ("graphene_core::raster::InvertRGBNode", "graphene_raster_nodes::adjustments::InvertNode"), + ("graphene_core::raster::adjustments::ThresholdNode", "graphene_raster_nodes::adjustments::ThresholdNode"), + ("graphene_core::raster::ThresholdNode", "graphene_raster_nodes::adjustments::ThresholdNode"), + ("graphene_core::raster::adjustments::BlendNode", "graphene_raster_nodes::adjustments::BlendNode"), + ("graphene_core::raster::BlendNode", "graphene_raster_nodes::adjustments::BlendNode"), + ("graphene_core::raster::BlendColorPairNode", "graphene_raster_nodes::adjustments::BlendColorPairNode"), + ("graphene_core::raster::adjustments::BlendColorsNode", "graphene_raster_nodes::adjustments::BlendColorsNode"), + ("graphene_core::raster::BlendColorsNode", "graphene_raster_nodes::adjustments::BlendColorsNode"), + ("graphene_core::raster::adjustments::GradientMapNode", "graphene_raster_nodes::adjustments::GradientMapNode"), + ("graphene_core::raster::GradientMapNode", "graphene_raster_nodes::adjustments::GradientMapNode"), + ("graphene_core::raster::adjustments::VibranceNode", "graphene_raster_nodes::adjustments::VibranceNode"), + ("graphene_core::raster::VibranceNode", "graphene_raster_nodes::adjustments::VibranceNode"), + ("graphene_core::raster::adjustments::ChannelMixerNode", "graphene_raster_nodes::adjustments::ChannelMixerNode"), + ("graphene_core::raster::ChannelMixerNode", "graphene_raster_nodes::adjustments::ChannelMixerNode"), + ("graphene_core::raster::adjustments::SelectiveColorNode", "graphene_raster_nodes::adjustments::SelectiveColorNode"), + ("graphene_core::raster::adjustments::PosterizeNode", "graphene_raster_nodes::adjustments::PosterizeNode"), + ("graphene_core::raster::PosterizeNode", "graphene_raster_nodes::adjustments::PosterizeNode"), + ("graphene_core::raster::adjustments::ExposureNode", "graphene_raster_nodes::adjustments::ExposureNode"), + ("graphene_core::raster::ExposureNode", "graphene_raster_nodes::adjustments::ExposureNode"), + ("graphene_core::raster::adjustments::ColorOverlayNode", "graphene_raster_nodes::adjustments::ColorOverlayNode"), + ("graphene_raster_nodes::generate_curves::ColorOverlayNode", "graphene_raster_nodes::adjustments::ColorOverlayNode"), + // raster + ("graphene_core::raster::adjustments::GenerateCurvesNode", "graphene_raster_nodes::generate_curves::GenerateCurvesNode"), + ("graphene_std::dehaze::DehazeNode", "graphene_raster_nodes::dehaze::DehazeNode"), + ("graphene_std::filter::BlurNode", "graphene_raster_nodes::filter::BlurNode"), + ( + "graphene_std::image_color_palette::ImageColorPaletteNode", + "graphene_raster_nodes::image_color_palette::ImageColorPaletteNode", + ), + ("graphene_std::raster::SampleImageNode", "graphene_raster_nodes::std_nodes::SampleImageNode"), + ("graphene_std::raster::CombineChannelsNode", "graphene_raster_nodes::std_nodes::CombineChannelsNode"), + ("graphene_std::raster::MaskNode", "graphene_raster_nodes::std_nodes::MaskNode"), + ("graphene_std::raster::ExtendImageToBoundsNode", "graphene_raster_nodes::std_nodes::ExtendImageToBoundsNode"), + ("graphene_std::raster::EmptyImageNode", "graphene_raster_nodes::std_nodes::EmptyImageNode"), + ("graphene_std::raster::ImageValueNode", "graphene_raster_nodes::std_nodes::ImageValueNode"), + ("graphene_std::raster::NoisePatternNode", "graphene_raster_nodes::std_nodes::NoisePatternNode"), + ("graphene_std::raster::MandelbrotNode", "graphene_raster_nodes::std_nodes::MandelbrotNode"), + // text + ("graphene_core::text::TextGeneratorNode", "graphene_core::text::TextNode"), + // transform + ("graphene_core::transform::SetTransformNode", "graphene_core::transform_nodes::ReplaceTransformNode"), + ("graphene_core::transform::ReplaceTransformNode", "graphene_core::transform_nodes::ReplaceTransformNode"), + ("graphene_core::transform::TransformNode", "graphene_core::transform_nodes::TransformNode"), + ("graphene_core::transform::BoundlessFootprintNode", "graphene_core::transform_nodes::BoundlessFootprintNode"), + ("graphene_core::transform::FreezeRealTimeNode", "graphene_core::transform_nodes::FreezeRealTimeNode"), + // ??? + ("graphene_core::vector::SplinesFromPointsNode", "graphene_core::vector::SplineNode"), + ("graphene_core::vector::generator_nodes::EllipseGenerator", "graphene_core::vector::generator_nodes::EllipseNode"), + ("graphene_core::vector::generator_nodes::LineGenerator", "graphene_core::vector::generator_nodes::LineNode"), + ("graphene_core::vector::generator_nodes::RectangleGenerator", "graphene_core::vector::generator_nodes::RectangleNode"), + ( + "graphene_core::vector::generator_nodes::RegularPolygonGenerator", + "graphene_core::vector::generator_nodes::RegularPolygonNode", + ), + ("graphene_core::vector::generator_nodes::StarGenerator", "graphene_core::vector::generator_nodes::StarNode"), + ("graphene_std::executor::BlendGpuImageNode", "graphene_std::gpu_nodes::BlendGpuImageNode"), + ("graphene_std::raster::SampleNode", "graphene_std::raster::SampleImageNode"), + ("graphene_core::transform::CullNode", "graphene_core::ops::IdentityNode"), + ("graphene_std::raster::MaskImageNode", "graphene_std::raster::MaskNode"), + ("graphene_core::vector::FlattenVectorElementsNode", "graphene_core::vector::FlattenPathNode"), + ("graphene_std::vector::BooleanOperationNode", "graphene_path_bool::BooleanOperationNode"), + // brush + ("graphene_std::brush::BrushStampGeneratorNode", "graphene_brush::brush::BrushStampGeneratorNode"), + ("graphene_std::brush::BlitNode", "graphene_brush::brush::BlitNode"), + ("graphene_std::brush::BrushNode", "graphene_brush::brush::BrushNode"), +]; + +pub fn document_migration_string_preprocessing(document_serialized_content: String) -> String { + TEXT_REPLACEMENTS + .iter() + .fold(document_serialized_content, |document_serialized_content, (old, new)| document_serialized_content.replace(old, new)) +} + +pub fn document_migration_reset_node_definition(document_serialized_content: &str) -> bool { + // Upgrade a document being opened to use fresh copies of all nodes + if document_serialized_content.contains("node_output_index") { + return true; + } + + // Upgrade layer implementation from https://github.com/GraphiteEditor/Graphite/pull/1946 (see also `fn fix_nodes()` in `main.rs` of Graphene CLI) + if document_serialized_content.contains("graphene_core::ConstructLayerNode") || document_serialized_content.contains("graphene_core::AddArtboardNode") { + return true; + } + + false +} + +pub fn document_migration_upgrades(document: &mut DocumentMessageHandler, reset_node_definitions_on_open: bool) { + let network = document.network_interface.document_network().clone(); + + // Apply string replacements to each node + for (node_id, node, network_path) in network.recursive_nodes() { + if let DocumentNodeImplementation::ProtoNode(protonode_id) = &node.implementation { + for (old, new) in REPLACEMENTS { + let node_path_without_type_args = protonode_id.name.split('<').next(); + let mut default_template = NodeTemplate::default(); + default_template.document_node.implementation = DocumentNodeImplementation::ProtoNode(new.to_string().into()); + if node_path_without_type_args == Some(old) { + document.network_interface.replace_implementation(node_id, &network_path, &mut default_template); + document.network_interface.set_manual_compostion(node_id, &network_path, Some(graph_craft::Type::Generic("T".into()))); + } + } + } + } + + // Apply upgrades to each unmodified node. + let nodes = document + .network_interface + .document_network() + .recursive_nodes() + .map(|(node_id, node, path)| (*node_id, node.clone(), path)) + .collect::)>>(); + for (node_id, node, network_path) in &nodes { + if reset_node_definitions_on_open { + if let Some(Some(reference)) = document.network_interface.reference(node_id, network_path) { + let Some(node_definition) = resolve_document_node_type(reference) else { continue }; + document.network_interface.replace_implementation(node_id, network_path, &mut node_definition.default_node_template()); + } + } + + // Upgrade old nodes to use `Context` instead of `()` or `Footprint` for manual composition + if node.manual_composition == Some(graph_craft::concrete!(())) || node.manual_composition == Some(graph_craft::concrete!(graphene_std::transform::Footprint)) { + document + .network_interface + .set_manual_compostion(node_id, network_path, graph_craft::concrete!(graphene_std::Context).into()); + } + + let Some(Some(reference)) = document.network_interface.reference(node_id, network_path).cloned() else { + // Only nodes that have not been modified and still refer to a definition can be updated + continue; + }; + let reference = &reference; + + let inputs_count = node.inputs.len(); + + // Upgrade Stroke node to reorder parameters and add "Align" and "Paint Order" (#2644) + if reference == "Stroke" && inputs_count == 8 { + let mut node_template = resolve_document_node_type(reference).unwrap().default_node_template(); + let old_inputs = document.network_interface.replace_inputs(node_id, network_path, &mut node_template).unwrap(); + + let align_input = NodeInput::value(TaggedValue::StrokeAlign(StrokeAlign::Center), false); + let paint_order_input = NodeInput::value(TaggedValue::PaintOrder(PaintOrder::StrokeAbove), false); + + document.network_interface.set_input(&InputConnector::node(*node_id, 0), old_inputs[0].clone(), network_path); + document.network_interface.set_input(&InputConnector::node(*node_id, 1), old_inputs[1].clone(), network_path); + document.network_interface.set_input(&InputConnector::node(*node_id, 2), old_inputs[2].clone(), network_path); + document.network_interface.set_input(&InputConnector::node(*node_id, 3), align_input, network_path); + document.network_interface.set_input(&InputConnector::node(*node_id, 4), old_inputs[5].clone(), network_path); + document.network_interface.set_input(&InputConnector::node(*node_id, 5), old_inputs[6].clone(), network_path); + document.network_interface.set_input(&InputConnector::node(*node_id, 6), old_inputs[7].clone(), network_path); + document.network_interface.set_input(&InputConnector::node(*node_id, 7), paint_order_input, network_path); + document.network_interface.set_input(&InputConnector::node(*node_id, 8), old_inputs[3].clone(), network_path); + document.network_interface.set_input(&InputConnector::node(*node_id, 9), old_inputs[4].clone(), network_path); + } + + // Rename the old "Splines from Points" node to "Spline" and upgrade it to the new "Spline" node + if reference == "Splines from Points" { + document.network_interface.set_reference(node_id, network_path, Some("Spline".to_string())); + } + + // Upgrade the old "Spline" node to the new "Spline" node + if reference == "Spline" { + // Retrieve the proto node identifier and verify it is the old "Spline" node, otherwise skip it if this is the new "Spline" node + let identifier = document + .network_interface + .implementation(node_id, network_path) + .and_then(|implementation| implementation.get_proto_node()); + if identifier.map(|identifier| &identifier.name) != Some(&"graphene_core::vector::generator_nodes::SplineNode".into()) { + continue; + } + + // Obtain the document node for the given node ID, extract the vector points, and create vector data from the list of points + let node = document.network_interface.document_node(node_id, network_path).unwrap(); + let Some(TaggedValue::VecDVec2(points)) = node.inputs.get(1).and_then(|tagged_value| tagged_value.as_value()) else { + log::error!("The old Spline node's input at index 1 is not a TaggedValue::VecDVec2"); + continue; + }; + let vector_data = VectorData::from_subpath(Subpath::from_anchors_linear(points.to_vec(), false)); + + // Retrieve the output connectors linked to the "Spline" node's output port + let spline_outputs = document + .network_interface + .outward_wires(network_path) + .unwrap() + .get(&OutputConnector::node(*node_id, 0)) + .expect("Vec of InputConnector Spline node is connected to its output port 0.") + .clone(); + + // Get the node's current position in the graph + let Some(node_position) = document.network_interface.position(node_id, network_path) else { + log::error!("Could not get position of spline node."); + continue; + }; + + // Get the "Path" node definition and fill it in with the vector data and default vector modification + let path_node_type = resolve_document_node_type("Path").expect("Path node does not exist."); + let path_node = path_node_type.node_template_input_override([ + Some(NodeInput::value(TaggedValue::VectorData(VectorDataTable::new(vector_data)), true)), + Some(NodeInput::value(TaggedValue::VectorModification(Default::default()), false)), + ]); + + // Get the "Spline" node definition and wire it up with the "Path" node as input + let spline_node_type = resolve_document_node_type("Spline").expect("Spline node does not exist."); + let spline_node = spline_node_type.node_template_input_override([Some(NodeInput::node(NodeId(1), 0))]); + + // Create a new node group with the "Path" and "Spline" nodes and generate new node IDs for them + let nodes = vec![(NodeId(1), path_node), (NodeId(0), spline_node)]; + let new_ids = nodes.iter().map(|(id, _)| (*id, NodeId::new())).collect::>(); + let new_spline_id = *new_ids.get(&NodeId(0)).unwrap(); + let new_path_id = *new_ids.get(&NodeId(1)).unwrap(); + + // Remove the old "Spline" node from the document + document.network_interface.delete_nodes(vec![*node_id], false, network_path); + + // Insert the new "Path" and "Spline" nodes into the network interface with generated IDs + document.network_interface.insert_node_group(nodes.clone(), new_ids, network_path); + + // Reposition the new "Spline" node to match the original "Spline" node's position + document.network_interface.shift_node(&new_spline_id, node_position, network_path); + + // Reposition the new "Path" node with an offset relative to the original "Spline" node's position + document.network_interface.shift_node(&new_path_id, node_position + IVec2::new(-7, 0), network_path); + + // Redirect each output connection from the old node to the new "Spline" node's output port + for input_connector in spline_outputs { + document.network_interface.set_input(&input_connector, NodeInput::node(new_spline_id, 0), network_path); + } + } + + // Upgrade Text node to include line height and character spacing, which were previously hardcoded to 1, from https://github.com/GraphiteEditor/Graphite/pull/2016 + if reference == "Text" && inputs_count != 9 { + let mut template = resolve_document_node_type(reference).unwrap().default_node_template(); + document.network_interface.replace_implementation(node_id, network_path, &mut template); + let old_inputs = document.network_interface.replace_inputs(node_id, network_path, &mut template).unwrap(); + + document.network_interface.set_input(&InputConnector::node(*node_id, 0), old_inputs[0].clone(), network_path); + document.network_interface.set_input(&InputConnector::node(*node_id, 1), old_inputs[1].clone(), network_path); + document.network_interface.set_input(&InputConnector::node(*node_id, 2), old_inputs[2].clone(), network_path); + document.network_interface.set_input(&InputConnector::node(*node_id, 3), old_inputs[3].clone(), network_path); + document.network_interface.set_input( + &InputConnector::node(*node_id, 4), + if inputs_count == 6 { + old_inputs[4].clone() + } else { + NodeInput::value(TaggedValue::F64(TypesettingConfig::default().line_height_ratio), false) + }, + network_path, + ); + document.network_interface.set_input( + &InputConnector::node(*node_id, 5), + if inputs_count == 6 { + old_inputs[5].clone() + } else { + NodeInput::value(TaggedValue::F64(TypesettingConfig::default().character_spacing), false) + }, + network_path, + ); + document.network_interface.set_input( + &InputConnector::node(*node_id, 6), + if inputs_count >= 7 { + old_inputs[6].clone() + } else { + NodeInput::value(TaggedValue::OptionalF64(TypesettingConfig::default().max_width), false) + }, + network_path, + ); + document.network_interface.set_input( + &InputConnector::node(*node_id, 7), + if inputs_count >= 8 { + old_inputs[7].clone() + } else { + NodeInput::value(TaggedValue::OptionalF64(TypesettingConfig::default().max_height), false) + }, + network_path, + ); + document.network_interface.set_input( + &InputConnector::node(*node_id, 8), + if inputs_count >= 9 { + old_inputs[8].clone() + } else { + NodeInput::value(TaggedValue::F64(TypesettingConfig::default().tilt), false) + }, + network_path, + ); + } + + // Upgrade Sine, Cosine, and Tangent nodes to include a boolean input for whether the output should be in radians, which was previously the only option but is now not the default + if (reference == "Sine" || reference == "Cosine" || reference == "Tangent") && inputs_count == 1 { + let mut node_template = resolve_document_node_type(reference).unwrap().default_node_template(); + document.network_interface.replace_implementation(node_id, network_path, &mut node_template); + + let old_inputs = document.network_interface.replace_inputs(node_id, network_path, &mut node_template).unwrap(); + + document.network_interface.set_input(&InputConnector::node(*node_id, 0), old_inputs[0].clone(), network_path); + document + .network_interface + .set_input(&InputConnector::node(*node_id, 1), NodeInput::value(TaggedValue::Bool(true), false), network_path); + } + + // Upgrade the Modulo node to include a boolean input for whether the output should be always positive, which was previously not an option + if reference == "Modulo" && inputs_count == 2 { + let mut node_template = resolve_document_node_type(reference).unwrap().default_node_template(); + document.network_interface.replace_implementation(node_id, network_path, &mut node_template); + + let old_inputs = document.network_interface.replace_inputs(node_id, network_path, &mut node_template).unwrap(); + + document.network_interface.set_input(&InputConnector::node(*node_id, 0), old_inputs[0].clone(), network_path); + document.network_interface.set_input(&InputConnector::node(*node_id, 1), old_inputs[1].clone(), network_path); + document + .network_interface + .set_input(&InputConnector::node(*node_id, 2), NodeInput::value(TaggedValue::Bool(false), false), network_path); + } + + // Upgrade the Mirror node to add the `keep_original` boolean input + if reference == "Mirror" && inputs_count == 3 { + let mut node_template = resolve_document_node_type(reference).unwrap().default_node_template(); + document.network_interface.replace_implementation(node_id, network_path, &mut node_template); + + let old_inputs = document.network_interface.replace_inputs(node_id, network_path, &mut node_template).unwrap(); + + document.network_interface.set_input(&InputConnector::node(*node_id, 0), old_inputs[0].clone(), network_path); + document.network_interface.set_input(&InputConnector::node(*node_id, 1), old_inputs[1].clone(), network_path); + document.network_interface.set_input(&InputConnector::node(*node_id, 2), old_inputs[2].clone(), network_path); + document + .network_interface + .set_input(&InputConnector::node(*node_id, 3), NodeInput::value(TaggedValue::Bool(true), false), network_path); + } + + // Upgrade the Mirror node to add the `reference_point` input and change `offset` from `DVec2` to `f64` + if reference == "Mirror" && inputs_count == 4 { + let mut node_template = resolve_document_node_type(reference).unwrap().default_node_template(); + document.network_interface.replace_implementation(node_id, network_path, &mut node_template); + + let old_inputs = document.network_interface.replace_inputs(node_id, network_path, &mut node_template).unwrap(); + + let Some(&TaggedValue::DVec2(old_offset)) = old_inputs[1].as_value() else { return }; + let old_offset = if old_offset.x.abs() > old_offset.y.abs() { old_offset.x } else { old_offset.y }; + + document.network_interface.set_input(&InputConnector::node(*node_id, 0), old_inputs[0].clone(), network_path); + document.network_interface.set_input( + &InputConnector::node(*node_id, 1), + NodeInput::value(TaggedValue::ReferencePoint(graphene_std::transform::ReferencePoint::Center), false), + network_path, + ); + document + .network_interface + .set_input(&InputConnector::node(*node_id, 2), NodeInput::value(TaggedValue::F64(old_offset), false), network_path); + document.network_interface.set_input(&InputConnector::node(*node_id, 3), old_inputs[2].clone(), network_path); + document.network_interface.set_input(&InputConnector::node(*node_id, 4), old_inputs[3].clone(), network_path); + } + + // Upgrade artboard name being passed as hidden value input to "To Artboard" + if reference == "Artboard" && reset_node_definitions_on_open { + let label = document.network_interface.display_name(node_id, network_path); + document + .network_interface + .set_input(&InputConnector::node(NodeId(0), 1), NodeInput::value(TaggedValue::String(label), false), &[*node_id]); + } + + if reference == "Image" && inputs_count == 1 { + let mut node_template = resolve_document_node_type(reference).unwrap().default_node_template(); + document.network_interface.replace_implementation(node_id, network_path, &mut node_template); + + // Insert a new empty input for the image + document.network_interface.add_import(TaggedValue::None, false, 0, "Empty", "", &[*node_id]); + document.network_interface.set_reference(node_id, network_path, Some("Image".to_string())); + } + + if reference == "Noise Pattern" && inputs_count == 15 { + let mut node_template = resolve_document_node_type(reference).unwrap().default_node_template(); + document.network_interface.replace_implementation(node_id, network_path, &mut node_template); + + let old_inputs = document.network_interface.replace_inputs(node_id, network_path, &mut node_template).unwrap(); + + document + .network_interface + .set_input(&InputConnector::node(*node_id, 0), NodeInput::value(TaggedValue::None, false), network_path); + for (i, input) in old_inputs.iter().enumerate() { + document.network_interface.set_input(&InputConnector::node(*node_id, i + 1), input.clone(), network_path); + } + } + + if reference == "Instance on Points" && inputs_count == 2 { + let mut node_template = resolve_document_node_type(reference).unwrap().default_node_template(); + document.network_interface.replace_implementation(node_id, network_path, &mut node_template); + + let old_inputs = document.network_interface.replace_inputs(node_id, network_path, &mut node_template).unwrap(); + + document.network_interface.set_input(&InputConnector::node(*node_id, 0), old_inputs[0].clone(), network_path); + document.network_interface.set_input(&InputConnector::node(*node_id, 1), old_inputs[1].clone(), network_path); + } + + if reference == "Morph" && inputs_count == 4 { + let mut node_template = resolve_document_node_type(reference).unwrap().default_node_template(); + document.network_interface.replace_implementation(node_id, network_path, &mut node_template); + + let old_inputs = document.network_interface.replace_inputs(node_id, network_path, &mut node_template).unwrap(); + + document.network_interface.set_input(&InputConnector::node(*node_id, 0), old_inputs[0].clone(), network_path); + document.network_interface.set_input(&InputConnector::node(*node_id, 1), old_inputs[1].clone(), network_path); + document.network_interface.set_input(&InputConnector::node(*node_id, 2), old_inputs[2].clone(), network_path); + // We have removed the last input, so we don't add index 3 + } + + if reference == "Brush" && inputs_count == 4 { + let mut node_template = resolve_document_node_type(reference).unwrap().default_node_template(); + document.network_interface.replace_implementation(node_id, network_path, &mut node_template); + + let old_inputs = document.network_interface.replace_inputs(node_id, network_path, &mut node_template).unwrap(); + + document.network_interface.set_input(&InputConnector::node(*node_id, 0), old_inputs[0].clone(), network_path); + // We have removed the second input ("bounds"), so we don't add index 1 and we shift the rest of the inputs down by one + document.network_interface.set_input(&InputConnector::node(*node_id, 1), old_inputs[2].clone(), network_path); + document.network_interface.set_input(&InputConnector::node(*node_id, 2), old_inputs[3].clone(), network_path); + } + + if reference == "Flatten Vector Elements" { + let mut node_template = resolve_document_node_type(reference).unwrap().default_node_template(); + document.network_interface.replace_implementation(node_id, network_path, &mut node_template); + + let old_inputs = document.network_interface.replace_inputs(node_id, network_path, &mut node_template).unwrap(); + + document.network_interface.set_input(&InputConnector::node(*node_id, 0), old_inputs[0].clone(), network_path); + + document.network_interface.replace_reference_name(node_id, network_path, "Flatten Path".to_string()); + } + + if reference == "Remove Handles" { + let mut node_template = resolve_document_node_type(reference).unwrap().default_node_template(); + document.network_interface.replace_implementation(node_id, network_path, &mut node_template); + + let old_inputs = document.network_interface.replace_inputs(node_id, network_path, &mut node_template).unwrap(); + + document.network_interface.set_input(&InputConnector::node(*node_id, 0), old_inputs[0].clone(), network_path); + document + .network_interface + .set_input(&InputConnector::node(*node_id, 1), NodeInput::value(TaggedValue::F64(0.), false), network_path); + document + .network_interface + .set_input(&InputConnector::node(*node_id, 2), NodeInput::value(TaggedValue::Bool(false), false), network_path); + + document.network_interface.replace_reference_name(node_id, network_path, "Auto-Tangents".to_string()); + } + + if reference == "Generate Handles" { + let mut node_template = resolve_document_node_type("Auto-Tangents").unwrap().default_node_template(); + document.network_interface.replace_implementation(node_id, network_path, &mut node_template); + + let old_inputs = document.network_interface.replace_inputs(node_id, network_path, &mut node_template).unwrap(); + + document.network_interface.set_input(&InputConnector::node(*node_id, 0), old_inputs[0].clone(), network_path); + document.network_interface.set_input(&InputConnector::node(*node_id, 1), old_inputs[1].clone(), network_path); + document + .network_interface + .set_input(&InputConnector::node(*node_id, 2), NodeInput::value(TaggedValue::Bool(true), false), network_path); + + document.network_interface.replace_reference_name(node_id, network_path, "Auto-Tangents".to_string()); + } + + if reference == "Merge by Distance" && inputs_count == 2 { + let mut node_template = resolve_document_node_type(reference).unwrap().default_node_template(); + document.network_interface.replace_implementation(node_id, network_path, &mut node_template); + + let old_inputs = document.network_interface.replace_inputs(node_id, network_path, &mut node_template).unwrap(); + + document.network_interface.set_input(&InputConnector::node(*node_id, 0), old_inputs[0].clone(), network_path); + document.network_interface.set_input(&InputConnector::node(*node_id, 1), old_inputs[1].clone(), network_path); + document.network_interface.set_input( + &InputConnector::node(*node_id, 2), + NodeInput::value(TaggedValue::MergeByDistanceAlgorithm(graphene_std::vector::misc::MergeByDistanceAlgorithm::Topological), false), + network_path, + ); + } + + if reference == "Spatial Merge by Distance" { + let mut node_template = resolve_document_node_type("Merge by Distance").unwrap().default_node_template(); + document.network_interface.replace_implementation(node_id, network_path, &mut node_template); + + let old_inputs = document.network_interface.replace_inputs(node_id, network_path, &mut node_template).unwrap(); + + document.network_interface.set_input(&InputConnector::node(*node_id, 0), old_inputs[0].clone(), network_path); + document.network_interface.set_input(&InputConnector::node(*node_id, 1), old_inputs[1].clone(), network_path); + document.network_interface.set_input( + &InputConnector::node(*node_id, 2), + NodeInput::value(TaggedValue::MergeByDistanceAlgorithm(graphene_std::vector::misc::MergeByDistanceAlgorithm::Spatial), false), + network_path, + ); + + document.network_interface.replace_reference_name(node_id, network_path, "Merge by Distance".to_string()); + } + + if reference == "Sample Points" && inputs_count == 5 { + let mut node_template = resolve_document_node_type("Sample Polyline").unwrap().default_node_template(); + document.network_interface.replace_implementation(node_id, network_path, &mut node_template); + + let old_inputs = document.network_interface.replace_inputs(node_id, network_path, &mut node_template).unwrap(); + let new_spacing_value = NodeInput::value(TaggedValue::PointSpacingType(graphene_std::vector::misc::PointSpacingType::Separation), false); + let new_quantity_value = NodeInput::value(TaggedValue::U32(100), false); + + document.network_interface.set_input(&InputConnector::node(*node_id, 0), old_inputs[0].clone(), network_path); + document.network_interface.set_input(&InputConnector::node(*node_id, 1), new_spacing_value, network_path); + document.network_interface.set_input(&InputConnector::node(*node_id, 2), old_inputs[1].clone(), network_path); + document.network_interface.set_input(&InputConnector::node(*node_id, 3), new_quantity_value, network_path); + document.network_interface.set_input(&InputConnector::node(*node_id, 4), old_inputs[2].clone(), network_path); + document.network_interface.set_input(&InputConnector::node(*node_id, 5), old_inputs[3].clone(), network_path); + document.network_interface.set_input(&InputConnector::node(*node_id, 6), old_inputs[4].clone(), network_path); + + document.network_interface.replace_reference_name(node_id, network_path, "Sample Polyline".to_string()); + } + + // Make the "Quantity" parameter a u32 instead of f64 + if reference == "Sample Polyline" { + let node_definition = resolve_document_node_type("Sample Polyline").unwrap(); + let mut new_node_template = node_definition.default_node_template(); + + // Get the inputs, obtain the quantity value, and put the inputs back + let old_inputs = document.network_interface.replace_inputs(node_id, network_path, &mut new_node_template).unwrap(); + let quantity_value = old_inputs.get(3).cloned(); + + if let Some(NodeInput::Value { tagged_value, exposed }) = quantity_value { + if let TaggedValue::F64(value) = *tagged_value { + let new_quantity_value = NodeInput::value(TaggedValue::U32(value as u32), exposed); + document.network_interface.set_input(&InputConnector::node(*node_id, 3), new_quantity_value, network_path); + } + } + } + + // Make the "Grid" node, if its input of index 3 is a DVec2 for "angles" instead of a u32 for the "columns" input that now succeeds "angles", move the angle to index 5 (after "columns" and "rows") + if reference == "Grid" && inputs_count == 6 { + let node_definition = resolve_document_node_type(reference).unwrap(); + let mut new_node_template = node_definition.default_node_template(); + + let mut current_node_template = document.network_interface.create_node_template(node_id, network_path).unwrap(); + let old_inputs = document.network_interface.replace_inputs(node_id, network_path, &mut new_node_template).unwrap(); + let index_3_value = old_inputs.get(3).cloned(); + + if let Some(NodeInput::Value { tagged_value, exposed: _ }) = index_3_value { + if matches!(*tagged_value, TaggedValue::DVec2(_)) { + // Move index 3 to the end + document.network_interface.set_input(&InputConnector::node(*node_id, 0), old_inputs[0].clone(), network_path); + document.network_interface.set_input(&InputConnector::node(*node_id, 1), old_inputs[1].clone(), network_path); + document.network_interface.set_input(&InputConnector::node(*node_id, 2), old_inputs[2].clone(), network_path); + document.network_interface.set_input(&InputConnector::node(*node_id, 3), old_inputs[4].clone(), network_path); + document.network_interface.set_input(&InputConnector::node(*node_id, 4), old_inputs[5].clone(), network_path); + document.network_interface.set_input(&InputConnector::node(*node_id, 5), old_inputs[3].clone(), network_path); + } else { + // Swap it back if we're not changing anything + let _ = document.network_interface.replace_inputs(node_id, network_path, &mut current_node_template); + } + } + } + + // Ensure layers are positioned as stacks if they are upstream siblings of another layer + document.network_interface.load_structure(); + let all_layers = LayerNodeIdentifier::ROOT_PARENT.descendants(document.network_interface.document_metadata()).collect::>(); + for layer in all_layers { + let Some((downstream_node, input_index)) = document + .network_interface + .outward_wires(&[]) + .and_then(|outward_wires| outward_wires.get(&OutputConnector::node(layer.to_node(), 0))) + .and_then(|outward_wires| outward_wires.first()) + .and_then(|input_connector| input_connector.node_id().map(|node_id| (node_id, input_connector.input_index()))) + else { + continue; + }; + // If the downstream node is a layer and the input is the first input and the current layer is not in a stack + if input_index == 0 && document.network_interface.is_layer(&downstream_node, &[]) && !document.network_interface.is_stack(&layer.to_node(), &[]) { + // Ensure the layer is horizontally aligned with the downstream layer to prevent changing the layout of old files + let (Some(layer_position), Some(downstream_position)) = (document.network_interface.position(&layer.to_node(), &[]), document.network_interface.position(&downstream_node, &[])) else { + log::error!("Could not get position for layer {:?} or downstream node {} when opening file", layer.to_node(), downstream_node); + continue; + }; + if layer_position.x == downstream_position.x { + document.network_interface.set_stack_position_calculated_offset(&layer.to_node(), &downstream_node, &[]); + } + } + } + } +} diff --git a/editor/src/messages/portfolio/menu_bar/menu_bar_message.rs b/editor/src/messages/portfolio/menu_bar/menu_bar_message.rs new file mode 100644 index 0000000000000000000000000000000000000000..f4f19c0a9f1658a99f56d4efb63d382b45027ac5 --- /dev/null +++ b/editor/src/messages/portfolio/menu_bar/menu_bar_message.rs @@ -0,0 +1,8 @@ +use crate::messages::prelude::*; + +#[impl_message(Message, PortfolioMessage, MenuBar)] +#[derive(PartialEq, Eq, Clone, Debug, Hash, serde::Serialize, serde::Deserialize)] +pub enum MenuBarMessage { + // Messages + SendLayout, +} diff --git a/editor/src/messages/portfolio/menu_bar/menu_bar_message_handler.rs b/editor/src/messages/portfolio/menu_bar/menu_bar_message_handler.rs new file mode 100644 index 0000000000000000000000000000000000000000..50cfa632ac067c14e5c16d0b4fd3a4cc5d7933ce --- /dev/null +++ b/editor/src/messages/portfolio/menu_bar/menu_bar_message_handler.rs @@ -0,0 +1,697 @@ +use crate::messages::debug::utility_types::MessageLoggingVerbosity; +use crate::messages::input_mapper::utility_types::macros::action_keys; +use crate::messages::layout::utility_types::widget_prelude::*; +use crate::messages::portfolio::document::utility_types::clipboards::Clipboard; +use crate::messages::portfolio::document::utility_types::misc::{AlignAggregate, AlignAxis, FlipAxis, GroupFolderType}; +use crate::messages::prelude::*; +use graphene_std::path_bool::BooleanOperation; + +#[derive(Debug, Clone, Default)] +pub struct MenuBarMessageHandler { + pub has_active_document: bool, + pub canvas_tilted: bool, + pub canvas_flipped: bool, + pub rulers_visible: bool, + pub node_graph_open: bool, + pub has_selected_nodes: bool, + pub has_selected_layers: bool, + pub has_selection_history: (bool, bool), + pub spreadsheet_view_open: bool, + pub message_logging_verbosity: MessageLoggingVerbosity, + pub reset_node_definitions_on_open: bool, +} + +impl MessageHandler for MenuBarMessageHandler { + fn process_message(&mut self, message: MenuBarMessage, responses: &mut VecDeque, _data: ()) { + match message { + MenuBarMessage::SendLayout => self.send_layout(responses, LayoutTarget::MenuBar), + } + } + + fn actions(&self) -> ActionList { + actions!(MenuBarMessageDiscriminant;) + } +} + +impl LayoutHolder for MenuBarMessageHandler { + fn layout(&self) -> Layout { + let no_active_document = !self.has_active_document; + let node_graph_open = self.node_graph_open; + let has_selected_nodes = self.has_selected_nodes; + let has_selected_layers = self.has_selected_layers; + let has_selection_history = self.has_selection_history; + let message_logging_verbosity_off = self.message_logging_verbosity == MessageLoggingVerbosity::Off; + let message_logging_verbosity_names = self.message_logging_verbosity == MessageLoggingVerbosity::Names; + let message_logging_verbosity_contents = self.message_logging_verbosity == MessageLoggingVerbosity::Contents; + let reset_node_definitions_on_open = self.reset_node_definitions_on_open; + + let menu_bar_entries = vec![ + MenuBarEntry { + icon: Some("GraphiteLogo".into()), + action: MenuBarEntry::create_action(|_| FrontendMessage::TriggerVisitLink { url: "https://graphite.rs".into() }.into()), + ..Default::default() + }, + MenuBarEntry::new_root( + "File".into(), + false, + MenuBarEntryChildren(vec![ + vec![ + MenuBarEntry { + label: "New…".into(), + icon: Some("File".into()), + action: MenuBarEntry::create_action(|_| DialogMessage::RequestNewDocumentDialog.into()), + shortcut: action_keys!(DialogMessageDiscriminant::RequestNewDocumentDialog), + children: MenuBarEntryChildren::empty(), + ..MenuBarEntry::default() + }, + MenuBarEntry { + label: "Open…".into(), + icon: Some("Folder".into()), + shortcut: action_keys!(PortfolioMessageDiscriminant::OpenDocument), + action: MenuBarEntry::create_action(|_| PortfolioMessage::OpenDocument.into()), + ..MenuBarEntry::default() + }, + MenuBarEntry { + label: "Open Demo Artwork…".into(), + icon: Some("Image".into()), + action: MenuBarEntry::create_action(|_| DialogMessage::RequestDemoArtworkDialog.into()), + ..MenuBarEntry::default() + }, + ], + vec![ + MenuBarEntry { + label: "Close".into(), + icon: Some("Close".into()), + shortcut: action_keys!(PortfolioMessageDiscriminant::CloseActiveDocumentWithConfirmation), + action: MenuBarEntry::create_action(|_| PortfolioMessage::CloseActiveDocumentWithConfirmation.into()), + disabled: no_active_document, + ..MenuBarEntry::default() + }, + MenuBarEntry { + label: "Close All".into(), + icon: Some("CloseAll".into()), + shortcut: action_keys!(PortfolioMessageDiscriminant::CloseAllDocumentsWithConfirmation), + action: MenuBarEntry::create_action(|_| PortfolioMessage::CloseAllDocumentsWithConfirmation.into()), + disabled: no_active_document, + ..MenuBarEntry::default() + }, + ], + vec![MenuBarEntry { + label: "Save".into(), + icon: Some("Save".into()), + shortcut: action_keys!(DocumentMessageDiscriminant::SaveDocument), + action: MenuBarEntry::create_action(|_| DocumentMessage::SaveDocument.into()), + disabled: no_active_document, + ..MenuBarEntry::default() + }], + vec![ + MenuBarEntry { + label: "Import…".into(), + icon: Some("FileImport".into()), + shortcut: action_keys!(PortfolioMessageDiscriminant::Import), + action: MenuBarEntry::create_action(|_| PortfolioMessage::Import.into()), + ..MenuBarEntry::default() + }, + MenuBarEntry { + label: "Export…".into(), + icon: Some("FileExport".into()), + shortcut: action_keys!(DialogMessageDiscriminant::RequestExportDialog), + action: MenuBarEntry::create_action(|_| DialogMessage::RequestExportDialog.into()), + disabled: no_active_document, + ..MenuBarEntry::default() + }, + ], + vec![MenuBarEntry { + label: "Preferences…".into(), + icon: Some("Settings".into()), + shortcut: action_keys!(DialogMessageDiscriminant::RequestPreferencesDialog), + action: MenuBarEntry::create_action(|_| DialogMessage::RequestPreferencesDialog.into()), + ..MenuBarEntry::default() + }], + ]), + ), + MenuBarEntry::new_root( + "Edit".into(), + false, + MenuBarEntryChildren(vec![ + vec![ + MenuBarEntry { + label: "Undo".into(), + icon: Some("HistoryUndo".into()), + shortcut: action_keys!(DocumentMessageDiscriminant::Undo), + action: MenuBarEntry::create_action(|_| DocumentMessage::Undo.into()), + disabled: no_active_document, + ..MenuBarEntry::default() + }, + MenuBarEntry { + label: "Redo".into(), + icon: Some("HistoryRedo".into()), + shortcut: action_keys!(DocumentMessageDiscriminant::Redo), + action: MenuBarEntry::create_action(|_| DocumentMessage::Redo.into()), + disabled: no_active_document, + ..MenuBarEntry::default() + }, + ], + vec![ + MenuBarEntry { + label: "Cut".into(), + icon: Some("Cut".into()), + shortcut: action_keys!(PortfolioMessageDiscriminant::Cut), + action: MenuBarEntry::create_action(|_| PortfolioMessage::Cut { clipboard: Clipboard::Device }.into()), + disabled: no_active_document || !has_selected_layers, + ..MenuBarEntry::default() + }, + MenuBarEntry { + label: "Copy".into(), + icon: Some("Copy".into()), + shortcut: action_keys!(PortfolioMessageDiscriminant::Copy), + action: MenuBarEntry::create_action(|_| PortfolioMessage::Copy { clipboard: Clipboard::Device }.into()), + disabled: no_active_document || !has_selected_layers, + ..MenuBarEntry::default() + }, + MenuBarEntry { + label: "Paste".into(), + icon: Some("Paste".into()), + shortcut: action_keys!(FrontendMessageDiscriminant::TriggerPaste), + action: MenuBarEntry::create_action(|_| FrontendMessage::TriggerPaste.into()), + disabled: no_active_document, + ..MenuBarEntry::default() + }, + ], + vec![ + MenuBarEntry { + label: "Duplicate".into(), + icon: Some("Copy".into()), + shortcut: action_keys!(DocumentMessageDiscriminant::DuplicateSelectedLayers), + action: MenuBarEntry::create_action(|_| DocumentMessage::DuplicateSelectedLayers.into()), + disabled: no_active_document || !has_selected_nodes, + ..MenuBarEntry::default() + }, + MenuBarEntry { + label: "Delete".into(), + icon: Some("Trash".into()), + shortcut: action_keys!(DocumentMessageDiscriminant::DeleteSelectedLayers), + action: MenuBarEntry::create_action(|_| DocumentMessage::DeleteSelectedLayers.into()), + disabled: no_active_document || !has_selected_nodes, + ..MenuBarEntry::default() + }, + ], + vec![MenuBarEntry { + label: "Convert to Infinite Canvas".into(), + icon: Some("Artboard".into()), + action: MenuBarEntry::create_action(|_| DocumentMessage::RemoveArtboards.into()), + disabled: no_active_document, + ..MenuBarEntry::default() + }], + ]), + ), + MenuBarEntry::new_root( + "Layer".into(), + no_active_document, + MenuBarEntryChildren(vec![ + vec![MenuBarEntry { + label: "New".into(), + icon: Some("NewLayer".into()), + shortcut: action_keys!(DocumentMessageDiscriminant::CreateEmptyFolder), + action: MenuBarEntry::create_action(|_| DocumentMessage::CreateEmptyFolder.into()), + disabled: no_active_document, + ..MenuBarEntry::default() + }], + vec![ + MenuBarEntry { + label: "Group".into(), + icon: Some("Folder".into()), + shortcut: action_keys!(DocumentMessageDiscriminant::GroupSelectedLayers), + action: MenuBarEntry::create_action(|_| { + DocumentMessage::GroupSelectedLayers { + group_folder_type: GroupFolderType::Layer, + } + .into() + }), + disabled: no_active_document || !has_selected_layers, + ..MenuBarEntry::default() + }, + MenuBarEntry { + label: "Ungroup".into(), + icon: Some("FolderOpen".into()), + shortcut: action_keys!(DocumentMessageDiscriminant::UngroupSelectedLayers), + action: MenuBarEntry::create_action(|_| DocumentMessage::UngroupSelectedLayers.into()), + disabled: no_active_document || !has_selected_layers, + ..MenuBarEntry::default() + }, + ], + vec![ + MenuBarEntry { + label: "Hide/Show".into(), + icon: Some("EyeHide".into()), + shortcut: action_keys!(DocumentMessageDiscriminant::ToggleSelectedVisibility), + action: MenuBarEntry::create_action(|_| DocumentMessage::ToggleSelectedVisibility.into()), + disabled: no_active_document || !has_selected_layers, + ..MenuBarEntry::default() + }, + MenuBarEntry { + label: "Lock/Unlock".into(), + icon: Some("PadlockLocked".into()), + shortcut: action_keys!(DocumentMessageDiscriminant::ToggleSelectedLocked), + action: MenuBarEntry::create_action(|_| DocumentMessage::ToggleSelectedLocked.into()), + disabled: no_active_document || !has_selected_layers, + ..MenuBarEntry::default() + }, + ], + vec![ + MenuBarEntry { + label: "Grab".into(), + icon: Some("TransformationGrab".into()), + shortcut: action_keys!(TransformLayerMessageDiscriminant::BeginGrab), + action: MenuBarEntry::create_action(|_| TransformLayerMessage::BeginGrab.into()), + disabled: no_active_document || !has_selected_layers, + ..MenuBarEntry::default() + }, + MenuBarEntry { + label: "Rotate".into(), + icon: Some("TransformationRotate".into()), + shortcut: action_keys!(TransformLayerMessageDiscriminant::BeginRotate), + action: MenuBarEntry::create_action(|_| TransformLayerMessage::BeginRotate.into()), + disabled: no_active_document || !has_selected_layers, + ..MenuBarEntry::default() + }, + MenuBarEntry { + label: "Scale".into(), + icon: Some("TransformationScale".into()), + shortcut: action_keys!(TransformLayerMessageDiscriminant::BeginScale), + action: MenuBarEntry::create_action(|_| TransformLayerMessage::BeginScale.into()), + disabled: no_active_document || !has_selected_layers, + ..MenuBarEntry::default() + }, + ], + vec![ + MenuBarEntry { + label: "Arrange".into(), + icon: Some("StackHollow".into()), + action: MenuBarEntry::no_action(), + disabled: no_active_document || !has_selected_layers, + children: MenuBarEntryChildren(vec![ + vec![ + MenuBarEntry { + label: "Raise To Front".into(), + icon: Some("Stack".into()), + shortcut: action_keys!(DocumentMessageDiscriminant::SelectedLayersRaiseToFront), + action: MenuBarEntry::create_action(|_| DocumentMessage::SelectedLayersRaiseToFront.into()), + disabled: no_active_document || !has_selected_layers, + ..MenuBarEntry::default() + }, + MenuBarEntry { + label: "Raise".into(), + icon: Some("StackRaise".into()), + shortcut: action_keys!(DocumentMessageDiscriminant::SelectedLayersRaise), + action: MenuBarEntry::create_action(|_| DocumentMessage::SelectedLayersRaise.into()), + disabled: no_active_document || !has_selected_layers, + ..MenuBarEntry::default() + }, + MenuBarEntry { + label: "Lower".into(), + icon: Some("StackLower".into()), + shortcut: action_keys!(DocumentMessageDiscriminant::SelectedLayersLower), + action: MenuBarEntry::create_action(|_| DocumentMessage::SelectedLayersLower.into()), + disabled: no_active_document || !has_selected_layers, + ..MenuBarEntry::default() + }, + MenuBarEntry { + label: "Lower to Back".into(), + icon: Some("StackBottom".into()), + shortcut: action_keys!(DocumentMessageDiscriminant::SelectedLayersLowerToBack), + action: MenuBarEntry::create_action(|_| DocumentMessage::SelectedLayersLowerToBack.into()), + disabled: no_active_document || !has_selected_layers, + ..MenuBarEntry::default() + }, + ], + vec![MenuBarEntry { + label: "Reverse".into(), + icon: Some("StackReverse".into()), + action: MenuBarEntry::create_action(|_| DocumentMessage::SelectedLayersReverse.into()), + disabled: no_active_document || !has_selected_layers, + ..MenuBarEntry::default() + }], + ]), + ..MenuBarEntry::default() + }, + MenuBarEntry { + label: "Align".into(), + icon: Some("AlignVerticalCenter".into()), + action: MenuBarEntry::no_action(), + disabled: no_active_document || !has_selected_layers, + children: MenuBarEntryChildren({ + let choices = [ + [ + (AlignAxis::X, AlignAggregate::Min, "AlignLeft", "Align Left"), + (AlignAxis::X, AlignAggregate::Center, "AlignHorizontalCenter", "Align Horizontal Center"), + (AlignAxis::X, AlignAggregate::Max, "AlignRight", "Align Right"), + ], + [ + (AlignAxis::Y, AlignAggregate::Min, "AlignTop", "Align Top"), + (AlignAxis::Y, AlignAggregate::Center, "AlignVerticalCenter", "Align Vertical Center"), + (AlignAxis::Y, AlignAggregate::Max, "AlignBottom", "Align Bottom"), + ], + ]; + + choices + .into_iter() + .map(|group| { + group + .into_iter() + .map(|(axis, aggregate, icon, name)| MenuBarEntry { + label: name.into(), + icon: Some(icon.into()), + action: MenuBarEntry::create_action(move |_| DocumentMessage::AlignSelectedLayers { axis, aggregate }.into()), + disabled: no_active_document || !has_selected_layers, + ..MenuBarEntry::default() + }) + .collect() + }) + .collect() + }), + ..MenuBarEntry::default() + }, + MenuBarEntry { + label: "Flip".into(), + icon: Some("FlipVertical".into()), + action: MenuBarEntry::no_action(), + disabled: no_active_document || !has_selected_layers, + children: MenuBarEntryChildren(vec![{ + [(FlipAxis::X, "FlipHorizontal", "Horizontal"), (FlipAxis::Y, "FlipVertical", "Vertical")] + .into_iter() + .map(|(flip_axis, icon, name)| MenuBarEntry { + label: name.into(), + icon: Some(icon.into()), + action: MenuBarEntry::create_action(move |_| DocumentMessage::FlipSelectedLayers { flip_axis }.into()), + disabled: no_active_document || !has_selected_layers, + ..MenuBarEntry::default() + }) + .collect() + }]), + ..MenuBarEntry::default() + }, + MenuBarEntry { + label: "Turn".into(), + icon: Some("TurnPositive90".into()), + action: MenuBarEntry::no_action(), + disabled: no_active_document || !has_selected_layers, + children: MenuBarEntryChildren(vec![{ + [(-90., "TurnNegative90", "Turn -90°"), (90., "TurnPositive90", "Turn 90°")] + .into_iter() + .map(|(degrees, icon, name)| MenuBarEntry { + label: name.into(), + icon: Some(icon.into()), + action: MenuBarEntry::create_action(move |_| DocumentMessage::RotateSelectedLayers { degrees }.into()), + disabled: no_active_document || !has_selected_layers, + ..MenuBarEntry::default() + }) + .collect() + }]), + ..MenuBarEntry::default() + }, + MenuBarEntry { + label: "Boolean".into(), + icon: Some("BooleanSubtractFront".into()), + action: MenuBarEntry::no_action(), + disabled: no_active_document || !has_selected_layers, + children: MenuBarEntryChildren(vec![{ + let list = ::list(); + list.into_iter() + .map(|i| i.into_iter()) + .flatten() + .map(move |(operation, info)| MenuBarEntry { + label: info.label.to_string(), + icon: info.icon.as_ref().map(|i| i.to_string()), + action: MenuBarEntry::create_action(move |_| { + let group_folder_type = GroupFolderType::BooleanOperation(*operation); + DocumentMessage::GroupSelectedLayers { group_folder_type }.into() + }), + disabled: no_active_document || !has_selected_layers, + ..MenuBarEntry::default() + }) + .collect() + }]), + ..MenuBarEntry::default() + }, + ], + ]), + ), + MenuBarEntry::new_root( + "Select".into(), + no_active_document, + MenuBarEntryChildren(vec![ + vec![ + MenuBarEntry { + label: "Select All".into(), + icon: Some("SelectAll".into()), + shortcut: action_keys!(DocumentMessageDiscriminant::SelectAllLayers), + action: MenuBarEntry::create_action(|_| DocumentMessage::SelectAllLayers.into()), + disabled: no_active_document, + ..MenuBarEntry::default() + }, + MenuBarEntry { + label: "Deselect All".into(), + icon: Some("DeselectAll".into()), + shortcut: action_keys!(DocumentMessageDiscriminant::DeselectAllLayers), + action: MenuBarEntry::create_action(|_| DocumentMessage::DeselectAllLayers.into()), + disabled: no_active_document || !has_selected_nodes, + ..MenuBarEntry::default() + }, + MenuBarEntry { + label: "Select Parent".into(), + icon: Some("SelectParent".into()), + shortcut: action_keys!(DocumentMessageDiscriminant::SelectParentLayer), + action: MenuBarEntry::create_action(|_| DocumentMessage::SelectParentLayer.into()), + disabled: no_active_document || !has_selected_nodes, + ..MenuBarEntry::default() + }, + ], + vec![ + MenuBarEntry { + label: "Previous Selection".into(), + icon: Some("HistoryUndo".into()), + shortcut: action_keys!(DocumentMessageDiscriminant::SelectionStepBack), + action: MenuBarEntry::create_action(|_| DocumentMessage::SelectionStepBack.into()), + disabled: !has_selection_history.0, + ..MenuBarEntry::default() + }, + MenuBarEntry { + label: "Next Selection".into(), + icon: Some("HistoryRedo".into()), + shortcut: action_keys!(DocumentMessageDiscriminant::SelectionStepForward), + action: MenuBarEntry::create_action(|_| DocumentMessage::SelectionStepForward.into()), + disabled: !has_selection_history.1, + ..MenuBarEntry::default() + }, + ], + ]), + ), + MenuBarEntry::new_root( + "View".into(), + no_active_document, + MenuBarEntryChildren(vec![ + vec![ + MenuBarEntry { + label: "Tilt".into(), + icon: Some("Tilt".into()), + shortcut: action_keys!(NavigationMessageDiscriminant::BeginCanvasTilt), + action: MenuBarEntry::create_action(|_| NavigationMessage::BeginCanvasTilt { was_dispatched_from_menu: true }.into()), + disabled: no_active_document || node_graph_open, + ..MenuBarEntry::default() + }, + MenuBarEntry { + label: "Reset Tilt".into(), + icon: Some("TiltReset".into()), + shortcut: action_keys!(NavigationMessageDiscriminant::CanvasTiltSet), + action: MenuBarEntry::create_action(|_| NavigationMessage::CanvasTiltSet { angle_radians: 0.into() }.into()), + disabled: no_active_document || node_graph_open || !self.canvas_tilted, + ..MenuBarEntry::default() + }, + ], + vec![ + MenuBarEntry { + label: "Zoom In".into(), + icon: Some("ZoomIn".into()), + shortcut: action_keys!(NavigationMessageDiscriminant::CanvasZoomIncrease), + action: MenuBarEntry::create_action(|_| NavigationMessage::CanvasZoomIncrease { center_on_mouse: false }.into()), + disabled: no_active_document, + ..MenuBarEntry::default() + }, + MenuBarEntry { + label: "Zoom Out".into(), + icon: Some("ZoomOut".into()), + shortcut: action_keys!(NavigationMessageDiscriminant::CanvasZoomDecrease), + action: MenuBarEntry::create_action(|_| NavigationMessage::CanvasZoomDecrease { center_on_mouse: false }.into()), + disabled: no_active_document, + ..MenuBarEntry::default() + }, + MenuBarEntry { + label: "Zoom to Selection".into(), + icon: Some("FrameSelected".into()), + shortcut: action_keys!(NavigationMessageDiscriminant::FitViewportToSelection), + action: MenuBarEntry::create_action(|_| NavigationMessage::FitViewportToSelection.into()), + disabled: no_active_document || !has_selected_layers, + ..MenuBarEntry::default() + }, + MenuBarEntry { + label: "Zoom to Fit".into(), + icon: Some("FrameAll".into()), + shortcut: action_keys!(DocumentMessageDiscriminant::ZoomCanvasToFitAll), + action: MenuBarEntry::create_action(|_| DocumentMessage::ZoomCanvasToFitAll.into()), + disabled: no_active_document, + ..MenuBarEntry::default() + }, + MenuBarEntry { + label: "Zoom to 100%".into(), + icon: Some("Zoom1x".into()), + shortcut: action_keys!(DocumentMessageDiscriminant::ZoomCanvasTo100Percent), + action: MenuBarEntry::create_action(|_| DocumentMessage::ZoomCanvasTo100Percent.into()), + disabled: no_active_document, + ..MenuBarEntry::default() + }, + MenuBarEntry { + label: "Zoom to 200%".into(), + icon: Some("Zoom2x".into()), + shortcut: action_keys!(DocumentMessageDiscriminant::ZoomCanvasTo200Percent), + action: MenuBarEntry::create_action(|_| DocumentMessage::ZoomCanvasTo200Percent.into()), + disabled: no_active_document, + ..MenuBarEntry::default() + }, + ], + vec![MenuBarEntry { + label: "Flip".into(), + icon: Some(if self.canvas_flipped { "CheckboxChecked" } else { "CheckboxUnchecked" }.into()), + shortcut: action_keys!(NavigationMessageDiscriminant::CanvasFlip), + action: MenuBarEntry::create_action(|_| NavigationMessage::CanvasFlip.into()), + disabled: no_active_document || node_graph_open, + ..MenuBarEntry::default() + }], + vec![MenuBarEntry { + label: "Rulers".into(), + icon: Some(if self.rulers_visible { "CheckboxChecked" } else { "CheckboxUnchecked" }.into()), + shortcut: action_keys!(PortfolioMessageDiscriminant::ToggleRulers), + action: MenuBarEntry::create_action(|_| PortfolioMessage::ToggleRulers.into()), + disabled: no_active_document, + ..MenuBarEntry::default() + }], + vec![MenuBarEntry { + label: "Window: Spreadsheet".into(), + icon: Some(if self.spreadsheet_view_open { "CheckboxChecked" } else { "CheckboxUnchecked" }.into()), + action: MenuBarEntry::create_action(|_| SpreadsheetMessage::ToggleOpen.into()), + disabled: no_active_document, + ..MenuBarEntry::default() + }], + ]), + ), + MenuBarEntry::new_root( + "Help".into(), + true, + MenuBarEntryChildren(vec![ + vec![MenuBarEntry { + label: "About Graphite…".into(), + icon: Some("GraphiteLogo".into()), + action: MenuBarEntry::create_action(|_| DialogMessage::RequestAboutGraphiteDialog.into()), + ..MenuBarEntry::default() + }], + vec![ + MenuBarEntry { + label: "Donate to Graphite".into(), + icon: Some("Heart".into()), + action: MenuBarEntry::create_action(|_| { + FrontendMessage::TriggerVisitLink { + url: "https://graphite.rs/donate/".into(), + } + .into() + }), + ..MenuBarEntry::default() + }, + MenuBarEntry { + label: "User Manual".into(), + icon: Some("UserManual".into()), + action: MenuBarEntry::create_action(|_| { + FrontendMessage::TriggerVisitLink { + url: "https://graphite.rs/learn/".into(), + } + .into() + }), + ..MenuBarEntry::default() + }, + MenuBarEntry { + label: "Report a Bug".into(), + icon: Some("Bug".into()), + action: MenuBarEntry::create_action(|_| { + FrontendMessage::TriggerVisitLink { + url: "https://github.com/GraphiteEditor/Graphite/issues/new".into(), + } + .into() + }), + ..MenuBarEntry::default() + }, + MenuBarEntry { + label: "Visit on GitHub".into(), + icon: Some("Website".into()), + action: MenuBarEntry::create_action(|_| { + FrontendMessage::TriggerVisitLink { + url: "https://github.com/GraphiteEditor/Graphite".into(), + } + .into() + }), + ..MenuBarEntry::default() + }, + ], + vec![MenuBarEntry { + label: "Developer Debug".into(), + icon: Some("Code".into()), + action: MenuBarEntry::no_action(), + children: MenuBarEntryChildren(vec![ + vec![MenuBarEntry { + label: "Reset Nodes to Definitions on Open".into(), + icon: Some(if reset_node_definitions_on_open { "CheckboxChecked" } else { "CheckboxUnchecked" }.into()), + action: MenuBarEntry::create_action(|_| PortfolioMessage::ToggleResetNodesToDefinitionsOnOpen.into()), + ..MenuBarEntry::default() + }], + vec![ + MenuBarEntry { + label: "Print Trace Logs".into(), + icon: Some(if log::max_level() == log::LevelFilter::Trace { "CheckboxChecked" } else { "CheckboxUnchecked" }.into()), + action: MenuBarEntry::create_action(|_| DebugMessage::ToggleTraceLogs.into()), + ..MenuBarEntry::default() + }, + MenuBarEntry { + label: "Print Messages: Off".into(), + icon: message_logging_verbosity_off.then_some("SmallDot".into()), + shortcut: action_keys!(DebugMessageDiscriminant::MessageOff), + action: MenuBarEntry::create_action(|_| DebugMessage::MessageOff.into()), + ..MenuBarEntry::default() + }, + MenuBarEntry { + label: "Print Messages: Only Names".into(), + icon: message_logging_verbosity_names.then_some("SmallDot".into()), + shortcut: action_keys!(DebugMessageDiscriminant::MessageNames), + action: MenuBarEntry::create_action(|_| DebugMessage::MessageNames.into()), + ..MenuBarEntry::default() + }, + MenuBarEntry { + label: "Print Messages: Full Contents".into(), + icon: message_logging_verbosity_contents.then_some("SmallDot".into()), + shortcut: action_keys!(DebugMessageDiscriminant::MessageContents), + action: MenuBarEntry::create_action(|_| DebugMessage::MessageContents.into()), + ..MenuBarEntry::default() + }, + ], + vec![MenuBarEntry { + label: "Trigger a Crash".into(), + icon: Some("Warning".into()), + action: MenuBarEntry::create_action(|_| panic!()), + ..MenuBarEntry::default() + }], + ]), + ..MenuBarEntry::default() + }], + ]), + ), + ]; + Layout::MenuLayout(MenuLayout::new(menu_bar_entries)) + } +} diff --git a/editor/src/messages/portfolio/menu_bar/mod.rs b/editor/src/messages/portfolio/menu_bar/mod.rs new file mode 100644 index 0000000000000000000000000000000000000000..27e741b208051fbf8fb4e53360cfcfa72683528a --- /dev/null +++ b/editor/src/messages/portfolio/menu_bar/mod.rs @@ -0,0 +1,7 @@ +mod menu_bar_message; +mod menu_bar_message_handler; + +#[doc(inline)] +pub use menu_bar_message::{MenuBarMessage, MenuBarMessageDiscriminant}; +#[doc(inline)] +pub use menu_bar_message_handler::MenuBarMessageHandler; diff --git a/editor/src/messages/portfolio/mod.rs b/editor/src/messages/portfolio/mod.rs new file mode 100644 index 0000000000000000000000000000000000000000..2203ac94036ed2f998f06bb01332690ab1570b66 --- /dev/null +++ b/editor/src/messages/portfolio/mod.rs @@ -0,0 +1,13 @@ +mod portfolio_message; +mod portfolio_message_handler; + +pub mod document; +pub mod document_migration; +pub mod menu_bar; +pub mod spreadsheet; +pub mod utility_types; + +#[doc(inline)] +pub use portfolio_message::{PortfolioMessage, PortfolioMessageDiscriminant}; +#[doc(inline)] +pub use portfolio_message_handler::{PortfolioMessageData, PortfolioMessageHandler}; diff --git a/editor/src/messages/portfolio/portfolio_message.rs b/editor/src/messages/portfolio/portfolio_message.rs new file mode 100644 index 0000000000000000000000000000000000000000..cb2fa34e3e9807408ef1ca2a8355ebe2cb5b99e8 --- /dev/null +++ b/editor/src/messages/portfolio/portfolio_message.rs @@ -0,0 +1,131 @@ +use super::document::utility_types::document_metadata::LayerNodeIdentifier; +use super::utility_types::PanelType; +use crate::messages::frontend::utility_types::{ExportBounds, FileType}; +use crate::messages::portfolio::document::utility_types::clipboards::Clipboard; +use crate::messages::prelude::*; +use graphene_std::Color; +use graphene_std::raster::Image; +use graphene_std::text::Font; + +#[impl_message(Message, Portfolio)] +#[derive(PartialEq, Clone, Debug, serde::Serialize, serde::Deserialize)] +pub enum PortfolioMessage { + // Sub-messages + #[child] + MenuBar(MenuBarMessage), + #[child] + Document(DocumentMessage), + #[child] + Spreadsheet(SpreadsheetMessage), + + // Messages + DocumentPassMessage { + document_id: DocumentId, + message: DocumentMessage, + }, + AutoSaveActiveDocument, + AutoSaveAllDocuments, + AutoSaveDocument { + document_id: DocumentId, + }, + CloseActiveDocumentWithConfirmation, + CloseAllDocuments, + CloseAllDocumentsWithConfirmation, + CloseDocument { + document_id: DocumentId, + }, + CloseDocumentWithConfirmation { + document_id: DocumentId, + }, + Copy { + clipboard: Clipboard, + }, + Cut { + clipboard: Clipboard, + }, + DeleteDocument { + document_id: DocumentId, + }, + DestroyAllDocuments, + EditorPreferences, + FontLoaded { + font_family: String, + font_style: String, + preview_url: String, + data: Vec, + }, + Import, + LoadDocumentResources { + document_id: DocumentId, + }, + LoadFont { + font: Font, + }, + NewDocumentWithName { + name: String, + }, + NextDocument, + OpenDocument, + OpenDocumentFile { + document_name: String, + document_serialized_content: String, + }, + ToggleResetNodesToDefinitionsOnOpen, + OpenDocumentFileWithId { + document_id: DocumentId, + document_name: String, + document_is_auto_saved: bool, + document_is_saved: bool, + document_serialized_content: String, + to_front: bool, + }, + PasteIntoFolder { + clipboard: Clipboard, + parent: LayerNodeIdentifier, + insert_index: usize, + }, + PasteSerializedData { + data: String, + }, + CenterPastedLayers { + layers: Vec, + }, + PasteImage { + name: Option, + image: Image, + mouse: Option<(f64, f64)>, + parent_and_insert_index: Option<(LayerNodeIdentifier, usize)>, + }, + PasteSvg { + name: Option, + svg: String, + mouse: Option<(f64, f64)>, + parent_and_insert_index: Option<(LayerNodeIdentifier, usize)>, + }, + PrevDocument, + SetActivePanel { + panel: PanelType, + }, + SetDevicePixelRatio { + ratio: f64, + }, + SelectDocument { + document_id: DocumentId, + }, + SubmitDocumentExport { + file_name: String, + file_type: FileType, + scale_factor: f64, + bounds: ExportBounds, + transparent_background: bool, + }, + SubmitActiveGraphRender, + SubmitGraphRender { + document_id: DocumentId, + ignore_hash: bool, + }, + ToggleRulers, + UpdateDocumentWidgets, + UpdateOpenDocumentsList, + UpdateVelloPreference, +} diff --git a/editor/src/messages/portfolio/portfolio_message_handler.rs b/editor/src/messages/portfolio/portfolio_message_handler.rs new file mode 100644 index 0000000000000000000000000000000000000000..35a1eb5160a679985899b599d2a64ba4704dd95c --- /dev/null +++ b/editor/src/messages/portfolio/portfolio_message_handler.rs @@ -0,0 +1,995 @@ +use super::document::utility_types::document_metadata::LayerNodeIdentifier; +use super::document::utility_types::network_interface; +use super::spreadsheet::SpreadsheetMessageHandler; +use super::utility_types::{PanelType, PersistentData}; +use crate::application::generate_uuid; +use crate::consts::DEFAULT_DOCUMENT_NAME; +use crate::messages::animation::TimingInformation; +use crate::messages::debug::utility_types::MessageLoggingVerbosity; +use crate::messages::dialog::simple_dialogs; +use crate::messages::frontend::utility_types::FrontendDocumentDetails; +use crate::messages::layout::utility_types::widget_prelude::*; +use crate::messages::portfolio::document::DocumentMessageData; +use crate::messages::portfolio::document::graph_operation::utility_types::TransformIn; +use crate::messages::portfolio::document::utility_types::clipboards::{Clipboard, CopyBufferEntry, INTERNAL_CLIPBOARD_COUNT}; +use crate::messages::portfolio::document::utility_types::network_interface::OutputConnector; +use crate::messages::portfolio::document::utility_types::nodes::SelectedNodes; +use crate::messages::portfolio::document_migration::*; +use crate::messages::preferences::SelectionMode; +use crate::messages::prelude::*; +use crate::messages::tool::utility_types::{HintData, HintGroup, ToolType}; +use crate::node_graph_executor::{ExportConfig, NodeGraphExecutor}; +use glam::{DAffine2, DVec2}; +use graph_craft::document::NodeId; +use graphene_std::renderer::Quad; +use graphene_std::text::Font; +use std::vec; + +pub struct PortfolioMessageData<'a> { + pub ipp: &'a InputPreprocessorMessageHandler, + pub preferences: &'a PreferencesMessageHandler, + pub current_tool: &'a ToolType, + pub message_logging_verbosity: MessageLoggingVerbosity, + pub reset_node_definitions_on_open: bool, + pub timing_information: TimingInformation, + pub animation: &'a AnimationMessageHandler, +} + +#[derive(Debug, Default)] +pub struct PortfolioMessageHandler { + menu_bar_message_handler: MenuBarMessageHandler, + pub documents: HashMap, + document_ids: VecDeque, + active_panel: PanelType, + pub(crate) active_document_id: Option, + copy_buffer: [Vec; INTERNAL_CLIPBOARD_COUNT as usize], + pub persistent_data: PersistentData, + pub executor: NodeGraphExecutor, + pub selection_mode: SelectionMode, + /// The spreadsheet UI allows for instance data to be previewed. + pub spreadsheet: SpreadsheetMessageHandler, + device_pixel_ratio: Option, + pub reset_node_definitions_on_open: bool, +} + +impl MessageHandler> for PortfolioMessageHandler { + fn process_message(&mut self, message: PortfolioMessage, responses: &mut VecDeque, data: PortfolioMessageData) { + let PortfolioMessageData { + ipp, + preferences, + current_tool, + message_logging_verbosity, + reset_node_definitions_on_open, + timing_information, + animation, + } = data; + + match message { + // Sub-messages + PortfolioMessage::MenuBar(message) => { + self.menu_bar_message_handler.has_active_document = false; + self.menu_bar_message_handler.canvas_tilted = false; + self.menu_bar_message_handler.canvas_flipped = false; + self.menu_bar_message_handler.rulers_visible = false; + self.menu_bar_message_handler.node_graph_open = false; + self.menu_bar_message_handler.has_selected_nodes = false; + self.menu_bar_message_handler.has_selected_layers = false; + self.menu_bar_message_handler.has_selection_history = (false, false); + self.menu_bar_message_handler.spreadsheet_view_open = self.spreadsheet.spreadsheet_view_open; + self.menu_bar_message_handler.message_logging_verbosity = message_logging_verbosity; + self.menu_bar_message_handler.reset_node_definitions_on_open = reset_node_definitions_on_open; + + if let Some(document) = self.active_document_id.and_then(|document_id| self.documents.get_mut(&document_id)) { + self.menu_bar_message_handler.has_active_document = true; + self.menu_bar_message_handler.canvas_tilted = document.document_ptz.tilt() != 0.; + self.menu_bar_message_handler.canvas_flipped = document.document_ptz.flip; + self.menu_bar_message_handler.rulers_visible = document.rulers_visible; + self.menu_bar_message_handler.node_graph_open = document.is_graph_overlay_open(); + let selected_nodes = document.network_interface.selected_nodes(); + self.menu_bar_message_handler.has_selected_nodes = selected_nodes.selected_nodes().next().is_some(); + self.menu_bar_message_handler.has_selected_layers = selected_nodes.selected_visible_layers(&document.network_interface).next().is_some(); + self.menu_bar_message_handler.has_selection_history = { + let metadata = &document.network_interface.document_network_metadata().persistent_metadata; + (!metadata.selection_undo_history.is_empty(), !metadata.selection_redo_history.is_empty()) + }; + } + + self.menu_bar_message_handler.process_message(message, responses, ()); + } + PortfolioMessage::Spreadsheet(message) => { + self.spreadsheet.process_message(message, responses, ()); + } + PortfolioMessage::Document(message) => { + if let Some(document_id) = self.active_document_id { + if let Some(document) = self.documents.get_mut(&document_id) { + let document_inputs = DocumentMessageData { + document_id, + ipp, + persistent_data: &self.persistent_data, + executor: &mut self.executor, + current_tool, + preferences, + device_pixel_ratio: self.device_pixel_ratio.unwrap_or(1.), + }; + document.process_message(message, responses, document_inputs) + } + } + } + + // Messages + PortfolioMessage::DocumentPassMessage { document_id, message } => { + if let Some(document) = self.documents.get_mut(&document_id) { + let document_inputs = DocumentMessageData { + document_id, + ipp, + persistent_data: &self.persistent_data, + executor: &mut self.executor, + current_tool, + preferences, + device_pixel_ratio: self.device_pixel_ratio.unwrap_or(1.), + }; + document.process_message(message, responses, document_inputs) + } + } + PortfolioMessage::AutoSaveActiveDocument => { + if let Some(document_id) = self.active_document_id { + if let Some(document) = self.active_document_mut() { + document.set_auto_save_state(true); + responses.add(PortfolioMessage::AutoSaveDocument { document_id }); + } + } + } + PortfolioMessage::AutoSaveAllDocuments => { + for (document_id, document) in self.documents.iter_mut() { + if !document.is_auto_saved() { + document.set_auto_save_state(true); + responses.add(PortfolioMessage::AutoSaveDocument { document_id: *document_id }); + } + } + } + PortfolioMessage::AutoSaveDocument { document_id } => { + let document = self.documents.get(&document_id).unwrap(); + responses.add(FrontendMessage::TriggerIndexedDbWriteDocument { + document: document.serialize_document(), + details: FrontendDocumentDetails { + is_auto_saved: document.is_auto_saved(), + is_saved: document.is_saved(), + id: document_id, + name: document.name.clone(), + }, + }) + } + PortfolioMessage::CloseActiveDocumentWithConfirmation => { + if let Some(document_id) = self.active_document_id { + responses.add(PortfolioMessage::CloseDocumentWithConfirmation { document_id }); + } + } + PortfolioMessage::CloseAllDocuments => { + if self.active_document_id.is_some() { + responses.add(BroadcastEvent::ToolAbort); + responses.add(ToolMessage::DeactivateTools); + + // Clear relevant UI layouts if there are no documents + responses.add(PropertiesPanelMessage::Clear); + responses.add(DocumentMessage::ClearLayersPanel); + let hint_data = HintData(vec![HintGroup(vec![])]); + responses.add(FrontendMessage::UpdateInputHints { hint_data }); + } + + for document_id in &self.document_ids { + responses.add(FrontendMessage::TriggerIndexedDbRemoveDocument { document_id: *document_id }); + } + + responses.add(PortfolioMessage::DestroyAllDocuments); + responses.add(PortfolioMessage::UpdateOpenDocumentsList); + } + PortfolioMessage::CloseAllDocumentsWithConfirmation => { + if self.unsaved_document_names().is_empty() { + responses.add(PortfolioMessage::CloseAllDocuments) + } else { + responses.add(DialogMessage::CloseAllDocumentsWithConfirmation) + } + } + PortfolioMessage::CloseDocument { document_id } => { + // Is this the last document? + if self.documents.len() == 1 && self.document_ids[0] == document_id { + // Clear UI layouts that assume the existence of a document + responses.add(PropertiesPanelMessage::Clear); + responses.add(DocumentMessage::ClearLayersPanel); + let hint_data = HintData(vec![HintGroup(vec![])]); + responses.add(FrontendMessage::UpdateInputHints { hint_data }); + } + + // Actually delete the document (delay to delete document is required to let the document and properties panel messages above get processed) + responses.add(PortfolioMessage::DeleteDocument { document_id }); + responses.add(FrontendMessage::TriggerIndexedDbRemoveDocument { document_id }); + + // Send the new list of document tab names + responses.add(PortfolioMessage::UpdateOpenDocumentsList); + } + PortfolioMessage::CloseDocumentWithConfirmation { document_id } => { + let target_document = self.documents.get(&document_id).unwrap(); + if target_document.is_saved() { + responses.add(BroadcastEvent::ToolAbort); + responses.add(PortfolioMessage::CloseDocument { document_id }); + } else { + let dialog = simple_dialogs::CloseDocumentDialog { + document_name: target_document.name.clone(), + document_id, + }; + dialog.send_dialog_to_frontend(responses); + + // Select the document being closed + responses.add(PortfolioMessage::SelectDocument { document_id }); + } + } + PortfolioMessage::Copy { clipboard } => { + // We can't use `self.active_document()` because it counts as an immutable borrow of the entirety of `self` + let Some(active_document) = self.active_document_id.and_then(|id| self.documents.get_mut(&id)) else { + return; + }; + + let mut copy_val = |buffer: &mut Vec| { + let mut ordered_last_elements = active_document.network_interface.shallowest_unique_layers(&[]).collect::>(); + + ordered_last_elements.sort_by_key(|layer| { + let Some(parent) = layer.parent(active_document.metadata()) else { return usize::MAX }; + DocumentMessageHandler::get_calculated_insert_index(active_document.metadata(), &SelectedNodes(vec![layer.to_node()]), parent) + }); + + for layer in ordered_last_elements.into_iter() { + let layer_node_id = layer.to_node(); + + let mut copy_ids = HashMap::new(); + copy_ids.insert(layer_node_id, NodeId(0)); + + active_document + .network_interface + .upstream_flow_back_from_nodes(vec![layer_node_id], &[], network_interface::FlowType::LayerChildrenUpstreamFlow) + .enumerate() + .for_each(|(index, node_id)| { + copy_ids.insert(node_id, NodeId((index + 1) as u64)); + }); + + buffer.push(CopyBufferEntry { + nodes: active_document.network_interface.copy_nodes(©_ids, &[]).collect(), + selected: active_document.network_interface.selected_nodes().selected_layers_contains(layer, active_document.metadata()), + visible: active_document.network_interface.selected_nodes().layer_visible(layer, &active_document.network_interface), + locked: active_document.network_interface.selected_nodes().layer_locked(layer, &active_document.network_interface), + collapsed: false, + }); + } + }; + + if clipboard == Clipboard::Device { + let mut buffer = Vec::new(); + copy_val(&mut buffer); + let mut copy_text = String::from("graphite/layer: "); + copy_text += &serde_json::to_string(&buffer).expect("Could not serialize paste"); + + responses.add(FrontendMessage::TriggerTextCopy { copy_text }); + } else { + let copy_buffer = &mut self.copy_buffer; + copy_buffer[clipboard as usize].clear(); + copy_val(&mut copy_buffer[clipboard as usize]); + } + } + PortfolioMessage::Cut { clipboard } => { + responses.add(PortfolioMessage::Copy { clipboard }); + responses.add(DocumentMessage::DeleteSelectedLayers); + } + PortfolioMessage::DeleteDocument { document_id } => { + let document_index = self.document_index(document_id); + self.documents.remove(&document_id); + self.document_ids.remove(document_index); + + if self.document_ids.is_empty() { + self.active_document_id = None; + responses.add(MenuBarMessage::SendLayout); + } else if self.active_document_id.is_some() { + let document_id = if document_index == self.document_ids.len() { + // If we closed the last document take the one previous (same as last) + *self.document_ids.back().unwrap() + } else { + // Move to the next tab + self.document_ids[document_index] + }; + responses.add(PortfolioMessage::SelectDocument { document_id }); + } + } + PortfolioMessage::DestroyAllDocuments => { + // Empty the list of internal document data + self.documents.clear(); + self.document_ids.clear(); + self.active_document_id = None; + responses.add(MenuBarMessage::SendLayout); + } + PortfolioMessage::FontLoaded { + font_family, + font_style, + preview_url, + data, + } => { + let font = Font::new(font_family, font_style); + + self.persistent_data.font_cache.insert(font, preview_url, data); + self.executor.update_font_cache(self.persistent_data.font_cache.clone()); + for document_id in self.document_ids.iter() { + let inspect_node = self.inspect_node_id(); + let _ = self.executor.submit_node_graph_evaluation( + self.documents.get_mut(document_id).expect("Tried to render non-existent document"), + ipp.viewport_bounds.size().as_uvec2(), + timing_information, + inspect_node, + true, + ); + } + + if self.active_document_mut().is_some() { + responses.add(NodeGraphMessage::RunDocumentGraph); + } + } + PortfolioMessage::EditorPreferences => self.executor.update_editor_preferences(preferences.editor_preferences()), + PortfolioMessage::Import => { + // This portfolio message wraps the frontend message so it can be listed as an action, which isn't possible for frontend messages + responses.add(FrontendMessage::TriggerImport); + } + PortfolioMessage::LoadDocumentResources { document_id } => { + if let Some(document) = self.document_mut(document_id) { + document.load_layer_resources(responses); + } + } + PortfolioMessage::LoadFont { font } => { + if !self.persistent_data.font_cache.loaded_font(&font) { + responses.add_front(FrontendMessage::TriggerFontLoad { font }); + } + } + PortfolioMessage::NewDocumentWithName { name } => { + let mut new_document = DocumentMessageHandler::default(); + new_document.name = name; + responses.add(DocumentMessage::PTZUpdate); + + let document_id = DocumentId(generate_uuid()); + if self.active_document().is_some() { + responses.add(BroadcastEvent::ToolAbort); + responses.add(NavigationMessage::CanvasPan { delta: (0., 0.).into() }); + } + + self.load_document(new_document, document_id, responses, false); + responses.add(PortfolioMessage::SelectDocument { document_id }); + } + PortfolioMessage::NextDocument => { + if let Some(active_document_id) = self.active_document_id { + let current_index = self.document_index(active_document_id); + let next_index = (current_index + 1) % self.document_ids.len(); + let next_id = self.document_ids[next_index]; + + responses.add(PortfolioMessage::SelectDocument { document_id: next_id }); + } + } + PortfolioMessage::OpenDocument => { + // This portfolio message wraps the frontend message so it can be listed as an action, which isn't possible for frontend messages + responses.add(FrontendMessage::TriggerOpenDocument); + } + PortfolioMessage::OpenDocumentFile { + document_name, + document_serialized_content, + } => { + let document_id = DocumentId(generate_uuid()); + responses.add(PortfolioMessage::OpenDocumentFileWithId { + document_id, + document_name, + document_is_auto_saved: false, + document_is_saved: true, + document_serialized_content, + to_front: false, + }); + responses.add(PortfolioMessage::SelectDocument { document_id }); + } + PortfolioMessage::ToggleResetNodesToDefinitionsOnOpen => { + self.reset_node_definitions_on_open = !self.reset_node_definitions_on_open; + responses.add(MenuBarMessage::SendLayout); + } + PortfolioMessage::OpenDocumentFileWithId { + document_id, + document_name, + document_is_auto_saved, + document_is_saved, + document_serialized_content, + to_front, + } => { + // Upgrade the document being opened to use fresh copies of all nodes + let reset_node_definitions_on_open = reset_node_definitions_on_open || document_migration_reset_node_definition(&document_serialized_content); + // Upgrade the document being opened with string replacements on the original JSON + let document_serialized_content = document_migration_string_preprocessing(document_serialized_content); + + // Deserialize the document + let document = DocumentMessageHandler::deserialize_document(&document_serialized_content).map(|mut document| { + document.name.clone_from(&document_name); + document + }); + + // Display an error to the user if the document could not be opened + let mut document = match document { + Ok(document) => document, + Err(e) => { + if !document_is_auto_saved { + responses.add(DialogMessage::DisplayDialogError { + title: "Failed to open document".to_string(), + description: e.to_string(), + }); + } + + return; + } + }; + + // Upgrade the document's nodes to be compatible with the latest version + document_migration_upgrades(&mut document, reset_node_definitions_on_open); + + // Ensure each node has the metadata for its inputs + for (node_id, node, path) in document.network_interface.document_network().clone().recursive_nodes() { + document.network_interface.validate_input_metadata(node_id, node, &path); + document.network_interface.validate_display_name_metadata(node_id, &path); + } + + // Ensure layers are positioned as stacks if they are upstream siblings of another layer + document.network_interface.load_structure(); + let all_layers = LayerNodeIdentifier::ROOT_PARENT.descendants(document.network_interface.document_metadata()).collect::>(); + for layer in all_layers { + let Some((downstream_node, input_index)) = document + .network_interface + .outward_wires(&[]) + .and_then(|outward_wires| outward_wires.get(&OutputConnector::node(layer.to_node(), 0))) + .and_then(|outward_wires| outward_wires.first()) + .and_then(|input_connector| input_connector.node_id().map(|node_id| (node_id, input_connector.input_index()))) + else { + continue; + }; + + // If the downstream node is a layer and the input is the first input and the current layer is not in a stack + if input_index == 0 && document.network_interface.is_layer(&downstream_node, &[]) && !document.network_interface.is_stack(&layer.to_node(), &[]) { + // Ensure the layer is horizontally aligned with the downstream layer to prevent changing the layout of old files + let (Some(layer_position), Some(downstream_position)) = + (document.network_interface.position(&layer.to_node(), &[]), document.network_interface.position(&downstream_node, &[])) + else { + log::error!("Could not get position for layer {:?} or downstream node {} when opening file", layer.to_node(), downstream_node); + continue; + }; + + if layer_position.x == downstream_position.x { + document.network_interface.set_stack_position_calculated_offset(&layer.to_node(), &downstream_node, &[]); + } + } + } + + // Set the save state of the document based on what's given to us by the caller to this message + document.set_auto_save_state(document_is_auto_saved); + document.set_save_state(document_is_saved); + + // Load the document into the portfolio so it opens in the editor + self.load_document(document, document_id, responses, to_front); + } + PortfolioMessage::PasteIntoFolder { clipboard, parent, insert_index } => { + let mut all_new_ids = Vec::new(); + let paste = |entry: &CopyBufferEntry, responses: &mut VecDeque<_>, all_new_ids: &mut Vec| { + if self.active_document().is_some() { + trace!("Pasting into folder {parent:?} as index: {insert_index}"); + let nodes = entry.clone().nodes; + let new_ids: HashMap<_, _> = nodes.iter().map(|(id, _)| (*id, NodeId::new())).collect(); + let layer = LayerNodeIdentifier::new_unchecked(new_ids[&NodeId(0)]); + all_new_ids.extend(new_ids.values().cloned()); + responses.add(NodeGraphMessage::AddNodes { nodes, new_ids: new_ids.clone() }); + responses.add(NodeGraphMessage::MoveLayerToStack { layer, parent, insert_index }); + } + }; + + responses.add(DocumentMessage::DeselectAllLayers); + + for entry in self.copy_buffer[clipboard as usize].iter().rev() { + paste(entry, responses, &mut all_new_ids) + } + responses.add(NodeGraphMessage::RunDocumentGraph); + responses.add(NodeGraphMessage::SelectedNodesSet { nodes: all_new_ids }); + } + PortfolioMessage::PasteSerializedData { data } => { + if let Some(document) = self.active_document() { + let mut all_new_ids = Vec::new(); + if let Ok(data) = serde_json::from_str::>(&data) { + let parent = document.new_layer_parent(false); + let mut layers = Vec::new(); + + let mut added_nodes = false; + + for entry in data.into_iter().rev() { + if !added_nodes { + responses.add(DocumentMessage::DeselectAllLayers); + responses.add(DocumentMessage::AddTransaction); + added_nodes = true; + } + + document.load_layer_resources(responses); + let new_ids: HashMap<_, _> = entry.nodes.iter().map(|(id, _)| (*id, NodeId::new())).collect(); + let layer = LayerNodeIdentifier::new_unchecked(new_ids[&NodeId(0)]); + all_new_ids.extend(new_ids.values().cloned()); + + responses.add(NodeGraphMessage::AddNodes { nodes: entry.nodes, new_ids }); + responses.add(NodeGraphMessage::MoveLayerToStack { layer, parent, insert_index: 0 }); + layers.push(layer); + } + + responses.add(NodeGraphMessage::RunDocumentGraph); + responses.add(NodeGraphMessage::SelectedNodesSet { nodes: all_new_ids }); + responses.add(Message::StartBuffer); + responses.add(PortfolioMessage::CenterPastedLayers { layers }); + } + } + } + PortfolioMessage::CenterPastedLayers { layers } => { + if let Some(document) = self.active_document_mut() { + let viewport_bounds_quad_pixels = Quad::from_box([DVec2::ZERO, ipp.viewport_bounds.size()]); + let viewport_center_pixels = viewport_bounds_quad_pixels.center(); // In viewport pixel coordinates + + let doc_to_viewport_transform = document.metadata().document_to_viewport; + let viewport_to_doc_transform = doc_to_viewport_transform.inverse(); + + let viewport_quad_doc_space = viewport_to_doc_transform * viewport_bounds_quad_pixels; + + let mut top_level_items_to_center: Vec = Vec::new(); + let mut artboards_in_selection: Vec = Vec::new(); + + for &layer_id in &layers { + if document.network_interface.is_artboard(&layer_id.to_node(), &document.node_graph_handler.network) { + artboards_in_selection.push(layer_id); + } + } + + for &layer_id in &layers { + let is_child_of_selected_artboard = artboards_in_selection.iter().any(|&artboard_id| { + if layer_id == artboard_id { + return false; + } + layer_id.ancestors(document.metadata()).any(|ancestor| ancestor == artboard_id) + }); + + if !is_child_of_selected_artboard { + top_level_items_to_center.push(layer_id); + } + } + + if top_level_items_to_center.is_empty() { + return; + } + + let mut combined_min_doc = DVec2::MAX; + let mut combined_max_doc = DVec2::MIN; + let mut has_any_bounds = false; + + for &item_id in &top_level_items_to_center { + if let Some(bounds_doc) = document.metadata().bounding_box_document(item_id) { + combined_min_doc = combined_min_doc.min(bounds_doc[0]); + combined_max_doc = combined_max_doc.max(bounds_doc[1]); + has_any_bounds = true; + } + } + + if !has_any_bounds { + return; + } + + let combined_bounds_doc_quad = Quad::from_box([combined_min_doc, combined_max_doc]); + + if combined_bounds_doc_quad.intersects(viewport_quad_doc_space) { + return; + } + + let combined_center_doc = combined_bounds_doc_quad.center(); + let combined_center_viewport_pixels = doc_to_viewport_transform.transform_point2(combined_center_doc); + let translation_viewport_pixels_rounded = (viewport_center_pixels - combined_center_viewport_pixels).round(); + + let final_translation_offset_doc = viewport_to_doc_transform.transform_vector2(translation_viewport_pixels_rounded); + + if final_translation_offset_doc.abs_diff_eq(glam::DVec2::ZERO, 1e-9) { + return; + } + + responses.add(DocumentMessage::AddTransaction); + + for &item_id in &top_level_items_to_center { + if document.network_interface.is_artboard(&item_id.to_node(), &document.node_graph_handler.network) { + if let Some(bounds_doc) = document.metadata().bounding_box_document(item_id) { + let current_artboard_origin_doc = bounds_doc[0]; + let dimensions_doc = bounds_doc[1] - bounds_doc[0]; + let new_artboard_origin_doc = current_artboard_origin_doc + final_translation_offset_doc; + + responses.add(GraphOperationMessage::ResizeArtboard { + layer: item_id, + location: new_artboard_origin_doc.round().as_ivec2(), + dimensions: dimensions_doc.round().as_ivec2(), + }); + } + } else { + let current_abs_doc_transform = document.metadata().transform_to_document(item_id); + + let new_abs_doc_transform = DAffine2 { + matrix2: current_abs_doc_transform.matrix2, + translation: current_abs_doc_transform.translation + final_translation_offset_doc, + }; + + let transform = doc_to_viewport_transform * new_abs_doc_transform; + + responses.add(GraphOperationMessage::TransformSet { + layer: item_id, + transform, + transform_in: TransformIn::Viewport, + skip_rerender: false, + }); + } + } + + responses.add(NodeGraphMessage::RunDocumentGraph); + } + } + PortfolioMessage::PasteImage { + name, + image, + mouse, + parent_and_insert_index, + } => { + let create_document = self.documents.is_empty(); + + if create_document { + responses.add(PortfolioMessage::NewDocumentWithName { + name: name.clone().unwrap_or("Untitled Document".into()), + }); + } + + responses.add(DocumentMessage::PasteImage { + name, + image, + mouse, + parent_and_insert_index, + }); + + if create_document { + // Wait for the document to be rendered so the click targets can be calculated in order to determine the artboard size that will encompass the pasted image + responses.add(Message::StartBuffer); + responses.add(DocumentMessage::WrapContentInArtboard { place_artboard_at_origin: true }); + + // TODO: Figure out how to get StartBuffer to work here so we can delete this and use `DocumentMessage::ZoomCanvasToFitAll` instead + // Currently, it is necessary to use `FrontendMessage::TriggerDelayedZoomCanvasToFitAll` rather than `DocumentMessage::ZoomCanvasToFitAll` because the size of the viewport is not yet populated + responses.add(Message::StartBuffer); + responses.add(FrontendMessage::TriggerDelayedZoomCanvasToFitAll); + } + } + PortfolioMessage::PasteSvg { + name, + svg, + mouse, + parent_and_insert_index, + } => { + let create_document = self.documents.is_empty(); + + if create_document { + responses.add(PortfolioMessage::NewDocumentWithName { + name: name.clone().unwrap_or("Untitled Document".into()), + }); + } + + responses.add(DocumentMessage::PasteSvg { + name, + svg, + mouse, + parent_and_insert_index, + }); + + if create_document { + // Wait for the document to be rendered so the click targets can be calculated in order to determine the artboard size that will encompass the pasted image + responses.add(Message::StartBuffer); + responses.add(DocumentMessage::WrapContentInArtboard { place_artboard_at_origin: true }); + + // TODO: Figure out how to get StartBuffer to work here so we can delete this and use `DocumentMessage::ZoomCanvasToFitAll` instead + // Currently, it is necessary to use `FrontendMessage::TriggerDelayedZoomCanvasToFitAll` rather than `DocumentMessage::ZoomCanvasToFitAll` because the size of the viewport is not yet populated + responses.add(Message::StartBuffer); + responses.add(FrontendMessage::TriggerDelayedZoomCanvasToFitAll); + } + } + PortfolioMessage::PrevDocument => { + if let Some(active_document_id) = self.active_document_id { + let len = self.document_ids.len(); + let current_index = self.document_index(active_document_id); + let prev_index = (current_index + len - 1) % len; + let prev_id = self.document_ids[prev_index]; + responses.add(PortfolioMessage::SelectDocument { document_id: prev_id }); + } + } + PortfolioMessage::SetActivePanel { panel } => { + self.active_panel = panel; + responses.add(DocumentMessage::SetActivePanel { active_panel: self.active_panel }); + } + PortfolioMessage::SetDevicePixelRatio { ratio } => { + self.device_pixel_ratio = Some(ratio); + responses.add(OverlaysMessage::Draw); + } + PortfolioMessage::SelectDocument { document_id } => { + // Auto-save the document we are leaving + let mut node_graph_open = false; + if let Some(document) = self.active_document() { + if !document.is_auto_saved() { + responses.add(PortfolioMessage::AutoSaveDocument { + // Safe to unwrap since we know that there is an active document + document_id: self.active_document_id.unwrap(), + }); + } + node_graph_open = document.is_graph_overlay_open(); + } + + // Set the new active document ID + self.active_document_id = Some(document_id); + + responses.add(MenuBarMessage::SendLayout); + responses.add(PortfolioMessage::UpdateOpenDocumentsList); + responses.add(FrontendMessage::UpdateActiveDocument { document_id }); + responses.add(FrontendMessage::TriggerSaveActiveDocument { document_id }); + responses.add(ToolMessage::InitTools); + responses.add(NodeGraphMessage::Init); + responses.add(OverlaysMessage::Draw); + responses.add(BroadcastEvent::ToolAbort); + responses.add(BroadcastEvent::SelectionChanged); + responses.add(NavigationMessage::CanvasPan { delta: (0., 0.).into() }); + responses.add(NodeGraphMessage::RunDocumentGraph); + responses.add(DocumentMessage::GraphViewOverlay { open: node_graph_open }); + if node_graph_open { + responses.add(NodeGraphMessage::UpdateGraphBarRight); + } else { + responses.add(PortfolioMessage::UpdateDocumentWidgets); + } + + let Some(document) = self.documents.get_mut(&document_id) else { + warn!("Tried to read non existent document"); + return; + }; + if !document.is_loaded { + document.is_loaded = true; + responses.add(PortfolioMessage::LoadDocumentResources { document_id }); + responses.add(PortfolioMessage::UpdateDocumentWidgets); + responses.add(PropertiesPanelMessage::Clear); + } + } + PortfolioMessage::SubmitDocumentExport { + file_name, + file_type, + scale_factor, + bounds, + transparent_background, + } => { + let document = self.active_document_id.and_then(|id| self.documents.get_mut(&id)).expect("Tried to render non-existent document"); + let export_config = ExportConfig { + file_name, + file_type, + scale_factor, + bounds, + transparent_background, + ..Default::default() + }; + let result = self.executor.submit_document_export(document, export_config); + + if let Err(description) = result { + responses.add(DialogMessage::DisplayDialogError { + title: "Unable to export document".to_string(), + description, + }); + } + } + PortfolioMessage::SubmitActiveGraphRender => { + if let Some(document_id) = self.active_document_id { + responses.add(PortfolioMessage::SubmitGraphRender { document_id, ignore_hash: false }); + } + } + PortfolioMessage::SubmitGraphRender { document_id, ignore_hash } => { + let inspect_node = self.inspect_node_id(); + let result = self.executor.submit_node_graph_evaluation( + self.documents.get_mut(&document_id).expect("Tried to render non-existent document"), + ipp.viewport_bounds.size().as_uvec2(), + timing_information, + inspect_node, + ignore_hash, + ); + + if let Err(description) = result { + responses.add(DialogMessage::DisplayDialogError { + title: "Unable to update node graph".to_string(), + description, + }); + } + } + PortfolioMessage::ToggleRulers => { + if let Some(document) = self.active_document_mut() { + document.rulers_visible = !document.rulers_visible; + + responses.add(DocumentMessage::RenderRulers); + responses.add(MenuBarMessage::SendLayout); + } + } + PortfolioMessage::UpdateDocumentWidgets => { + if let Some(document) = self.active_document() { + document.update_document_widgets(responses, animation.is_playing(), timing_information.animation_time); + } + } + PortfolioMessage::UpdateOpenDocumentsList => { + // Send the list of document tab names + let open_documents = self + .document_ids + .iter() + .filter_map(|id| { + self.documents.get(id).map(|document| FrontendDocumentDetails { + is_auto_saved: document.is_auto_saved(), + is_saved: document.is_saved(), + id: *id, + name: document.name.clone(), + }) + }) + .collect::>(); + responses.add(FrontendMessage::UpdateOpenDocumentsList { open_documents }); + } + PortfolioMessage::UpdateVelloPreference => { + responses.add(NodeGraphMessage::RunDocumentGraph); + self.persistent_data.use_vello = preferences.use_vello; + } + } + } + + fn actions(&self) -> ActionList { + let mut common = actions!(PortfolioMessageDiscriminant; + CloseActiveDocumentWithConfirmation, + CloseAllDocuments, + CloseAllDocumentsWithConfirmation, + Import, + NextDocument, + OpenDocument, + PasteIntoFolder, + PrevDocument, + ToggleRulers, + ); + + // Extend with actions that require an active document + if let Some(document) = self.active_document() { + common.extend(document.actions()); + + // Extend with actions that must have a selected layer + if document.network_interface.selected_nodes().selected_layers(document.metadata()).next().is_some() { + common.extend(actions!(PortfolioMessageDiscriminant; + Copy, + Cut, + )); + } + } + + common + } +} + +impl PortfolioMessageHandler { + pub fn with_executor(executor: crate::node_graph_executor::NodeGraphExecutor) -> Self { + Self { executor, ..Default::default() } + } + + pub fn document(&self, document_id: DocumentId) -> Option<&DocumentMessageHandler> { + self.documents.get(&document_id) + } + + pub fn document_mut(&mut self, document_id: DocumentId) -> Option<&mut DocumentMessageHandler> { + self.documents.get_mut(&document_id) + } + + pub fn active_document(&self) -> Option<&DocumentMessageHandler> { + self.active_document_id.and_then(|id| self.documents.get(&id)) + } + + pub fn active_document_mut(&mut self) -> Option<&mut DocumentMessageHandler> { + self.active_document_id.and_then(|id| self.documents.get_mut(&id)) + } + + pub fn active_document_id(&self) -> Option { + self.active_document_id + } + + pub fn unsaved_document_names(&self) -> Vec { + self.documents.values().filter(|document| !document.is_saved()).map(|document| document.name.clone()).collect() + } + + pub fn generate_new_document_name(&self) -> String { + let mut doc_title_numbers = self + .ordered_document_iterator() + .filter_map(|doc| { + doc.name + .rsplit_once(DEFAULT_DOCUMENT_NAME) + .map(|(prefix, number)| (prefix.is_empty()).then(|| number.trim().parse::().ok()).flatten().unwrap_or(1)) + }) + .collect::>(); + + doc_title_numbers.sort_unstable(); + doc_title_numbers.iter_mut().enumerate().for_each(|(i, number)| *number = *number - i as isize - 2); + // Uses binary search to find the index of the element where number is bigger than i + let new_doc_title_num = doc_title_numbers.binary_search(&0).unwrap_or_else(|e| e) + 1; + + match new_doc_title_num { + 1 => DEFAULT_DOCUMENT_NAME.to_string(), + _ => format!("{DEFAULT_DOCUMENT_NAME} {new_doc_title_num}"), + } + } + + fn load_document(&mut self, new_document: DocumentMessageHandler, document_id: DocumentId, responses: &mut VecDeque, to_front: bool) { + if to_front { + self.document_ids.push_front(document_id); + } else { + self.document_ids.push_back(document_id); + } + new_document.update_layers_panel_control_bar_widgets(responses); + new_document.update_layers_panel_bottom_bar_widgets(responses); + + self.documents.insert(document_id, new_document); + + if self.active_document().is_some() { + responses.add(BroadcastEvent::ToolAbort); + responses.add(ToolMessage::DeactivateTools); + } else { + // Load the default font upon creating the first document + let font = Font::new(graphene_std::consts::DEFAULT_FONT_FAMILY.into(), graphene_std::consts::DEFAULT_FONT_STYLE.into()); + responses.add(FrontendMessage::TriggerFontLoad { font }); + } + + // TODO: Remove this and find a way to fix the issue where creating a new document when the node graph is open causes the transform in the new document to be incorrect + responses.add(DocumentMessage::GraphViewOverlay { open: false }); + responses.add(PortfolioMessage::UpdateOpenDocumentsList); + } + + /// Returns an iterator over the open documents in order. + pub fn ordered_document_iterator(&self) -> impl Iterator { + self.document_ids.iter().map(|id| self.documents.get(id).expect("document id was not found in the document hashmap")) + } + + fn document_index(&self, document_id: DocumentId) -> usize { + self.document_ids.iter().position(|id| id == &document_id).expect("Active document is missing from document ids") + } + + pub fn poll_node_graph_evaluation(&mut self, responses: &mut VecDeque) -> Result<(), String> { + let Some(active_document) = self.active_document_id.and_then(|id| self.documents.get_mut(&id)) else { + return Err("No active document".to_string()); + }; + + let result = self.executor.poll_node_graph_evaluation(active_document, responses); + if result.is_err() { + let error = r#" + + + The document cannot render in its current state. + Undo to go back, if available, or check for error details + by clicking the Node Graph button up at the top right. + /text>"# + // It's a mystery why the `/text>` tag above needs to be missing its `<`, but when it exists it prints the `<` character in the text. However this works with it removed. + .to_string(); + responses.add(Message::EndBuffer(graphene_std::renderer::RenderMetadata::default())); + responses.add(FrontendMessage::UpdateDocumentArtwork { svg: error }); + } + result + } + + /// Get the id of the node that should be used as the target for the spreadsheet + pub fn inspect_node_id(&self) -> Option { + // Spreadsheet not open, skipping + if !self.spreadsheet.spreadsheet_view_open { + return None; + } + + let document = self.documents.get(&self.active_document_id?)?; + let selected_nodes = document.network_interface.selected_nodes().0; + + // Selected nodes != 1, skipping + if selected_nodes.len() != 1 { + return None; + } + + selected_nodes.first().copied() + } +} diff --git a/editor/src/messages/portfolio/spreadsheet/mod.rs b/editor/src/messages/portfolio/spreadsheet/mod.rs new file mode 100644 index 0000000000000000000000000000000000000000..1523ea0d2ced4263c43e792b961e9d049f81312b --- /dev/null +++ b/editor/src/messages/portfolio/spreadsheet/mod.rs @@ -0,0 +1,7 @@ +mod spreadsheet_message; +mod spreadsheet_message_handler; + +#[doc(inline)] +pub use spreadsheet_message::*; +#[doc(inline)] +pub use spreadsheet_message_handler::*; diff --git a/editor/src/messages/portfolio/spreadsheet/spreadsheet_message.rs b/editor/src/messages/portfolio/spreadsheet/spreadsheet_message.rs new file mode 100644 index 0000000000000000000000000000000000000000..af579cc17fab6df2261239af3640966fb2e14891 --- /dev/null +++ b/editor/src/messages/portfolio/spreadsheet/spreadsheet_message.rs @@ -0,0 +1,33 @@ +use crate::messages::prelude::*; +use crate::node_graph_executor::InspectResult; + +/// The spreadsheet UI allows for instance data to be previewed. +#[impl_message(Message, PortfolioMessage, Spreadsheet)] +#[derive(PartialEq, Clone, Debug, serde::Serialize, serde::Deserialize)] +pub enum SpreadsheetMessage { + ToggleOpen, + + UpdateLayout { + #[serde(skip)] + inspect_result: InspectResult, + }, + + PushToInstancePath { + index: usize, + }, + TruncateInstancePath { + len: usize, + }, + + ViewVectorDataDomain { + domain: VectorDataDomain, + }, +} + +#[derive(PartialEq, Eq, Clone, Copy, Default, Debug, serde::Serialize, serde::Deserialize)] +pub enum VectorDataDomain { + #[default] + Points, + Segments, + Regions, +} diff --git a/editor/src/messages/portfolio/spreadsheet/spreadsheet_message_handler.rs b/editor/src/messages/portfolio/spreadsheet/spreadsheet_message_handler.rs new file mode 100644 index 0000000000000000000000000000000000000000..378c8b1b5220a1aac5a048e10b51d9f1a789510a --- /dev/null +++ b/editor/src/messages/portfolio/spreadsheet/spreadsheet_message_handler.rs @@ -0,0 +1,321 @@ +use super::VectorDataDomain; +use crate::messages::layout::utility_types::layout_widget::{Layout, LayoutGroup, LayoutTarget, WidgetLayout}; +use crate::messages::prelude::*; +use crate::messages::tool::tool_messages::tool_prelude::*; +use graph_craft::document::NodeId; +use graphene_std::Color; +use graphene_std::Context; +use graphene_std::GraphicGroupTable; +use graphene_std::instances::Instances; +use graphene_std::memo::IORecord; +use graphene_std::raster::Image; +use graphene_std::vector::{VectorData, VectorDataTable}; +use graphene_std::{Artboard, ArtboardGroupTable, GraphicElement}; +use std::any::Any; +use std::sync::Arc; + +/// The spreadsheet UI allows for instance data to be previewed. +#[derive(Default, Debug, Clone)] +pub struct SpreadsheetMessageHandler { + /// Sets whether or not the spreadsheet is drawn. + pub spreadsheet_view_open: bool, + inspect_node: Option, + introspected_data: Option>, + instances_path: Vec, + viewing_vector_data_domain: VectorDataDomain, +} + +impl MessageHandler for SpreadsheetMessageHandler { + fn process_message(&mut self, message: SpreadsheetMessage, responses: &mut VecDeque, _data: ()) { + match message { + SpreadsheetMessage::ToggleOpen => { + self.spreadsheet_view_open = !self.spreadsheet_view_open; + // Run the graph to grab the data + if self.spreadsheet_view_open { + responses.add(NodeGraphMessage::RunDocumentGraph); + } + // Update checked UI state for open + responses.add(MenuBarMessage::SendLayout); + self.update_layout(responses); + } + + SpreadsheetMessage::UpdateLayout { mut inspect_result } => { + self.inspect_node = Some(inspect_result.inspect_node); + self.introspected_data = inspect_result.take_data(); + self.update_layout(responses) + } + + SpreadsheetMessage::PushToInstancePath { index } => { + self.instances_path.push(index); + self.update_layout(responses); + } + SpreadsheetMessage::TruncateInstancePath { len } => { + self.instances_path.truncate(len); + self.update_layout(responses); + } + + SpreadsheetMessage::ViewVectorDataDomain { domain } => { + self.viewing_vector_data_domain = domain; + self.update_layout(responses); + } + } + } + + fn actions(&self) -> ActionList { + actions!(SpreadsheetMessage;) + } +} + +impl SpreadsheetMessageHandler { + fn update_layout(&mut self, responses: &mut VecDeque) { + responses.add(FrontendMessage::UpdateSpreadsheetState { + node: self.inspect_node, + open: self.spreadsheet_view_open, + }); + if !self.spreadsheet_view_open { + return; + } + let mut layout_data = LayoutData { + current_depth: 0, + desired_path: &mut self.instances_path, + breadcrumbs: Vec::new(), + vector_data_domain: self.viewing_vector_data_domain, + }; + let mut layout = self + .introspected_data + .as_ref() + .map(|instrospected_data| generate_layout(instrospected_data, &mut layout_data)) + .unwrap_or_else(|| Some(label("No data"))) + .unwrap_or_else(|| label("Failed to downcast data")); + + if layout_data.breadcrumbs.len() > 1 { + let breadcrumb = BreadcrumbTrailButtons::new(layout_data.breadcrumbs) + .on_update(|&len| SpreadsheetMessage::TruncateInstancePath { len: len as usize }.into()) + .widget_holder(); + layout.insert(0, LayoutGroup::Row { widgets: vec![breadcrumb] }); + } + + responses.add(LayoutMessage::SendLayout { + layout: Layout::WidgetLayout(WidgetLayout { layout }), + layout_target: LayoutTarget::Spreadsheet, + }); + } +} + +struct LayoutData<'a> { + current_depth: usize, + desired_path: &'a mut Vec, + breadcrumbs: Vec, + vector_data_domain: VectorDataDomain, +} + +fn generate_layout(introspected_data: &Arc, data: &mut LayoutData) -> Option> { + // We simply try random types. TODO: better strategy. + #[allow(clippy::manual_map)] + if let Some(io) = introspected_data.downcast_ref::>() { + Some(io.output.layout_with_breadcrumb(data)) + } else if let Some(io) = introspected_data.downcast_ref::>() { + Some(io.output.layout_with_breadcrumb(data)) + } else if let Some(io) = introspected_data.downcast_ref::>() { + Some(io.output.layout_with_breadcrumb(data)) + } else if let Some(io) = introspected_data.downcast_ref::>() { + Some(io.output.layout_with_breadcrumb(data)) + } else if let Some(io) = introspected_data.downcast_ref::>() { + Some(io.output.layout_with_breadcrumb(data)) + } else if let Some(io) = introspected_data.downcast_ref::>() { + Some(io.output.layout_with_breadcrumb(data)) + } else { + None + } +} + +fn column_headings(value: &[&str]) -> Vec { + value.iter().map(|text| TextLabel::new(*text).widget_holder()).collect() +} + +fn label(x: impl Into) -> Vec { + let error = vec![TextLabel::new(x).widget_holder()]; + vec![LayoutGroup::Row { widgets: error }] +} + +trait InstanceLayout { + fn type_name() -> &'static str; + fn identifier(&self) -> String; + fn layout_with_breadcrumb(&self, data: &mut LayoutData) -> Vec { + data.breadcrumbs.push(self.identifier()); + self.compute_layout(data) + } + fn compute_layout(&self, data: &mut LayoutData) -> Vec; +} + +impl InstanceLayout for GraphicElement { + fn type_name() -> &'static str { + "GraphicElement" + } + fn identifier(&self) -> String { + match self { + Self::GraphicGroup(instances) => instances.identifier(), + Self::VectorData(instances) => instances.identifier(), + Self::RasterDataCPU(_) => "RasterDataCPU".to_string(), + Self::RasterDataGPU(_) => "RasterDataGPU".to_string(), + } + } + // Don't put a breadcrumb for GraphicElement + fn layout_with_breadcrumb(&self, data: &mut LayoutData) -> Vec { + self.compute_layout(data) + } + fn compute_layout(&self, data: &mut LayoutData) -> Vec { + match self { + Self::GraphicGroup(instances) => instances.layout_with_breadcrumb(data), + Self::VectorData(instances) => instances.layout_with_breadcrumb(data), + Self::RasterDataCPU(_) => label("Raster frame not supported"), + Self::RasterDataGPU(_) => label("Raster frame not supported"), + } + } +} + +impl InstanceLayout for VectorData { + fn type_name() -> &'static str { + "VectorData" + } + fn identifier(&self) -> String { + format!("Vector Data (points={}, segments={})", self.point_domain.ids().len(), self.segment_domain.ids().len()) + } + fn compute_layout(&self, data: &mut LayoutData) -> Vec { + let colinear = self.colinear_manipulators.iter().map(|[a, b]| format!("[{a} / {b}]")).collect::>().join(", "); + let colinear = if colinear.is_empty() { "None" } else { &colinear }; + let style = vec![ + TextLabel::new(format!( + "{}\n\nColinear Handle IDs: {}\n\nUpstream Graphic Group Table: {}", + self.style, + colinear, + if self.upstream_graphic_group.is_some() { "Yes" } else { "No" } + )) + .multiline(true) + .widget_holder(), + ]; + + let domain_entries = [VectorDataDomain::Points, VectorDataDomain::Segments, VectorDataDomain::Regions] + .into_iter() + .map(|domain| { + RadioEntryData::new(format!("{domain:?}")) + .label(format!("{domain:?}")) + .on_update(move |_| SpreadsheetMessage::ViewVectorDataDomain { domain }.into()) + }) + .collect(); + let domain = vec![RadioInput::new(domain_entries).selected_index(Some(data.vector_data_domain as u32)).widget_holder()]; + + let mut table_rows = Vec::new(); + match data.vector_data_domain { + VectorDataDomain::Points => { + table_rows.push(column_headings(&["", "position"])); + table_rows.extend( + self.point_domain + .iter() + .map(|(id, position)| vec![TextLabel::new(format!("{}", id.inner())).widget_holder(), TextLabel::new(format!("{}", position)).widget_holder()]), + ); + } + VectorDataDomain::Segments => { + table_rows.push(column_headings(&["", "start_index", "end_index", "handles"])); + table_rows.extend(self.segment_domain.iter().map(|(id, start, end, handles)| { + vec![ + TextLabel::new(format!("{}", id.inner())).widget_holder(), + TextLabel::new(format!("{}", start)).widget_holder(), + TextLabel::new(format!("{}", end)).widget_holder(), + TextLabel::new(format!("{:?}", handles)).widget_holder(), + ] + })); + } + VectorDataDomain::Regions => { + table_rows.push(column_headings(&["", "segment_range", "fill"])); + table_rows.extend(self.region_domain.iter().map(|(id, segment_range, fill)| { + vec![ + TextLabel::new(format!("{}", id.inner())).widget_holder(), + TextLabel::new(format!("{:?}", segment_range)).widget_holder(), + TextLabel::new(format!("{}", fill.inner())).widget_holder(), + ] + })); + } + } + + vec![LayoutGroup::Row { widgets: style }, LayoutGroup::Row { widgets: domain }, LayoutGroup::Table { rows: table_rows }] + } +} + +impl InstanceLayout for Image { + fn type_name() -> &'static str { + "Image" + } + fn identifier(&self) -> String { + format!("Image (width={}, height={})", self.width, self.height) + } + fn compute_layout(&self, _data: &mut LayoutData) -> Vec { + let rows = vec![vec![TextLabel::new(format!("Image (width={}, height={})", self.width, self.height)).widget_holder()]]; + vec![LayoutGroup::Table { rows }] + } +} + +impl InstanceLayout for Artboard { + fn type_name() -> &'static str { + "Artboard" + } + fn identifier(&self) -> String { + self.label.clone() + } + fn compute_layout(&self, data: &mut LayoutData) -> Vec { + self.graphic_group.compute_layout(data) + } +} + +impl InstanceLayout for Instances { + fn type_name() -> &'static str { + "Instances" + } + fn identifier(&self) -> String { + format!("Instances<{}> (length={})", T::type_name(), self.len()) + } + fn compute_layout(&self, data: &mut LayoutData) -> Vec { + if let Some(index) = data.desired_path.get(data.current_depth).copied() { + if let Some(instance) = self.get(index) { + data.current_depth += 1; + let result = instance.instance.layout_with_breadcrumb(data); + data.current_depth -= 1; + return result; + } else { + warn!("Desired path truncated"); + data.desired_path.truncate(data.current_depth); + } + } + + let mut rows = self + .instance_ref_iter() + .enumerate() + .map(|(index, instance)| { + let (scale, angle, translation) = instance.transform.to_scale_angle_translation(); + let rotation = if angle == -0. { 0. } else { angle.to_degrees() }; + let round = |x: f64| (x * 1e3).round() / 1e3; + vec![ + TextLabel::new(format!("{}", index)).widget_holder(), + TextButton::new(instance.instance.identifier()) + .on_update(move |_| SpreadsheetMessage::PushToInstancePath { index }.into()) + .widget_holder(), + TextLabel::new(format!( + "Location: ({} px, {} px) — Rotation: {rotation:2}° — Scale: ({}x, {}x)", + round(translation.x), + round(translation.y), + round(scale.x), + round(scale.y) + )) + .widget_holder(), + TextLabel::new(format!("{}", instance.alpha_blending)).widget_holder(), + TextLabel::new(instance.source_node_id.map_or_else(|| "-".to_string(), |id| format!("{}", id.0))).widget_holder(), + ] + }) + .collect::>(); + + rows.insert(0, column_headings(&["", "instance", "transform", "alpha_blending", "source_node_id"])); + + let instances = vec![TextLabel::new("Instances:").widget_holder()]; + vec![LayoutGroup::Row { widgets: instances }, LayoutGroup::Table { rows }] + } +} diff --git a/editor/src/messages/portfolio/utility_types.rs b/editor/src/messages/portfolio/utility_types.rs new file mode 100644 index 0000000000000000000000000000000000000000..fb0b2e4b4d7272064921da5026931a77e7bd62ba --- /dev/null +++ b/editor/src/messages/portfolio/utility_types.rs @@ -0,0 +1,59 @@ +use graphene_std::text::FontCache; + +#[derive(Debug, Default)] +pub struct PersistentData { + pub font_cache: FontCache, + pub use_vello: bool, +} + +#[derive(PartialEq, Eq, Clone, Copy, Default, Debug, serde::Serialize, serde::Deserialize)] +pub enum Platform { + #[default] + Unknown, + Windows, + Mac, + Linux, +} + +impl Platform { + pub fn as_keyboard_platform_layout(&self) -> KeyboardPlatformLayout { + match self { + Platform::Mac => KeyboardPlatformLayout::Mac, + Platform::Windows | Platform::Linux => KeyboardPlatformLayout::Standard, + Platform::Unknown => { + warn!("The platform has not been set, remember to send `GlobalsMessage::SetPlatform` during editor initialization."); + KeyboardPlatformLayout::Standard + } + } + } +} + +#[derive(PartialEq, Eq, Clone, Copy, Default, Debug, serde::Serialize, serde::Deserialize)] +pub enum KeyboardPlatformLayout { + /// Standard keyboard mapping used by Windows and Linux + #[default] + Standard, + /// Keyboard mapping used by Macs where Command is sometimes used in favor of Control + Mac, +} + +#[derive(PartialEq, Eq, Clone, Copy, Debug, Default, serde::Serialize, serde::Deserialize)] +pub enum PanelType { + #[default] + Document, + Layers, + Properties, + Spreadsheet, +} + +impl From for PanelType { + fn from(value: String) -> Self { + match value.as_str() { + "Document" => PanelType::Document, + "Layers" => PanelType::Layers, + "Properties" => PanelType::Properties, + "Spreadsheet" => PanelType::Spreadsheet, + _ => panic!("Unknown panel type: {}", value), + } + } +} diff --git a/editor/src/messages/preferences/mod.rs b/editor/src/messages/preferences/mod.rs new file mode 100644 index 0000000000000000000000000000000000000000..916c384f8a6938d6a2f1ee4d2132c547673ee682 --- /dev/null +++ b/editor/src/messages/preferences/mod.rs @@ -0,0 +1,10 @@ +mod preferences_message; +mod preferences_message_handler; +pub mod utility_types; + +#[doc(inline)] +pub use preferences_message::{PreferencesMessage, PreferencesMessageDiscriminant}; +#[doc(inline)] +pub use preferences_message_handler::PreferencesMessageHandler; +#[doc(inline)] +pub use utility_types::SelectionMode; diff --git a/editor/src/messages/preferences/preferences_message.rs b/editor/src/messages/preferences/preferences_message.rs new file mode 100644 index 0000000000000000000000000000000000000000..b8988fa3e5c10c28165b2b95bad1bd158b4ebb00 --- /dev/null +++ b/editor/src/messages/preferences/preferences_message.rs @@ -0,0 +1,19 @@ +use crate::messages::portfolio::document::utility_types::wires::GraphWireStyle; +use crate::messages::preferences::SelectionMode; +use crate::messages::prelude::*; + +#[impl_message(Message, Preferences)] +#[derive(PartialEq, Clone, Debug, serde::Serialize, serde::Deserialize)] +pub enum PreferencesMessage { + // Management messages + Load { preferences: String }, + ResetToDefaults, + + // Per-preference messages + UseVello { use_vello: bool }, + SelectionMode { selection_mode: SelectionMode }, + VectorMeshes { enabled: bool }, + ModifyLayout { zoom_with_scroll: bool }, + GraphWireStyle { style: GraphWireStyle }, + ViewportZoomWheelRate { rate: f64 }, +} diff --git a/editor/src/messages/preferences/preferences_message_handler.rs b/editor/src/messages/preferences/preferences_message_handler.rs new file mode 100644 index 0000000000000000000000000000000000000000..b52e4e49a8e11674dbbb46e0afdb1adc82200d2e --- /dev/null +++ b/editor/src/messages/preferences/preferences_message_handler.rs @@ -0,0 +1,108 @@ +use crate::consts::VIEWPORT_ZOOM_WHEEL_RATE; +use crate::messages::input_mapper::key_mapping::MappingVariant; +use crate::messages::portfolio::document::utility_types::wires::GraphWireStyle; +use crate::messages::preferences::SelectionMode; +use crate::messages::prelude::*; +use graph_craft::wasm_application_io::EditorPreferences; + +#[derive(Debug, PartialEq, Clone, serde::Serialize, serde::Deserialize, specta::Type)] +pub struct PreferencesMessageHandler { + pub selection_mode: SelectionMode, + pub zoom_with_scroll: bool, + pub use_vello: bool, + pub vector_meshes: bool, + pub graph_wire_style: GraphWireStyle, + pub viewport_zoom_wheel_rate: f64, +} + +impl PreferencesMessageHandler { + pub fn get_selection_mode(&self) -> SelectionMode { + self.selection_mode + } + + pub fn editor_preferences(&self) -> EditorPreferences { + EditorPreferences { + use_vello: self.use_vello && self.supports_wgpu(), + } + } + + pub fn supports_wgpu(&self) -> bool { + graph_craft::wasm_application_io::wgpu_available().unwrap_or_default() + } +} + +impl Default for PreferencesMessageHandler { + fn default() -> Self { + Self { + selection_mode: SelectionMode::Touched, + zoom_with_scroll: matches!(MappingVariant::default(), MappingVariant::ZoomWithScroll), + use_vello: EditorPreferences::default().use_vello, + vector_meshes: false, + graph_wire_style: GraphWireStyle::default(), + viewport_zoom_wheel_rate: VIEWPORT_ZOOM_WHEEL_RATE, + } + } +} + +impl MessageHandler for PreferencesMessageHandler { + fn process_message(&mut self, message: PreferencesMessage, responses: &mut VecDeque, _data: ()) { + match message { + // Management messages + PreferencesMessage::Load { preferences } => { + if let Ok(deserialized_preferences) = serde_json::from_str::(&preferences) { + *self = deserialized_preferences; + + responses.add(PortfolioMessage::EditorPreferences); + responses.add(PortfolioMessage::UpdateVelloPreference); + responses.add(PreferencesMessage::ModifyLayout { + zoom_with_scroll: self.zoom_with_scroll, + }); + } + } + PreferencesMessage::ResetToDefaults => { + refresh_dialog(responses); + responses.add(KeyMappingMessage::ModifyMapping(MappingVariant::Default)); + + *self = Self::default() + } + + // Per-preference messages + PreferencesMessage::UseVello { use_vello } => { + self.use_vello = use_vello; + responses.add(PortfolioMessage::UpdateVelloPreference); + responses.add(PortfolioMessage::EditorPreferences); + } + PreferencesMessage::VectorMeshes { enabled } => { + self.vector_meshes = enabled; + } + PreferencesMessage::ModifyLayout { zoom_with_scroll } => { + self.zoom_with_scroll = zoom_with_scroll; + + let variant = if zoom_with_scroll { MappingVariant::ZoomWithScroll } else { MappingVariant::Default }; + responses.add(KeyMappingMessage::ModifyMapping(variant)); + } + PreferencesMessage::SelectionMode { selection_mode } => { + self.selection_mode = selection_mode; + } + PreferencesMessage::GraphWireStyle { style } => { + self.graph_wire_style = style; + responses.add(NodeGraphMessage::UnloadWires); + responses.add(NodeGraphMessage::SendWires); + } + PreferencesMessage::ViewportZoomWheelRate { rate } => { + self.viewport_zoom_wheel_rate = rate; + } + } + + responses.add(FrontendMessage::TriggerSavePreferences { preferences: self.clone() }); + } + + advertise_actions!(PreferencesMessageDiscriminant; + ); +} + +fn refresh_dialog(responses: &mut VecDeque) { + responses.add(DialogMessage::CloseDialogAndThen { + followups: vec![DialogMessage::RequestPreferencesDialog.into()], + }); +} diff --git a/editor/src/messages/preferences/utility_types.rs b/editor/src/messages/preferences/utility_types.rs new file mode 100644 index 0000000000000000000000000000000000000000..a2ee5dece1478140b90d0655d81cc7d5f836dd0a --- /dev/null +++ b/editor/src/messages/preferences/utility_types.rs @@ -0,0 +1,27 @@ +#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize, specta::Type, Hash)] +pub enum SelectionMode { + #[default] + Touched = 0, + Enclosed = 1, + Directional = 2, +} + +impl std::fmt::Display for SelectionMode { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + SelectionMode::Touched => write!(f, "Touched"), + SelectionMode::Enclosed => write!(f, "Enclosed"), + SelectionMode::Directional => write!(f, "Directional"), + } + } +} + +impl SelectionMode { + pub fn tooltip_description(&self) -> &'static str { + match self { + SelectionMode::Touched => "Select all layers at least partially covered by the dragged selection area", + SelectionMode::Enclosed => "Select only layers fully enclosed by the dragged selection area", + SelectionMode::Directional => r#""Touched" for leftward drags, "Enclosed" for rightward drags"#, + } + } +} diff --git a/editor/src/messages/prelude.rs b/editor/src/messages/prelude.rs new file mode 100644 index 0000000000000000000000000000000000000000..d33b7c235ca3131b173150bb9bc6e0d7f8b9eef6 --- /dev/null +++ b/editor/src/messages/prelude.rs @@ -0,0 +1,75 @@ +// Root +pub use crate::utility_traits::{ActionList, AsMessage, MessageHandler, ToDiscriminant, TransitiveChild}; + +// Message, MessageData, MessageDiscriminant, MessageHandler +pub use crate::messages::animation::{AnimationMessage, AnimationMessageDiscriminant, AnimationMessageHandler}; +pub use crate::messages::broadcast::{BroadcastMessage, BroadcastMessageDiscriminant, BroadcastMessageHandler}; +pub use crate::messages::debug::{DebugMessage, DebugMessageDiscriminant, DebugMessageHandler}; +pub use crate::messages::dialog::export_dialog::{ExportDialogMessage, ExportDialogMessageData, ExportDialogMessageDiscriminant, ExportDialogMessageHandler}; +pub use crate::messages::dialog::new_document_dialog::{NewDocumentDialogMessage, NewDocumentDialogMessageDiscriminant, NewDocumentDialogMessageHandler}; +pub use crate::messages::dialog::preferences_dialog::{PreferencesDialogMessage, PreferencesDialogMessageData, PreferencesDialogMessageDiscriminant, PreferencesDialogMessageHandler}; +pub use crate::messages::dialog::{DialogMessage, DialogMessageData, DialogMessageDiscriminant, DialogMessageHandler}; +pub use crate::messages::frontend::{FrontendMessage, FrontendMessageDiscriminant}; +pub use crate::messages::globals::{GlobalsMessage, GlobalsMessageDiscriminant, GlobalsMessageHandler}; +pub use crate::messages::input_mapper::key_mapping::{KeyMappingMessage, KeyMappingMessageData, KeyMappingMessageDiscriminant, KeyMappingMessageHandler}; +pub use crate::messages::input_mapper::{InputMapperMessage, InputMapperMessageData, InputMapperMessageDiscriminant, InputMapperMessageHandler}; +pub use crate::messages::input_preprocessor::{InputPreprocessorMessage, InputPreprocessorMessageData, InputPreprocessorMessageDiscriminant, InputPreprocessorMessageHandler}; +pub use crate::messages::layout::{LayoutMessage, LayoutMessageDiscriminant, LayoutMessageHandler}; +pub use crate::messages::portfolio::document::graph_operation::{GraphOperationMessage, GraphOperationMessageData, GraphOperationMessageDiscriminant, GraphOperationMessageHandler}; +pub use crate::messages::portfolio::document::navigation::{NavigationMessage, NavigationMessageData, NavigationMessageDiscriminant, NavigationMessageHandler}; +pub use crate::messages::portfolio::document::node_graph::{NodeGraphMessage, NodeGraphMessageDiscriminant, NodeGraphMessageHandler}; +pub use crate::messages::portfolio::document::overlays::{OverlaysMessage, OverlaysMessageData, OverlaysMessageDiscriminant, OverlaysMessageHandler}; +pub use crate::messages::portfolio::document::properties_panel::{PropertiesPanelMessage, PropertiesPanelMessageDiscriminant, PropertiesPanelMessageHandler}; +pub use crate::messages::portfolio::document::{DocumentMessage, DocumentMessageData, DocumentMessageDiscriminant, DocumentMessageHandler}; +pub use crate::messages::portfolio::menu_bar::{MenuBarMessage, MenuBarMessageDiscriminant, MenuBarMessageHandler}; +pub use crate::messages::portfolio::spreadsheet::{SpreadsheetMessage, SpreadsheetMessageDiscriminant}; +pub use crate::messages::portfolio::{PortfolioMessage, PortfolioMessageData, PortfolioMessageDiscriminant, PortfolioMessageHandler}; +pub use crate::messages::preferences::{PreferencesMessage, PreferencesMessageDiscriminant, PreferencesMessageHandler}; +pub use crate::messages::tool::transform_layer::{TransformLayerMessage, TransformLayerMessageDiscriminant, TransformLayerMessageHandler}; +pub use crate::messages::tool::{ToolMessage, ToolMessageData, ToolMessageDiscriminant, ToolMessageHandler}; +pub use crate::messages::workspace::{WorkspaceMessage, WorkspaceMessageDiscriminant, WorkspaceMessageHandler}; + +// Message, MessageDiscriminant +pub use crate::messages::broadcast::broadcast_event::{BroadcastEvent, BroadcastEventDiscriminant}; +pub use crate::messages::message::{Message, MessageDiscriminant}; +pub use crate::messages::tool::tool_messages::artboard_tool::{ArtboardToolMessage, ArtboardToolMessageDiscriminant}; +pub use crate::messages::tool::tool_messages::brush_tool::{BrushToolMessage, BrushToolMessageDiscriminant}; +pub use crate::messages::tool::tool_messages::eyedropper_tool::{EyedropperToolMessage, EyedropperToolMessageDiscriminant}; +pub use crate::messages::tool::tool_messages::fill_tool::{FillToolMessage, FillToolMessageDiscriminant}; +pub use crate::messages::tool::tool_messages::freehand_tool::{FreehandToolMessage, FreehandToolMessageDiscriminant}; +pub use crate::messages::tool::tool_messages::gradient_tool::{GradientToolMessage, GradientToolMessageDiscriminant}; +pub use crate::messages::tool::tool_messages::navigate_tool::{NavigateToolMessage, NavigateToolMessageDiscriminant}; +pub use crate::messages::tool::tool_messages::path_tool::{PathToolMessage, PathToolMessageDiscriminant}; +pub use crate::messages::tool::tool_messages::pen_tool::{PenToolMessage, PenToolMessageDiscriminant}; +pub use crate::messages::tool::tool_messages::select_tool::{SelectToolMessage, SelectToolMessageDiscriminant}; +pub use crate::messages::tool::tool_messages::shape_tool::{ShapeToolMessage, ShapeToolMessageDiscriminant}; +pub use crate::messages::tool::tool_messages::spline_tool::{SplineToolMessage, SplineToolMessageDiscriminant}; +pub use crate::messages::tool::tool_messages::text_tool::{TextToolMessage, TextToolMessageDiscriminant}; + +// Helper +pub use crate::messages::globals::global_variables::*; +pub use crate::messages::portfolio::document::utility_types::misc::DocumentId; +pub use graphite_proc_macros::*; +pub use std::collections::{HashMap, HashSet, VecDeque}; + +pub trait Responses { + fn add(&mut self, message: impl Into); + + fn add_front(&mut self, message: impl Into); + + fn try_add(&mut self, message: Option>) { + if let Some(message) = message { + self.add(message); + } + } +} + +impl Responses for VecDeque { + fn add(&mut self, message: impl Into) { + self.push_back(message.into()); + } + + fn add_front(&mut self, message: impl Into) { + self.push_front(message.into()); + } +} diff --git a/editor/src/messages/tool/common_functionality/auto_panning.rs b/editor/src/messages/tool/common_functionality/auto_panning.rs new file mode 100644 index 0000000000000000000000000000000000000000..a13f6706e067de50a9ee31f60d2083d33d03b4ce --- /dev/null +++ b/editor/src/messages/tool/common_functionality/auto_panning.rs @@ -0,0 +1,88 @@ +use crate::consts::{DRAG_BEYOND_VIEWPORT_MAX_OVEREXTENSION_PIXELS, DRAG_BEYOND_VIEWPORT_SPEED_FACTOR}; +use crate::messages::prelude::*; +use crate::messages::tool::tool_messages::tool_prelude::*; + +#[derive(Clone, Debug, Default)] +pub struct AutoPanning { + subscribed_to_animation_frame: bool, +} + +impl AutoPanning { + pub fn start(&mut self, messages: &[Message], responses: &mut VecDeque) { + if !self.subscribed_to_animation_frame { + self.subscribed_to_animation_frame = true; + + for message in messages { + responses.add(BroadcastMessage::SubscribeEvent { + on: BroadcastEvent::AnimationFrame, + send: Box::new(message.clone()), + }); + } + } + } + + pub fn stop(&mut self, messages: &[Message], responses: &mut VecDeque) { + if self.subscribed_to_animation_frame { + self.subscribed_to_animation_frame = false; + + for message in messages { + responses.add(BroadcastMessage::UnsubscribeEvent { + on: BroadcastEvent::AnimationFrame, + message: Box::new(message.clone()), + }); + } + } + } + + pub fn setup_by_mouse_position(&mut self, input: &InputPreprocessorMessageHandler, messages: &[Message], responses: &mut VecDeque) { + let mouse_position = input.mouse.position; + let viewport_size = input.viewport_bounds.size(); + let is_pointer_outside_edge = mouse_position.x < 0. || mouse_position.x > viewport_size.x || mouse_position.y < 0. || mouse_position.y > viewport_size.y; + + match is_pointer_outside_edge { + true => self.start(messages, responses), + false => self.stop(messages, responses), + } + } + + /// Shifts the viewport when the mouse reaches the edge of the viewport. + /// + /// If the mouse was beyond any edge, it returns the amount shifted. Otherwise it returns None. + /// The shift is proportional to the distance between edge and mouse, and to the duration of the frame. + /// It is also guaranteed to be integral. + pub fn shift_viewport(&self, input: &InputPreprocessorMessageHandler, responses: &mut VecDeque) -> Option { + if !self.subscribed_to_animation_frame { + return None; + } + + let viewport_size = input.viewport_bounds.size(); + let mouse_position = input.mouse.position.clamp( + DVec2::ZERO - DVec2::splat(DRAG_BEYOND_VIEWPORT_MAX_OVEREXTENSION_PIXELS), + viewport_size + DVec2::splat(DRAG_BEYOND_VIEWPORT_MAX_OVEREXTENSION_PIXELS), + ); + let mouse_position_percent = mouse_position / viewport_size; + + let mut shift_percent = DVec2::ZERO; + + if mouse_position_percent.x < 0. { + shift_percent.x = -mouse_position_percent.x; + } else if mouse_position_percent.x > 1. { + shift_percent.x = 1. - mouse_position_percent.x; + } + + if mouse_position_percent.y < 0. { + shift_percent.y = -mouse_position_percent.y; + } else if mouse_position_percent.y > 1. { + shift_percent.y = 1. - mouse_position_percent.y; + } + + if shift_percent.x == 0. && shift_percent.y == 0. { + return None; + } + + let time_delta = input.frame_time.frame_duration()?.as_secs_f64(); + let delta = (shift_percent * DRAG_BEYOND_VIEWPORT_SPEED_FACTOR * viewport_size * time_delta).round(); + responses.add(NavigationMessage::CanvasPan { delta }); + Some(delta) + } +} diff --git a/editor/src/messages/tool/common_functionality/color_selector.rs b/editor/src/messages/tool/common_functionality/color_selector.rs new file mode 100644 index 0000000000000000000000000000000000000000..885aff8bcf8c30153acce72c3f7d4e93e8318c95 --- /dev/null +++ b/editor/src/messages/tool/common_functionality/color_selector.rs @@ -0,0 +1,123 @@ +use crate::messages::layout::utility_types::widget_prelude::*; +use crate::messages::portfolio::document::utility_types::document_metadata::LayerNodeIdentifier; +use crate::messages::prelude::*; +use graphene_std::Color; +use graphene_std::vector::style::FillChoice; + +#[derive(PartialEq, Clone, Debug, serde::Serialize, serde::Deserialize, specta::Type)] +pub enum ToolColorType { + Primary, + Secondary, + Custom, +} + +/// Color selector widgets seen in [`LayoutTarget::ToolOptions`] bar. +pub struct ToolColorOptions { + pub custom_color: Option, + pub primary_working_color: Option, + pub secondary_working_color: Option, + pub color_type: ToolColorType, +} + +impl Default for ToolColorOptions { + fn default() -> Self { + Self { + color_type: ToolColorType::Primary, + custom_color: Some(Color::BLACK), + primary_working_color: Some(Color::BLACK), + secondary_working_color: Some(Color::WHITE), + } + } +} + +impl ToolColorOptions { + pub fn new_primary() -> Self { + Self::default() + } + + pub fn new_secondary() -> Self { + Self { + color_type: ToolColorType::Secondary, + ..Default::default() + } + } + + pub fn new_none() -> Self { + Self { + color_type: ToolColorType::Custom, + custom_color: None, + ..Default::default() + } + } + + pub fn active_color(&self) -> Option { + match self.color_type { + ToolColorType::Custom => self.custom_color, + ToolColorType::Primary => self.primary_working_color, + ToolColorType::Secondary => self.secondary_working_color, + } + } + + pub fn apply_fill(&self, layer: LayerNodeIdentifier, responses: &mut VecDeque) { + if let Some(color) = self.active_color() { + let fill = graphene_std::vector::style::Fill::solid(color.to_gamma_srgb()); + responses.add(GraphOperationMessage::FillSet { layer, fill }); + } + } + + pub fn apply_stroke(&self, weight: f64, layer: LayerNodeIdentifier, responses: &mut VecDeque) { + if let Some(color) = self.active_color() { + let stroke = graphene_std::vector::style::Stroke::new(Some(color.to_gamma_srgb()), weight); + responses.add(GraphOperationMessage::StrokeSet { layer, stroke }); + } + } + + pub fn create_widgets( + &self, + label_text: impl Into, + color_allow_none: bool, + reset_callback: impl Fn(&IconButton) -> Message + 'static + Send + Sync, + radio_callback: fn(ToolColorType) -> WidgetCallback<()>, + color_callback: impl Fn(&ColorInput) -> Message + 'static + Send + Sync, + ) -> Vec { + let mut widgets = vec![TextLabel::new(label_text).widget_holder()]; + + if !color_allow_none { + widgets.push(Separator::new(SeparatorType::Unrelated).widget_holder()); + } else { + let reset = IconButton::new("CloseX", 12) + .disabled(self.custom_color.is_none() && self.color_type == ToolColorType::Custom) + .tooltip("Clear Color") + .on_update(reset_callback); + + widgets.push(Separator::new(SeparatorType::Related).widget_holder()); + widgets.push(reset.widget_holder()); + widgets.push(Separator::new(SeparatorType::Related).widget_holder()); + }; + + let entries = vec![ + ("WorkingColorsPrimary", "Primary Working Color", ToolColorType::Primary), + ("WorkingColorsSecondary", "Secondary Working Color", ToolColorType::Secondary), + ("CustomColor", "Custom Color", ToolColorType::Custom), + ] + .into_iter() + .map(|(icon, tooltip, color_type)| { + let mut entry = RadioEntryData::new(format!("{color_type:?}")).tooltip(tooltip).icon(icon); + entry.on_update = radio_callback(color_type); + entry + }) + .collect(); + let radio = RadioInput::new(entries).selected_index(Some(self.color_type.clone() as u32)).widget_holder(); + widgets.push(radio); + widgets.push(Separator::new(SeparatorType::Related).widget_holder()); + + let fill_choice = match self.active_color() { + Some(color) => FillChoice::Solid(color.to_gamma_srgb()), + None => FillChoice::None, + }; + let color_button = ColorInput::new(fill_choice).allow_none(color_allow_none).on_update(color_callback); + widgets.push(color_button.widget_holder()); + + widgets + } +} diff --git a/editor/src/messages/tool/common_functionality/compass_rose.rs b/editor/src/messages/tool/common_functionality/compass_rose.rs new file mode 100644 index 0000000000000000000000000000000000000000..8a7a2f6b2a0302e2f4f0008ceed3479ad6aaf663 --- /dev/null +++ b/editor/src/messages/tool/common_functionality/compass_rose.rs @@ -0,0 +1,113 @@ +use crate::consts::{COMPASS_ROSE_ARROW_CLICK_TARGET_ANGLE, COMPASS_ROSE_HOVER_RING_DIAMETER, COMPASS_ROSE_RING_INNER_DIAMETER}; +use crate::messages::portfolio::document::utility_types::document_metadata::LayerNodeIdentifier; +use crate::messages::prelude::DocumentMessageHandler; +use glam::{DAffine2, DVec2}; +use std::f64::consts::FRAC_PI_2; + +#[derive(Clone, Default, Debug)] +pub struct CompassRose { + compass_center: DVec2, +} + +impl CompassRose { + fn get_layer_pivot_transform(layer: LayerNodeIdentifier, document: &DocumentMessageHandler) -> DAffine2 { + let [min, max] = document.metadata().nonzero_bounding_box(layer); + + let bounds_transform = DAffine2::from_translation(min) * DAffine2::from_scale(max - min); + let layer_transform = document.metadata().transform_to_viewport(layer); + layer_transform * bounds_transform + } + pub fn refresh_position(&mut self, document: &DocumentMessageHandler) { + let selected_nodes = document.network_interface.selected_nodes(); + let mut layers = selected_nodes.selected_visible_and_unlocked_layers(&document.network_interface); + + let Some(first) = layers.next() else { return }; + let count = layers.count() + 1; + let transform = if count == 1 { + Self::get_layer_pivot_transform(first, document) + } else { + let [min, max] = document.selected_visible_and_unlock_layers_bounding_box_viewport().unwrap_or([DVec2::ZERO, DVec2::ONE]); + DAffine2::from_translation(min) * DAffine2::from_scale(max - min) + }; + + self.compass_center = transform.transform_point2(DVec2::splat(0.5)); + } + + pub fn compass_rose_position(&self) -> DVec2 { + self.compass_center + } + + pub fn compass_rose_state(&self, mouse: DVec2, angle: f64) -> CompassRoseState { + const COMPASS_ROSE_RING_INNER_RADIUS_SQUARED: f64 = (COMPASS_ROSE_RING_INNER_DIAMETER / 2.) * (COMPASS_ROSE_RING_INNER_DIAMETER / 2.); + const COMPASS_ROSE_HOVER_RING_RADIUS_SQUARED: f64 = (COMPASS_ROSE_HOVER_RING_DIAMETER / 2.) * (COMPASS_ROSE_HOVER_RING_DIAMETER / 2.); + + let compass_distance_squared = mouse.distance_squared(self.compass_center); + + if !(COMPASS_ROSE_RING_INNER_RADIUS_SQUARED..COMPASS_ROSE_HOVER_RING_RADIUS_SQUARED).contains(&compass_distance_squared) { + return CompassRoseState::None; + } + + let angle = (mouse - self.compass_center).angle_to(DVec2::from_angle(angle)).abs(); + let resolved_angle = (FRAC_PI_2 - angle).abs(); + let angular_width = COMPASS_ROSE_ARROW_CLICK_TARGET_ANGLE.to_radians(); + + if resolved_angle < angular_width { + CompassRoseState::AxisY + } else if resolved_angle > (FRAC_PI_2 - angular_width) { + CompassRoseState::AxisX + } else { + CompassRoseState::Ring + } + } +} + +#[derive(Clone, Debug, PartialEq)] +pub enum CompassRoseState { + Ring, + AxisX, + AxisY, + None, +} + +impl CompassRoseState { + pub fn can_grab(&self) -> bool { + matches!(self, Self::Ring | Self::AxisX | Self::AxisY) + } + + pub fn is_ring(&self) -> bool { + matches!(self, Self::Ring) + } + + pub fn axis_type(&self) -> Option { + match self { + CompassRoseState::AxisX => Some(Axis::X), + CompassRoseState::AxisY => Some(Axis::Y), + CompassRoseState::Ring => Some(Axis::None), + _ => None, + } + } +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Default)] +pub enum Axis { + #[default] + None, + X, + Y, +} + +impl Axis { + pub fn is_constraint(&self) -> bool { + matches!(self, Self::X | Self::Y) + } +} + +impl From for DVec2 { + fn from(value: Axis) -> Self { + match value { + Axis::X => DVec2::X, + Axis::Y => DVec2::Y, + Axis::None => DVec2::ZERO, + } + } +} diff --git a/editor/src/messages/tool/common_functionality/gizmos/gizmo_manager.rs b/editor/src/messages/tool/common_functionality/gizmos/gizmo_manager.rs new file mode 100644 index 0000000000000000000000000000000000000000..703c85e14d6c651387def82f62dc7045186aab0e --- /dev/null +++ b/editor/src/messages/tool/common_functionality/gizmos/gizmo_manager.rs @@ -0,0 +1,246 @@ +use crate::messages::message::Message; +use crate::messages::portfolio::document::overlays::utility_types::OverlayContext; +use crate::messages::portfolio::document::utility_types::document_metadata::LayerNodeIdentifier; +use crate::messages::prelude::{DocumentMessageHandler, InputPreprocessorMessageHandler}; +use crate::messages::tool::common_functionality::graph_modification_utils; +use crate::messages::tool::common_functionality::shape_editor::ShapeState; +use crate::messages::tool::common_functionality::shapes::polygon_shape::PolygonGizmoHandler; +use crate::messages::tool::common_functionality::shapes::shape_utility::ShapeGizmoHandler; +use crate::messages::tool::common_functionality::shapes::star_shape::StarGizmoHandler; +use glam::DVec2; +use std::collections::VecDeque; + +/// A unified enum wrapper around all available shape-specific gizmo handlers. +/// +/// This abstraction allows `GizmoManager` to interact with different shape gizmos (like Star or Polygon) +/// using a common interface without needing to know the specific shape type at compile time. +/// +/// Each variant stores a concrete handler (e.g., `StarGizmoHandler`, `PolygonGizmoHandler`) that implements +/// the shape-specific logic for rendering overlays, responding to input, and modifying shape parameters. +#[derive(Clone, Debug, Default)] +pub enum ShapeGizmoHandlers { + #[default] + None, + Star(StarGizmoHandler), + Polygon(PolygonGizmoHandler), +} + +impl ShapeGizmoHandlers { + /// Returns the kind of shape the handler is managing, such as `"star"` or `"polygon"`. + /// Used for grouping logic and distinguishing between handler types at runtime. + pub fn kind(&self) -> &'static str { + match self { + Self::Star(_) => "star", + Self::Polygon(_) => "polygon", + Self::None => "none", + } + } + + /// Dispatches interaction state updates to the corresponding shape-specific handler. + pub fn handle_state(&mut self, layer: LayerNodeIdentifier, mouse_position: DVec2, document: &DocumentMessageHandler, responses: &mut VecDeque) { + match self { + Self::Star(h) => h.handle_state(layer, mouse_position, document, responses), + Self::Polygon(h) => h.handle_state(layer, mouse_position, document, responses), + Self::None => {} + } + } + + /// Checks if any interactive part of the gizmo is currently hovered. + pub fn is_any_gizmo_hovered(&self) -> bool { + match self { + Self::Star(h) => h.is_any_gizmo_hovered(), + Self::Polygon(h) => h.is_any_gizmo_hovered(), + Self::None => false, + } + } + + /// Passes the click interaction to the appropriate gizmo handler if one is hovered. + pub fn handle_click(&mut self) { + match self { + Self::Star(h) => h.handle_click(), + Self::Polygon(h) => h.handle_click(), + Self::None => {} + } + } + + /// Updates the gizmo state while the user is dragging a handle (e.g., adjusting radius). + pub fn handle_update(&mut self, drag_start: DVec2, document: &DocumentMessageHandler, input: &InputPreprocessorMessageHandler, responses: &mut VecDeque) { + match self { + Self::Star(h) => h.handle_update(drag_start, document, input, responses), + Self::Polygon(h) => h.handle_update(drag_start, document, input, responses), + Self::None => {} + } + } + + /// Cleans up any state used by the gizmo handler. + pub fn cleanup(&mut self) { + match self { + Self::Star(h) => h.cleanup(), + Self::Polygon(h) => h.cleanup(), + Self::None => {} + } + } + + /// Draws overlays like control points or outlines for the shape handled by this gizmo. + pub fn overlays( + &self, + document: &DocumentMessageHandler, + layer: Option, + input: &InputPreprocessorMessageHandler, + shape_editor: &mut &mut ShapeState, + mouse_position: DVec2, + overlay_context: &mut OverlayContext, + ) { + match self { + Self::Star(h) => h.overlays(document, layer, input, shape_editor, mouse_position, overlay_context), + Self::Polygon(h) => h.overlays(document, layer, input, shape_editor, mouse_position, overlay_context), + Self::None => {} + } + } + + /// Draws live-updating overlays during drag interactions for the shape handled by this gizmo. + pub fn dragging_overlays( + &self, + document: &DocumentMessageHandler, + input: &InputPreprocessorMessageHandler, + shape_editor: &mut &mut ShapeState, + mouse_position: DVec2, + overlay_context: &mut OverlayContext, + ) { + match self { + Self::Star(h) => h.dragging_overlays(document, input, shape_editor, mouse_position, overlay_context), + Self::Polygon(h) => h.dragging_overlays(document, input, shape_editor, mouse_position, overlay_context), + Self::None => {} + } + } +} + +/// Central manager that coordinates shape gizmo handlers for interactive editing on the canvas. +/// +/// The `GizmoManager` is responsible for detecting which shapes are selected, activating the appropriate +/// shape-specific gizmo, and routing user interactions (hover, click, drag) to the correct handler. +/// It allows editing multiple shapes of the same type or focusing on a single active shape when a gizmo is hovered. +/// +/// ## Responsibilities: +/// - Detect which selected layers support shape gizmos (e.g., stars, polygons) +/// - Activate the correct handler and manage state between frames +/// - Route click, hover, and drag events to the proper shape gizmo +/// - Render overlays and dragging visuals +#[derive(Clone, Debug, Default)] +pub struct GizmoManager { + active_shape_handler: Option, + layers_handlers: Vec<(ShapeGizmoHandlers, Vec)>, +} + +impl GizmoManager { + /// Detects and returns a shape gizmo handler based on the layer type (e.g., star, polygon). + /// + /// Returns `None` if the given layer does not represent a shape with a registered gizmo. + pub fn detect_shape_handler(layer: LayerNodeIdentifier, document: &DocumentMessageHandler) -> Option { + // Star + if graph_modification_utils::get_star_id(layer, &document.network_interface).is_some() { + return Some(ShapeGizmoHandlers::Star(StarGizmoHandler::default())); + } + + // Polygon + if graph_modification_utils::get_polygon_id(layer, &document.network_interface).is_some() { + return Some(ShapeGizmoHandlers::Polygon(PolygonGizmoHandler::default())); + } + + None + } + + /// Returns `true` if a gizmo is currently active (hovered or being interacted with). + pub fn hovering_over_gizmo(&self) -> bool { + self.active_shape_handler.is_some() + } + + /// Called every frame to check selected layers and update the active shape gizmo, if hovered. + /// + /// Also groups all shape layers with the same kind of gizmo to support overlays for multi-shape editing. + pub fn handle_actions(&mut self, mouse_position: DVec2, document: &DocumentMessageHandler, responses: &mut VecDeque) { + let mut handlers_layer: Vec<(ShapeGizmoHandlers, Vec)> = Vec::new(); + + for layer in document.network_interface.selected_nodes().selected_visible_and_unlocked_layers(&document.network_interface) { + if let Some(mut handler) = Self::detect_shape_handler(layer, document) { + handler.handle_state(layer, mouse_position, document, responses); + let is_hovered = handler.is_any_gizmo_hovered(); + + if is_hovered { + self.layers_handlers.clear(); + self.active_shape_handler = Some(handler); + return; + } + + // Try to group this handler with others of the same type + if let Some((_, layers)) = handlers_layer.iter_mut().find(|(existing_handler, _)| existing_handler.kind() == handler.kind()) { + layers.push(layer); + } else { + handlers_layer.push((handler, vec![layer])); + } + } + } + + self.layers_handlers = handlers_layer; + self.active_shape_handler = None; + } + + /// Handles click interactions if a gizmo is active. Returns `true` if a gizmo handled the click. + pub fn handle_click(&mut self) -> bool { + if let Some(handle) = &mut self.active_shape_handler { + handle.handle_click(); + return true; + } + false + } + + pub fn handle_cleanup(&mut self) { + if let Some(handle) = &mut self.active_shape_handler { + handle.cleanup(); + } + } + + /// Passes drag update data to the active gizmo to update shape parameters live. + pub fn handle_update(&mut self, drag_start: DVec2, document: &DocumentMessageHandler, input: &InputPreprocessorMessageHandler, responses: &mut VecDeque) { + if let Some(handle) = &mut self.active_shape_handler { + handle.handle_update(drag_start, document, input, responses); + } + } + + /// Draws overlays for the currently active shape gizmo during a drag interaction. + pub fn dragging_overlays( + &self, + document: &DocumentMessageHandler, + input: &InputPreprocessorMessageHandler, + shape_editor: &mut &mut ShapeState, + mouse_position: DVec2, + overlay_context: &mut OverlayContext, + ) { + if let Some(handle) = &self.active_shape_handler { + handle.dragging_overlays(document, input, shape_editor, mouse_position, overlay_context); + } + } + + /// Draws overlays for either the active gizmo (if hovered) or all grouped selected gizmos. + /// + /// If no single gizmo is active, it renders overlays for all grouped layers with associated handlers. + pub fn overlays( + &self, + document: &DocumentMessageHandler, + input: &InputPreprocessorMessageHandler, + shape_editor: &mut &mut ShapeState, + mouse_position: DVec2, + overlay_context: &mut OverlayContext, + ) { + if let Some(handler) = &self.active_shape_handler { + handler.overlays(document, None, input, shape_editor, mouse_position, overlay_context); + return; + } + + for (handler, selected_layers) in &self.layers_handlers { + for layer in selected_layers { + handler.overlays(document, Some(*layer), input, shape_editor, mouse_position, overlay_context); + } + } + } +} diff --git a/editor/src/messages/tool/common_functionality/gizmos/mod.rs b/editor/src/messages/tool/common_functionality/gizmos/mod.rs new file mode 100644 index 0000000000000000000000000000000000000000..108c45d6a3b1db97fdf99712975f7511443e73a6 --- /dev/null +++ b/editor/src/messages/tool/common_functionality/gizmos/mod.rs @@ -0,0 +1,2 @@ +pub mod gizmo_manager; +pub mod shape_gizmos; diff --git a/editor/src/messages/tool/common_functionality/gizmos/shape_gizmos/mod.rs b/editor/src/messages/tool/common_functionality/gizmos/shape_gizmos/mod.rs new file mode 100644 index 0000000000000000000000000000000000000000..2b88dddd5ee4495a2ede55ff85f4e63503134d76 --- /dev/null +++ b/editor/src/messages/tool/common_functionality/gizmos/shape_gizmos/mod.rs @@ -0,0 +1,2 @@ +pub mod number_of_points_dial; +pub mod point_radius_handle; diff --git a/editor/src/messages/tool/common_functionality/gizmos/shape_gizmos/number_of_points_dial.rs b/editor/src/messages/tool/common_functionality/gizmos/shape_gizmos/number_of_points_dial.rs new file mode 100644 index 0000000000000000000000000000000000000000..3995a1f4016cc2d961760a7d32fafee4bf93e03e --- /dev/null +++ b/editor/src/messages/tool/common_functionality/gizmos/shape_gizmos/number_of_points_dial.rs @@ -0,0 +1,209 @@ +use crate::consts::{GIZMO_HIDE_THRESHOLD, NUMBER_OF_POINTS_DIAL_SPOKE_EXTENSION, NUMBER_OF_POINTS_DIAL_SPOKE_LENGTH, POINT_RADIUS_HANDLE_SEGMENT_THRESHOLD}; +use crate::messages::frontend::utility_types::MouseCursorIcon; +use crate::messages::message::Message; +use crate::messages::portfolio::document::overlays::utility_types::OverlayContext; +use crate::messages::portfolio::document::utility_types::document_metadata::LayerNodeIdentifier; +use crate::messages::portfolio::document::utility_types::network_interface::InputConnector; +use crate::messages::prelude::Responses; +use crate::messages::prelude::{DocumentMessageHandler, FrontendMessage, InputPreprocessorMessageHandler, NodeGraphMessage}; +use crate::messages::tool::common_functionality::graph_modification_utils; +use crate::messages::tool::common_functionality::shape_editor::ShapeState; +use crate::messages::tool::common_functionality::shapes::shape_utility::{extract_polygon_parameters, inside_polygon, inside_star, polygon_outline, polygon_vertex_position, star_outline}; +use crate::messages::tool::common_functionality::shapes::shape_utility::{extract_star_parameters, star_vertex_position}; +use glam::{DAffine2, DVec2}; +use graph_craft::document::NodeInput; +use graph_craft::document::value::TaggedValue; +use std::collections::VecDeque; +use std::f64::consts::TAU; + +#[derive(Clone, Debug, Default, PartialEq)] +pub enum NumberOfPointsDialState { + #[default] + Inactive, + Hover, + Dragging, +} + +#[derive(Clone, Debug, Default)] +pub struct NumberOfPointsDial { + pub layer: Option, + pub initial_points: u32, + pub handle_state: NumberOfPointsDialState, +} + +impl NumberOfPointsDial { + pub fn cleanup(&mut self) { + self.handle_state = NumberOfPointsDialState::Inactive; + self.layer = None; + } + + pub fn update_state(&mut self, state: NumberOfPointsDialState) { + self.handle_state = state; + } + + pub fn is_hovering(&self) -> bool { + self.handle_state == NumberOfPointsDialState::Hover + } + + pub fn is_dragging(&self) -> bool { + self.handle_state == NumberOfPointsDialState::Dragging + } + + pub fn handle_actions(&mut self, layer: LayerNodeIdentifier, mouse_position: DVec2, document: &DocumentMessageHandler, responses: &mut VecDeque) { + match &self.handle_state { + NumberOfPointsDialState::Inactive => { + // Star + if let Some((sides, radius1, radius2)) = extract_star_parameters(Some(layer), document) { + let viewport = document.metadata().transform_to_viewport(layer); + let center = viewport.transform_point2(DVec2::ZERO); + + let point_on_max_radius = star_vertex_position(viewport, 0, sides, radius1, radius2); + + if mouse_position.distance(center) < NUMBER_OF_POINTS_DIAL_SPOKE_LENGTH && point_on_max_radius.distance(center) > GIZMO_HIDE_THRESHOLD { + self.layer = Some(layer); + self.initial_points = sides; + self.update_state(NumberOfPointsDialState::Hover); + responses.add(FrontendMessage::UpdateMouseCursor { cursor: MouseCursorIcon::EWResize }); + } + } + + // Polygon + if let Some((sides, radius)) = extract_polygon_parameters(Some(layer), document) { + let viewport = document.metadata().transform_to_viewport(layer); + let center = viewport.transform_point2(DVec2::ZERO); + + let point_on_max_radius = polygon_vertex_position(viewport, 0, sides, radius); + + if mouse_position.distance(center) < NUMBER_OF_POINTS_DIAL_SPOKE_LENGTH && point_on_max_radius.distance(center) > GIZMO_HIDE_THRESHOLD { + self.layer = Some(layer); + self.initial_points = sides; + self.update_state(NumberOfPointsDialState::Hover); + responses.add(FrontendMessage::UpdateMouseCursor { cursor: MouseCursorIcon::EWResize }); + } + } + } + NumberOfPointsDialState::Hover | NumberOfPointsDialState::Dragging => { + let Some(layer) = self.layer else { return }; + + let viewport = document.metadata().transform_to_viewport(layer); + let center = viewport.transform_point2(DVec2::ZERO); + + if mouse_position.distance(center) > NUMBER_OF_POINTS_DIAL_SPOKE_LENGTH && matches!(&self.handle_state, NumberOfPointsDialState::Hover) { + self.update_state(NumberOfPointsDialState::Inactive); + self.layer = None; + responses.add(FrontendMessage::UpdateMouseCursor { cursor: MouseCursorIcon::Default }); + } + } + } + } + + pub fn overlays(&self, document: &DocumentMessageHandler, layer: Option, shape_editor: &mut &mut ShapeState, mouse_position: DVec2, overlay_context: &mut OverlayContext) { + match &self.handle_state { + NumberOfPointsDialState::Inactive => { + let Some(layer) = layer else { return }; + + // Star + if let Some((sides, radius1, radius2)) = extract_star_parameters(Some(layer), document) { + let radius = radius1.max(radius2); + let viewport = document.metadata().transform_to_viewport(layer); + let center = viewport.transform_point2(DVec2::ZERO); + + if let Some(closest_segment) = shape_editor.upper_closest_segment(&document.network_interface, mouse_position, POINT_RADIUS_HANDLE_SEGMENT_THRESHOLD) { + if closest_segment.layer() == layer { + return; + } + } + let point_on_max_radius = star_vertex_position(viewport, 0, sides, radius1, radius2); + + if inside_star(viewport, sides, radius1, radius2, mouse_position) && point_on_max_radius.distance(center) > GIZMO_HIDE_THRESHOLD { + self.draw_spokes(center, viewport, sides, radius, overlay_context); + return; + } + } + + // Polygon + if let Some((sides, radius)) = extract_polygon_parameters(Some(layer), document) { + let viewport = document.metadata().transform_to_viewport(layer); + let center = viewport.transform_point2(DVec2::ZERO); + + if let Some(closest_segment) = shape_editor.upper_closest_segment(&document.network_interface, mouse_position, POINT_RADIUS_HANDLE_SEGMENT_THRESHOLD) { + if closest_segment.layer() == layer { + return; + } + } + let point_on_max_radius = polygon_vertex_position(viewport, 0, sides, radius); + + if inside_polygon(viewport, sides, radius, mouse_position) && point_on_max_radius.distance(center) > GIZMO_HIDE_THRESHOLD { + self.draw_spokes(center, viewport, sides, radius, overlay_context); + } + } + } + NumberOfPointsDialState::Hover | NumberOfPointsDialState::Dragging => { + let Some(layer) = self.layer else { + return; + }; + + // Get the star's greater radius or polygon's radius, as well as the number of sides + let Some((sides, radius)) = extract_star_parameters(Some(layer), document) + .map(|(sides, r1, r2)| (sides, r1.max(r2))) + .or_else(|| extract_polygon_parameters(Some(layer), document)) + else { + return; + }; + + let viewport = document.metadata().transform_to_viewport(layer); + let center = viewport.transform_point2(DVec2::ZERO); + + // Draw either the star or polygon outline + star_outline(Some(layer), document, overlay_context); + polygon_outline(Some(layer), document, overlay_context); + + self.draw_spokes(center, viewport, sides, radius, overlay_context); + } + } + } + + fn draw_spokes(&self, center: DVec2, viewport: DAffine2, sides: u32, radius: f64, overlay_context: &mut OverlayContext) { + for i in 0..sides { + let angle = ((i as f64) * TAU) / (sides as f64); + + let point = viewport.transform_point2(DVec2 { + x: radius * angle.sin(), + y: -radius * angle.cos(), + }); + + let Some(direction) = (point - center).try_normalize() else { continue }; + + // If the user zooms out such that shape is very small hide the gizmo + if point.distance(center) < GIZMO_HIDE_THRESHOLD { + return; + } + + let end_point = direction * NUMBER_OF_POINTS_DIAL_SPOKE_LENGTH; + if matches!(self.handle_state, NumberOfPointsDialState::Hover | NumberOfPointsDialState::Dragging) { + overlay_context.line(center, end_point * NUMBER_OF_POINTS_DIAL_SPOKE_EXTENSION + center, None, None); + } else { + overlay_context.line(center, end_point + center, None, None); + } + } + } + + pub fn update_number_of_sides(&self, document: &DocumentMessageHandler, input: &InputPreprocessorMessageHandler, responses: &mut VecDeque, drag_start: DVec2) { + let delta = input.mouse.position - document.metadata().document_to_viewport.transform_point2(drag_start); + let sign = (input.mouse.position.x - document.metadata().document_to_viewport.transform_point2(drag_start).x).signum(); + let net_delta = (delta.length() / 25.).round() * sign; + + let Some(layer) = self.layer else { return }; + let Some(node_id) = graph_modification_utils::get_star_id(layer, &document.network_interface).or(graph_modification_utils::get_polygon_id(layer, &document.network_interface)) else { + return; + }; + + let new_point_count = ((self.initial_points as i32) + (net_delta as i32)).max(3); + + responses.add(NodeGraphMessage::SetInput { + input_connector: InputConnector::node(node_id, 1), + input: NodeInput::value(TaggedValue::U32(new_point_count as u32), false), + }); + responses.add(NodeGraphMessage::RunDocumentGraph); + } +} diff --git a/editor/src/messages/tool/common_functionality/gizmos/shape_gizmos/point_radius_handle.rs b/editor/src/messages/tool/common_functionality/gizmos/shape_gizmos/point_radius_handle.rs new file mode 100644 index 0000000000000000000000000000000000000000..fc00e078cf5b1a26a501de53097043ddd01fc6f7 --- /dev/null +++ b/editor/src/messages/tool/common_functionality/gizmos/shape_gizmos/point_radius_handle.rs @@ -0,0 +1,455 @@ +use crate::consts::GIZMO_HIDE_THRESHOLD; +use crate::consts::{COLOR_OVERLAY_RED, POINT_RADIUS_HANDLE_SNAP_THRESHOLD}; +use crate::messages::frontend::utility_types::MouseCursorIcon; +use crate::messages::message::Message; +use crate::messages::portfolio::document::utility_types::document_metadata::LayerNodeIdentifier; +use crate::messages::portfolio::document::{overlays::utility_types::OverlayContext, utility_types::network_interface::InputConnector}; +use crate::messages::prelude::FrontendMessage; +use crate::messages::prelude::Responses; +use crate::messages::prelude::{DocumentMessageHandler, InputPreprocessorMessageHandler, NodeGraphMessage}; +use crate::messages::tool::common_functionality::graph_modification_utils::{self, NodeGraphLayer}; +use crate::messages::tool::common_functionality::shapes::shape_utility::{draw_snapping_ticks, extract_polygon_parameters, polygon_outline, polygon_vertex_position, star_outline}; +use crate::messages::tool::common_functionality::shapes::shape_utility::{extract_star_parameters, star_vertex_position}; +use glam::DVec2; +use graph_craft::document::NodeInput; +use graph_craft::document::value::TaggedValue; +use std::collections::VecDeque; +use std::f64::consts::{FRAC_1_SQRT_2, FRAC_PI_4, PI, SQRT_2}; + +#[derive(Clone, Debug, Default, PartialEq)] +pub enum PointRadiusHandleState { + #[default] + Inactive, + Hover, + Dragging, + Snapped(usize), +} + +#[derive(Clone, Debug, Default, PartialEq)] +pub struct PointRadiusHandle { + pub layer: Option, + point: u32, + radius_index: usize, + snap_radii: Vec, + initial_radius: f64, + handle_state: PointRadiusHandleState, +} + +impl PointRadiusHandle { + pub fn cleanup(&mut self) { + self.handle_state = PointRadiusHandleState::Inactive; + self.snap_radii.clear(); + self.layer = None; + } + + pub fn hovered(&self) -> bool { + self.handle_state == PointRadiusHandleState::Hover + } + + pub fn is_dragging_or_snapped(&self) -> bool { + self.handle_state == PointRadiusHandleState::Dragging || matches!(self.handle_state, PointRadiusHandleState::Snapped(_)) + } + + pub fn update_state(&mut self, state: PointRadiusHandleState) { + self.handle_state = state; + } + + pub fn handle_actions(&mut self, layer: LayerNodeIdentifier, document: &DocumentMessageHandler, mouse_position: DVec2, responses: &mut VecDeque) { + match &self.handle_state { + PointRadiusHandleState::Inactive => { + // Draw the point handle gizmo for the star shape + if let Some((sides, radius1, radius2)) = extract_star_parameters(Some(layer), document) { + let viewport = document.metadata().transform_to_viewport(layer); + + for i in 0..2 * sides { + let (radius, radius_index) = if i % 2 == 0 { (radius1, 2) } else { (radius2, 3) }; + let point = star_vertex_position(viewport, i as i32, sides, radius1, radius2); + let center = viewport.transform_point2(DVec2::ZERO); + + // If the user zooms out such that shape is very small hide the gizmo + if point.distance(center) < GIZMO_HIDE_THRESHOLD { + return; + } + + if point.distance(mouse_position) < 5. { + self.radius_index = radius_index; + self.layer = Some(layer); + self.point = i; + self.snap_radii = Self::calculate_snap_radii(document, layer, radius_index); + self.initial_radius = radius; + responses.add(FrontendMessage::UpdateMouseCursor { cursor: MouseCursorIcon::Default }); + self.update_state(PointRadiusHandleState::Hover); + + return; + } + } + } + + // Draw the point handle gizmo for the polygon shape + if let Some((sides, radius)) = extract_polygon_parameters(Some(layer), document) { + let viewport = document.metadata().transform_to_viewport(layer); + + for i in 0..sides { + let point = polygon_vertex_position(viewport, i as i32, sides, radius); + let center = viewport.transform_point2(DVec2::ZERO); + + // If the user zooms out such that shape is very small hide the gizmo + if point.distance(center) < GIZMO_HIDE_THRESHOLD { + return; + } + + if point.distance(mouse_position) < 5. { + self.radius_index = 2; + self.layer = Some(layer); + self.point = i; + self.snap_radii.clear(); + self.initial_radius = radius; + self.update_state(PointRadiusHandleState::Hover); + responses.add(FrontendMessage::UpdateMouseCursor { cursor: MouseCursorIcon::Default }); + return; + } + } + } + } + + PointRadiusHandleState::Dragging | PointRadiusHandleState::Hover => { + let Some(layer) = self.layer else { return }; + + let viewport = document.metadata().transform_to_viewport(layer); + + // Star + if let Some((sides, radius1, radius2)) = extract_star_parameters(Some(layer), document) { + let point = star_vertex_position(viewport, self.point as i32, sides, radius1, radius2); + + if matches!(&self.handle_state, PointRadiusHandleState::Hover) && (mouse_position - point).length() > 5. { + self.update_state(PointRadiusHandleState::Inactive); + self.layer = None; + return; + } + } + + // Polygon + if let Some((sides, radius)) = extract_polygon_parameters(Some(layer), document) { + let point = polygon_vertex_position(viewport, self.point as i32, sides, radius); + + if matches!(&self.handle_state, PointRadiusHandleState::Hover) && (mouse_position - point).length() > 5. { + self.update_state(PointRadiusHandleState::Inactive); + self.layer = None; + } + } + } + PointRadiusHandleState::Snapped(_) => {} + } + } + + pub fn overlays( + &self, + selected_star_layer: Option, + document: &DocumentMessageHandler, + input: &InputPreprocessorMessageHandler, + mouse_position: DVec2, + overlay_context: &mut OverlayContext, + ) { + match &self.handle_state { + PointRadiusHandleState::Inactive => { + let Some(layer) = selected_star_layer else { return }; + + // Draw the point handle gizmo for the star shape + if let Some((sides, radius1, radius2)) = extract_star_parameters(Some(layer), document) { + let viewport = document.metadata().transform_to_viewport(layer); + + for i in 0..(2 * sides) { + let point = star_vertex_position(viewport, i as i32, sides, radius1, radius2); + let center = viewport.transform_point2(DVec2::ZERO); + let viewport_diagonal = input.viewport_bounds.size().length(); + + // If the user zooms out such that shape is very small hide the gizmo + if point.distance(center) < GIZMO_HIDE_THRESHOLD { + return; + } + + if point.distance(mouse_position) < 5. { + let Some(direction) = (point - center).try_normalize() else { continue }; + + overlay_context.manipulator_handle(point, true, None); + let angle = ((i as f64) * PI) / (sides as f64); + overlay_context.line(center, center + direction * viewport_diagonal, None, None); + + draw_snapping_ticks(&self.snap_radii, direction, viewport, angle, overlay_context); + + return; + } + + overlay_context.manipulator_handle(point, false, None); + } + } + + // Draw the point handle gizmo for the Polygon shape + if let Some((sides, radius)) = extract_polygon_parameters(Some(layer), document) { + let viewport = document.metadata().transform_to_viewport(layer); + + for i in 0..sides { + let point = polygon_vertex_position(viewport, i as i32, sides, radius); + let center = viewport.transform_point2(DVec2::ZERO); + let viewport_diagonal = input.viewport_bounds.size().length(); + + // If the user zooms out such that shape is very small hide the gizmo + if point.distance(center) < GIZMO_HIDE_THRESHOLD { + return; + } + + if point.distance(mouse_position) < 5. { + let Some(direction) = (point - center).try_normalize() else { continue }; + + overlay_context.manipulator_handle(point, true, None); + overlay_context.line(center, center + direction * viewport_diagonal, None, None); + + return; + } + + overlay_context.manipulator_handle(point, false, None); + } + } + } + + PointRadiusHandleState::Dragging | PointRadiusHandleState::Hover => { + let Some(layer) = self.layer else { return }; + + let viewport = document.metadata().transform_to_viewport(layer); + let center = viewport.transform_point2(DVec2::ZERO); + let viewport_diagonal = input.viewport_bounds.size().length(); + + // Star + if let Some((sides, radius1, radius2)) = extract_star_parameters(Some(layer), document) { + let angle = ((self.point as f64) * PI) / (sides as f64); + let point = star_vertex_position(viewport, self.point as i32, sides, radius1, radius2); + + let Some(direction) = (point - center).try_normalize() else { return }; + + // Draws the ray from the center to the dragging point extending till the viewport + overlay_context.manipulator_handle(point, true, None); + overlay_context.line(center, center + direction * viewport_diagonal, None, None); + star_outline(Some(layer), document, overlay_context); + + // Make the ticks for snapping + + // If dragging to make radius negative don't show the + if (mouse_position - center).dot(direction) < 0. { + return; + } + draw_snapping_ticks(&self.snap_radii, direction, viewport, angle, overlay_context); + + return; + } + + // Polygon + if let Some((sides, radius)) = extract_polygon_parameters(Some(layer), document) { + let point = polygon_vertex_position(viewport, self.point as i32, sides, radius); + + let Some(direction) = (point - center).try_normalize() else { return }; + + // Draws the ray from the center to the dragging point extending till the viewport + overlay_context.manipulator_handle(point, true, None); + overlay_context.line(center, center + direction * viewport_diagonal, None, None); + + polygon_outline(Some(layer), document, overlay_context); + } + } + PointRadiusHandleState::Snapped(snapping_index) => { + let Some(layer) = self.layer else { return }; + let Some((sides, radius1, radius2)) = extract_star_parameters(Some(layer), document) else { + return; + }; + + let viewport = document.metadata().transform_to_viewport(layer); + let center = viewport.transform_point2(DVec2::ZERO); + + match snapping_index { + // Make a triangle with previous two points + 0 => { + let before_outer_position = star_vertex_position(viewport, (self.point as i32) - 2, sides, radius1, radius2); + let outer_position = star_vertex_position(viewport, (self.point as i32) - 1, sides, radius1, radius2); + let point_position = star_vertex_position(viewport, self.point as i32, sides, radius1, radius2); + + overlay_context.line(before_outer_position, outer_position, Some(COLOR_OVERLAY_RED), Some(3.)); + overlay_context.line(outer_position, point_position, Some(COLOR_OVERLAY_RED), Some(3.)); + + let l1 = (before_outer_position - outer_position).length() * 0.2; + let Some(l1_direction) = (before_outer_position - outer_position).try_normalize() else { return }; + let Some(l2_direction) = (point_position - outer_position).try_normalize() else { return }; + let Some(direction) = (center - outer_position).try_normalize() else { return }; + + let new_point = SQRT_2 * l1 * direction + outer_position; + + let before_outer_position = l1 * l1_direction + outer_position; + let point_position = l1 * l2_direction + outer_position; + + overlay_context.line(before_outer_position, new_point, Some(COLOR_OVERLAY_RED), Some(3.)); + overlay_context.line(new_point, point_position, Some(COLOR_OVERLAY_RED), Some(3.)); + } + 1 => { + let before_outer_position = star_vertex_position(viewport, (self.point as i32) - 1, sides, radius1, radius2); + + let after_point_position = star_vertex_position(viewport, (self.point as i32) + 1, sides, radius1, radius2); + + let point_position = star_vertex_position(viewport, self.point as i32, sides, radius1, radius2); + + overlay_context.line(before_outer_position, point_position, Some(COLOR_OVERLAY_RED), Some(3.)); + overlay_context.line(point_position, after_point_position, Some(COLOR_OVERLAY_RED), Some(3.)); + + let l1 = (before_outer_position - point_position).length() * 0.2; + let Some(l1_direction) = (before_outer_position - point_position).try_normalize() else { return }; + let Some(l2_direction) = (after_point_position - point_position).try_normalize() else { return }; + let Some(direction) = (center - point_position).try_normalize() else { return }; + + let new_point = SQRT_2 * l1 * direction + point_position; + + let before_outer_position = l1 * l1_direction + point_position; + let after_point_position = l1 * l2_direction + point_position; + + overlay_context.line(before_outer_position, new_point, Some(COLOR_OVERLAY_RED), Some(3.)); + overlay_context.line(new_point, after_point_position, Some(COLOR_OVERLAY_RED), Some(3.)); + } + i => { + // Use `self.point` as absolute reference as it matches the index of vertices of the star starting from 0 + if i % 2 != 0 { + // Flipped case + let point_position = star_vertex_position(viewport, self.point as i32, sides, radius1, radius2); + let target_index = (1 - (*i as i32)).abs() + (self.point as i32); + let target_point_position = star_vertex_position(viewport, target_index, sides, radius1, radius2); + + let mirrored_index = 2 * (self.point as i32) - target_index; + let mirrored = star_vertex_position(viewport, mirrored_index, sides, radius1, radius2); + + overlay_context.line(point_position, target_point_position, Some(COLOR_OVERLAY_RED), Some(3.)); + overlay_context.line(point_position, mirrored, Some(COLOR_OVERLAY_RED), Some(3.)); + } else { + let outer_index = (self.point as i32) - 1; + let outer_position = star_vertex_position(viewport, outer_index, sides, radius1, radius2); + + // The vertex which is colinear with the point we are dragging and its previous outer vertex + let target_index = (self.point as i32) + (*i as i32) - 1; + let target_point_position = star_vertex_position(viewport, target_index, sides, radius1, radius2); + + let mirrored_index = 2 * outer_index - target_index; + + let mirrored = star_vertex_position(viewport, mirrored_index, sides, radius1, radius2); + + overlay_context.line(outer_position, target_point_position, Some(COLOR_OVERLAY_RED), Some(3.)); + overlay_context.line(outer_position, mirrored, Some(COLOR_OVERLAY_RED), Some(3.)); + } + } + } + + star_outline(Some(layer), document, overlay_context); + } + } + } + + fn calculate_snap_radii(document: &DocumentMessageHandler, layer: LayerNodeIdentifier, radius_index: usize) -> Vec { + let mut snap_radii = Vec::new(); + + let Some(node_inputs) = NodeGraphLayer::new(layer, &document.network_interface).find_node_inputs("Star") else { + return snap_radii; + }; + + let other_index = if radius_index == 3 { 2 } else { 3 }; + + let Some(&TaggedValue::F64(other_radius)) = node_inputs[other_index].as_value() else { + return snap_radii; + }; + let Some(&TaggedValue::U32(sides)) = node_inputs[1].as_value() else { + return snap_radii; + }; + + // Inner radius for 90° + let b = FRAC_PI_4 * 3. - PI / (sides as f64); + let angle = b.sin(); + let required_radius = (other_radius / angle) * FRAC_1_SQRT_2; + + snap_radii.push(required_radius); + + // Also push the case when the when it length increases more than the other + + let flipped = other_radius * angle * SQRT_2; + + snap_radii.push(flipped); + + for i in 1..sides { + let sides = sides as f64; + let i = i as f64; + let denominator = 2. * ((PI * (i - 1.)) / sides).cos() * ((PI * i) / sides).sin(); + let numerator = ((2. * PI * i) / sides).sin(); + let factor = numerator / denominator; + + if factor < 0. { + break; + } + + if other_radius * factor > 1e-6 { + snap_radii.push(other_radius * factor); + } + + snap_radii.push((other_radius * 1.) / factor); + } + + snap_radii + } + + fn check_snapping(&self, new_radius: f64, original_radius: f64) -> Option<(usize, f64)> { + self.snap_radii + .iter() + .enumerate() + .filter(|(_, rad)| (**rad - new_radius).abs() < POINT_RADIUS_HANDLE_SNAP_THRESHOLD) + .min_by(|(i_a, a), (i_b, b)| { + let dist_a = (**a - new_radius).abs(); + let dist_b = (**b - new_radius).abs(); + + // Check if either index is 0 or 1 and prioritize them + match (*i_a == 0 || *i_a == 1, *i_b == 0 || *i_b == 1) { + // `a` is priority index, `b` is not + (true, false) => std::cmp::Ordering::Less, + // `b` is priority index, `a` is not + (false, true) => std::cmp::Ordering::Greater, + // Normal comparison + _ => dist_a.partial_cmp(&dist_b).unwrap_or(std::cmp::Ordering::Equal), + } + }) + .map(|(i, rad)| (i, *rad - original_radius)) + } + + pub fn update_inner_radius(&mut self, document: &DocumentMessageHandler, input: &InputPreprocessorMessageHandler, responses: &mut VecDeque, drag_start: DVec2) { + let Some(layer) = self.layer else { return }; + + let Some(node_id) = graph_modification_utils::get_star_id(layer, &document.network_interface).or(graph_modification_utils::get_polygon_id(layer, &document.network_interface)) else { + return; + }; + + let viewport_transform = document.network_interface.document_metadata().transform_to_viewport(layer); + let document_transform = document.network_interface.document_metadata().transform_to_document(layer); + let center = viewport_transform.transform_point2(DVec2::ZERO); + let radius_index = self.radius_index; + + let original_radius = self.initial_radius; + + let delta = viewport_transform.inverse().transform_point2(input.mouse.position) - document_transform.inverse().transform_point2(drag_start); + let radius = document.metadata().document_to_viewport.transform_point2(drag_start) - center; + let projection = delta.project_onto(radius); + let sign = radius.dot(delta).signum(); + + let mut net_delta = projection.length() * sign; + let new_radius = original_radius + net_delta; + + self.update_state(PointRadiusHandleState::Dragging); + if let Some((index, snapped_delta)) = self.check_snapping(new_radius, original_radius) { + net_delta = snapped_delta; + self.update_state(PointRadiusHandleState::Snapped(index)); + } + + responses.add(NodeGraphMessage::SetInput { + input_connector: InputConnector::node(node_id, radius_index), + input: NodeInput::value(TaggedValue::F64(original_radius + net_delta), false), + }); + responses.add(NodeGraphMessage::RunDocumentGraph); + } +} diff --git a/editor/src/messages/tool/common_functionality/graph_modification_utils.rs b/editor/src/messages/tool/common_functionality/graph_modification_utils.rs new file mode 100644 index 0000000000000000000000000000000000000000..765bfc1eac518d28c58c2be14665367938e35078 --- /dev/null +++ b/editor/src/messages/tool/common_functionality/graph_modification_utils.rs @@ -0,0 +1,451 @@ +use crate::messages::portfolio::document::graph_operation::utility_types::TransformIn; +use crate::messages::portfolio::document::node_graph::document_node_definitions; +use crate::messages::portfolio::document::utility_types::document_metadata::LayerNodeIdentifier; +use crate::messages::portfolio::document::utility_types::network_interface::{FlowType, InputConnector, NodeNetworkInterface, NodeTemplate}; +use crate::messages::prelude::*; +use bezier_rs::Subpath; +use glam::DVec2; +use graph_craft::concrete; +use graph_craft::document::value::TaggedValue; +use graph_craft::document::{NodeId, NodeInput}; +use graphene_std::Color; +use graphene_std::NodeInputDecleration; +use graphene_std::raster::BlendMode; +use graphene_std::raster_types::{CPU, GPU, RasterDataTable}; +use graphene_std::text::{Font, TypesettingConfig}; +use graphene_std::vector::style::Gradient; +use graphene_std::vector::{ManipulatorPointId, PointId, SegmentId, VectorModificationType}; +use std::collections::VecDeque; + +/// Returns the ID of the first Spline node in the horizontal flow which is not followed by a `Path` node, or `None` if none exists. +pub fn find_spline(document: &DocumentMessageHandler, layer: LayerNodeIdentifier) -> Option { + document + .network_interface + .upstream_flow_back_from_nodes([layer.to_node()].to_vec(), &[], FlowType::HorizontalFlow) + .map(|node_id| (document.network_interface.reference(&node_id, &[]).unwrap(), node_id)) + .take_while(|(reference, _)| reference.as_ref().is_some_and(|node_ref| node_ref != "Path")) + .find(|(reference, _)| reference.as_ref().is_some_and(|node_ref| node_ref == "Spline")) + .map(|node| node.1) +} + +/// Merge `second_layer` to the `first_layer`. +pub fn merge_layers(document: &DocumentMessageHandler, first_layer: LayerNodeIdentifier, second_layer: LayerNodeIdentifier, responses: &mut VecDeque) { + if first_layer == second_layer { + return; + } + // Calculate the downstream transforms in order to bring the other vector data into the same layer space + let first_layer_transform = document.metadata().downstream_transform_to_document(first_layer); + let second_layer_transform = document.metadata().downstream_transform_to_document(second_layer); + + // Represents the change in position that would occur if the other layer was moved below the current layer + let transform_delta = first_layer_transform * second_layer_transform.inverse(); + let offset = transform_delta.inverse(); + responses.add(GraphOperationMessage::TransformChange { + layer: second_layer, + transform: offset, + transform_in: TransformIn::Local, + skip_rerender: false, + }); + + let mut current_and_other_layer_is_spline = false; + + if let (Some(current_layer_spline), Some(other_layer_spline)) = (find_spline(document, first_layer), find_spline(document, second_layer)) { + responses.add(NodeGraphMessage::DeleteNodes { + node_ids: [current_layer_spline, other_layer_spline].to_vec(), + delete_children: false, + }); + current_and_other_layer_is_spline = true; + } + + // Move the `second_layer` below the `first_layer` for positioning purposes + let Some(first_layer_parent) = first_layer.parent(document.metadata()) else { return }; + let Some(first_layer_index) = first_layer_parent.children(document.metadata()).position(|child| child == first_layer) else { + return; + }; + responses.add(NodeGraphMessage::MoveLayerToStack { + layer: second_layer, + parent: first_layer_parent, + insert_index: first_layer_index + 1, + }); + + // Merge the inputs of the two layers + let merge_node_id = NodeId::new(); + let merge_node = document_node_definitions::resolve_document_node_type("Merge") + .expect("Failed to create merge node") + .default_node_template(); + responses.add(NodeGraphMessage::InsertNode { + node_id: merge_node_id, + node_template: merge_node, + }); + responses.add(NodeGraphMessage::SetToNodeOrLayer { + node_id: merge_node_id, + is_layer: false, + }); + responses.add(NodeGraphMessage::MoveNodeToChainStart { + node_id: merge_node_id, + parent: first_layer, + }); + responses.add(NodeGraphMessage::ConnectUpstreamOutputToInput { + downstream_input: InputConnector::node(second_layer.to_node(), 1), + input_connector: InputConnector::node(merge_node_id, 1), + }); + responses.add(NodeGraphMessage::DeleteNodes { + node_ids: vec![second_layer.to_node()], + delete_children: false, + }); + + // Add a Flatten Path node after the merge + let flatten_node_id = NodeId::new(); + let flatten_node = document_node_definitions::resolve_document_node_type("Flatten Path") + .expect("Failed to create flatten node") + .default_node_template(); + responses.add(NodeGraphMessage::InsertNode { + node_id: flatten_node_id, + node_template: flatten_node, + }); + responses.add(NodeGraphMessage::MoveNodeToChainStart { + node_id: flatten_node_id, + parent: first_layer, + }); + + // Add a path node after the flatten node + let path_node_id = NodeId::new(); + let path_node = document_node_definitions::resolve_document_node_type("Path") + .expect("Failed to create path node") + .default_node_template(); + responses.add(NodeGraphMessage::InsertNode { + node_id: path_node_id, + node_template: path_node, + }); + responses.add(NodeGraphMessage::MoveNodeToChainStart { + node_id: path_node_id, + parent: first_layer, + }); + + // Add a Spline node after the Path node if both the layers we are merging is spline. + if current_and_other_layer_is_spline { + let spline_node_id = NodeId::new(); + let spline_node = document_node_definitions::resolve_document_node_type("Spline") + .expect("Failed to create Spline node") + .default_node_template(); + responses.add(NodeGraphMessage::InsertNode { + node_id: spline_node_id, + node_template: spline_node, + }); + responses.add(NodeGraphMessage::MoveNodeToChainStart { + node_id: spline_node_id, + parent: first_layer, + }); + } + + // Add a transform node to ensure correct tooling modifications + let transform_node_id = NodeId::new(); + let transform_node = document_node_definitions::resolve_document_node_type("Transform") + .expect("Failed to create transform node") + .default_node_template(); + responses.add(NodeGraphMessage::InsertNode { + node_id: transform_node_id, + node_template: transform_node, + }); + responses.add(NodeGraphMessage::MoveNodeToChainStart { + node_id: transform_node_id, + parent: first_layer, + }); + + responses.add(NodeGraphMessage::RunDocumentGraph); + responses.add(Message::StartBuffer); + responses.add(PenToolMessage::RecalculateLatestPointsPosition); +} + +/// Merge the `first_endpoint` with `second_endpoint`. +pub fn merge_points(document: &DocumentMessageHandler, layer: LayerNodeIdentifier, first_endpoint: PointId, second_endpont: PointId, responses: &mut VecDeque) { + let transform = document.metadata().transform_to_document(layer); + let Some(vector_data) = document.network_interface.compute_modified_vector(layer) else { return }; + + let segment = vector_data.segment_bezier_iter().find(|(_, _, start, end)| *end == second_endpont || *start == second_endpont); + let Some((segment, _, mut segment_start_point, mut segment_end_point)) = segment else { + log::error!("Could not get the segment for second_endpoint."); + return; + }; + + let mut handles = [None; 2]; + if let Some(handle_position) = ManipulatorPointId::PrimaryHandle(segment).get_position(&vector_data) { + let anchor_position = ManipulatorPointId::Anchor(segment_start_point).get_position(&vector_data).unwrap(); + let handle_position = transform.transform_point2(handle_position); + let anchor_position = transform.transform_point2(anchor_position); + let anchor_to_handle = handle_position - anchor_position; + handles[0] = Some(anchor_to_handle); + } + if let Some(handle_position) = ManipulatorPointId::EndHandle(segment).get_position(&vector_data) { + let anchor_position = ManipulatorPointId::Anchor(segment_end_point).get_position(&vector_data).unwrap(); + let handle_position = transform.transform_point2(handle_position); + let anchor_position = transform.transform_point2(anchor_position); + let anchor_to_handle = handle_position - anchor_position; + handles[1] = Some(anchor_to_handle); + } + + if segment_start_point == second_endpont { + core::mem::swap(&mut segment_start_point, &mut segment_end_point); + handles.reverse(); + } + + let modification_type = VectorModificationType::RemovePoint { id: second_endpont }; + responses.add(GraphOperationMessage::Vector { layer, modification_type }); + let modification_type = VectorModificationType::RemoveSegment { id: segment }; + responses.add(GraphOperationMessage::Vector { layer, modification_type }); + + let points = [segment_start_point, first_endpoint]; + let id = SegmentId::generate(); + let modification_type = VectorModificationType::InsertSegment { id, points, handles }; + responses.add(GraphOperationMessage::Vector { layer, modification_type }); +} + +/// Create a new vector layer. +pub fn new_vector_layer(subpaths: Vec>, id: NodeId, parent: LayerNodeIdentifier, responses: &mut VecDeque) -> LayerNodeIdentifier { + let insert_index = 0; + responses.add(GraphOperationMessage::NewVectorLayer { id, subpaths, parent, insert_index }); + responses.add(NodeGraphMessage::SelectedNodesSet { nodes: vec![id] }); + + LayerNodeIdentifier::new_unchecked(id) +} + +/// Create a new bitmap layer. +pub fn new_image_layer(image_frame: RasterDataTable, id: NodeId, parent: LayerNodeIdentifier, responses: &mut VecDeque) -> LayerNodeIdentifier { + let insert_index = 0; + responses.add(GraphOperationMessage::NewBitmapLayer { + id, + image_frame, + parent, + insert_index, + }); + LayerNodeIdentifier::new_unchecked(id) +} + +/// Create a new group layer from an SVG string. +pub fn new_svg_layer(svg: String, transform: glam::DAffine2, id: NodeId, parent: LayerNodeIdentifier, responses: &mut VecDeque) -> LayerNodeIdentifier { + let insert_index = 0; + responses.add(GraphOperationMessage::NewSvg { + id, + svg, + transform, + parent, + insert_index, + }); + LayerNodeIdentifier::new_unchecked(id) +} + +pub fn new_custom(id: NodeId, nodes: Vec<(NodeId, NodeTemplate)>, parent: LayerNodeIdentifier, responses: &mut VecDeque) -> LayerNodeIdentifier { + responses.add(GraphOperationMessage::NewCustomLayer { id, nodes, parent, insert_index: 0 }); + responses.add(GraphOperationMessage::SetUpstreamToChain { + layer: LayerNodeIdentifier::new_unchecked(id), + }); + responses.add(NodeGraphMessage::SelectedNodesSet { nodes: vec![id] }); + LayerNodeIdentifier::new_unchecked(id) +} + +/// Locate the final pivot from the transform (TODO: decide how the pivot should actually work) +pub fn get_pivot(layer: LayerNodeIdentifier, network_interface: &NodeNetworkInterface) -> Option { + let pivot_node_input_index = 5; + if let TaggedValue::DVec2(pivot) = NodeGraphLayer::new(layer, network_interface).find_input("Transform", pivot_node_input_index)? { + Some(*pivot) + } else { + None + } +} + +pub fn get_viewport_pivot(layer: LayerNodeIdentifier, network_interface: &NodeNetworkInterface) -> DVec2 { + let [min, max] = network_interface.document_metadata().nonzero_bounding_box(layer); + let pivot = get_pivot(layer, network_interface).unwrap_or(DVec2::splat(0.5)); + network_interface.document_metadata().transform_to_viewport(layer).transform_point2(min + (max - min) * pivot) +} + +/// Get the current gradient of a layer from the closest "Fill" node. +pub fn get_gradient(layer: LayerNodeIdentifier, network_interface: &NodeNetworkInterface) -> Option { + let fill_index = 1; + + let inputs = NodeGraphLayer::new(layer, network_interface).find_node_inputs("Fill")?; + let TaggedValue::Fill(graphene_std::vector::style::Fill::Gradient(gradient)) = inputs.get(fill_index)?.as_value()? else { + return None; + }; + Some(gradient.clone()) +} + +/// Get the current fill of a layer from the closest "Fill" node. +pub fn get_fill_color(layer: LayerNodeIdentifier, network_interface: &NodeNetworkInterface) -> Option { + let fill_index = 1; + + let inputs = NodeGraphLayer::new(layer, network_interface).find_node_inputs("Fill")?; + let TaggedValue::Fill(graphene_std::vector::style::Fill::Solid(color)) = inputs.get(fill_index)?.as_value()? else { + return None; + }; + Some(color.to_linear_srgb()) +} + +/// Get the current blend mode of a layer from the closest "Blending" node. +pub fn get_blend_mode(layer: LayerNodeIdentifier, network_interface: &NodeNetworkInterface) -> Option { + let inputs = NodeGraphLayer::new(layer, network_interface).find_node_inputs("Blending")?; + let TaggedValue::BlendMode(blend_mode) = inputs.get(1)?.as_value()? else { + return None; + }; + Some(*blend_mode) +} + +/// Get the current opacity of a layer from the closest "Blending" node. +/// This may differ from the actual opacity contained within the data type reaching this layer, because that actual opacity may be: +/// - Multiplied with additional opacity nodes earlier in the chain +/// - Set by an Opacity node with an exposed input value driven by another node +/// - Already factored into the pixel alpha channel of an image +/// - The default value of 100% if no Opacity node is present, but this function returns None in that case +/// +/// With those limitations in mind, the intention of this function is to show just the value already present in an upstream Opacity node so that value can be directly edited. +pub fn get_opacity(layer: LayerNodeIdentifier, network_interface: &NodeNetworkInterface) -> Option { + let inputs = NodeGraphLayer::new(layer, network_interface).find_node_inputs("Blending")?; + let TaggedValue::F64(opacity) = inputs.get(2)?.as_value()? else { + return None; + }; + Some(*opacity) +} + +pub fn get_clip_mode(layer: LayerNodeIdentifier, network_interface: &NodeNetworkInterface) -> Option { + let inputs = NodeGraphLayer::new(layer, network_interface).find_node_inputs("Blending")?; + let TaggedValue::Bool(clip) = inputs.get(4)?.as_value()? else { + return None; + }; + Some(*clip) +} + +pub fn get_fill(layer: LayerNodeIdentifier, network_interface: &NodeNetworkInterface) -> Option { + let inputs = NodeGraphLayer::new(layer, network_interface).find_node_inputs("Blending")?; + let TaggedValue::F64(fill) = inputs.get(3)?.as_value()? else { + return None; + }; + Some(*fill) +} + +pub fn get_fill_id(layer: LayerNodeIdentifier, network_interface: &NodeNetworkInterface) -> Option { + NodeGraphLayer::new(layer, network_interface).upstream_node_id_from_name("Fill") +} + +pub fn get_ellipse_id(layer: LayerNodeIdentifier, network_interface: &NodeNetworkInterface) -> Option { + NodeGraphLayer::new(layer, network_interface).upstream_node_id_from_name("Ellipse") +} + +pub fn get_line_id(layer: LayerNodeIdentifier, network_interface: &NodeNetworkInterface) -> Option { + NodeGraphLayer::new(layer, network_interface).upstream_node_id_from_name("Line") +} + +pub fn get_polygon_id(layer: LayerNodeIdentifier, network_interface: &NodeNetworkInterface) -> Option { + NodeGraphLayer::new(layer, network_interface).upstream_node_id_from_name("Regular Polygon") +} + +pub fn get_rectangle_id(layer: LayerNodeIdentifier, network_interface: &NodeNetworkInterface) -> Option { + NodeGraphLayer::new(layer, network_interface).upstream_node_id_from_name("Rectangle") +} + +pub fn get_star_id(layer: LayerNodeIdentifier, network_interface: &NodeNetworkInterface) -> Option { + NodeGraphLayer::new(layer, network_interface).upstream_node_id_from_name("Star") +} + +pub fn get_text_id(layer: LayerNodeIdentifier, network_interface: &NodeNetworkInterface) -> Option { + NodeGraphLayer::new(layer, network_interface).upstream_node_id_from_name("Text") +} + +/// Gets properties from the Text node +pub fn get_text(layer: LayerNodeIdentifier, network_interface: &NodeNetworkInterface) -> Option<(&String, &Font, TypesettingConfig)> { + let inputs = NodeGraphLayer::new(layer, network_interface).find_node_inputs("Text")?; + + let Some(TaggedValue::String(text)) = &inputs[1].as_value() else { return None }; + let Some(TaggedValue::Font(font)) = &inputs[2].as_value() else { return None }; + let Some(&TaggedValue::F64(font_size)) = inputs[3].as_value() else { return None }; + let Some(&TaggedValue::F64(line_height_ratio)) = inputs[4].as_value() else { return None }; + let Some(&TaggedValue::F64(character_spacing)) = inputs[5].as_value() else { return None }; + let Some(&TaggedValue::OptionalF64(max_width)) = inputs[6].as_value() else { return None }; + let Some(&TaggedValue::OptionalF64(max_height)) = inputs[7].as_value() else { return None }; + let Some(&TaggedValue::F64(tilt)) = inputs[8].as_value() else { return None }; + + let typesetting = TypesettingConfig { + font_size, + line_height_ratio, + max_width, + character_spacing, + max_height, + tilt, + }; + Some((text, font, typesetting)) +} + +pub fn get_stroke_width(layer: LayerNodeIdentifier, network_interface: &NodeNetworkInterface) -> Option { + let weight_node_input_index = graphene_std::vector::stroke::WeightInput::INDEX; + if let TaggedValue::F64(width) = NodeGraphLayer::new(layer, network_interface).find_input("Stroke", weight_node_input_index)? { + Some(*width) + } else { + None + } +} + +/// Checks if a specified layer uses an upstream node matching the given name. +pub fn is_layer_fed_by_node_of_name(layer: LayerNodeIdentifier, network_interface: &NodeNetworkInterface, node_name: &str) -> bool { + NodeGraphLayer::new(layer, network_interface).find_node_inputs(node_name).is_some() +} + +/// An immutable reference to a layer within the document node graph for easy access. +pub struct NodeGraphLayer<'a> { + network_interface: &'a NodeNetworkInterface, + layer_node: NodeId, +} + +impl<'a> NodeGraphLayer<'a> { + /// Get the layer node from the document + pub fn new(layer: LayerNodeIdentifier, network_interface: &'a NodeNetworkInterface) -> Self { + debug_assert!(layer != LayerNodeIdentifier::ROOT_PARENT, "Cannot create new NodeGraphLayer from ROOT_PARENT"); + Self { + network_interface, + layer_node: layer.to_node(), + } + } + + /// Return an iterator up the horizontal flow of the layer + pub fn horizontal_layer_flow(&self) -> impl Iterator + use<'a> { + self.network_interface.upstream_flow_back_from_nodes(vec![self.layer_node], &[], FlowType::HorizontalFlow) + } + + /// Node id of a node if it exists in the layer's primary flow + pub fn upstream_node_id_from_name(&self, node_name: &str) -> Option { + self.horizontal_layer_flow() + .find(|node_id| self.network_interface.reference(node_id, &[]).is_some_and(|reference| *reference == Some(node_name.to_string()))) + } + + /// Node id of a protonode if it exists in the layer's primary flow + pub fn upstream_node_id_from_protonode(&self, protonode_identifier: &'static str) -> Option { + self.horizontal_layer_flow() + // Take until a different layer is reached + .take_while(|&node_id| node_id == self.layer_node || !self.network_interface.is_layer(&node_id, &[])) + .find(move |node_id| { + self.network_interface + .implementation(node_id, &[]) + .is_some_and(move |implementation| *implementation == graph_craft::document::DocumentNodeImplementation::proto(protonode_identifier)) + }) + } + + /// Find all of the inputs of a specific node within the layer's primary flow, up until the next layer is reached. + pub fn find_node_inputs(&self, node_name: &str) -> Option<&'a Vec> { + self.horizontal_layer_flow() + .skip(1)// Skip self + .take_while(|node_id| !self.network_interface.is_layer(node_id,&[])) + .find(|node_id| self.network_interface.reference(node_id,&[]).is_some_and(|reference| *reference == Some(node_name.to_string()))) + .and_then(|node_id| self.network_interface.document_network().nodes.get(&node_id).map(|node| &node.inputs)) + } + + /// Find a specific input of a node within the layer's primary flow + pub fn find_input(&self, node_name: &str, index: usize) -> Option<&'a TaggedValue> { + // TODO: Find a better way to accept a node input rather than using its index (which is quite unclear and fragile) + self.find_node_inputs(node_name)?.get(index)?.as_value() + } + + /// Check if a layer is a raster layer + pub fn is_raster_layer(layer: LayerNodeIdentifier, network_interface: &mut NodeNetworkInterface) -> bool { + let layer_input_type = network_interface.input_type(&InputConnector::node(layer.to_node(), 1), &[]).0.nested_type().clone(); + + layer_input_type == concrete!(RasterDataTable) || layer_input_type == concrete!(RasterDataTable) + } +} diff --git a/editor/src/messages/tool/common_functionality/measure.rs b/editor/src/messages/tool/common_functionality/measure.rs new file mode 100644 index 0000000000000000000000000000000000000000..5a76a5bd222851cb16c2bafe45b4d530c1ee74bf --- /dev/null +++ b/editor/src/messages/tool/common_functionality/measure.rs @@ -0,0 +1,496 @@ +use crate::consts::COLOR_OVERLAY_BLUE; +use crate::messages::portfolio::document::overlays::utility_types::{OverlayContext, Pivot}; +use crate::messages::tool::tool_messages::tool_prelude::*; +use graphene_std::renderer::Rect; + +/// Draws a dashed line between two points transformed by the given affine transformation. +fn draw_dashed_line(line_start: DVec2, line_end: DVec2, transform: DAffine2, overlay_context: &mut OverlayContext) { + let min_viewport = transform.transform_point2(line_start); + let max_viewport = transform.transform_point2(line_end); + + overlay_context.dashed_line(min_viewport, max_viewport, None, None, Some(2.), Some(2.), Some(0.5)); +} + +/// Draws a solid line with a length annotation between two points transformed by the given affine transformations. +fn draw_line_with_length(line_start: DVec2, line_end: DVec2, transform: DAffine2, document_to_viewport: DAffine2, overlay_context: &mut OverlayContext, label_alignment: LabelAlignment) { + let transform_to_document = document_to_viewport.inverse() * transform; + let min_viewport = transform.transform_point2(line_start); + let max_viewport = transform.transform_point2(line_end); + + overlay_context.line(min_viewport, max_viewport, None, None); + + // Remove trailing zeros from the formatted string + let length = format!("{:.2}", transform_to_document.transform_vector2(line_end - line_start).length()) + .trim_end_matches('0') + .trim_end_matches('.') + .to_string(); + + const TOLERANCE: f64 = 0.01; + if transform_to_document.transform_vector2(line_end - line_start).length() >= TOLERANCE { + const TEXT_PADDING: f64 = 5.; + // Calculate midpoint of the line + let midpoint = (min_viewport + max_viewport) / 2.; + + // Adjust text position based on line orientation and flags + // Determine text position based on line orientation and flags + let (pivot_x, pivot_y) = match (label_alignment.is_vertical_line, label_alignment.text_on_left, label_alignment.text_on_top) { + (true, true, _) => (Pivot::End, Pivot::Middle), // Vertical line, text on the left + (true, false, _) => (Pivot::Start, Pivot::Middle), // Vertical line, text on the right + (false, _, true) => (Pivot::Middle, Pivot::End), // Horizontal line, text on top + (false, _, false) => (Pivot::Middle, Pivot::Start), // Horizontal line, text on bottom + }; + overlay_context.text(&length, COLOR_OVERLAY_BLUE, None, DAffine2::from_translation(midpoint), TEXT_PADDING, [pivot_x, pivot_y]); + } +} + +/// Draws a dashed outline around a rectangle to visualize the AABB +fn draw_dashed_rect_outline(rect: Rect, transform: DAffine2, overlay_context: &mut OverlayContext) { + let min = rect.min(); + let max = rect.max(); + + // Create the four corners of the rectangle + let top_left = transform.transform_point2(DVec2::new(min.x, min.y)); + let top_right = transform.transform_point2(DVec2::new(max.x, min.y)); + let bottom_right = transform.transform_point2(DVec2::new(max.x, max.y)); + let bottom_left = transform.transform_point2(DVec2::new(min.x, max.y)); + + // Draw the four sides as dashed lines + draw_dashed_line(top_left, top_right, transform, overlay_context); + draw_dashed_line(top_right, bottom_right, transform, overlay_context); + draw_dashed_line(bottom_right, bottom_left, transform, overlay_context); + draw_dashed_line(bottom_left, top_left, transform, overlay_context); +} + +/// Checks if the selected bounds overlap with the hovered bounds on the Y-axis. +fn does_overlap_y(selected_bounds: Rect, hovered_bounds: Rect) -> bool { + selected_bounds.min().x <= hovered_bounds.max().x && selected_bounds.max().x >= hovered_bounds.min().x +} + +/// Checks if the selected bounds overlap with the hovered bounds on the X-axis. +fn does_overlap_x(selected_bounds: Rect, hovered_bounds: Rect) -> bool { + selected_bounds.min().y <= hovered_bounds.max().y && selected_bounds.max().y >= hovered_bounds.min().y +} + +/// Draws measurements when both X and Y axes are involved in the overlap between selected and hovered bounds. +fn draw_zero_axis_crossings(selected_bounds: Rect, hovered_bounds: Rect, transform: DAffine2, document_to_viewport: DAffine2, overlay_context: &mut OverlayContext) { + let (selected_min, selected_max) = (selected_bounds.min(), selected_bounds.max()); + let (hovered_min, hovered_max) = (hovered_bounds.min(), hovered_bounds.max()); + + let selected_on_right = selected_min.x > hovered_max.x; + let selected_on_bottom = selected_min.y > hovered_max.y; + + let selected_y = if selected_on_bottom { selected_min.y } else { selected_max.y }; + let hovered_y = if selected_on_bottom { hovered_max.y } else { hovered_min.y }; + let selected_x = if selected_on_right { selected_min.x } else { selected_max.x }; + let hovered_x = if selected_on_right { hovered_max.x } else { hovered_min.x }; + + // Draw horizontal solid line with length + let line_start = DVec2::new(selected_x, selected_y); + let line_end = DVec2::new(hovered_x, selected_y); + let label_alignment = LabelAlignment::new(false, false, !selected_on_bottom); + draw_line_with_length(line_start, line_end, transform, document_to_viewport, overlay_context, label_alignment); + + // Draw horizontal dashed line + let line_start = DVec2::new(selected_x, hovered_y); + let line_end = DVec2::new(hovered_x, hovered_y); + draw_dashed_line(line_start, line_end, transform, overlay_context); + + // Draw vertical solid line with length + let line_start = DVec2::new(selected_x, selected_y); + let line_end = DVec2::new(selected_x, hovered_y); + let label_alignment = LabelAlignment::new(true, !selected_on_right, false); + draw_line_with_length(line_start, line_end, transform, document_to_viewport, overlay_context, label_alignment); + + // Draw vertical dashed line + let line_start = DVec2::new(hovered_x, selected_y); + let line_end = DVec2::new(hovered_x, hovered_y); + draw_dashed_line(line_start, line_end, transform, overlay_context); +} + +/// Draws measurements when only one axis is involved in the overlap between selected and hovered bounds. +fn draw_single_axis_zero_crossings(selected_bounds: Rect, hovered_bounds: Rect, transform: DAffine2, document_to_viewport: DAffine2, overlay_context: &mut OverlayContext) { + let (selected_min, selected_max) = (selected_bounds.min(), selected_bounds.max()); + let (hovered_min, hovered_max) = (hovered_bounds.min(), hovered_bounds.max()); + + let overlap_y = does_overlap_y(selected_bounds, hovered_bounds) || does_overlap_y(hovered_bounds, selected_bounds); + let overlap_x = does_overlap_x(selected_bounds, hovered_bounds) || does_overlap_x(hovered_bounds, selected_bounds); + + let selected_on_bottom = selected_bounds.center().y > hovered_bounds.center().y; + let selected_on_right = selected_bounds.center().x > hovered_bounds.center().x; + if overlap_y { + let selected_facing_edge = if hovered_max.y < selected_min.y { selected_min.y } else { selected_max.y }; + let hovered_facing_edge = if hovered_max.y < selected_min.y { hovered_max.y } else { hovered_min.y }; + let vertical_line_start_x = if hovered_max.x > selected_max.x { selected_max.x } else { selected_min.x }; + let dashed_vertical_line_start_x = if hovered_max.x > selected_max.x { hovered_min.x } else { hovered_max.x }; + + // Draw horizontal solid line with length + let line_start = DVec2::new(f64::min(hovered_max.x, selected_max.x), selected_facing_edge); + let line_end = DVec2::new(f64::max(hovered_min.x, selected_min.x), selected_facing_edge); + let label_alignment = LabelAlignment::new(false, false, selected_on_bottom); + draw_line_with_length(line_start, line_end, transform, document_to_viewport, overlay_context, label_alignment); + + // Draw vertical solid line with length + let line_start = DVec2::new(vertical_line_start_x, selected_facing_edge); + let line_end = DVec2::new(vertical_line_start_x, hovered_facing_edge); + let label_alignment = LabelAlignment::new(true, !selected_on_right, false); + draw_line_with_length(line_start, line_end, transform, document_to_viewport, overlay_context, label_alignment); + + // Draw vertical dashed line + let dashed_line_start = DVec2::new(dashed_vertical_line_start_x, selected_facing_edge); + let dashed_line_end = DVec2::new(dashed_vertical_line_start_x, hovered_facing_edge); + draw_dashed_line(dashed_line_start, dashed_line_end, transform, overlay_context); + } else if overlap_x { + let selected_facing_edge = if hovered_max.x < selected_min.x { selected_min.x } else { selected_max.x }; + let hovered_facing_edge = if hovered_max.x < selected_min.x { hovered_max.x } else { hovered_min.x }; + let horizontal_line_start_y = if hovered_max.y > selected_max.y { selected_max.y } else { selected_min.y }; + let dashed_horizontal_line_start_y = if hovered_max.y > selected_max.y { hovered_min.y } else { hovered_max.y }; + + // Draw vertical solid line with length + let line_start = DVec2::new(selected_facing_edge, f64::min(hovered_max.y, selected_max.y)); + let line_end = DVec2::new(selected_facing_edge, f64::max(hovered_min.y, selected_min.y)); + let label_alignment = LabelAlignment::new(true, selected_on_right, false); + draw_line_with_length(line_start, line_end, transform, document_to_viewport, overlay_context, label_alignment); + + // Draw horizontal solid line with length + let line_start = DVec2::new(selected_facing_edge, horizontal_line_start_y); + let line_end = DVec2::new(hovered_facing_edge, horizontal_line_start_y); + let label_alignment = LabelAlignment::new(false, false, !selected_on_bottom); + draw_line_with_length(line_start, line_end, transform, document_to_viewport, overlay_context, label_alignment); + + // Draw horizontal dashed line + let dashed_line_start = DVec2::new(selected_facing_edge, dashed_horizontal_line_start_y); + let dashed_line_end = DVec2::new(hovered_facing_edge, dashed_horizontal_line_start_y); + draw_dashed_line(dashed_line_start, dashed_line_end, transform, overlay_context); + } +} + +/// Draws measurements when only one axis is involved and there is one crossing between selected and hovered bounds. +fn draw_single_axis_one_crossings(selected_bounds: Rect, hovered_bounds: Rect, transform: DAffine2, document_to_viewport: DAffine2, overlay_context: &mut OverlayContext) { + let (selected_min, selected_max) = (selected_bounds.min(), selected_bounds.max()); + let (hovered_min, hovered_max) = (hovered_bounds.min(), hovered_bounds.max()); + + let selected_center = selected_bounds.center(); + let hovered_center = hovered_bounds.center(); + + let overlap_y = does_overlap_y(selected_bounds, hovered_bounds) || does_overlap_y(hovered_bounds, selected_bounds); + let overlap_x = does_overlap_x(selected_bounds, hovered_bounds) || does_overlap_x(hovered_bounds, selected_bounds); + + if overlap_y { + let selected_facing_edge = if hovered_max.y < selected_min.y { selected_min.y } else { selected_max.y }; + let hovered_facing_edge = if hovered_max.y < selected_min.y { hovered_max.y } else { hovered_min.y }; + let vertical_line_start = if selected_center.x < hovered_max.x && selected_center.x > hovered_min.x { + selected_center.x + } else { + hovered_center.x + }; + + // Draw vertical solid line with length + let line_start = DVec2::new(vertical_line_start, selected_facing_edge); + let line_end = DVec2::new(vertical_line_start, hovered_facing_edge); + let label_alignment = LabelAlignment::new(true, true, false); + draw_line_with_length(line_start, line_end, transform, document_to_viewport, overlay_context, label_alignment); + } else if overlap_x { + let selected_facing_edge = if hovered_max.x < selected_min.x { selected_min.x } else { selected_max.x }; + let hovered_facing_edge = if hovered_max.x < selected_min.x { hovered_max.x } else { hovered_min.x }; + let horizontal_line_start_y = if selected_center.y < hovered_max.y && selected_center.y > hovered_min.y { + selected_center.y + } else { + hovered_center.y + }; + + // Draw horizontal solid line with length + let line_start = DVec2::new(selected_facing_edge, horizontal_line_start_y); + let line_end = DVec2::new(hovered_facing_edge, horizontal_line_start_y); + let label_alignment = LabelAlignment::new(false, false, true); + draw_line_with_length(line_start, line_end, transform, document_to_viewport, overlay_context, label_alignment); + } +} + +/// Draws measurements for cases where lines cross on both X and Y axes, handling diagonal intersections. +fn draw_two_axis_one_one_crossing(selected_bounds: Rect, hovered_bounds: Rect, transform: DAffine2, document_to_viewport: DAffine2, overlay_context: &mut OverlayContext) { + let (selected_min, selected_max) = (selected_bounds.min(), selected_bounds.max()); + let (hovered_min, hovered_max) = (hovered_bounds.min(), hovered_bounds.max()); + + let mut top_y_bound = f64::min(selected_min.y, hovered_min.y); + let mut bottom_y_bound = f64::max(selected_max.y, hovered_max.y); + let mut top_x_bound = f64::max(selected_max.x, hovered_max.x); + let mut bottom_x_bound = f64::min(selected_min.x, hovered_min.x); + + // Handle diagonal intersection cases by swapping bounds if necessary + if (hovered_bounds.center().x > selected_bounds.center().x && hovered_bounds.center().y < selected_bounds.center().y) + || (hovered_bounds.center().x < selected_bounds.center().x && hovered_bounds.center().y > selected_bounds.center().y) + { + std::mem::swap(&mut top_y_bound, &mut bottom_y_bound); + std::mem::swap(&mut top_x_bound, &mut bottom_x_bound); + } + + // Draw horizontal solid lines with length + let top_x_start = DVec2::new(f64::min(selected_max.x, hovered_max.x), top_y_bound); + let top_x_end = DVec2::new(f64::max(selected_max.x, hovered_max.x), top_y_bound); + let label_alignment = LabelAlignment::new(false, false, true); + draw_line_with_length(top_x_start, top_x_end, transform, document_to_viewport, overlay_context, label_alignment); + + let bottom_x_start = DVec2::new(f64::min(selected_min.x, hovered_min.x), bottom_y_bound); + let bottom_x_end = DVec2::new(f64::max(selected_min.x, hovered_min.x), bottom_y_bound); + let label_alignment = LabelAlignment::new(false, false, false); + draw_line_with_length(bottom_x_start, bottom_x_end, transform, document_to_viewport, overlay_context, label_alignment); + + // Draw vertical solid lines with length + let top_y_start = DVec2::new(top_x_bound, f64::min(selected_min.y, hovered_min.y)); + let top_y_end = DVec2::new(top_x_bound, f64::max(selected_min.y, hovered_min.y)); + let label_alignment = LabelAlignment::new(true, false, false); + draw_line_with_length(top_y_start, top_y_end, transform, document_to_viewport, overlay_context, label_alignment); + + let bottom_y_start = DVec2::new(bottom_x_bound, f64::min(selected_max.y, hovered_max.y)); + let bottom_y_end = DVec2::new(bottom_x_bound, f64::max(selected_max.y, hovered_max.y)); + let label_alignment = LabelAlignment::new(true, true, false); + draw_line_with_length(bottom_y_start, bottom_y_end, transform, document_to_viewport, overlay_context, label_alignment); +} + +/// Draws measurements for partial overlaps with two vertical or horizontal edge intersections. +fn draw_two_axis_one_one_two_zero_crossing( + selected_bounds: Rect, + hovered_bounds: Rect, + transform: DAffine2, + document_to_viewport: DAffine2, + overlay_context: &mut OverlayContext, + two_vertical_edge_intersect: bool, +) { + let (selected_min, selected_max) = (selected_bounds.min(), selected_bounds.max()); + let (hovered_min, hovered_max) = (hovered_bounds.min(), hovered_bounds.max()); + + if two_vertical_edge_intersect { + let selected_bound_edge = if selected_bounds.center().y >= hovered_bounds.center().y { + selected_max.y + } else { + selected_min.y + }; + let hovered_bound_edge = if selected_bounds.center().y >= hovered_bounds.center().y { hovered_max.y } else { hovered_min.y }; + + // Draw vertical solid lines with length + let y_start_left = DVec2::new(hovered_min.x, f64::min(selected_bound_edge, hovered_bound_edge)); + let y_end_left = DVec2::new(hovered_min.x, f64::max(selected_bound_edge, hovered_bound_edge)); + let label_alignment = LabelAlignment::new(true, true, false); + draw_line_with_length(y_start_left, y_end_left, transform, document_to_viewport, overlay_context, label_alignment); + + let y_start_right = DVec2::new(hovered_max.x, f64::min(selected_bound_edge, hovered_bound_edge)); + let y_end_right = DVec2::new(hovered_max.x, f64::max(selected_bound_edge, hovered_bound_edge)); + let label_alignment = LabelAlignment::new(true, false, false); + draw_line_with_length(y_start_right, y_end_right, transform, document_to_viewport, overlay_context, label_alignment); + + // Draw horizontal solid lines with length + let horizontal_line_y_bound = if selected_bounds.center().y >= hovered_bounds.center().y { + f64::max(selected_bound_edge, hovered_bound_edge) + } else { + f64::min(selected_bound_edge, hovered_bound_edge) + }; + + let x_start_left = DVec2::new(hovered_min.x, horizontal_line_y_bound); + let x_end_left = DVec2::new(selected_min.x, horizontal_line_y_bound); + let label_alignment = LabelAlignment::new(false, false, false); + draw_line_with_length(x_start_left, x_end_left, transform, document_to_viewport, overlay_context, label_alignment); + + let x_start_right = DVec2::new(hovered_max.x, horizontal_line_y_bound); + let x_end_right = DVec2::new(selected_max.x, horizontal_line_y_bound); + let label_alignment = LabelAlignment::new(false, false, false); + draw_line_with_length(x_start_right, x_end_right, transform, document_to_viewport, overlay_context, label_alignment); + } else { + let selected_bound_edge = if selected_bounds.center().x >= hovered_bounds.center().x { + selected_max.x + } else { + selected_min.x + }; + let hovered_bound_edge = if selected_bounds.center().x >= hovered_bounds.center().x { hovered_max.x } else { hovered_min.x }; + + // Determine the outermost X position for vertical lines + let vertical_line_x = if selected_bounds.center().x >= hovered_bounds.center().x { + f64::max(selected_bound_edge, hovered_bound_edge) + } else { + f64::min(selected_bound_edge, hovered_bound_edge) + }; + + // Draw vertical solid lines with length + let y_start_up = DVec2::new(vertical_line_x, selected_min.y); + let y_end_up = DVec2::new(vertical_line_x, hovered_min.y); + let label_alignment = LabelAlignment::new(true, false, false); + draw_line_with_length(y_start_up, y_end_up, transform, document_to_viewport, overlay_context, label_alignment); + + let y_start_down = DVec2::new(vertical_line_x, selected_max.y); + let y_end_down = DVec2::new(vertical_line_x, hovered_max.y); + let label_alignment = LabelAlignment::new(true, false, false); + draw_line_with_length(y_start_down, y_end_down, transform, document_to_viewport, overlay_context, label_alignment); + + // Draw horizontal solid lines with length + let horizontal_line_inner_x = if selected_bounds.center().x >= hovered_bounds.center().x { + f64::min(selected_bound_edge, hovered_bound_edge) + } else { + f64::max(selected_bound_edge, hovered_bound_edge) + }; + let x_start_up = DVec2::new(vertical_line_x, f64::min(selected_min.y, hovered_min.y)); + let x_end_up = DVec2::new(horizontal_line_inner_x, f64::min(selected_min.y, hovered_min.y)); + let label_alignment = LabelAlignment::new(false, false, true); + draw_line_with_length(x_start_up, x_end_up, transform, document_to_viewport, overlay_context, label_alignment); + + let x_start_down = DVec2::new(vertical_line_x, f64::max(selected_max.y, hovered_max.y)); + let x_end_down = DVec2::new(horizontal_line_inner_x, f64::max(selected_max.y, hovered_max.y)); + let label_alignment = LabelAlignment::new(false, false, false); + draw_line_with_length(x_start_down, x_end_down, transform, document_to_viewport, overlay_context, label_alignment); + } +} + +/// Draws measurements for cases with two vertical and two horizontal zero crossings. +fn draw_two_axis_two_zero_zero_two(selected_bounds: Rect, hovered_bounds: Rect, transform: DAffine2, document_to_viewport: DAffine2, overlay_context: &mut OverlayContext) { + let (selected_min, selected_max) = (selected_bounds.min(), selected_bounds.max()); + let (hovered_min, hovered_max) = (hovered_bounds.min(), hovered_bounds.max()); + + // Draw vertical solid lines with length + let y_start_left_top = DVec2::new(f64::min(hovered_min.x, selected_min.x), f64::min(hovered_min.y, selected_min.y)); + let y_end_left_top = DVec2::new(f64::min(hovered_min.x, selected_min.x), f64::max(hovered_min.y, selected_min.y)); + let label_alignment = LabelAlignment::new(true, true, false); + draw_line_with_length(y_start_left_top, y_end_left_top, transform, document_to_viewport, overlay_context, label_alignment); + let label_alignment = LabelAlignment::new(true, true, false); + draw_line_with_length(y_start_left_top, y_end_left_top, transform, document_to_viewport, overlay_context, label_alignment); + + let y_start_left_bottom = DVec2::new(f64::min(hovered_min.x, selected_min.x), f64::min(hovered_max.y, selected_max.y)); + let y_end_left_bottom = DVec2::new(f64::min(hovered_min.x, selected_min.x), f64::max(hovered_max.y, selected_max.y)); + let label_alignment = LabelAlignment::new(true, true, false); + draw_line_with_length(y_start_left_bottom, y_end_left_bottom, transform, document_to_viewport, overlay_context, label_alignment); + + let y_start_right_top = DVec2::new(f64::max(hovered_max.x, selected_max.x), f64::min(hovered_min.y, selected_min.y)); + let y_end_right_top = DVec2::new(f64::max(hovered_max.x, selected_max.x), f64::max(hovered_min.y, selected_min.y)); + let label_alignment = LabelAlignment::new(true, false, false); + draw_line_with_length(y_start_right_top, y_end_right_top, transform, document_to_viewport, overlay_context, label_alignment); + + let y_start_right_bottom = DVec2::new(f64::max(hovered_max.x, selected_max.x), f64::min(hovered_max.y, selected_max.y)); + let y_end_right_bottom = DVec2::new(f64::max(hovered_max.x, selected_max.x), f64::max(hovered_max.y, selected_max.y)); + let label_alignment = LabelAlignment::new(true, false, false); + draw_line_with_length(y_start_right_bottom, y_end_right_bottom, transform, document_to_viewport, overlay_context, label_alignment); + + // Draw horizontal solid lines with length + let x_start_left_top = DVec2::new(f64::min(hovered_min.x, selected_min.x), f64::min(hovered_min.y, selected_min.y)); + let x_end_left_top = DVec2::new(f64::max(hovered_min.x, selected_min.x), f64::min(hovered_min.y, selected_min.y)); + let label_alignment = LabelAlignment::new(false, false, true); + draw_line_with_length(x_start_left_top, x_end_left_top, transform, document_to_viewport, overlay_context, label_alignment); + + let x_start_right_top = DVec2::new(f64::min(hovered_max.x, selected_max.x), f64::min(hovered_min.y, selected_min.y)); + let x_end_right_top = DVec2::new(f64::max(hovered_max.x, selected_max.x), f64::min(hovered_min.y, selected_min.y)); + let label_alignment = LabelAlignment::new(false, false, true); + draw_line_with_length(x_start_right_top, x_end_right_top, transform, document_to_viewport, overlay_context, label_alignment); + + let x_start_left_bottom = DVec2::new(f64::min(hovered_min.x, selected_min.x), f64::max(hovered_max.y, selected_max.y)); + let x_end_left_bottom = DVec2::new(f64::max(hovered_min.x, selected_min.x), f64::max(hovered_max.y, selected_max.y)); + let label_alignment = LabelAlignment::new(false, false, false); + draw_line_with_length(x_start_left_bottom, x_end_left_bottom, transform, document_to_viewport, overlay_context, label_alignment); + + let x_start_right_bottom = DVec2::new(f64::min(hovered_max.x, selected_max.x), f64::max(hovered_max.y, selected_max.y)); + let x_end_right_bottom = DVec2::new(f64::max(hovered_max.x, selected_max.x), f64::max(hovered_max.y, selected_max.y)); + let label_alignment = LabelAlignment::new(false, false, false); + draw_line_with_length(x_start_right_bottom, x_end_right_bottom, transform, document_to_viewport, overlay_context, label_alignment); +} + +/// Draws measurements where selected and hovered bounds have two vertical edges crossing each other. +fn draw_two_axis_two_zero_two_zero(selected_bounds: Rect, hovered_bounds: Rect, transform: DAffine2, document_to_viewport: DAffine2, overlay_context: &mut OverlayContext) { + let (selected_min, selected_max) = (selected_bounds.min(), selected_bounds.max()); + let (hovered_min, hovered_max) = (hovered_bounds.min(), hovered_bounds.max()); + + // Draw horizontal solid lines with length + let x_start_left = DVec2::new(f64::max(hovered_min.x, selected_min.x), selected_bounds.center().y); + let x_end_left = DVec2::new(f64::min(hovered_min.x, selected_min.x), selected_bounds.center().y); + let label_alignment = LabelAlignment::new(false, false, true); + draw_line_with_length(x_start_left, x_end_left, transform, document_to_viewport, overlay_context, label_alignment); + + let x_start_right = DVec2::new(f64::min(hovered_max.x, selected_max.x), selected_bounds.center().y); + let x_end_right = DVec2::new(f64::max(hovered_max.x, selected_max.x), selected_bounds.center().y); + let label_alignment = LabelAlignment::new(false, false, true); + draw_line_with_length(x_start_right, x_end_right, transform, document_to_viewport, overlay_context, label_alignment); + + // Draw vertical solid lines with length + let y_start_top = DVec2::new(selected_bounds.center().x, f64::max(hovered_min.y, selected_min.y)); + let y_end_top = DVec2::new(selected_bounds.center().x, f64::min(hovered_min.y, selected_min.y)); + let label_alignment = LabelAlignment::new(true, false, false); + draw_line_with_length(y_start_top, y_end_top, transform, document_to_viewport, overlay_context, label_alignment); + + let y_start_bottom = DVec2::new(selected_bounds.center().x, f64::min(hovered_max.y, selected_max.y)); + let y_end_bottom = DVec2::new(selected_bounds.center().x, f64::max(hovered_max.y, selected_max.y)); + let label_alignment = LabelAlignment::new(true, false, false); + draw_line_with_length(y_start_bottom, y_end_bottom, transform, document_to_viewport, overlay_context, label_alignment); +} + +/// Handles overlapping scenarios involving two axes between selected and hovered bounds. +fn handle_two_axis_overlap(selected_bounds: Rect, hovered_bounds: Rect, transform: DAffine2, document_to_viewport: DAffine2, overlay_context: &mut OverlayContext) { + let (selected_min, selected_max) = (selected_bounds.min(), selected_bounds.max()); + let (hovered_min, hovered_max) = (hovered_bounds.min(), hovered_bounds.max()); + + // Calculate edge crossings on the X-axis + let selected_x_crosses = (selected_min.y >= hovered_min.y && selected_min.y <= hovered_max.y) as u8 + (selected_max.y >= hovered_min.y && selected_max.y <= hovered_max.y) as u8; + let hovered_x_crosses = (hovered_min.y >= selected_min.y && hovered_min.y <= selected_max.y) as u8 + (hovered_max.y >= selected_min.y && hovered_max.y <= selected_max.y) as u8; + + // Calculate edge crossings on the Y-axis + let selected_y_crosses = (selected_min.x >= hovered_min.x && selected_min.x <= hovered_max.x) as u8 + (selected_max.x >= hovered_min.x && selected_max.x <= hovered_max.x) as u8; + let hovered_y_crosses = (hovered_min.x >= selected_min.x && hovered_min.x <= selected_max.x) as u8 + (hovered_max.x >= selected_min.x && hovered_max.x <= selected_max.x) as u8; + + // Determine the overlap case based on edge crossings + match ((selected_x_crosses, hovered_x_crosses), (selected_y_crosses, hovered_y_crosses)) { + ((1, 1), (1, 1)) => draw_two_axis_one_one_crossing(selected_bounds, hovered_bounds, transform, document_to_viewport, overlay_context), + ((1, 1), (2, 0)) => draw_two_axis_one_one_two_zero_crossing(selected_bounds, hovered_bounds, transform, document_to_viewport, overlay_context, true), + ((1, 1), (0, 2)) => draw_two_axis_one_one_two_zero_crossing(hovered_bounds, selected_bounds, transform, document_to_viewport, overlay_context, true), + ((2, 0), (1, 1)) => draw_two_axis_one_one_two_zero_crossing(selected_bounds, hovered_bounds, transform, document_to_viewport, overlay_context, false), + ((0, 2), (1, 1)) => draw_two_axis_one_one_two_zero_crossing(hovered_bounds, selected_bounds, transform, document_to_viewport, overlay_context, false), + ((2, 0), (0, 2)) | ((0, 2), (2, 0)) => draw_two_axis_two_zero_zero_two(selected_bounds, hovered_bounds, transform, document_to_viewport, overlay_context), + ((2, 0), (2, 0)) | ((0, 2), (0, 2)) => draw_two_axis_two_zero_two_zero(selected_bounds, hovered_bounds, transform, document_to_viewport, overlay_context), + _ => (), + } +} + +/// Overlays measurement lines between selected and hovered bounds based on their spatial relationships. +pub fn overlay(selected_bounds: Rect, hovered_bounds: Rect, transform: DAffine2, document_to_viewport: DAffine2, overlay_context: &mut OverlayContext) { + draw_dashed_rect_outline(selected_bounds, transform, overlay_context); + draw_dashed_rect_outline(hovered_bounds, transform, overlay_context); + let (selected_min, selected_max) = (selected_bounds.min(), selected_bounds.max()); + let (hovered_min, hovered_max) = (hovered_bounds.min(), hovered_bounds.max()); + + // Determine axis overlaps + let overlap_y = does_overlap_y(selected_bounds, hovered_bounds) || does_overlap_y(hovered_bounds, selected_bounds); + let overlap_x = does_overlap_x(selected_bounds, hovered_bounds) || does_overlap_x(hovered_bounds, selected_bounds); + let overlap_axes = match (overlap_x, overlap_y) { + (true, true) => 2, + (true, false) | (false, true) => 1, + _ => 0, + }; + + // Determine centerline crossings + let center_x_intersects = + (selected_bounds.center().y >= hovered_min.y && selected_bounds.center().y <= hovered_max.y) || (hovered_bounds.center().y >= selected_min.y && hovered_bounds.center().y <= selected_max.y); + let center_y_intersects = + (selected_bounds.center().x >= hovered_min.x && selected_bounds.center().x <= hovered_max.x) || (hovered_bounds.center().x >= selected_min.x && hovered_bounds.center().x <= selected_max.x); + let centerline_crosses = match (center_x_intersects, center_y_intersects) { + (true, true) => 2, + (true, false) | (false, true) => 1, + _ => 0, + }; + + // Handle each overlap case + match (overlap_axes, centerline_crosses) { + (0, _) => draw_zero_axis_crossings(selected_bounds, hovered_bounds, transform, document_to_viewport, overlay_context), + (1, 0) => draw_single_axis_zero_crossings(selected_bounds, hovered_bounds, transform, document_to_viewport, overlay_context), + (1, 1) | (1, 2) => draw_single_axis_one_crossings(selected_bounds, hovered_bounds, transform, document_to_viewport, overlay_context), + (2, _) => handle_two_axis_overlap(selected_bounds, hovered_bounds, transform, document_to_viewport, overlay_context), + _ => (), // Fallback case, should not typically happen + } +} + +struct LabelAlignment { + is_vertical_line: bool, + text_on_left: bool, + text_on_top: bool, +} + +impl LabelAlignment { + fn new(is_vertical_line: bool, text_on_left: bool, text_on_top: bool) -> Self { + Self { + is_vertical_line, + text_on_left, + text_on_top, + } + } +} diff --git a/editor/src/messages/tool/common_functionality/mod.rs b/editor/src/messages/tool/common_functionality/mod.rs new file mode 100644 index 0000000000000000000000000000000000000000..ca3e629e195aa25c5e909b82867dfc1da1e386f6 --- /dev/null +++ b/editor/src/messages/tool/common_functionality/mod.rs @@ -0,0 +1,13 @@ +pub mod auto_panning; +pub mod color_selector; +pub mod compass_rose; +pub mod gizmos; +pub mod graph_modification_utils; +pub mod measure; +pub mod pivot; +pub mod resize; +pub mod shape_editor; +pub mod shapes; +pub mod snapping; +pub mod transformation_cage; +pub mod utility_functions; diff --git a/editor/src/messages/tool/common_functionality/pivot.rs b/editor/src/messages/tool/common_functionality/pivot.rs new file mode 100644 index 0000000000000000000000000000000000000000..67ce7f5dc55a6b52226665362cf89458ad229b11 --- /dev/null +++ b/editor/src/messages/tool/common_functionality/pivot.rs @@ -0,0 +1,154 @@ +//! Handler for the pivot overlay visible on the selected layer(s) whilst using the Select tool which controls the center of rotation/scale and origin of the layer. + +use super::graph_modification_utils; +use crate::consts::PIVOT_DIAMETER; +use crate::messages::portfolio::document::overlays::utility_types::OverlayContext; +use crate::messages::portfolio::document::utility_types::document_metadata::LayerNodeIdentifier; +use crate::messages::prelude::*; +use glam::{DAffine2, DVec2}; +use graphene_std::transform::ReferencePoint; +use std::collections::VecDeque; + +#[derive(Clone, Debug)] +pub struct Pivot { + /// Pivot between (0,0) and (1,1) + normalized_pivot: DVec2, + /// Transform to get from normalized pivot to viewspace + transform_from_normalized: DAffine2, + /// The viewspace pivot position (if applicable) + pivot: Option, + /// The old pivot position in the GUI, used to reduce refreshes of the document bar + old_pivot_position: ReferencePoint, + /// Used to enable and disable the pivot + active: bool, +} + +impl Default for Pivot { + fn default() -> Self { + Self { + normalized_pivot: DVec2::splat(0.5), + transform_from_normalized: Default::default(), + pivot: Default::default(), + old_pivot_position: ReferencePoint::Center, + active: true, + } + } +} + +impl Pivot { + /// Calculates the transform that gets from normalized pivot to viewspace. + fn get_layer_pivot_transform(layer: LayerNodeIdentifier, document: &DocumentMessageHandler) -> DAffine2 { + let [min, max] = document.metadata().nonzero_bounding_box(layer); + + let bounds_transform = DAffine2::from_translation(min) * DAffine2::from_scale(max - min); + let layer_transform = document.metadata().transform_to_viewport(layer); + layer_transform * bounds_transform + } + + /// Recomputes the pivot position and transform. + fn recalculate_pivot(&mut self, document: &DocumentMessageHandler) { + if !self.active { + return; + } + + let selected_nodes = document.network_interface.selected_nodes(); + let mut layers = selected_nodes.selected_visible_and_unlocked_layers(&document.network_interface); + let Some(first) = layers.next() else { + // If no layers are selected then we revert things back to default + self.normalized_pivot = DVec2::splat(0.5); + self.pivot = None; + return; + }; + + // Add one because the first item is consumed above. + let selected_layers_count = layers.count() + 1; + + // If just one layer is selected we can use its inner transform (as it accounts for rotation) + if selected_layers_count == 1 { + let normalized_pivot = graph_modification_utils::get_pivot(first, &document.network_interface).unwrap_or(DVec2::splat(0.5)); + self.normalized_pivot = normalized_pivot; + self.transform_from_normalized = Self::get_layer_pivot_transform(first, document); + self.pivot = Some(self.transform_from_normalized.transform_point2(normalized_pivot)); + } else { + // If more than one layer is selected we use the AABB with the mean of the pivots + let xy_summation = document + .network_interface + .selected_nodes() + .selected_visible_and_unlocked_layers(&document.network_interface) + .map(|layer| graph_modification_utils::get_viewport_pivot(layer, &document.network_interface)) + .reduce(|a, b| a + b) + .unwrap_or_default(); + + let pivot = xy_summation / selected_layers_count as f64; + self.pivot = Some(pivot); + let [min, max] = document.selected_visible_and_unlock_layers_bounding_box_viewport().unwrap_or([DVec2::ZERO, DVec2::ONE]); + self.normalized_pivot = (pivot - min) / (max - min); + + self.transform_from_normalized = DAffine2::from_translation(min) * DAffine2::from_scale(max - min); + } + } + + pub fn update_pivot(&mut self, document: &DocumentMessageHandler, overlay_context: &mut OverlayContext, draw_data: Option<(f64,)>) { + if !overlay_context.visibility_settings.pivot() { + self.active = false; + return; + } else { + self.active = true; + } + + self.recalculate_pivot(document); + if let (Some(pivot), Some(data)) = (self.pivot, draw_data) { + overlay_context.pivot(pivot, data.0); + } + } + + /// Answers if the pivot widget has changed (so we should refresh the tool bar at the top of the canvas). + pub fn should_refresh_pivot_position(&mut self) -> bool { + if !self.active { + return false; + } + + let new = self.to_pivot_position(); + let should_refresh = new != self.old_pivot_position; + self.old_pivot_position = new; + should_refresh + } + + pub fn to_pivot_position(&self) -> ReferencePoint { + self.normalized_pivot.into() + } + + /// Sets the viewport position of the pivot for all selected layers. + pub fn set_viewport_position(&self, position: DVec2, document: &DocumentMessageHandler, responses: &mut VecDeque) { + if !self.active { + return; + } + + for layer in document.network_interface.selected_nodes().selected_visible_and_unlocked_layers(&document.network_interface) { + let transform = Self::get_layer_pivot_transform(layer, document); + // Only update the pivot when computed position is finite. + if transform.matrix2.determinant().abs() <= f64::EPSILON { + return; + }; + let pivot = transform.inverse().transform_point2(position); + responses.add(GraphOperationMessage::TransformSetPivot { layer, pivot }); + } + } + + /// Set the pivot using the normalized transform that is set above. + pub fn set_normalized_position(&self, position: DVec2, document: &DocumentMessageHandler, responses: &mut VecDeque) { + if !self.active { + return; + } + + self.set_viewport_position(self.transform_from_normalized.transform_point2(position), document, responses); + } + + /// Answers if the pointer is currently positioned over the pivot. + pub fn is_over(&self, mouse: DVec2) -> bool { + if !self.active { + return false; + } + self.pivot.filter(|&pivot| mouse.distance_squared(pivot) < (PIVOT_DIAMETER / 2.).powi(2)).is_some() + } +} diff --git a/editor/src/messages/tool/common_functionality/resize.rs b/editor/src/messages/tool/common_functionality/resize.rs new file mode 100644 index 0000000000000000000000000000000000000000..fc8f1ee6da643a7b7811e1b888ffe203b74ef710 --- /dev/null +++ b/editor/src/messages/tool/common_functionality/resize.rs @@ -0,0 +1,120 @@ +use crate::messages::input_mapper::utility_types::input_keyboard::Key; +use crate::messages::portfolio::document::graph_operation::utility_types::TransformIn; +use crate::messages::portfolio::document::utility_types::document_metadata::LayerNodeIdentifier; +use crate::messages::prelude::*; +use crate::messages::tool::common_functionality::snapping::{SnapCandidatePoint, SnapConstraint, SnapData, SnapManager, SnapTypeConfiguration}; +use glam::{DAffine2, DVec2, Vec2Swizzles}; + +#[derive(Clone, Debug, Default)] +pub struct Resize { + /// Stored as a document position so the start doesn't move if the canvas is panned. + pub drag_start: DVec2, + pub layer: Option, + pub snap_manager: SnapManager, +} + +impl Resize { + /// Starts a resize, assigning the snap targets and snapping the starting position. + pub fn start(&mut self, document: &DocumentMessageHandler, input: &InputPreprocessorMessageHandler) { + let root_transform = document.metadata().document_to_viewport; + let point = SnapCandidatePoint::handle(root_transform.inverse().transform_point2(input.mouse.position)); + let snapped = self.snap_manager.free_snap(&SnapData::new(document, input), &point, SnapTypeConfiguration::default()); + self.drag_start = snapped.snapped_point_document; + } + + /// Calculate the drag start position in viewport space. + pub fn viewport_drag_start(&self, document: &DocumentMessageHandler) -> DVec2 { + let root_transform = document.metadata().document_to_viewport; + root_transform.transform_point2(self.drag_start) + } + + /// Compute the drag start and end based on the current mouse position. If the layer doesn't exist, returns [`None`]. + /// If you want to draw even without a layer, use [`Resize::calculate_points_ignore_layer`]. + pub fn calculate_points(&mut self, document: &DocumentMessageHandler, input: &InputPreprocessorMessageHandler, center: Key, lock_ratio: Key) -> Option<[DVec2; 2]> { + let layer = self.layer?; + + if layer == LayerNodeIdentifier::ROOT_PARENT { + log::error!("Resize layer cannot be ROOT_PARENT"); + return None; + } + + if !document.network_interface.document_network().nodes.contains_key(&layer.to_node()) { + self.layer.take(); + return None; + } + Some(self.calculate_points_ignore_layer(document, input, center, lock_ratio, false)) + } + + /// Compute the drag start and end based on the current mouse position. Ignores the state of the layer. + /// If you want to only draw whilst a layer exists, use [`Resize::calculate_points`]. + pub fn calculate_points_ignore_layer(&mut self, document: &DocumentMessageHandler, input: &InputPreprocessorMessageHandler, center: Key, lock_ratio: Key, in_document: bool) -> [DVec2; 2] { + let start = self.viewport_drag_start(document); + let mouse = input.mouse.position; + let document_to_viewport = document.navigation_handler.calculate_offset_transform(input.viewport_bounds.center(), &document.document_ptz); + let document_mouse = document_to_viewport.inverse().transform_point2(mouse); + let mut points_viewport = [start, mouse]; + let ignore = if let Some(layer) = self.layer { vec![layer] } else { vec![] }; + let ratio = input.keyboard.get(lock_ratio as usize); + let center = input.keyboard.get(center as usize); + let snap_data = SnapData::ignore(document, input, &ignore); + let config = SnapTypeConfiguration::default(); + if ratio { + let viewport_size = points_viewport[1] - points_viewport[0]; + let raw_size = if in_document { document_to_viewport.inverse() } else { DAffine2::IDENTITY }.transform_vector2(viewport_size); + let adjusted_size = raw_size.abs().max(raw_size.abs().yx()) * raw_size.signum(); + let size = if in_document { document_to_viewport.transform_vector2(adjusted_size) } else { adjusted_size }; + points_viewport[1] = points_viewport[0] + size; + + let end_document = document_to_viewport.inverse().transform_point2(points_viewport[1]); + let constraint = SnapConstraint::Line { + origin: self.drag_start, + direction: end_document - self.drag_start, + }; + if center { + let snapped = self.snap_manager.constrained_snap(&snap_data, &SnapCandidatePoint::handle(end_document), constraint, config); + let far = SnapCandidatePoint::handle(2. * self.drag_start - end_document); + let snapped_far = self.snap_manager.constrained_snap(&snap_data, &far, constraint, config); + let best = if snapped_far.other_snap_better(&snapped) { snapped } else { snapped_far }; + points_viewport[0] = document_to_viewport.transform_point2(best.snapped_point_document); + points_viewport[1] = document_to_viewport.transform_point2(self.drag_start * 2. - best.snapped_point_document); + self.snap_manager.update_indicator(best); + } else { + let snapped = self.snap_manager.constrained_snap(&snap_data, &SnapCandidatePoint::handle(end_document), constraint, config); + points_viewport[1] = document_to_viewport.transform_point2(snapped.snapped_point_document); + self.snap_manager.update_indicator(snapped); + } + } else if center { + let snapped = self.snap_manager.free_snap(&snap_data, &SnapCandidatePoint::handle(document_mouse), config); + let opposite = 2. * self.drag_start - document_mouse; + let snapped_far = self.snap_manager.free_snap(&snap_data, &SnapCandidatePoint::handle(opposite), config); + let best = if snapped_far.other_snap_better(&snapped) { snapped } else { snapped_far }; + points_viewport[0] = document_to_viewport.transform_point2(best.snapped_point_document); + points_viewport[1] = document_to_viewport.transform_point2(self.drag_start * 2. - best.snapped_point_document); + self.snap_manager.update_indicator(best); + } else { + let snapped = self.snap_manager.free_snap(&snap_data, &SnapCandidatePoint::handle(document_mouse), config); + points_viewport[1] = document_to_viewport.transform_point2(snapped.snapped_point_document); + self.snap_manager.update_indicator(snapped); + } + + points_viewport + } + + pub fn calculate_transform(&mut self, document: &DocumentMessageHandler, input: &InputPreprocessorMessageHandler, center: Key, lock_ratio: Key, skip_rerender: bool) -> Option { + let points_viewport = self.calculate_points(document, input, center, lock_ratio)?; + Some( + GraphOperationMessage::TransformSet { + layer: self.layer?, + transform: DAffine2::from_scale_angle_translation(points_viewport[1] - points_viewport[0], 0., points_viewport[0]), + transform_in: TransformIn::Viewport, + skip_rerender, + } + .into(), + ) + } + + pub fn cleanup(&mut self, responses: &mut VecDeque) { + self.snap_manager.cleanup(responses); + self.layer = None; + } +} diff --git a/editor/src/messages/tool/common_functionality/shape_editor.rs b/editor/src/messages/tool/common_functionality/shape_editor.rs new file mode 100644 index 0000000000000000000000000000000000000000..b491e0943d62cef0038f7976044dfa7031421439 --- /dev/null +++ b/editor/src/messages/tool/common_functionality/shape_editor.rs @@ -0,0 +1,1973 @@ +use super::graph_modification_utils::merge_layers; +use super::snapping::{SnapCache, SnapCandidatePoint, SnapData, SnapManager, SnappedPoint}; +use super::utility_functions::{adjust_handle_colinearity, calculate_bezier_bbox, calculate_segment_angle, restore_g1_continuity, restore_previous_handle_position}; +use crate::consts::HANDLE_LENGTH_FACTOR; +use crate::messages::portfolio::document::overlays::utility_functions::selected_segments; +use crate::messages::portfolio::document::utility_types::document_metadata::{DocumentMetadata, LayerNodeIdentifier}; +use crate::messages::portfolio::document::utility_types::misc::{PathSnapSource, SnapSource}; +use crate::messages::portfolio::document::utility_types::network_interface::NodeNetworkInterface; +use crate::messages::preferences::SelectionMode; +use crate::messages::prelude::*; +use crate::messages::tool::common_functionality::snapping::SnapTypeConfiguration; +use crate::messages::tool::common_functionality::utility_functions::{is_intersecting, is_visible_point}; +use crate::messages::tool::tool_messages::path_tool::{PathOverlayMode, PointSelectState}; +use bezier_rs::{Bezier, BezierHandles, Subpath, TValue}; +use glam::{DAffine2, DVec2}; +use graphene_std::vector::{HandleExt, HandleId, SegmentId}; +use graphene_std::vector::{ManipulatorPointId, PointId, VectorData, VectorModificationType}; + +#[derive(Debug, Copy, Clone, PartialEq, Eq)] +pub enum SelectionChange { + Clear, + Extend, + Shrink, +} + +#[derive(Clone, Copy, Debug)] +pub enum SelectionShape<'a> { + Box([DVec2; 2]), + Lasso(&'a Vec), +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] +pub enum SelectionShapeType { + Box, + Lasso, +} + +#[derive(Debug, PartialEq, Eq, Copy, Clone, Default)] +pub enum ManipulatorAngle { + #[default] + Colinear, + Free, + Mixed, +} + +#[derive(Clone, Debug, Default)] +pub struct SelectedLayerState { + selected_points: HashSet, + selected_segments: HashSet, + /// Keeps track of the current state; helps avoid unnecessary computation when called by [`ShapeState`]. + ignore_handles: bool, + ignore_anchors: bool, + /// Points that are selected but ignored (when their overlays are disabled) are stored here. + ignored_handle_points: HashSet, + ignored_anchor_points: HashSet, +} + +impl SelectedLayerState { + pub fn selected_points(&self) -> impl Iterator + '_ { + self.selected_points.iter().copied() + } + + pub fn selected_segments(&self) -> impl Iterator + '_ { + self.selected_segments.iter().copied() + } + + pub fn selected_points_count(&self) -> usize { + self.selected_points.len() + } + + pub fn selected_segments_count(&self) -> usize { + self.selected_segments.len() + } + + pub fn is_segment_selected(&self, segment: SegmentId) -> bool { + self.selected_segments.contains(&segment) + } + + pub fn is_point_selected(&self, point: ManipulatorPointId) -> bool { + self.selected_points.contains(&point) + } + + pub fn select_point(&mut self, point: ManipulatorPointId) { + self.selected_points.insert(point); + } + + pub fn select_segment(&mut self, segment: SegmentId) { + self.selected_segments.insert(segment); + } + + pub fn deselect_point(&mut self, point: ManipulatorPointId) { + self.selected_points.remove(&point); + } + + pub fn deselect_segment(&mut self, segment: SegmentId) { + self.selected_segments.remove(&segment); + } + + pub fn clear_points(&mut self) { + self.selected_points.clear(); + } + + pub fn clear_segments(&mut self) { + self.selected_segments.clear(); + } + + pub fn ignore_handles(&mut self, status: bool) { + if self.ignore_handles != status { + return; + } + + self.ignore_handles = !status; + + if self.ignore_handles { + self.ignored_handle_points.extend(self.selected_points.iter().copied().filter(|point| point.as_handle().is_some())); + self.selected_points.retain(|point| !self.ignored_handle_points.contains(point)); + } else { + self.selected_points.extend(self.ignored_handle_points.iter().copied()); + self.ignored_handle_points.clear(); + } + } + + pub fn ignore_anchors(&mut self, status: bool) { + if self.ignore_anchors != status { + return; + } + + self.ignore_anchors = !status; + + if self.ignore_anchors { + self.ignored_anchor_points.extend(self.selected_points.iter().copied().filter(|point| point.as_anchor().is_some())); + self.selected_points.retain(|point| !self.ignored_anchor_points.contains(point)); + } else { + self.selected_points.extend(self.ignored_anchor_points.iter().copied()); + self.ignored_anchor_points.clear(); + } + } +} + +pub type SelectedShapeState = HashMap; + +#[derive(Debug, Default)] +pub struct ShapeState { + /// The layers we can select and edit manipulators (anchors and handles) from. + pub selected_shape_state: SelectedShapeState, + ignore_handles: bool, + ignore_anchors: bool, +} + +#[derive(Debug)] +pub struct SelectedPointsInfo { + pub points: Vec, + pub offset: DVec2, + pub vector_data: VectorData, +} + +#[derive(Debug)] +pub struct SelectedSegmentsInfo { + pub segments: Vec, + pub vector_data: VectorData, +} + +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +pub struct ManipulatorPointInfo { + pub layer: LayerNodeIdentifier, + pub point_id: ManipulatorPointId, +} + +pub type OpposingHandleLengths = HashMap>; + +#[derive(Clone)] +pub struct ClosestSegment { + layer: LayerNodeIdentifier, + segment: SegmentId, + bezier: Bezier, + points: [PointId; 2], + colinear: [Option; 2], + t: f64, + bezier_point_to_viewport: DVec2, +} + +impl ClosestSegment { + pub fn layer(&self) -> LayerNodeIdentifier { + self.layer + } + + pub fn segment(&self) -> SegmentId { + self.segment + } + + pub fn points(&self) -> [PointId; 2] { + self.points + } + + pub fn bezier(&self) -> Bezier { + self.bezier + } + + pub fn closest_point_document(&self) -> DVec2 { + self.bezier.evaluate(TValue::Parametric(self.t)) + } + + pub fn closest_point_to_viewport(&self) -> DVec2 { + self.bezier_point_to_viewport + } + + pub fn closest_point(&self, document_metadata: &DocumentMetadata) -> DVec2 { + let transform = document_metadata.transform_to_viewport(self.layer); + let bezier_point = self.bezier.evaluate(TValue::Parametric(self.t)); + transform.transform_point2(bezier_point) + } + + /// Updates this [`ClosestSegment`] with the viewport-space location of the closest point on the segment to the given mouse position. + pub fn update_closest_point(&mut self, document_metadata: &DocumentMetadata, mouse_position: DVec2) { + let transform = document_metadata.transform_to_viewport(self.layer); + let layer_mouse_pos = transform.inverse().transform_point2(mouse_position); + + let t = self.bezier.project(layer_mouse_pos).clamp(0., 1.); + self.t = t; + + let bezier_point = self.bezier.evaluate(TValue::Parametric(t)); + let bezier_point = transform.transform_point2(bezier_point); + self.bezier_point_to_viewport = bezier_point; + } + + pub fn distance_squared(&self, mouse_position: DVec2) -> f64 { + self.bezier_point_to_viewport.distance_squared(mouse_position) + } + + pub fn too_far(&self, mouse_position: DVec2, tolerance: f64) -> bool { + tolerance.powi(2) < self.distance_squared(mouse_position) + } + + pub fn handle_positions(&self, document_metadata: &DocumentMetadata) -> (Option, Option) { + // Transform to viewport space + let transform = document_metadata.transform_to_viewport(self.layer); + + // Split the Bezier at the parameter `t` + let [first, second] = self.bezier.split(TValue::Parametric(self.t)); + + // Transform the handle positions to viewport space + let first_handle = first.handle_end().map(|handle| transform.transform_point2(handle)); + let second_handle = second.handle_start().map(|handle| transform.transform_point2(handle)); + + (first_handle, second_handle) + } + + pub fn adjusted_insert(&self, responses: &mut VecDeque) -> (PointId, [SegmentId; 2]) { + let layer = self.layer; + let [first, second] = self.bezier.split(TValue::Parametric(self.t)); + + // Point + let midpoint = PointId::generate(); + let modification_type = VectorModificationType::InsertPoint { id: midpoint, position: first.end }; + responses.add(GraphOperationMessage::Vector { layer, modification_type }); + + // First segment + let segment_ids = [SegmentId::generate(), SegmentId::generate()]; + let modification_type = VectorModificationType::InsertSegment { + id: segment_ids[0], + points: [self.points[0], midpoint], + handles: [first.handle_start().map(|handle| handle - first.start), first.handle_end().map(|handle| handle - first.end)], + }; + responses.add(GraphOperationMessage::Vector { layer, modification_type }); + + // Last segment + let modification_type = VectorModificationType::InsertSegment { + id: segment_ids[1], + points: [midpoint, self.points[1]], + handles: [second.handle_start().map(|handle| handle - second.start), second.handle_end().map(|handle| handle - second.end)], + }; + responses.add(GraphOperationMessage::Vector { layer, modification_type }); + + // G1 continuous on new handles + if self.bezier.handle_end().is_some() { + let handles = [HandleId::end(segment_ids[0]), HandleId::primary(segment_ids[1])]; + let modification_type = VectorModificationType::SetG1Continuous { handles, enabled: true }; + responses.add(GraphOperationMessage::Vector { layer, modification_type }); + } + + // Remove old segment + let modification_type = VectorModificationType::RemoveSegment { id: self.segment }; + responses.add(GraphOperationMessage::Vector { layer, modification_type }); + + // Restore mirroring on end handles + for (handle, other) in self.colinear.into_iter().zip([HandleId::primary(segment_ids[0]), HandleId::end(segment_ids[1])]) { + let Some(handle) = handle else { continue }; + let handles = [handle, other]; + let modification_type = VectorModificationType::SetG1Continuous { handles, enabled: true }; + responses.add(GraphOperationMessage::Vector { layer, modification_type }); + } + + (midpoint, segment_ids) + } + + pub fn adjusted_insert_and_select(&self, shape_editor: &mut ShapeState, responses: &mut VecDeque, extend_selection: bool) { + let (id, _) = self.adjusted_insert(responses); + shape_editor.select_anchor_point_by_id(self.layer, id, extend_selection) + } + + pub fn calculate_perp(&self, document: &DocumentMessageHandler) -> DVec2 { + let tangent = if let (Some(handle1), Some(handle2)) = self.handle_positions(document.metadata()) { + (handle1 - handle2).try_normalize() + } else { + let [first_point, last_point] = self.points(); + if let Some(vector_data) = document.network_interface.compute_modified_vector(self.layer()) { + if let (Some(pos1), Some(pos2)) = ( + ManipulatorPointId::Anchor(first_point).get_position(&vector_data), + ManipulatorPointId::Anchor(last_point).get_position(&vector_data), + ) { + (pos1 - pos2).try_normalize() + } else { + None + } + } else { + None + } + } + .unwrap_or(DVec2::ZERO); + tangent.perp() + } + + /// Molding the bezier curve. + /// Returns adjacent handles' [`HandleId`] if colinearity is broken temporarily. + pub fn mold_handle_positions( + &self, + document: &DocumentMessageHandler, + responses: &mut VecDeque, + (c1, c2): (DVec2, DVec2), + new_b: DVec2, + break_colinear_molding: bool, + temporary_adjacent_handles_while_molding: Option<[Option; 2]>, + ) -> Option<[Option; 2]> { + let transform = document.metadata().transform_to_viewport(self.layer); + + let start = self.bezier.start; + let end = self.bezier.end; + + // Apply the drag delta to the segment's handles + let b = self.bezier_point_to_viewport; + let delta = transform.inverse().transform_vector2(new_b - b); + let (nc1, nc2) = (c1 + delta, c2 + delta); + + let handle1 = HandleId::primary(self.segment); + let handle2 = HandleId::end(self.segment); + let layer = self.layer; + + let modification_type = handle1.set_relative_position(nc1 - start); + responses.add(GraphOperationMessage::Vector { layer, modification_type }); + + let modification_type = handle2.set_relative_position(nc2 - end); + responses.add(GraphOperationMessage::Vector { layer, modification_type }); + + // If adjacent segments have colinear handles, their direction is changed but their handle lengths is preserved + // TODO: Find something which is more appropriate + let vector_data = document.network_interface.compute_modified_vector(self.layer())?; + + if break_colinear_molding { + // Disable G1 continuity + let other_handles = [ + restore_previous_handle_position(handle1, c1, start, &vector_data, layer, responses), + restore_previous_handle_position(handle2, c2, end, &vector_data, layer, responses), + ]; + + // Store other HandleId in tool data to regain colinearity later + if temporary_adjacent_handles_while_molding.is_some() { + temporary_adjacent_handles_while_molding + } else { + Some(other_handles) + } + } else { + // Move the colinear handles so that colinearity is maintained + adjust_handle_colinearity(handle1, start, nc1, &vector_data, layer, responses); + adjust_handle_colinearity(handle2, end, nc2, &vector_data, layer, responses); + + if let Some(adjacent_handles) = temporary_adjacent_handles_while_molding { + if let Some(other_handle1) = adjacent_handles[0] { + restore_g1_continuity(handle1, other_handle1, nc1, start, &vector_data, layer, responses); + } + if let Some(other_handle2) = adjacent_handles[1] { + restore_g1_continuity(handle2, other_handle2, nc2, end, &vector_data, layer, responses); + } + } + None + } + } +} + +// TODO Consider keeping a list of selected manipulators to minimize traversals of the layers +impl ShapeState { + pub fn is_point_ignored(&self, point: &ManipulatorPointId) -> bool { + (point.as_handle().is_some() && self.ignore_handles) || (point.as_anchor().is_some() && self.ignore_anchors) + } + + pub fn close_selected_path(&self, document: &DocumentMessageHandler, responses: &mut VecDeque) { + // First collect all selected anchor points across all layers + let all_selected_points: Vec<(LayerNodeIdentifier, PointId)> = self + .selected_shape_state + .iter() + .flat_map(|(&layer, state)| { + if document.network_interface.compute_modified_vector(layer).is_none() { + return Vec::new().into_iter(); + }; + + // Collect selected anchor points from this layer + state + .selected_points + .iter() + .filter_map(|&point| if let ManipulatorPointId::Anchor(id) = point { Some((layer, id)) } else { None }) + .collect::>() + .into_iter() + }) + .collect(); + + // If exactly two points are selected (regardless of layer), connect them + if all_selected_points.len() == 2 { + let (layer1, start_point) = all_selected_points[0]; + let (layer2, end_point) = all_selected_points[1]; + + let Some(vector_data1) = document.network_interface.compute_modified_vector(layer1) else { return }; + let Some(vector_data2) = document.network_interface.compute_modified_vector(layer2) else { return }; + + if vector_data1.all_connected(start_point).count() != 1 || vector_data2.all_connected(end_point).count() != 1 { + return; + } + + if layer1 == layer2 { + if start_point == end_point { + return; + } + + let segment_id = SegmentId::generate(); + let modification_type = VectorModificationType::InsertSegment { + id: segment_id, + points: [end_point, start_point], + handles: [None, None], + }; + responses.add(GraphOperationMessage::Vector { layer: layer1, modification_type }); + } else { + // Merge the layers + merge_layers(document, layer1, layer2, responses); + // Create segment between the two points + let segment_id = SegmentId::generate(); + let modification_type = VectorModificationType::InsertSegment { + id: segment_id, + points: [end_point, start_point], + handles: [None, None], + }; + responses.add(GraphOperationMessage::Vector { layer: layer1, modification_type }); + } + return; + } + + // If no points are selected, try to find a single continuous subpath in each layer to connect the endpoints of + for &layer in self.selected_shape_state.keys() { + let Some(vector_data) = document.network_interface.compute_modified_vector(layer) else { continue }; + + let endpoints: Vec = vector_data + .point_domain + .ids() + .iter() + .copied() + .filter(|&point_id| vector_data.all_connected(point_id).count() == 1) + .collect(); + + if endpoints.len() == 2 { + let start_point = endpoints[0]; + let end_point = endpoints[1]; + + let segment_id = SegmentId::generate(); + let modification_type = VectorModificationType::InsertSegment { + id: segment_id, + points: [end_point, start_point], + handles: [None, None], + }; + responses.add(GraphOperationMessage::Vector { layer, modification_type }); + } + } + } + + // Snap, returning a viewport delta + pub fn snap(&self, snap_manager: &mut SnapManager, snap_cache: &SnapCache, document: &DocumentMessageHandler, input: &InputPreprocessorMessageHandler, previous_mouse: DVec2) -> DVec2 { + let snap_data = SnapData::new_snap_cache(document, input, snap_cache); + + let mouse_delta = document + .network_interface + .document_metadata() + .document_to_viewport + .inverse() + .transform_vector2(input.mouse.position - previous_mouse); + let mut offset = mouse_delta; + let mut best_snapped = SnappedPoint::infinite_snap(document.metadata().document_to_viewport.inverse().transform_point2(input.mouse.position)); + for (layer, state) in &self.selected_shape_state { + let Some(vector_data) = document.network_interface.compute_modified_vector(*layer) else { + continue; + }; + + let to_document = document.metadata().transform_to_document(*layer); + + for &selected in &state.selected_points { + let source = match selected { + ManipulatorPointId::Anchor(_) if vector_data.colinear(selected) => SnapSource::Path(PathSnapSource::AnchorPointWithColinearHandles), + ManipulatorPointId::Anchor(_) => SnapSource::Path(PathSnapSource::AnchorPointWithFreeHandles), + // TODO: This doesn't actually work for handles, instead handles enter the arm above for free handles + ManipulatorPointId::PrimaryHandle(_) | ManipulatorPointId::EndHandle(_) => SnapSource::Path(PathSnapSource::HandlePoint), + }; + + let Some(position) = selected.get_position(&vector_data) else { continue }; + let mut point = SnapCandidatePoint::new_source(to_document.transform_point2(position) + mouse_delta, source); + + if let Some(id) = selected.as_anchor() { + for neighbor in vector_data.connected_points(id) { + if state.is_point_selected(ManipulatorPointId::Anchor(neighbor)) { + continue; + } + let Some(position) = vector_data.point_domain.position_from_id(neighbor) else { continue }; + point.neighbors.push(to_document.transform_point2(position)); + } + } + + let snapped = snap_manager.free_snap(&snap_data, &point, SnapTypeConfiguration::default()); + if best_snapped.other_snap_better(&snapped) { + offset = snapped.snapped_point_document - point.document_point + mouse_delta; + best_snapped = snapped; + } + } + } + snap_manager.update_indicator(best_snapped); + document.metadata().document_to_viewport.transform_vector2(offset) + } + + /// Select/deselect the first point within the selection threshold. + /// Returns a tuple of the points if found and the offset, or `None` otherwise. + pub fn change_point_selection( + &mut self, + network_interface: &NodeNetworkInterface, + mouse_position: DVec2, + select_threshold: f64, + extend_selection: bool, + path_overlay_mode: PathOverlayMode, + frontier_handles_info: Option>>, + ) -> Option> { + if self.selected_shape_state.is_empty() { + return None; + } + + if let Some((layer, manipulator_point_id)) = self.find_nearest_visible_point_indices(network_interface, mouse_position, select_threshold, path_overlay_mode, frontier_handles_info) { + let vector_data = network_interface.compute_modified_vector(layer)?; + let point_position = manipulator_point_id.get_position(&vector_data)?; + + let selected_shape_state = self.selected_shape_state.get(&layer)?; + let already_selected = selected_shape_state.is_point_selected(manipulator_point_id); + + // Offset to snap the selected point to the cursor + let offset = mouse_position - network_interface.document_metadata().transform_to_viewport(layer).transform_point2(point_position); + + // This is selecting the manipulator only for now, next to generalize to points + + let retain_existing_selection = extend_selection || already_selected; + if !retain_existing_selection { + self.deselect_all_points(); + self.deselect_all_segments(); + } + + // Add to the selected points (deselect is managed in DraggingState, DragStop) + let selected_shape_state = self.selected_shape_state.get_mut(&layer)?; + selected_shape_state.select_point(manipulator_point_id); + + let points = self + .selected_shape_state + .iter() + .flat_map(|(layer, state)| state.selected_points.iter().map(|&point_id| ManipulatorPointInfo { layer: *layer, point_id })) + .collect(); + + return Some(Some(SelectedPointsInfo { points, offset, vector_data })); + } + None + } + + pub fn get_point_selection_state( + &mut self, + network_interface: &NodeNetworkInterface, + mouse_position: DVec2, + select_threshold: f64, + path_overlay_mode: PathOverlayMode, + frontier_handles_info: Option>>, + point_editing_mode: bool, + ) -> Option<(bool, Option)> { + if self.selected_shape_state.is_empty() { + return None; + } + + if !point_editing_mode { + return None; + } + + if let Some((layer, manipulator_point_id)) = self.find_nearest_point_indices(network_interface, mouse_position, select_threshold) { + let vector_data = network_interface.compute_modified_vector(layer)?; + let point_position = manipulator_point_id.get_position(&vector_data)?; + + // Check if point is visible under current overlay mode or not + let selected_segments = selected_segments(network_interface, self); + let selected_points = self.selected_points().cloned().collect::>(); + if !is_visible_point(manipulator_point_id, &vector_data, path_overlay_mode, frontier_handles_info, selected_segments, &selected_points) { + return None; + } + + let selected_shape_state = self.selected_shape_state.get(&layer)?; + let already_selected = selected_shape_state.is_point_selected(manipulator_point_id); + + // Offset to snap the selected point to the cursor + let offset = mouse_position - network_interface.document_metadata().transform_to_viewport(layer).transform_point2(point_position); + + // Gather current selection information + let points = self + .selected_shape_state + .iter() + .flat_map(|(layer, state)| state.selected_points.iter().map(|&point_id| ManipulatorPointInfo { layer: *layer, point_id })) + .collect(); + + let selection_info = SelectedPointsInfo { points, offset, vector_data }; + + // Return the current selection state and info + return Some((already_selected, Some(selection_info))); + } + + None + } + + pub fn select_anchor_point_by_id(&mut self, layer: LayerNodeIdentifier, id: PointId, extend_selection: bool) { + if !extend_selection { + self.deselect_all_points(); + } + let point = ManipulatorPointId::Anchor(id); + let Some(selected_state) = self.selected_shape_state.get_mut(&layer) else { return }; + selected_state.select_point(point); + } + + /// Selects all anchors connected to the selected subpath, and deselects all handles, for the given layer. + pub fn select_connected_anchors(&mut self, document: &DocumentMessageHandler, layer: LayerNodeIdentifier, mouse: DVec2) { + let Some(vector_data) = document.network_interface.compute_modified_vector(layer) else { + return; + }; + let to_viewport = document.metadata().transform_to_viewport(layer); + let layer_mouse = to_viewport.inverse().transform_point2(mouse); + let state = self.selected_shape_state.entry(layer).or_default(); + + let mut selected_stack = Vec::new(); + // Find all subpaths that have been clicked + for stroke in vector_data.stroke_bezier_paths() { + if stroke.contains_point(layer_mouse) { + if let Some(first) = stroke.manipulator_groups().first() { + selected_stack.push(first.id); + } + } + } + state.clear_points(); + if selected_stack.is_empty() { + // Fall back on just selecting all points in the layer + for &point in vector_data.point_domain.ids() { + state.select_point(ManipulatorPointId::Anchor(point)) + } + } else { + // Select all connected points + while let Some(point) = selected_stack.pop() { + let anchor_point = ManipulatorPointId::Anchor(point); + if !state.is_point_selected(anchor_point) { + state.select_point(anchor_point); + selected_stack.extend(vector_data.connected_points(point)); + } + } + } + } + + /// Selects all anchors, and deselects all handles, for the given layer. + pub fn select_all_anchors_in_layer(&mut self, document: &DocumentMessageHandler, layer: LayerNodeIdentifier) { + let state = self.selected_shape_state.entry(layer).or_default(); + Self::select_all_anchors_in_layer_with_state(document, layer, state); + } + + /// Selects all anchors, and deselects all handles, for the selected layers. + pub fn select_all_anchors_in_selected_layers(&mut self, document: &DocumentMessageHandler) { + for (&layer, state) in self.selected_shape_state.iter_mut() { + Self::select_all_anchors_in_layer_with_state(document, layer, state); + } + } + + /// Internal helper function that selects all anchors, and deselects all handles, for a layer given its [`LayerNodeIdentifier`] and [`SelectedLayerState`]. + fn select_all_anchors_in_layer_with_state(document: &DocumentMessageHandler, layer: LayerNodeIdentifier, state: &mut SelectedLayerState) { + let Some(vector_data) = document.network_interface.compute_modified_vector(layer) else { + return; + }; + + state.clear_points(); + + for &point in vector_data.point_domain.ids() { + state.select_point(ManipulatorPointId::Anchor(point)) + } + } + + /// Deselects all points (anchors and handles) across every selected layer. + pub fn deselect_all_points(&mut self) { + for state in self.selected_shape_state.values_mut() { + state.selected_points.clear() + } + } + + /// Deselects all segments across every selected layer + pub fn deselect_all_segments(&mut self) { + for state in self.selected_shape_state.values_mut() { + state.selected_segments.clear() + } + } + + pub fn update_selected_anchors_status(&mut self, status: bool) { + for state in self.selected_shape_state.values_mut() { + self.ignore_anchors = !status; + state.ignore_anchors(status); + } + } + + pub fn update_selected_handles_status(&mut self, status: bool) { + for state in self.selected_shape_state.values_mut() { + self.ignore_handles = !status; + state.ignore_handles(status); + } + } + + /// Deselects all the anchors across every selected layer. + pub fn deselect_all_anchors(&mut self) { + for (_, state) in self.selected_shape_state.iter_mut() { + let selected_anchor_points: Vec = state.selected_points.iter().filter(|selected_point| selected_point.as_anchor().is_some()).cloned().collect(); + + for point in selected_anchor_points { + state.deselect_point(point); + } + } + } + + /// Deselects all the handles across every selected layer. + pub fn deselect_all_handles(&mut self) { + for (_, state) in self.selected_shape_state.iter_mut() { + let selected_handle_points: Vec = state.selected_points.iter().filter(|selected_point| selected_point.as_handle().is_some()).cloned().collect(); + + for point in selected_handle_points { + state.deselect_point(point); + } + } + } + + /// Set the shapes we consider for selection, we will choose draggable manipulators from these shapes. + pub fn set_selected_layers(&mut self, target_layers: Vec) { + self.selected_shape_state.retain(|layer_path, _| target_layers.contains(layer_path)); + for layer in target_layers { + self.selected_shape_state.entry(layer).or_default(); + } + } + + /// Returns an iterator over the currently selected layers to get their [`LayerNodeIdentifier`]s. + pub fn selected_layers(&self) -> impl Iterator { + self.selected_shape_state.keys() + } + + /// iterate over all selected layers in order from top to bottom + /// # WARN + /// iterate over all layers of the document + pub fn sorted_selected_layers<'a>(&'a self, document_metadata: &'a DocumentMetadata) -> impl Iterator + 'a { + document_metadata.all_layers().filter(|layer| self.selected_shape_state.contains_key(layer)) + } + + pub fn has_selected_layers(&self) -> bool { + !self.selected_shape_state.is_empty() + } + + /// Provide the currently selected points by reference. + pub fn selected_points(&self) -> impl Iterator { + self.selected_shape_state.values().flat_map(|state| &state.selected_points) + } + + pub fn selected_segments(&self) -> impl Iterator { + self.selected_shape_state.values().flat_map(|state| &state.selected_segments) + } + + pub fn selected_points_in_layer(&self, layer: LayerNodeIdentifier) -> Option<&HashSet> { + self.selected_shape_state.get(&layer).map(|state| &state.selected_points) + } + + pub fn selected_segments_in_layer(&self, layer: LayerNodeIdentifier) -> Option<&HashSet> { + self.selected_shape_state.get(&layer).map(|state| &state.selected_segments) + } + + pub fn move_primary(&self, segment: SegmentId, delta: DVec2, layer: LayerNodeIdentifier, responses: &mut VecDeque) { + responses.add(GraphOperationMessage::Vector { + layer, + modification_type: VectorModificationType::ApplyPrimaryDelta { segment, delta }, + }); + } + + pub fn move_end(&self, segment: SegmentId, delta: DVec2, layer: LayerNodeIdentifier, responses: &mut VecDeque) { + responses.add(GraphOperationMessage::Vector { + layer, + modification_type: VectorModificationType::ApplyEndDelta { segment, delta }, + }); + } + + pub fn move_anchor(&self, point: PointId, vector_data: &VectorData, delta: DVec2, layer: LayerNodeIdentifier, selected: Option<&SelectedLayerState>, responses: &mut VecDeque) { + // Move anchor + responses.add(GraphOperationMessage::Vector { + layer, + modification_type: VectorModificationType::ApplyPointDelta { point, delta }, + }); + + // Move the other handle for a quadratic bezier + for segment in vector_data.end_connected(point) { + let Some((start, _end, bezier)) = vector_data.segment_points_from_id(segment) else { continue }; + + if let BezierHandles::Quadratic { handle } = bezier.handles { + if selected.is_some_and(|selected| selected.is_point_selected(ManipulatorPointId::Anchor(start))) { + continue; + } + + let relative_position = handle - bezier.start + delta; + let modification_type = VectorModificationType::SetPrimaryHandle { segment, relative_position }; + + responses.add(GraphOperationMessage::Vector { layer, modification_type }); + } + } + } + + /// Moves a control point to a `new_position` in document space. + /// Returns `Some(())` if successful and `None` otherwise. + pub fn reposition_control_point( + &self, + point: &ManipulatorPointId, + network_interface: &NodeNetworkInterface, + new_position: DVec2, + layer: LayerNodeIdentifier, + responses: &mut VecDeque, + ) -> Option<()> { + if self.is_point_ignored(point) { + return None; + } + + let vector_data = network_interface.compute_modified_vector(layer)?; + let transform = network_interface.document_metadata().transform_to_document(layer).inverse(); + let position = transform.transform_point2(new_position); + let current_position = point.get_position(&vector_data)?; + let delta = position - current_position; + + match *point { + ManipulatorPointId::Anchor(point) => self.move_anchor(point, &vector_data, delta, layer, None, responses), + ManipulatorPointId::PrimaryHandle(segment) => { + self.move_primary(segment, delta, layer, responses); + if let Some(handles) = point.get_handle_pair(&vector_data) { + let modification_type = VectorModificationType::SetG1Continuous { handles, enabled: false }; + responses.add(GraphOperationMessage::Vector { layer, modification_type }); + } + } + ManipulatorPointId::EndHandle(segment) => { + self.move_end(segment, delta, layer, responses); + if let Some(handles) = point.get_handle_pair(&vector_data) { + let modification_type = VectorModificationType::SetG1Continuous { handles, enabled: false }; + responses.add(GraphOperationMessage::Vector { layer, modification_type }); + } + } + } + + Some(()) + } + + /// Iterates over the selected manipulator groups excluding endpoints, returning whether their handles have mixed, colinear, or free angles. + /// If there are no points selected this function returns mixed. + pub fn selected_manipulator_angles(&self, network_interface: &NodeNetworkInterface) -> ManipulatorAngle { + // This iterator contains a bool indicating whether or not selected points' manipulator groups have colinear handles. + let mut points_colinear_status = self + .selected_shape_state + .iter() + .map(|(&layer, selection_state)| (network_interface.compute_modified_vector(layer), selection_state)) + .flat_map(|(data, selection_state)| { + selection_state.selected_points.iter().filter_map(move |&point| { + let Some(data) = &data else { return None }; + let _ = point.get_handle_pair(data)?; // ignores the endpoints. + Some(data.colinear(point)) + }) + }); + + let Some(first_is_colinear) = points_colinear_status.next() else { return ManipulatorAngle::Mixed }; + if points_colinear_status.any(|point| first_is_colinear != point) { + return ManipulatorAngle::Mixed; + } + if first_is_colinear { ManipulatorAngle::Colinear } else { ManipulatorAngle::Free } + } + + pub fn convert_manipulator_handles_to_colinear(&self, vector_data: &VectorData, point_id: PointId, responses: &mut VecDeque, layer: LayerNodeIdentifier) { + let Some(anchor_position) = ManipulatorPointId::Anchor(point_id).get_position(vector_data) else { + return; + }; + let handles = vector_data.all_connected(point_id).take(2).collect::>(); + let non_zero_handles = handles.iter().filter(|handle| handle.length(vector_data) > 1e-6).count(); + let handle_segments = handles.iter().map(|handles| handles.segment).collect::>(); + + // Check if the anchor is connected to linear segments and has no handles + let linear_segments = vector_data.connected_linear_segments(point_id) != 0; + + // Grab the next and previous manipulator groups by simply looking at the next / previous index + let points = handles.iter().map(|handle| vector_data.other_point(handle.segment, point_id)); + let anchor_positions = points + .map(|point| point.and_then(|point| ManipulatorPointId::Anchor(point).get_position(vector_data))) + .collect::>(); + + let mut segment_angle = 0.; + let mut segment_count = 0.; + + for segment in &handle_segments { + let Some(angle) = calculate_segment_angle(point_id, *segment, vector_data, false) else { + continue; + }; + segment_angle += angle; + segment_count += 1.; + } + + // For a non-endpoint anchor, handles are perpendicular to the average tangent of adjacent segments.(Refer:https://github.com/GraphiteEditor/Graphite/pull/2620#issuecomment-2881501494) + let mut handle_direction = if segment_count > 1. { + segment_angle /= segment_count; + segment_angle += std::f64::consts::FRAC_PI_2; + DVec2::new(segment_angle.cos(), segment_angle.sin()) + } else { + DVec2::new(segment_angle.cos(), segment_angle.sin()) + }; + + // Set the manipulator to have colinear handles + if let (Some(a), Some(b)) = (handles.first(), handles.get(1)) { + let handles = [*a, *b]; + let modification_type = VectorModificationType::SetG1Continuous { handles, enabled: true }; + responses.add(GraphOperationMessage::Vector { layer, modification_type }); + } + + // Flip the vector if it is not facing towards the same direction as the anchor + let [first, second] = [anchor_positions.first().copied().flatten(), anchor_positions.get(1).copied().flatten()]; + if first.is_some_and(|group| (group - anchor_position).normalize_or_zero().dot(handle_direction) < 0.) + || second.is_some_and(|group| (group - anchor_position).normalize_or_zero().dot(handle_direction) > 0.) + { + handle_direction *= -1.; + } + + if non_zero_handles != 0 && !linear_segments { + let [a, b] = handles.as_slice() else { return }; + let (non_zero_handle, zero_handle) = if a.length(vector_data) > 1e-6 { (a, b) } else { (b, a) }; + let Some(direction) = non_zero_handle + .to_manipulator_point() + .get_position(vector_data) + .and_then(|position| (position - anchor_position).try_normalize()) + else { + return; + }; + let new_position = -direction * non_zero_handle.length(vector_data); + let modification_type = zero_handle.set_relative_position(new_position); + responses.add(GraphOperationMessage::Vector { layer, modification_type }); + } else { + // Push both in and out handles into the correct position + for ((handle, sign), other_anchor) in handles.iter().zip([1., -1.]).zip(&anchor_positions) { + let Some(anchor_vector) = other_anchor.map(|position| (position - anchor_position)) else { + continue; + }; + + let Some(unit_vector) = anchor_vector.try_normalize() else { + continue; + }; + + let projection = anchor_vector.length() * HANDLE_LENGTH_FACTOR * handle_direction.dot(unit_vector).abs(); + + let new_position = handle_direction * projection * sign; + let modification_type = handle.set_relative_position(new_position); + responses.add(GraphOperationMessage::Vector { layer, modification_type }); + + // Create the opposite handle if it doesn't exist (if it is not a cubic segment) + if handle.opposite().to_manipulator_point().get_position(vector_data).is_none() { + let modification_type = handle.opposite().set_relative_position(DVec2::ZERO); + responses.add(GraphOperationMessage::Vector { layer, modification_type }); + } + } + } + } + + /// Converts all selected points to colinear while moving the handles to ensure their 180° angle separation. + /// If only one handle is selected, the other handle will be moved to match the angle of the selected handle. + /// If both or neither handles are selected, the angle of both handles will be averaged from their current angles, weighted by their lengths. + /// Assumes all selected manipulators have handles that are already not colinear. + pub fn convert_selected_manipulators_to_colinear_handles(&self, responses: &mut VecDeque, document: &DocumentMessageHandler) { + let mut skip_set = HashSet::new(); + + for (&layer, layer_state) in self.selected_shape_state.iter() { + let Some(vector_data) = document.network_interface.compute_modified_vector(layer) else { + continue; + }; + let transform = document.metadata().transform_to_document(layer); + + for &point in layer_state.selected_points.iter() { + let Some(handles) = point.get_handle_pair(&vector_data) else { continue }; + if skip_set.contains(&handles) || skip_set.contains(&[handles[1], handles[0]]) { + continue; + }; + + skip_set.insert(handles); + + let [selected0, selected1] = handles.map(|handle| layer_state.selected_points.contains(&handle.to_manipulator_point())); + let handle_positions = handles.map(|handle| handle.to_manipulator_point().get_position(&vector_data)); + + let Some(anchor_id) = point.get_anchor(&vector_data) else { continue }; + let Some(anchor) = vector_data.point_domain.position_from_id(anchor_id) else { continue }; + + let anchor_points = handles.map(|handle| vector_data.other_point(handle.segment, anchor_id)); + let anchor_positions = anchor_points.map(|point| point.and_then(|point| vector_data.point_domain.position_from_id(point))); + + // If one handle is selected (but both exist), only move the other handle + if let (true, [Some(pos0), Some(pos1)]) = ((selected0 ^ selected1), handle_positions) { + let [(_selected_handle, selected_position), (unselected_handle, unselected_position)] = if selected0 { + [(handles[0], pos0), (handles[1], pos1)] + } else { + [(handles[1], pos1), (handles[0], pos0)] + }; + let direction = transform + .transform_vector2(anchor - selected_position) + .try_normalize() + .unwrap_or_else(|| transform.transform_vector2(unselected_position - anchor).normalize_or_zero()); + + let length = transform.transform_vector2(unselected_position - anchor).length(); + let position = transform.inverse().transform_vector2(direction * length); + let modification_type = unselected_handle.set_relative_position(position); + if (anchor - selected_position).length() > 1e-6 { + responses.add(GraphOperationMessage::Vector { layer, modification_type }); + } + } + // If both handles are selected, average the angles of the handles + else { + // We could normalize these directions? + let mut handle_directions = handle_positions.map(|handle| handle.map(|handle| handle - anchor)); + + let mut normalized = handle_directions[0].and_then(|a| handle_directions[1].and_then(|b| (a - b).try_normalize())); + + if normalized.is_none() { + handle_directions = anchor_positions.map(|relative_anchor| relative_anchor.map(|relative_anchor| (relative_anchor - anchor) / 3.)); + normalized = handle_directions[0].and_then(|a| handle_directions[1].and_then(|b| (a - b).try_normalize())) + } + let Some(normalized) = normalized else { continue }; + + // Push both in and out handles into the correct position + for (index, sign) in [(0, 1.), (1, -1.)] { + let Some(direction) = handle_directions[index] else { continue }; + let new_position = direction.length() * normalized * sign; + let modification_type = handles[index].set_relative_position(new_position); + responses.add(GraphOperationMessage::Vector { layer, modification_type }); + + // Create the opposite handle if it doesn't exist (if it is not a cubic segment) + if handles[index].opposite().to_manipulator_point().get_position(&vector_data).is_none() { + let modification_type = handles[index].opposite().set_relative_position(DVec2::ZERO); + responses.add(GraphOperationMessage::Vector { layer, modification_type }); + } + } + } + let modification_type = VectorModificationType::SetG1Continuous { handles, enabled: true }; + responses.add(GraphOperationMessage::Vector { layer, modification_type }); + } + } + } + + /// Move the selected points and segments by dragging the mouse. + #[allow(clippy::too_many_arguments)] + pub fn move_selected_points_and_segments( + &self, + handle_lengths: Option, + document: &DocumentMessageHandler, + delta: DVec2, + equidistant: bool, + in_viewport_space: bool, + was_alt_dragging: bool, + opposite_handle_position: Option, + skip_opposite_handle: bool, + responses: &mut VecDeque, + ) { + for (&layer, state) in &self.selected_shape_state { + let Some(vector_data) = document.network_interface.compute_modified_vector(layer) else { continue }; + + let opposing_handles = handle_lengths.as_ref().and_then(|handle_lengths| handle_lengths.get(&layer)); + + let transform_to_viewport_space = document.metadata().transform_to_viewport(layer); + let transform_to_document_space = document.metadata().transform_to_document(layer); + let delta_transform = if in_viewport_space { + transform_to_viewport_space + } else { + DAffine2::from_angle(document.document_ptz.tilt()) * transform_to_document_space + }; + let delta = delta_transform.inverse().transform_vector2(delta); + + // Make a new collection of anchor points which needs to be moved + let mut affected_points = state.selected_points.clone(); + + for (segment_id, _, start, end) in vector_data.segment_bezier_iter() { + if state.is_segment_selected(segment_id) { + affected_points.insert(ManipulatorPointId::Anchor(start)); + affected_points.insert(ManipulatorPointId::Anchor(end)); + } + } + + for &point in affected_points.iter() { + if self.is_point_ignored(&point) { + continue; + } + + let handle = match point { + ManipulatorPointId::Anchor(point) => { + self.move_anchor(point, &vector_data, delta, layer, Some(state), responses); + continue; + } + ManipulatorPointId::PrimaryHandle(segment) => HandleId::primary(segment), + ManipulatorPointId::EndHandle(segment) => HandleId::end(segment), + }; + + let Some(anchor_id) = point.get_anchor(&vector_data) else { continue }; + if state.is_point_selected(ManipulatorPointId::Anchor(anchor_id)) { + continue; + } + + let Some(anchor_position) = vector_data.point_domain.position_from_id(anchor_id) else { continue }; + + let Some(handle_position) = point.get_position(&vector_data) else { continue }; + let handle_position = handle_position + delta; + + let modification_type = handle.set_relative_position(handle_position - anchor_position); + + responses.add(GraphOperationMessage::Vector { layer, modification_type }); + + let Some(other) = vector_data.other_colinear_handle(handle) else { continue }; + + if skip_opposite_handle { + continue; + } + + if state.is_point_selected(other.to_manipulator_point()) { + // If two colinear handles are being dragged at the same time but not the anchor, it is necessary to break the colinear state. + let handles = [handle, other]; + let modification_type = VectorModificationType::SetG1Continuous { handles, enabled: false }; + responses.add(GraphOperationMessage::Vector { layer, modification_type }); + continue; + } + + let new_relative = if equidistant { + -(handle_position - anchor_position) + } + // If the handle is very close to the anchor, return the original position + else if (handle_position - anchor_position).length_squared() < f64::EPSILON * 1e5 { + let Some(opposite_handle_position) = opposite_handle_position else { continue }; + opposite_handle_position - anchor_position + } else { + // TODO: Is this equivalent to `transform_to_document_space`? If changed, the before and after should be tested. + let transform = document.metadata().document_to_viewport.inverse() * transform_to_viewport_space; + let Some(other_position) = other.to_manipulator_point().get_position(&vector_data) else { + continue; + }; + let direction = transform.transform_vector2(handle_position - anchor_position).try_normalize(); + let opposing_handle = opposing_handles.and_then(|handles| handles.get(&other)); + let length = opposing_handle.copied().unwrap_or_else(|| transform.transform_vector2(other_position - anchor_position).length()); + direction.map_or(other_position - anchor_position, |direction| transform.inverse().transform_vector2(-direction * length)) + }; + + if !was_alt_dragging { + let modification_type = other.set_relative_position(new_relative); + responses.add(GraphOperationMessage::Vector { layer, modification_type }); + } + } + } + } + + /// The opposing handle lengths. + pub fn opposing_handle_lengths(&self, document: &DocumentMessageHandler) -> OpposingHandleLengths { + self.selected_shape_state + .iter() + .filter_map(|(&layer, state)| { + let vector_data = document.network_interface.compute_modified_vector(layer)?; + let transform = document.metadata().transform_to_document(layer); + let opposing_handle_lengths = vector_data + .colinear_manipulators + .iter() + .filter_map(|&handles| { + // We will keep track of the opposing handle length when: + // i) Exactly one handle is selected. + // ii) The anchor is not selected. + + let anchor = handles[0].to_manipulator_point().get_anchor(&vector_data)?; + let anchor_selected = state.is_point_selected(ManipulatorPointId::Anchor(anchor)); + if anchor_selected { + return None; + } + + let handles_selected = handles.map(|handle| state.is_point_selected(handle.to_manipulator_point())); + + let other = match handles_selected { + [true, false] => handles[1], + [false, true] => handles[0], + _ => return None, + }; + + let opposing_handle_position = other.to_manipulator_point().get_position(&vector_data)?; + let anchor_position = vector_data.point_domain.position_from_id(anchor)?; + + let opposing_handle_length = transform.transform_vector2(opposing_handle_position - anchor_position).length(); + Some((other, opposing_handle_length)) + }) + .collect::>(); + Some((layer, opposing_handle_lengths)) + }) + .collect::>() + } + + pub fn dissolve_segment(&self, responses: &mut VecDeque, layer: LayerNodeIdentifier, vector_data: &VectorData, segment: SegmentId, points: [PointId; 2]) { + // Checking which point is terminal point + let is_point1_terminal = vector_data.connected_count(points[0]) == 1; + let is_point2_terminal = vector_data.connected_count(points[1]) == 1; + + // Delete the segment and terminal points + let modification_type = VectorModificationType::RemoveSegment { id: segment }; + responses.add(GraphOperationMessage::Vector { layer, modification_type }); + for &handles in vector_data.colinear_manipulators.iter().filter(|handles| handles.iter().any(|handle| handle.segment == segment)) { + let modification_type = VectorModificationType::SetG1Continuous { handles, enabled: false }; + responses.add(GraphOperationMessage::Vector { layer, modification_type }); + } + + if is_point1_terminal { + let modification_type = VectorModificationType::RemovePoint { id: points[0] }; + responses.add(GraphOperationMessage::Vector { layer, modification_type }); + } + if is_point2_terminal { + let modification_type = VectorModificationType::RemovePoint { id: points[1] }; + responses.add(GraphOperationMessage::Vector { layer, modification_type }); + } + } + + fn dissolve_anchor(anchor: PointId, responses: &mut VecDeque, layer: LayerNodeIdentifier, vector_data: &VectorData) -> Option<[(HandleId, PointId); 2]> { + // Delete point + let modification_type = VectorModificationType::RemovePoint { id: anchor }; + responses.add(GraphOperationMessage::Vector { layer, modification_type }); + + // Delete connected segments + for HandleId { segment, .. } in vector_data.all_connected(anchor) { + let modification_type = VectorModificationType::RemoveSegment { id: segment }; + responses.add(GraphOperationMessage::Vector { layer, modification_type }); + for &handles in vector_data.colinear_manipulators.iter().filter(|handles| handles.iter().any(|handle| handle.segment == segment)) { + let modification_type = VectorModificationType::SetG1Continuous { handles, enabled: false }; + responses.add(GraphOperationMessage::Vector { layer, modification_type }); + } + } + + // Add in new segment if possible + let mut handles = ManipulatorPointId::Anchor(anchor).get_handle_pair(vector_data)?; + handles.reverse(); + let opposites = handles.map(|handle| handle.opposite()); + + let [Some(start), Some(end)] = opposites.map(|opposite| opposite.to_manipulator_point().get_anchor(vector_data)) else { + return None; + }; + Some([(handles[0], start), (handles[1], end)]) + } + + /// Dissolve the selected points. + pub fn delete_selected_points(&mut self, document: &DocumentMessageHandler, responses: &mut VecDeque) { + for (&layer, state) in &mut self.selected_shape_state { + let mut missing_anchors = HashMap::new(); + let mut deleted_anchors = HashSet::new(); + let Some(vector_data) = document.network_interface.compute_modified_vector(layer) else { + continue; + }; + + let selected_segments = &state.selected_segments; + + for point in std::mem::take(&mut state.selected_points) { + match point { + ManipulatorPointId::Anchor(anchor) => { + if let Some(handles) = Self::dissolve_anchor(anchor, responses, layer, &vector_data) { + if !vector_data.all_connected(anchor).any(|a| selected_segments.contains(&a.segment)) { + missing_anchors.insert(anchor, handles); + } + } + deleted_anchors.insert(anchor); + } + ManipulatorPointId::PrimaryHandle(_) | ManipulatorPointId::EndHandle(_) => { + let Some(handle) = point.as_handle() else { continue }; + + // Place the handle on top of the anchor + let modification_type = handle.set_relative_position(DVec2::ZERO); + responses.add(GraphOperationMessage::Vector { layer, modification_type }); + + // Disable the g1 continuous + for &handles in &vector_data.colinear_manipulators { + if handles.contains(&handle) { + let modification_type = VectorModificationType::SetG1Continuous { handles, enabled: false }; + responses.add(GraphOperationMessage::Vector { layer, modification_type }); + } + } + } + } + } + + let mut visited = Vec::new(); + while let Some((anchor, handles)) = missing_anchors.keys().next().copied().and_then(|id| missing_anchors.remove_entry(&id)) { + visited.push(anchor); + + // If the adjacent point is just this point then skip + let mut handles = handles.map(|handle| (handle.1 != anchor).then_some(handle)); + + // If the adjacent points are themselves being deleted, then repeatedly visit the newest agacent points. + for handle in &mut handles { + while let Some((point, connected)) = (*handle).and_then(|(_, point)| missing_anchors.remove_entry(&point)) { + visited.push(point); + + *handle = connected.into_iter().find(|(_, point)| !visited.contains(point)); + } + } + + let [Some(start), Some(end)] = handles else { continue }; + + // Avoid reconnecting to points that are being deleted (this can happen if a whole loop is deleted) + if deleted_anchors.contains(&start.1) || deleted_anchors.contains(&end.1) { + continue; + } + + // Avoid reconnecting to points which have adjacent segments selected + + // Grab the handles from the opposite side of the segment(s) being deleted and make it relative to the anchor + let [handle_start, handle_end] = [start, end].map(|(handle, _)| { + let handle = handle.opposite(); + let handle_position = handle.to_manipulator_point().get_position(&vector_data); + let relative_position = handle + .to_manipulator_point() + .get_anchor(&vector_data) + .and_then(|anchor| vector_data.point_domain.position_from_id(anchor)); + handle_position.and_then(|handle| relative_position.map(|relative| handle - relative)).unwrap_or_default() + }); + + let segment = start.0.segment; + + let modification_type = VectorModificationType::InsertSegment { + id: segment, + points: [start.1, end.1], + handles: [Some(handle_start), Some(handle_end)], + }; + + responses.add(GraphOperationMessage::Vector { layer, modification_type }); + + for &handles in vector_data.colinear_manipulators.iter() { + if !handles.iter().any(|&handle| handle == start.0.opposite() || handle == end.0.opposite()) { + continue; + } + + let Some(anchor) = handles[0].to_manipulator_point().get_anchor(&vector_data) else { continue }; + let Some(other) = handles.iter().find(|&&handle| handle != start.0.opposite() && handle != end.0.opposite()) else { + continue; + }; + + let handle_ty = if anchor == start.1 { + HandleId::primary(segment) + } else if anchor == end.1 { + HandleId::end(segment) + } else { + continue; + }; + let handles = [*other, handle_ty]; + let modification_type = VectorModificationType::SetG1Continuous { handles, enabled: true }; + + responses.add(GraphOperationMessage::Vector { layer, modification_type }); + } + } + } + } + + pub fn delete_selected_segments(&mut self, document: &DocumentMessageHandler, responses: &mut VecDeque) { + for (&layer, state) in &self.selected_shape_state { + let Some(vector_data) = document.network_interface.compute_modified_vector(layer) else { + continue; + }; + + for (segment, _, start, end) in vector_data.segment_bezier_iter() { + if state.selected_segments.contains(&segment) { + self.dissolve_segment(responses, layer, &vector_data, segment, [start, end]); + } + } + } + } + + pub fn break_path_at_selected_point(&self, document: &DocumentMessageHandler, responses: &mut VecDeque) { + for (&layer, state) in &self.selected_shape_state { + let Some(vector_data) = document.network_interface.compute_modified_vector(layer) else { continue }; + + for &delete in &state.selected_points { + let Some(point) = delete.get_anchor(&vector_data) else { continue }; + let Some(pos) = vector_data.point_domain.position_from_id(point) else { continue }; + + let mut used_initial_point = false; + for handle in vector_data.all_connected(point) { + // Disable the g1 continuous + for &handles in &vector_data.colinear_manipulators { + if handles.contains(&handle) { + let modification_type = VectorModificationType::SetG1Continuous { handles, enabled: false }; + responses.add(GraphOperationMessage::Vector { layer, modification_type }); + } + } + + // Keep the existing point for the first segment + if !used_initial_point { + used_initial_point = true; + continue; + } + + // Create new point + let id = PointId::generate(); + let modification_type = VectorModificationType::InsertPoint { id, position: pos }; + + responses.add(GraphOperationMessage::Vector { layer, modification_type }); + + // Update segment + let HandleId { ty, segment } = handle; + let modification_type = match ty { + graphene_std::vector::HandleType::Primary => VectorModificationType::SetStartPoint { segment, id }, + graphene_std::vector::HandleType::End => VectorModificationType::SetEndPoint { segment, id }, + }; + + responses.add(GraphOperationMessage::Vector { layer, modification_type }); + } + } + } + } + + /// Delete point(s) and adjacent segments. + pub fn delete_point_and_break_path(&mut self, document: &DocumentMessageHandler, responses: &mut VecDeque) { + for (&layer, state) in &mut self.selected_shape_state { + let Some(vector_data) = document.network_interface.compute_modified_vector(layer) else { + continue; + }; + + for delete in std::mem::take(&mut state.selected_points) { + let Some(point) = delete.get_anchor(&vector_data) else { continue }; + + // Delete point + let modification_type = VectorModificationType::RemovePoint { id: point }; + responses.add(GraphOperationMessage::Vector { layer, modification_type }); + + // Delete connected segments + for HandleId { segment, .. } in vector_data.all_connected(point) { + let modification_type = VectorModificationType::RemoveSegment { id: segment }; + responses.add(GraphOperationMessage::Vector { layer, modification_type }); + } + } + } + } + + /// Disable colinear handles colinear. + pub fn disable_colinear_handles_state_on_selected(&self, network_interface: &NodeNetworkInterface, responses: &mut VecDeque) { + for (&layer, state) in &self.selected_shape_state { + let Some(vector_data) = network_interface.compute_modified_vector(layer) else { + continue; + }; + + for &point in &state.selected_points { + if let ManipulatorPointId::Anchor(point) = point { + for connected in vector_data.all_connected(point) { + if let Some(&handles) = vector_data.colinear_manipulators.iter().find(|target| target.iter().any(|&target| target == connected)) { + let modification_type = VectorModificationType::SetG1Continuous { handles, enabled: false }; + responses.add(GraphOperationMessage::Vector { layer, modification_type }); + } + } + } else if let Some(handles) = point.get_handle_pair(&vector_data) { + let modification_type = VectorModificationType::SetG1Continuous { handles, enabled: false }; + responses.add(GraphOperationMessage::Vector { layer, modification_type }); + } + } + } + } + + /// Find a [ManipulatorPoint] that is within the selection threshold and return the layer path, an index to the [ManipulatorGroup], and an enum index for [ManipulatorPoint]. + pub fn find_nearest_point_indices(&mut self, network_interface: &NodeNetworkInterface, mouse_position: DVec2, select_threshold: f64) -> Option<(LayerNodeIdentifier, ManipulatorPointId)> { + if self.selected_shape_state.is_empty() { + return None; + } + + let select_threshold_squared = select_threshold * select_threshold; + + // Find the closest control point among all elements of shapes_to_modify + for &layer in self.selected_shape_state.keys() { + if let Some((manipulator_point_id, distance_squared)) = Self::closest_point_in_layer(network_interface, layer, mouse_position) { + // Choose the first point under the threshold + if distance_squared < select_threshold_squared { + trace!("Selecting... manipulator point: {manipulator_point_id:?}"); + return Some((layer, manipulator_point_id)); + } + } + } + + None + } + + pub fn find_nearest_visible_point_indices( + &mut self, + network_interface: &NodeNetworkInterface, + mouse_position: DVec2, + select_threshold: f64, + path_overlay_mode: PathOverlayMode, + frontier_handles_info: Option>>, + ) -> Option<(LayerNodeIdentifier, ManipulatorPointId)> { + if self.selected_shape_state.is_empty() { + return None; + } + + let select_threshold_squared = select_threshold.powi(2); + + // Find the closest control point among all elements of shapes_to_modify + for &layer in self.selected_shape_state.keys() { + if let Some((manipulator_point_id, distance_squared)) = Self::closest_point_in_layer(network_interface, layer, mouse_position) { + // Choose the first point under the threshold + if distance_squared < select_threshold_squared { + // Check if point is visible in current PathOverlayMode + let vector_data = network_interface.compute_modified_vector(layer)?; + let selected_segments = selected_segments(network_interface, self); + let selected_points = self.selected_points().cloned().collect::>(); + + if !is_visible_point(manipulator_point_id, &vector_data, path_overlay_mode, frontier_handles_info, selected_segments, &selected_points) { + return None; + } + + return Some((layer, manipulator_point_id)); + } + } + } + + None + } + + // TODO Use quadtree or some equivalent spatial acceleration structure to improve this to O(log(n)) + /// Find the closest manipulator, manipulator point, and distance so we can select path elements. + /// Brute force comparison to determine which manipulator (handle or anchor) we want to select taking O(n) time. + /// Return value is an `Option` of the tuple representing `(ManipulatorPointId, distance squared)`. + fn closest_point_in_layer(network_interface: &NodeNetworkInterface, layer: LayerNodeIdentifier, pos: glam::DVec2) -> Option<(ManipulatorPointId, f64)> { + let mut closest_distance_squared: f64 = f64::MAX; + let mut manipulator_point = None; + + let vector_data = network_interface.compute_modified_vector(layer)?; + let viewspace = network_interface.document_metadata().transform_to_viewport(layer); + + // Handles + for (segment_id, bezier, _, _) in vector_data.segment_bezier_iter() { + let bezier = bezier.apply_transformation(|point| viewspace.transform_point2(point)); + let valid = |handle: DVec2, control: DVec2| handle.distance_squared(control) > crate::consts::HIDE_HANDLE_DISTANCE.powi(2); + + if let Some(primary_handle) = bezier.handle_start() { + if valid(primary_handle, bezier.start) && (bezier.handle_end().is_some() || valid(primary_handle, bezier.end)) && primary_handle.distance_squared(pos) <= closest_distance_squared { + closest_distance_squared = primary_handle.distance_squared(pos); + manipulator_point = Some(ManipulatorPointId::PrimaryHandle(segment_id)); + } + } + if let Some(end_handle) = bezier.handle_end() { + if valid(end_handle, bezier.end) && end_handle.distance_squared(pos) <= closest_distance_squared { + closest_distance_squared = end_handle.distance_squared(pos); + manipulator_point = Some(ManipulatorPointId::EndHandle(segment_id)); + } + } + } + + // Anchors + for (&id, &point) in vector_data.point_domain.ids().iter().zip(vector_data.point_domain.positions()) { + let point = viewspace.transform_point2(point); + + if point.distance_squared(pos) <= closest_distance_squared { + closest_distance_squared = point.distance_squared(pos); + manipulator_point = Some(ManipulatorPointId::Anchor(id)); + } + } + + manipulator_point.map(|id| (id, closest_distance_squared)) + } + + /// Find the `t` value along the path segment we have clicked upon, together with that segment ID. + fn closest_segment(&self, network_interface: &NodeNetworkInterface, layer: LayerNodeIdentifier, position: glam::DVec2, tolerance: f64) -> Option { + let transform = network_interface.document_metadata().transform_to_viewport(layer); + let layer_pos = transform.inverse().transform_point2(position); + + let tolerance = tolerance + 0.5; + + let mut closest = None; + let mut closest_distance_squared: f64 = tolerance * tolerance; + + let vector_data = network_interface.compute_modified_vector(layer)?; + + for (segment, mut bezier, start, end) in vector_data.segment_bezier_iter() { + let t = bezier.project(layer_pos); + let layerspace = bezier.evaluate(TValue::Parametric(t)); + + let screenspace = transform.transform_point2(layerspace); + let distance_squared = screenspace.distance_squared(position); + + if distance_squared < closest_distance_squared { + closest_distance_squared = distance_squared; + + // Convert to linear if handes are on top of control points + if let bezier_rs::BezierHandles::Cubic { handle_start, handle_end } = bezier.handles { + if handle_start.abs_diff_eq(bezier.start(), f64::EPSILON * 100.) && handle_end.abs_diff_eq(bezier.end(), f64::EPSILON * 100.) { + bezier = Bezier::from_linear_dvec2(bezier.start, bezier.end); + } + } + + let primary_handle = vector_data.colinear_manipulators.iter().find(|handles| handles.contains(&HandleId::primary(segment))); + let end_handle = vector_data.colinear_manipulators.iter().find(|handles| handles.contains(&HandleId::end(segment))); + let primary_handle = primary_handle.and_then(|&handles| handles.into_iter().find(|handle| handle.segment != segment)); + let end_handle = end_handle.and_then(|&handles| handles.into_iter().find(|handle| handle.segment != segment)); + + closest = Some(ClosestSegment { + segment, + bezier, + points: [start, end], + colinear: [primary_handle, end_handle], + t, + bezier_point_to_viewport: screenspace, + layer, + }); + } + } + + closest + } + + /// find closest to the position segment on selected layers. If there is more than one layers with close enough segment it return upper from them + pub fn upper_closest_segment(&self, network_interface: &NodeNetworkInterface, position: glam::DVec2, tolerance: f64) -> Option { + let closest_seg = |layer| self.closest_segment(network_interface, layer, position, tolerance); + match self.selected_shape_state.len() { + 0 => None, + 1 => self.selected_layers().next().copied().and_then(closest_seg), + _ => self.sorted_selected_layers(network_interface.document_metadata()).find_map(closest_seg), + } + } + pub fn get_dragging_state(&self, network_interface: &NodeNetworkInterface) -> PointSelectState { + for &layer in self.selected_shape_state.keys() { + let Some(vector_data) = network_interface.compute_modified_vector(layer) else { continue }; + + for point in self.selected_points() { + if point.as_anchor().is_some() { + return PointSelectState::Anchor; + } + if point.get_handle_pair(&vector_data).is_some() { + return PointSelectState::HandleWithPair; + } + } + } + PointSelectState::HandleNoPair + } + + /// Returns true if at least one handle with pair is selected + pub fn handle_with_pair_selected(&mut self, network_interface: &NodeNetworkInterface) -> bool { + for &layer in self.selected_shape_state.keys() { + let Some(vector_data) = network_interface.compute_modified_vector(layer) else { continue }; + + for point in self.selected_points() { + if point.as_anchor().is_some() { + return false; + } + if point.get_handle_pair(&vector_data).is_some() { + return true; + } + } + } + + false + } + + /// Alternate selected handles to mirrors + pub fn alternate_selected_handles(&mut self, network_interface: &NodeNetworkInterface) { + let mut handles_to_update = Vec::new(); + + for &layer in self.selected_shape_state.keys() { + let Some(vector_data) = network_interface.compute_modified_vector(layer) else { continue }; + + for point in self.selected_points() { + if point.as_anchor().is_some() { + continue; + } + if let Some(handles) = point.get_handle_pair(&vector_data) { + // handle[0] is selected, handle[1] is opposite / mirror handle + handles_to_update.push((layer, handles[0].to_manipulator_point(), handles[1].to_manipulator_point())); + } + } + } + + for (layer, handle_to_deselect, handle_to_select) in handles_to_update { + if let Some(state) = self.selected_shape_state.get_mut(&layer) { + let points = &state.selected_points; + let both_selected = points.contains(&handle_to_deselect) && points.contains(&handle_to_select); + if both_selected { + continue; + } + + state.deselect_point(handle_to_deselect); + state.select_point(handle_to_select); + } + } + } + + /// Selects handles and anchor connected to current handle + pub fn select_handles_and_anchor_connected_to_current_handle(&mut self, network_interface: &NodeNetworkInterface) { + let mut points_to_select: Vec<(LayerNodeIdentifier, Option, Option)> = Vec::new(); + + for &layer in self.selected_shape_state.keys() { + let Some(vector_data) = network_interface.compute_modified_vector(layer) else { + continue; + }; + + for point in self.selected_points().filter(|point| point.as_handle().is_some()) { + let anchor = point.get_anchor(&vector_data); + match point.get_handle_pair(&vector_data) { + Some(handles) => { + points_to_select.push((layer, anchor, Some(handles[1].to_manipulator_point()))); + } + _ => { + points_to_select.push((layer, anchor, None)); + } + } + } + } + + for (layer, anchor, handle) in points_to_select { + if let Some(state) = self.selected_shape_state.get_mut(&layer) { + if let Some(anchor) = anchor { + state.select_point(ManipulatorPointId::Anchor(anchor)); + } + if let Some(handle) = handle { + state.select_point(handle); + } + } + } + } + + pub fn select_points_by_manipulator_id(&mut self, points: &Vec) { + let layers_to_modify: Vec<_> = self.selected_shape_state.keys().cloned().collect(); + + for layer in layers_to_modify { + if let Some(state) = self.selected_shape_state.get_mut(&layer) { + for point in points { + state.select_point(*point); + } + } + } + } + + /// Converts a nearby clicked anchor point's handles between sharp (zero-length handles) and smooth (pulled-apart handle(s)). + /// If both handles aren't zero-length, they are set that. If both are zero-length, they are stretched apart by a reasonable amount. + /// This can can be activated by double clicking on an anchor with the Path tool. + pub fn flip_smooth_sharp(&self, network_interface: &NodeNetworkInterface, target: glam::DVec2, tolerance: f64, responses: &mut VecDeque) -> bool { + let mut process_layer = |layer| { + let vector_data = network_interface.compute_modified_vector(layer)?; + let transform_to_screenspace = network_interface.document_metadata().transform_to_viewport(layer); + + let mut result = None; + let mut closest_distance_squared = tolerance * tolerance; + + // Find the closest anchor point on the current layer + for (&id, &anchor) in vector_data.point_domain.ids().iter().zip(vector_data.point_domain.positions()) { + let screenspace = transform_to_screenspace.transform_point2(anchor); + let distance_squared = screenspace.distance_squared(target); + + if distance_squared < closest_distance_squared { + closest_distance_squared = distance_squared; + result = Some((id, anchor)); + } + } + + let (id, anchor) = result?; + let handles = vector_data.all_connected(id); + let positions = handles + .filter_map(|handle| handle.to_manipulator_point().get_position(&vector_data)) + .filter(|&handle| anchor.abs_diff_eq(handle, 1e-5)) + .count(); + + // Check if the anchor is connected to linear segments. + let one_or_more_segment_linear = vector_data.connected_linear_segments(id) != 0; + + // Check by comparing the handle positions to the anchor if this manipulator group is a point + for point in self.selected_points() { + let Some(point_id) = point.as_anchor() else { continue }; + if positions != 0 || one_or_more_segment_linear { + self.convert_manipulator_handles_to_colinear(&vector_data, point_id, responses, layer); + } else { + for handle in vector_data.all_connected(point_id) { + let Some(bezier) = vector_data.segment_from_id(handle.segment) else { continue }; + + match bezier.handles { + BezierHandles::Linear => {} + BezierHandles::Quadratic { .. } => { + let segment = handle.segment; + // Convert to linear + let modification_type = VectorModificationType::SetHandles { segment, handles: [None; 2] }; + responses.add(GraphOperationMessage::Vector { layer, modification_type }); + + // Set the manipulator to have non-colinear handles + for &handles in &vector_data.colinear_manipulators { + if handles.contains(&HandleId::primary(segment)) { + let modification_type = VectorModificationType::SetG1Continuous { handles, enabled: false }; + responses.add(GraphOperationMessage::Vector { layer, modification_type }); + } + } + } + BezierHandles::Cubic { .. } => { + // Set handle position to anchor position + let modification_type = handle.set_relative_position(DVec2::ZERO); + responses.add(GraphOperationMessage::Vector { layer, modification_type }); + + // Set the manipulator to have non-colinear handles + for &handles in &vector_data.colinear_manipulators { + if handles.contains(&handle) { + let modification_type = VectorModificationType::SetG1Continuous { handles, enabled: false }; + responses.add(GraphOperationMessage::Vector { layer, modification_type }); + } + } + } + } + } + }; + } + + Some(true) + }; + + for &layer in self.selected_shape_state.keys() { + if let Some(result) = process_layer(layer) { + return result; + } + } + + false + } + + #[allow(clippy::too_many_arguments)] + pub fn select_all_in_shape( + &mut self, + network_interface: &NodeNetworkInterface, + selection_shape: SelectionShape, + selection_change: SelectionChange, + path_overlay_mode: PathOverlayMode, + frontier_handles_info: Option>>, + select_segments: bool, + // Here, "selection mode" represents touched or enclosed, not to be confused with editing modes + selection_mode: SelectionMode, + ) { + let selected_points = self.selected_points().cloned().collect::>(); + let selected_segments = selected_segments(network_interface, self); + + for (&layer, state) in &mut self.selected_shape_state { + if selection_change == SelectionChange::Clear { + state.clear_points(); + state.clear_segments(); + } + + let vector_data = network_interface.compute_modified_vector(layer); + let Some(vector_data) = vector_data else { continue }; + let transform = network_interface.document_metadata().transform_to_viewport(layer); + + assert_eq!(vector_data.segment_domain.ids().len(), vector_data.start_point().count()); + assert_eq!(vector_data.segment_domain.ids().len(), vector_data.end_point().count()); + for start in vector_data.start_point() { + assert!(vector_data.point_domain.ids().contains(&start)); + } + for end in vector_data.end_point() { + assert!(vector_data.point_domain.ids().contains(&end)); + } + + let polygon_subpath = if let SelectionShape::Lasso(polygon) = selection_shape { + if polygon.len() < 2 { + return; + } + let polygon: Subpath = Subpath::from_anchors_linear(polygon.to_vec(), true); + Some(polygon) + } else { + None + }; + + // Selection segments + for (id, bezier, _, _) in vector_data.segment_bezier_iter() { + if select_segments { + // Select segments if they lie inside the bounding box or lasso polygon + let segment_bbox = calculate_bezier_bbox(bezier); + let bottom_left = transform.transform_point2(segment_bbox[0]); + let top_right = transform.transform_point2(segment_bbox[1]); + + let select = match selection_shape { + SelectionShape::Box(quad) => { + let enclosed = quad[0].min(quad[1]).cmple(bottom_left).all() && quad[0].max(quad[1]).cmpge(top_right).all(); + match selection_mode { + SelectionMode::Enclosed => enclosed, + _ => { + // Check for intersection with the segment + enclosed || is_intersecting(bezier, quad, transform) + } + } + } + SelectionShape::Lasso(_) => { + let polygon = polygon_subpath.as_ref().expect("If `selection_shape` is a polygon then subpath is constructed beforehand."); + + // Sample 10 points on the bezier and check if all or some lie inside the polygon + let points = bezier.compute_lookup_table(Some(10), None); + match selection_mode { + SelectionMode::Enclosed => points.map(|p| transform.transform_point2(p)).all(|p| polygon.contains_point(p)), + _ => points.map(|p| transform.transform_point2(p)).any(|p| polygon.contains_point(p)), + } + } + }; + + if select { + match selection_change { + SelectionChange::Shrink => state.deselect_segment(id), + _ => state.select_segment(id), + } + } + } + + // Selecting handles + for (position, id) in [(bezier.handle_start(), ManipulatorPointId::PrimaryHandle(id)), (bezier.handle_end(), ManipulatorPointId::EndHandle(id))] { + let Some(position) = position else { continue }; + let transformed_position = transform.transform_point2(position); + + let select = match selection_shape { + SelectionShape::Box(quad) => quad[0].min(quad[1]).cmple(transformed_position).all() && quad[0].max(quad[1]).cmpge(transformed_position).all(), + SelectionShape::Lasso(_) => polygon_subpath + .as_ref() + .expect("If `selection_shape` is a polygon then subpath is constructed beforehand.") + .contains_point(transformed_position), + }; + + if select { + let is_visible_handle = is_visible_point(id, &vector_data, path_overlay_mode, frontier_handles_info.clone(), selected_segments.clone(), &selected_points); + + if is_visible_handle { + match selection_change { + SelectionChange::Shrink => state.deselect_point(id), + _ => { + // Select only the handles which are of nonzero length + if let Some(handle) = id.as_handle() { + if handle.length(&vector_data) > 0. { + state.select_point(id) + } + } + } + } + } + } + } + } + + // Checking for selection of anchor points + for (&id, &position) in vector_data.point_domain.ids().iter().zip(vector_data.point_domain.positions()) { + let transformed_position = transform.transform_point2(position); + + let select = match selection_shape { + SelectionShape::Box(quad) => quad[0].min(quad[1]).cmple(transformed_position).all() && quad[0].max(quad[1]).cmpge(transformed_position).all(), + SelectionShape::Lasso(_) => polygon_subpath + .as_ref() + .expect("If `selection_shape` is a polygon then subpath is constructed beforehand.") + .contains_point(transformed_position), + }; + + if select { + match selection_change { + SelectionChange::Shrink => state.deselect_point(ManipulatorPointId::Anchor(id)), + _ => state.select_point(ManipulatorPointId::Anchor(id)), + } + } + } + } + } +} diff --git a/editor/src/messages/tool/common_functionality/shapes/ellipse_shape.rs b/editor/src/messages/tool/common_functionality/shapes/ellipse_shape.rs new file mode 100644 index 0000000000000000000000000000000000000000..fe97c223180c58ee648cf17dbd5d9a909cbec739 --- /dev/null +++ b/editor/src/messages/tool/common_functionality/shapes/ellipse_shape.rs @@ -0,0 +1,181 @@ +use super::shape_utility::ShapeToolModifierKey; +use super::*; +use crate::messages::portfolio::document::graph_operation::utility_types::TransformIn; +use crate::messages::portfolio::document::node_graph::document_node_definitions::resolve_document_node_type; +use crate::messages::portfolio::document::utility_types::document_metadata::LayerNodeIdentifier; +use crate::messages::portfolio::document::utility_types::network_interface::{InputConnector, NodeTemplate}; +use crate::messages::tool::common_functionality::graph_modification_utils; +use crate::messages::tool::tool_messages::tool_prelude::*; +use glam::DAffine2; +use graph_craft::document::NodeInput; +use graph_craft::document::value::TaggedValue; +use std::collections::VecDeque; + +#[derive(Default)] +pub struct Ellipse; + +impl Ellipse { + pub fn create_node() -> NodeTemplate { + let node_type = resolve_document_node_type("Ellipse").expect("Ellipse node can't be found"); + node_type.node_template_input_override([None, Some(NodeInput::value(TaggedValue::F64(0.5), false)), Some(NodeInput::value(TaggedValue::F64(0.5), false))]) + } + + pub fn update_shape( + document: &DocumentMessageHandler, + ipp: &InputPreprocessorMessageHandler, + layer: LayerNodeIdentifier, + shape_tool_data: &mut ShapeToolData, + modifier: ShapeToolModifierKey, + responses: &mut VecDeque, + ) { + let [center, lock_ratio, _, _] = modifier; + + if let Some([start, end]) = shape_tool_data.data.calculate_points(document, ipp, center, lock_ratio) { + let Some(node_id) = graph_modification_utils::get_ellipse_id(layer, &document.network_interface) else { + return; + }; + + responses.add(NodeGraphMessage::SetInput { + input_connector: InputConnector::node(node_id, 1), + input: NodeInput::value(TaggedValue::F64(((start.x - end.x) / 2.).abs()), false), + }); + responses.add(NodeGraphMessage::SetInput { + input_connector: InputConnector::node(node_id, 2), + input: NodeInput::value(TaggedValue::F64(((start.y - end.y) / 2.).abs()), false), + }); + responses.add(GraphOperationMessage::TransformSet { + layer, + transform: DAffine2::from_translation(start.midpoint(end)), + transform_in: TransformIn::Viewport, + skip_rerender: false, + }); + } + } +} + +#[cfg(test)] +mod test_ellipse { + pub use crate::test_utils::test_prelude::*; + use glam::DAffine2; + use graphene_std::vector::generator_nodes::ellipse; + + #[derive(Debug, PartialEq)] + struct ResolvedEllipse { + radius_x: f64, + radius_y: f64, + transform: DAffine2, + } + + async fn get_ellipse(editor: &mut EditorTestUtils) -> Vec { + let instrumented = match editor.eval_graph().await { + Ok(instrumented) => instrumented, + Err(e) => panic!("Failed to evaluate graph: {e}"), + }; + + let document = editor.active_document(); + let layers = document.metadata().all_layers(); + layers + .filter_map(|layer| { + let node_graph_layer = NodeGraphLayer::new(layer, &document.network_interface); + let ellipse_node = node_graph_layer.upstream_node_id_from_protonode(ellipse::protonode_identifier())?; + Some(ResolvedEllipse { + radius_x: instrumented.grab_protonode_input::(&vec![ellipse_node], &editor.runtime).unwrap(), + radius_y: instrumented.grab_protonode_input::(&vec![ellipse_node], &editor.runtime).unwrap(), + transform: document.metadata().transform_to_document(layer), + }) + }) + .collect() + } + + #[tokio::test] + async fn ellipse_draw_simple() { + let mut editor = EditorTestUtils::create(); + editor.new_document().await; + editor.drag_tool(ToolType::Ellipse, 10., 10., 19., 0., ModifierKeys::empty()).await; + + assert_eq!(editor.active_document().metadata().all_layers().count(), 1); + + let ellipse = get_ellipse(&mut editor).await; + assert_eq!(ellipse.len(), 1); + assert_eq!( + ellipse[0], + ResolvedEllipse { + radius_x: 4.5, + radius_y: 5., + transform: DAffine2::from_translation(DVec2::new(14.5, 5.)) // Uses center + } + ); + } + + #[tokio::test] + async fn ellipse_draw_circle() { + let mut editor = EditorTestUtils::create(); + editor.new_document().await; + editor.drag_tool(ToolType::Ellipse, 10., 10., -10., 11., ModifierKeys::SHIFT).await; + + let ellipse = get_ellipse(&mut editor).await; + assert_eq!(ellipse.len(), 1); + assert_eq!( + ellipse[0], + ResolvedEllipse { + radius_x: 10., + radius_y: 10., + transform: DAffine2::from_translation(DVec2::new(0., 20.)) // Uses center + } + ); + } + + #[tokio::test] + async fn ellipse_draw_square_rotated() { + let mut editor = EditorTestUtils::create(); + editor.new_document().await; + editor + .handle_message(NavigationMessage::CanvasTiltSet { + // 45 degree rotation of content clockwise + angle_radians: f64::consts::FRAC_PI_4, + }) + .await; + editor.drag_tool(ToolType::Ellipse, 0., 0., 1., 10., ModifierKeys::SHIFT).await; // Viewport coordinates + + let ellipse = get_ellipse(&mut editor).await; + assert_eq!(ellipse.len(), 1); + println!("{ellipse:?}"); + assert_eq!(ellipse[0].radius_x, 5.); + assert_eq!(ellipse[0].radius_y, 5.); + + assert!( + ellipse[0] + .transform + .abs_diff_eq(DAffine2::from_angle_translation(-f64::consts::FRAC_PI_4, DVec2::X * f64::consts::FRAC_1_SQRT_2 * 10.), 0.001) + ); + } + + #[tokio::test] + async fn ellipse_draw_center_square_rotated() { + let mut editor = EditorTestUtils::create(); + editor.new_document().await; + editor + .handle_message(NavigationMessage::CanvasTiltSet { + // 45 degree rotation of content clockwise + angle_radians: f64::consts::FRAC_PI_4, + }) + .await; + editor.drag_tool(ToolType::Ellipse, 0., 0., 1., 10., ModifierKeys::SHIFT | ModifierKeys::ALT).await; // Viewport coordinates + + let ellipse = get_ellipse(&mut editor).await; + assert_eq!(ellipse.len(), 1); + assert_eq!(ellipse[0].radius_x, 10.); + assert_eq!(ellipse[0].radius_y, 10.); + assert!(ellipse[0].transform.abs_diff_eq(DAffine2::from_angle(-f64::consts::FRAC_PI_4), 0.001)); + } + + #[tokio::test] + async fn ellipse_cancel() { + let mut editor = EditorTestUtils::create(); + editor.new_document().await; + editor.drag_tool_cancel_rmb(ToolType::Ellipse).await; + + let ellipse = get_ellipse(&mut editor).await; + assert_eq!(ellipse.len(), 0); + } +} diff --git a/editor/src/messages/tool/common_functionality/shapes/line_shape.rs b/editor/src/messages/tool/common_functionality/shapes/line_shape.rs new file mode 100644 index 0000000000000000000000000000000000000000..985457c2087b40342e030938238d781d5c373514 --- /dev/null +++ b/editor/src/messages/tool/common_functionality/shapes/line_shape.rs @@ -0,0 +1,383 @@ +use super::shape_utility::ShapeToolModifierKey; +use crate::consts::{BOUNDS_SELECT_THRESHOLD, LINE_ROTATE_SNAP_ANGLE}; +use crate::messages::portfolio::document::node_graph::document_node_definitions::resolve_document_node_type; +use crate::messages::portfolio::document::overlays::utility_types::OverlayContext; +use crate::messages::portfolio::document::utility_types::document_metadata::LayerNodeIdentifier; +use crate::messages::portfolio::document::utility_types::network_interface::{InputConnector, NodeTemplate}; +use crate::messages::tool::common_functionality::graph_modification_utils; +pub use crate::messages::tool::common_functionality::graph_modification_utils::NodeGraphLayer; +use crate::messages::tool::common_functionality::snapping::{SnapCandidatePoint, SnapConstraint, SnapData, SnapTypeConfiguration}; +use crate::messages::tool::tool_messages::shape_tool::ShapeToolData; +use crate::messages::tool::tool_messages::tool_prelude::*; +use glam::DVec2; +use graph_craft::document::NodeInput; +use graph_craft::document::value::TaggedValue; +use std::collections::VecDeque; + +#[derive(Clone, PartialEq, Debug, Default)] +pub enum LineEnd { + #[default] + Start, + End, +} + +#[derive(Clone, Debug, Default)] +pub struct LineToolData { + pub drag_start: DVec2, + pub drag_current: DVec2, + pub angle: f64, + pub weight: f64, + pub selected_layers_with_position: HashMap, + pub editing_layer: Option, + pub dragging_endpoint: Option, +} + +#[derive(Default)] +pub struct Line; + +impl Line { + pub fn create_node(document: &DocumentMessageHandler, drag_start: DVec2) -> NodeTemplate { + let node_type = resolve_document_node_type("Line").expect("Line node can't be found"); + node_type.node_template_input_override([ + None, + Some(NodeInput::value(TaggedValue::DVec2(document.metadata().document_to_viewport.transform_point2(drag_start)), false)), + Some(NodeInput::value(TaggedValue::DVec2(document.metadata().document_to_viewport.transform_point2(drag_start)), false)), + ]) + } + + pub fn update_shape( + document: &DocumentMessageHandler, + ipp: &InputPreprocessorMessageHandler, + layer: LayerNodeIdentifier, + shape_tool_data: &mut ShapeToolData, + modifier: ShapeToolModifierKey, + responses: &mut VecDeque, + ) { + let [center, _, lock_angle, snap_angle] = modifier; + + shape_tool_data.line_data.drag_current = ipp.mouse.position; + + let keyboard = &ipp.keyboard; + let ignore = [layer]; + let snap_data = SnapData::ignore(document, ipp, &ignore); + let mut document_points = generate_line(shape_tool_data, snap_data, keyboard.key(lock_angle), keyboard.key(snap_angle), keyboard.key(center)); + + if shape_tool_data.line_data.dragging_endpoint == Some(LineEnd::Start) { + document_points.swap(0, 1); + } + + let Some(node_id) = graph_modification_utils::get_line_id(layer, &document.network_interface) else { + return; + }; + + responses.add(NodeGraphMessage::SetInput { + input_connector: InputConnector::node(node_id, 1), + input: NodeInput::value(TaggedValue::DVec2(document_points[0]), false), + }); + responses.add(NodeGraphMessage::SetInput { + input_connector: InputConnector::node(node_id, 2), + input: NodeInput::value(TaggedValue::DVec2(document_points[1]), false), + }); + responses.add(NodeGraphMessage::RunDocumentGraph); + } + + pub fn overlays(document: &DocumentMessageHandler, shape_tool_data: &mut ShapeToolData, overlay_context: &mut OverlayContext) { + shape_tool_data.line_data.selected_layers_with_position = document + .network_interface + .selected_nodes() + .selected_visible_and_unlocked_layers(&document.network_interface) + .filter_map(|layer| { + let node_inputs = NodeGraphLayer::new(layer, &document.network_interface).find_node_inputs("Line")?; + + let (Some(&TaggedValue::DVec2(start)), Some(&TaggedValue::DVec2(end))) = (node_inputs[1].as_value(), node_inputs[2].as_value()) else { + return None; + }; + + let [viewport_start, viewport_end] = [start, end].map(|point| document.metadata().transform_to_viewport(layer).transform_point2(point)); + if !start.abs_diff_eq(end, f64::EPSILON * 1000.) { + overlay_context.line(viewport_start, viewport_end, None, None); + overlay_context.square(viewport_start, Some(6.), None, None); + overlay_context.square(viewport_end, Some(6.), None, None); + } + + Some((layer, [start, end])) + }) + .collect::>(); + } +} + +fn generate_line(tool_data: &mut ShapeToolData, snap_data: SnapData, lock_angle: bool, snap_angle: bool, center: bool) -> [DVec2; 2] { + let document_to_viewport = snap_data.document.metadata().document_to_viewport; + let mut document_points = [tool_data.data.drag_start, document_to_viewport.inverse().transform_point2(tool_data.line_data.drag_current)]; + + let mut angle = -(document_points[1] - document_points[0]).angle_to(DVec2::X); + let mut line_length = (document_points[1] - document_points[0]).length(); + + if lock_angle { + angle = tool_data.line_data.angle; + } else if snap_angle { + let snap_resolution = LINE_ROTATE_SNAP_ANGLE.to_radians(); + angle = (angle / snap_resolution).round() * snap_resolution; + } + + tool_data.line_data.angle = angle; + + if lock_angle { + let angle_vec = DVec2::new(angle.cos(), angle.sin()); + line_length = (document_points[1] - document_points[0]).dot(angle_vec); + } + + document_points[1] = document_points[0] + line_length * DVec2::new(angle.cos(), angle.sin()); + + let constrained = snap_angle || lock_angle; + let snap = &mut tool_data.data.snap_manager; + + let near_point = SnapCandidatePoint::handle_neighbors(document_points[1], [tool_data.data.drag_start]); + let far_point = SnapCandidatePoint::handle_neighbors(2. * document_points[0] - document_points[1], [tool_data.data.drag_start]); + let config = SnapTypeConfiguration::default(); + + if constrained { + let constraint = SnapConstraint::Line { + origin: document_points[0], + direction: document_points[1] - document_points[0], + }; + if center { + let snapped = snap.constrained_snap(&snap_data, &near_point, constraint, config); + let snapped_far = snap.constrained_snap(&snap_data, &far_point, constraint, config); + let best = if snapped_far.other_snap_better(&snapped) { snapped } else { snapped_far }; + document_points[1] = document_points[0] * 2. - best.snapped_point_document; + document_points[0] = best.snapped_point_document; + snap.update_indicator(best); + } else { + let snapped = snap.constrained_snap(&snap_data, &near_point, constraint, config); + document_points[1] = snapped.snapped_point_document; + snap.update_indicator(snapped); + } + } else if center { + let snapped = snap.free_snap(&snap_data, &near_point, config); + let snapped_far = snap.free_snap(&snap_data, &far_point, config); + let best = if snapped_far.other_snap_better(&snapped) { snapped } else { snapped_far }; + document_points[1] = document_points[0] * 2. - best.snapped_point_document; + document_points[0] = best.snapped_point_document; + snap.update_indicator(best); + } else { + let snapped = snap.free_snap(&snap_data, &near_point, config); + document_points[1] = snapped.snapped_point_document; + snap.update_indicator(snapped); + } + + document_points +} + +pub fn clicked_on_line_endpoints(layer: LayerNodeIdentifier, document: &DocumentMessageHandler, input: &InputPreprocessorMessageHandler, shape_tool_data: &mut ShapeToolData) -> bool { + let Some(node_inputs) = NodeGraphLayer::new(layer, &document.network_interface).find_node_inputs("Line") else { + return false; + }; + + let (Some(&TaggedValue::DVec2(document_start)), Some(&TaggedValue::DVec2(document_end))) = (node_inputs[1].as_value(), node_inputs[2].as_value()) else { + return false; + }; + + let transform = document.metadata().transform_to_viewport(layer); + let viewport_x = transform.transform_vector2(DVec2::X).normalize_or_zero() * BOUNDS_SELECT_THRESHOLD; + let viewport_y = transform.transform_vector2(DVec2::Y).normalize_or_zero() * BOUNDS_SELECT_THRESHOLD; + let threshold_x = transform.inverse().transform_vector2(viewport_x).length(); + let threshold_y = transform.inverse().transform_vector2(viewport_y).length(); + + let drag_start = input.mouse.position; + let [start, end] = [document_start, document_end].map(|point| transform.transform_point2(point)); + + let start_click = (drag_start.y - start.y).abs() < threshold_y && (drag_start.x - start.x).abs() < threshold_x; + let end_click = (drag_start.y - end.y).abs() < threshold_y && (drag_start.x - end.x).abs() < threshold_x; + + if start_click || end_click { + shape_tool_data.line_data.dragging_endpoint = Some(if end_click { LineEnd::End } else { LineEnd::Start }); + shape_tool_data.data.drag_start = if end_click { document_start } else { document_end }; + shape_tool_data.line_data.editing_layer = Some(layer); + return true; + } + false +} + +#[cfg(test)] +mod test_line_tool { + use crate::messages::portfolio::document::graph_operation::utility_types::TransformIn; + use crate::messages::tool::common_functionality::graph_modification_utils::NodeGraphLayer; + use crate::test_utils::test_prelude::*; + use glam::DAffine2; + use graph_craft::document::value::TaggedValue; + + async fn get_line_node_inputs(editor: &mut EditorTestUtils) -> Option<(DVec2, DVec2)> { + let document = editor.active_document(); + let network_interface = &document.network_interface; + let node_id = network_interface + .selected_nodes() + .selected_visible_and_unlocked_layers(network_interface) + .filter_map(|layer| { + let node_inputs = NodeGraphLayer::new(layer, &network_interface).find_node_inputs("Line")?; + let (Some(&TaggedValue::DVec2(start)), Some(&TaggedValue::DVec2(end))) = (node_inputs[1].as_value(), node_inputs[2].as_value()) else { + return None; + }; + Some((start, end)) + }) + .next(); + node_id + } + + #[tokio::test] + async fn test_line_tool_basicdraw() { + let mut editor = EditorTestUtils::create(); + editor.new_document().await; + editor.drag_tool(ToolType::Line, 0., 0., 100., 100., ModifierKeys::empty()).await; + if let Some((start_input, end_input)) = get_line_node_inputs(&mut editor).await { + match (start_input, end_input) { + (start_input, end_input) => { + assert!((start_input - DVec2::ZERO).length() < 1., "Start point should be near (0,0)"); + assert!((end_input - DVec2::new(100., 100.)).length() < 1., "End point should be near (100,100)"); + } + } + } + } + + #[tokio::test] + async fn test_line_tool_with_transformed_viewport() { + let mut editor = EditorTestUtils::create(); + editor.new_document().await; + editor.handle_message(NavigationMessage::CanvasZoomSet { zoom_factor: 2. }).await; + editor.handle_message(NavigationMessage::CanvasPan { delta: DVec2::new(100., 50.) }).await; + editor + .handle_message(NavigationMessage::CanvasTiltSet { + angle_radians: (30. as f64).to_radians(), + }) + .await; + editor.drag_tool(ToolType::Line, 0., 0., 100., 100., ModifierKeys::empty()).await; + if let Some((start_input, end_input)) = get_line_node_inputs(&mut editor).await { + let document = editor.active_document(); + let document_to_viewport = document.metadata().document_to_viewport; + let viewport_to_document = document_to_viewport.inverse(); + + let expected_start = viewport_to_document.transform_point2(DVec2::ZERO); + let expected_end = viewport_to_document.transform_point2(DVec2::new(100., 100.)); + + assert!( + (start_input - expected_start).length() < 1., + "Start point should match expected document coordinates. Got {:?}, expected {:?}", + start_input, + expected_start + ); + assert!( + (end_input - expected_end).length() < 1., + "End point should match expected document coordinates. Got {:?}, expected {:?}", + end_input, + expected_end + ); + } else { + panic!("Line was not created successfully with transformed viewport"); + } + } + + #[tokio::test] + async fn test_line_tool_ctrl_anglelock() { + let mut editor = EditorTestUtils::create(); + editor.new_document().await; + editor.drag_tool(ToolType::Line, 0., 0., 100., 100., ModifierKeys::CONTROL).await; + if let Some((start_input, end_input)) = get_line_node_inputs(&mut editor).await { + match (start_input, end_input) { + (start_input, end_input) => { + let line_vec = end_input - start_input; + let original_angle = line_vec.angle_to(DVec2::X); + editor.drag_tool(ToolType::Line, 0., 0., 200., 50., ModifierKeys::CONTROL).await; + if let Some((updated_start, updated_end)) = get_line_node_inputs(&mut editor).await { + match (updated_start, updated_end) { + (updated_start, updated_end) => { + let updated_line_vec = updated_end - updated_start; + let updated_angle = updated_line_vec.angle_to(DVec2::X); + print!("{:?}", original_angle); + print!("{:?}", updated_angle); + assert!( + line_vec.normalize().dot(updated_line_vec.normalize()).abs() - 1. < 1e-6, + "Line angle should be locked when Ctrl is kept pressed" + ); + assert!((updated_start - updated_end).length() > 1., "Line should be able to change length when Ctrl is kept pressed"); + } + } + } + } + } + } + } + + #[tokio::test] + async fn test_line_tool_alt() { + let mut editor = EditorTestUtils::create(); + editor.new_document().await; + editor.drag_tool(ToolType::Line, 100., 100., 200., 100., ModifierKeys::ALT).await; + if let Some((start_input, end_input)) = get_line_node_inputs(&mut editor).await { + match (start_input, end_input) { + (start_input, end_input) => { + let expected_start = DVec2::new(0., 100.); + let expected_end = DVec2::new(200., 100.); + assert!((start_input - expected_start).length() < 1., "Start point should be near (0, 100)"); + assert!((end_input - expected_end).length() < 1., "End point should be near (200, 100)"); + } + } + } + } + + #[tokio::test] + async fn test_line_tool_alt_shift_drag() { + let mut editor = EditorTestUtils::create(); + editor.new_document().await; + editor.drag_tool(ToolType::Line, 100., 100., 150., 120., ModifierKeys::ALT | ModifierKeys::SHIFT).await; + if let Some((start_input, end_input)) = get_line_node_inputs(&mut editor).await { + match (start_input, end_input) { + (start_input, end_input) => { + let line_vec = end_input - start_input; + let angle_radians = line_vec.angle_to(DVec2::X); + let angle_degrees = angle_radians.to_degrees(); + let nearest_angle = (angle_degrees / 15.).round() * 15.; + + assert!((angle_degrees - nearest_angle).abs() < 1., "Angle should snap to the nearest 15 degrees"); + } + } + } + } + + #[tokio::test] + async fn test_line_tool_with_transformed_artboard() { + let mut editor = EditorTestUtils::create(); + editor.new_document().await; + editor.drag_tool(ToolType::Artboard, 0., 0., 200., 200., ModifierKeys::empty()).await; + + let artboard_id = editor.get_selected_layer().await.expect("Should have selected the artboard"); + + editor + .handle_message(GraphOperationMessage::TransformChange { + layer: artboard_id, + transform: DAffine2::from_angle(45_f64.to_radians()), + transform_in: TransformIn::Local, + skip_rerender: false, + }) + .await; + + editor.drag_tool(ToolType::Line, 50., 50., 150., 150., ModifierKeys::empty()).await; + + let (start_input, end_input) = get_line_node_inputs(&mut editor).await.expect("Line was not created successfully within transformed artboard"); + // The line should still be diagonal with equal change in x and y + let line_vector = end_input - start_input; + // Verifying the line is approximately 100*sqrt(2) units in length (diagonal of 100x100 square) + let line_length = line_vector.length(); + assert!( + (line_length - 141.42).abs() < 1., // 100 * sqrt(2) ~= 141.42 + "Line length should be approximately 141.42 units. Got: {line_length}" + ); + assert!((line_vector.x - 100.).abs() < 1., "X-component of line vector should be approximately 100. Got: {}", line_vector.x); + assert!( + (line_vector.y.abs() - 100.).abs() < 1., + "Absolute Y-component of line vector should be approximately 100. Got: {}", + line_vector.y.abs() + ); + let angle_degrees = line_vector.angle_to(DVec2::X).to_degrees(); + assert!((angle_degrees - (-45.)).abs() < 1., "Line angle should be close to -45 degrees. Got: {angle_degrees}"); + } +} diff --git a/editor/src/messages/tool/common_functionality/shapes/mod.rs b/editor/src/messages/tool/common_functionality/shapes/mod.rs new file mode 100644 index 0000000000000000000000000000000000000000..44f40b5982a32fbc21878d62f6d83338e038470b --- /dev/null +++ b/editor/src/messages/tool/common_functionality/shapes/mod.rs @@ -0,0 +1,11 @@ +pub mod ellipse_shape; +pub mod line_shape; +pub mod polygon_shape; +pub mod rectangle_shape; +pub mod shape_utility; +pub mod star_shape; + +pub use super::shapes::ellipse_shape::Ellipse; +pub use super::shapes::line_shape::{Line, LineEnd}; +pub use super::shapes::rectangle_shape::Rectangle; +pub use crate::messages::tool::tool_messages::shape_tool::ShapeToolData; diff --git a/editor/src/messages/tool/common_functionality/shapes/polygon_shape.rs b/editor/src/messages/tool/common_functionality/shapes/polygon_shape.rs new file mode 100644 index 0000000000000000000000000000000000000000..82dcf10cfc2b8aec728994d9262325397a29e957 --- /dev/null +++ b/editor/src/messages/tool/common_functionality/shapes/polygon_shape.rs @@ -0,0 +1,151 @@ +use super::shape_utility::ShapeToolModifierKey; +use super::shape_utility::update_radius_sign; +use super::*; +use crate::messages::portfolio::document::graph_operation::utility_types::TransformIn; +use crate::messages::portfolio::document::node_graph::document_node_definitions::resolve_document_node_type; +use crate::messages::portfolio::document::overlays::utility_types::OverlayContext; +use crate::messages::portfolio::document::utility_types::document_metadata::LayerNodeIdentifier; +use crate::messages::portfolio::document::utility_types::network_interface::{InputConnector, NodeTemplate}; +use crate::messages::tool::common_functionality::gizmos::shape_gizmos::number_of_points_dial::NumberOfPointsDial; +use crate::messages::tool::common_functionality::gizmos::shape_gizmos::number_of_points_dial::NumberOfPointsDialState; +use crate::messages::tool::common_functionality::gizmos::shape_gizmos::point_radius_handle::PointRadiusHandle; +use crate::messages::tool::common_functionality::gizmos::shape_gizmos::point_radius_handle::PointRadiusHandleState; +use crate::messages::tool::common_functionality::graph_modification_utils; +use crate::messages::tool::common_functionality::shape_editor::ShapeState; +use crate::messages::tool::common_functionality::shapes::shape_utility::ShapeGizmoHandler; +use crate::messages::tool::common_functionality::shapes::shape_utility::polygon_outline; +use crate::messages::tool::tool_messages::tool_prelude::*; +use glam::DAffine2; +use graph_craft::document::NodeInput; +use graph_craft::document::value::TaggedValue; +use std::collections::VecDeque; + +#[derive(Clone, Debug, Default)] +pub struct PolygonGizmoHandler { + number_of_points_dial: NumberOfPointsDial, + point_radius_handle: PointRadiusHandle, +} + +impl ShapeGizmoHandler for PolygonGizmoHandler { + fn is_any_gizmo_hovered(&self) -> bool { + self.number_of_points_dial.is_hovering() || self.point_radius_handle.hovered() + } + + fn handle_state(&mut self, selected_star_layer: LayerNodeIdentifier, mouse_position: DVec2, document: &DocumentMessageHandler, responses: &mut VecDeque) { + self.number_of_points_dial.handle_actions(selected_star_layer, mouse_position, document, responses); + self.point_radius_handle.handle_actions(selected_star_layer, document, mouse_position, responses); + } + + fn handle_click(&mut self) { + if self.number_of_points_dial.is_hovering() { + self.number_of_points_dial.update_state(NumberOfPointsDialState::Dragging); + return; + } + + if self.point_radius_handle.hovered() { + self.point_radius_handle.update_state(PointRadiusHandleState::Dragging); + } + } + + fn handle_update(&mut self, drag_start: DVec2, document: &DocumentMessageHandler, input: &InputPreprocessorMessageHandler, responses: &mut VecDeque) { + if self.number_of_points_dial.is_dragging() { + self.number_of_points_dial.update_number_of_sides(document, input, responses, drag_start); + } + + if self.point_radius_handle.is_dragging_or_snapped() { + self.point_radius_handle.update_inner_radius(document, input, responses, drag_start); + } + } + + fn overlays( + &self, + document: &DocumentMessageHandler, + selected_polygon_layer: Option, + input: &InputPreprocessorMessageHandler, + shape_editor: &mut &mut ShapeState, + mouse_position: DVec2, + overlay_context: &mut OverlayContext, + ) { + self.number_of_points_dial.overlays(document, selected_polygon_layer, shape_editor, mouse_position, overlay_context); + self.point_radius_handle.overlays(selected_polygon_layer, document, input, mouse_position, overlay_context); + + polygon_outline(selected_polygon_layer, document, overlay_context); + } + + fn dragging_overlays( + &self, + document: &DocumentMessageHandler, + input: &InputPreprocessorMessageHandler, + shape_editor: &mut &mut ShapeState, + mouse_position: DVec2, + overlay_context: &mut OverlayContext, + ) { + if self.number_of_points_dial.is_dragging() { + self.number_of_points_dial.overlays(document, None, shape_editor, mouse_position, overlay_context); + } + + if self.point_radius_handle.is_dragging_or_snapped() { + self.point_radius_handle.overlays(None, document, input, mouse_position, overlay_context); + } + } + + fn cleanup(&mut self) { + self.number_of_points_dial.cleanup(); + self.point_radius_handle.cleanup(); + } +} + +#[derive(Default)] +pub struct Polygon; + +impl Polygon { + pub fn create_node(vertices: u32) -> NodeTemplate { + let node_type = resolve_document_node_type("Regular Polygon").expect("Regular Polygon can't be found"); + node_type.node_template_input_override([None, Some(NodeInput::value(TaggedValue::U32(vertices), false)), Some(NodeInput::value(TaggedValue::F64(0.5), false))]) + } + + pub fn update_shape( + document: &DocumentMessageHandler, + ipp: &InputPreprocessorMessageHandler, + layer: LayerNodeIdentifier, + shape_tool_data: &mut ShapeToolData, + modifier: ShapeToolModifierKey, + responses: &mut VecDeque, + ) { + let [center, lock_ratio, _, _] = modifier; + + if let Some([start, end]) = shape_tool_data.data.calculate_points(document, ipp, center, lock_ratio) { + // TODO: We need to determine how to allow the polygon node to make irregular shapes + update_radius_sign(end, start, layer, document, responses); + + let dimensions = (start - end).abs(); + + // We keep the smaller dimension's scale at 1 and scale the other dimension accordingly + let mut scale = DVec2::ONE; + let radius; + if dimensions.x > dimensions.y { + scale.x = dimensions.x / dimensions.y; + radius = dimensions.y / 2.; + } else { + scale.y = dimensions.y / dimensions.x; + radius = dimensions.x / 2.; + } + + let Some(node_id) = graph_modification_utils::get_polygon_id(layer, &document.network_interface) else { + return; + }; + + responses.add(NodeGraphMessage::SetInput { + input_connector: InputConnector::node(node_id, 2), + input: NodeInput::value(TaggedValue::F64(radius), false), + }); + + responses.add(GraphOperationMessage::TransformSet { + layer, + transform: DAffine2::from_scale_angle_translation(scale, 0., (start + end) / 2.), + transform_in: TransformIn::Viewport, + skip_rerender: false, + }); + } + } +} diff --git a/editor/src/messages/tool/common_functionality/shapes/rectangle_shape.rs b/editor/src/messages/tool/common_functionality/shapes/rectangle_shape.rs new file mode 100644 index 0000000000000000000000000000000000000000..cbd6722960f0c5f19f07075805baedd9e54cf166 --- /dev/null +++ b/editor/src/messages/tool/common_functionality/shapes/rectangle_shape.rs @@ -0,0 +1,54 @@ +use super::shape_utility::ShapeToolModifierKey; +use super::*; +use crate::messages::portfolio::document::graph_operation::utility_types::TransformIn; +use crate::messages::portfolio::document::node_graph::document_node_definitions::resolve_document_node_type; +use crate::messages::portfolio::document::utility_types::document_metadata::LayerNodeIdentifier; +use crate::messages::portfolio::document::utility_types::network_interface::{InputConnector, NodeTemplate}; +use crate::messages::tool::common_functionality::graph_modification_utils; +use crate::messages::tool::tool_messages::tool_prelude::*; +use glam::DAffine2; +use graph_craft::document::NodeInput; +use graph_craft::document::value::TaggedValue; +use std::collections::VecDeque; + +#[derive(Default)] +pub struct Rectangle; + +impl Rectangle { + pub fn create_node() -> NodeTemplate { + let node_type = resolve_document_node_type("Rectangle").expect("Rectangle node can't be found"); + node_type.node_template_input_override([None, Some(NodeInput::value(TaggedValue::F64(1.), false)), Some(NodeInput::value(TaggedValue::F64(1.), false))]) + } + + pub fn update_shape( + document: &DocumentMessageHandler, + ipp: &InputPreprocessorMessageHandler, + layer: LayerNodeIdentifier, + shape_tool_data: &mut ShapeToolData, + modifier: ShapeToolModifierKey, + responses: &mut VecDeque, + ) { + let [center, lock_ratio, _, _] = modifier; + + if let Some([start, end]) = shape_tool_data.data.calculate_points(document, ipp, center, lock_ratio) { + let Some(node_id) = graph_modification_utils::get_rectangle_id(layer, &document.network_interface) else { + return; + }; + + responses.add(NodeGraphMessage::SetInput { + input_connector: InputConnector::node(node_id, 1), + input: NodeInput::value(TaggedValue::F64((start.x - end.x).abs()), false), + }); + responses.add(NodeGraphMessage::SetInput { + input_connector: InputConnector::node(node_id, 2), + input: NodeInput::value(TaggedValue::F64((start.y - end.y).abs()), false), + }); + responses.add(GraphOperationMessage::TransformSet { + layer, + transform: DAffine2::from_translation(start.midpoint(end)), + transform_in: TransformIn::Viewport, + skip_rerender: false, + }); + } + } +} diff --git a/editor/src/messages/tool/common_functionality/shapes/shape_utility.rs b/editor/src/messages/tool/common_functionality/shapes/shape_utility.rs new file mode 100644 index 0000000000000000000000000000000000000000..955984150b8e1930a69f105e0949f637e0811646 --- /dev/null +++ b/editor/src/messages/tool/common_functionality/shapes/shape_utility.rs @@ -0,0 +1,365 @@ +use super::ShapeToolData; +use crate::messages::message::Message; +use crate::messages::portfolio::document::overlays::utility_types::OverlayContext; +use crate::messages::portfolio::document::utility_types::document_metadata::LayerNodeIdentifier; +use crate::messages::portfolio::document::utility_types::network_interface::InputConnector; +use crate::messages::prelude::{DocumentMessageHandler, InputPreprocessorMessageHandler, NodeGraphMessage, Responses}; +use crate::messages::tool::common_functionality::graph_modification_utils::NodeGraphLayer; +use crate::messages::tool::common_functionality::shape_editor::ShapeState; +use crate::messages::tool::common_functionality::transformation_cage::BoundingBoxManager; +use crate::messages::tool::tool_messages::tool_prelude::Key; +use crate::messages::tool::utility_types::*; +use bezier_rs::Subpath; +use glam::{DAffine2, DMat2, DVec2}; +use graph_craft::document::NodeInput; +use graph_craft::document::value::TaggedValue; +use graphene_std::vector::click_target::ClickTargetType; +use graphene_std::vector::misc::dvec2_to_point; +use kurbo::{BezPath, PathEl, Shape}; +use std::collections::VecDeque; +use std::f64::consts::{PI, TAU}; + +#[derive(Debug, Clone, Copy, Eq, PartialEq, Default, serde::Serialize, serde::Deserialize, specta::Type)] +pub enum ShapeType { + #[default] + Polygon = 0, + Star = 1, + Rectangle = 2, + Ellipse = 3, + Line = 4, +} + +impl ShapeType { + pub fn name(&self) -> String { + (match self { + Self::Polygon => "Polygon", + Self::Star => "Star", + Self::Rectangle => "Rectangle", + Self::Ellipse => "Ellipse", + Self::Line => "Line", + }) + .into() + } + + pub fn tooltip(&self) -> String { + (match self { + Self::Line => "Line Tool", + Self::Rectangle => "Rectangle Tool", + Self::Ellipse => "Ellipse Tool", + _ => "", + }) + .into() + } + + pub fn icon_name(&self) -> String { + (match self { + Self::Line => "VectorLineTool", + Self::Rectangle => "VectorRectangleTool", + Self::Ellipse => "VectorEllipseTool", + _ => "", + }) + .into() + } + + pub fn tool_type(&self) -> ToolType { + match self { + Self::Line => ToolType::Line, + Self::Rectangle => ToolType::Rectangle, + Self::Ellipse => ToolType::Ellipse, + _ => ToolType::Shape, + } + } +} + +pub type ShapeToolModifierKey = [Key; 4]; + +/// The `ShapeGizmoHandler` trait defines the interactive behavior and overlay logic for shape-specific tools in the editor. +/// A gizmo is a visual handle or control point used to manipulate a shape's properties (e.g., number of sides, radius, angle). +pub trait ShapeGizmoHandler { + /// Called every frame to update the gizmo's interaction state based on the mouse position and selection. + /// + /// This includes detecting hover states and preparing interaction flags or visual feedback (e.g., highlighting a hovered handle). + fn handle_state(&mut self, selected_shape_layers: LayerNodeIdentifier, mouse_position: DVec2, document: &DocumentMessageHandler, responses: &mut VecDeque); + + /// Called when a mouse click occurs over the canvas and a gizmo handle is hovered. + /// + /// Used to initiate drag interactions or toggle states on the handle, depending on the tool. + /// For example, a hovered "number of points" handle might enter a "Dragging" state. + fn handle_click(&mut self); + + /// Called during a drag interaction to update the shape's parameters in real time. + /// + /// For example, a handle might calculate the distance from the drag start to determine a new radius or update the number of points. + fn handle_update(&mut self, drag_start: DVec2, document: &DocumentMessageHandler, input: &InputPreprocessorMessageHandler, responses: &mut VecDeque); + + /// Draws the static or hover-dependent overlays associated with the gizmo. + /// + /// These overlays include visual indicators like shape outlines, control points, and hover highlights. + fn overlays( + &self, + document: &DocumentMessageHandler, + selected_shape_layers: Option, + input: &InputPreprocessorMessageHandler, + shape_editor: &mut &mut ShapeState, + mouse_position: DVec2, + overlay_context: &mut OverlayContext, + ); + + /// Draws overlays specifically during a drag operation. + /// + /// Used to give real-time visual feedback based on drag progress, such as showing the updated shape preview or snapping guides. + fn dragging_overlays( + &self, + document: &DocumentMessageHandler, + input: &InputPreprocessorMessageHandler, + shape_editor: &mut &mut ShapeState, + mouse_position: DVec2, + overlay_context: &mut OverlayContext, + ); + + /// Returns `true` if any handle or control point in the gizmo is currently being hovered. + fn is_any_gizmo_hovered(&self) -> bool; + + /// Resets or clears any internal state maintained by the gizmo when it is no longer active. + /// + /// For example, dragging states or hover flags should be cleared to avoid visual glitches when switching tools or shapes. + fn cleanup(&mut self); +} + +/// Center, Lock Ratio, Lock Angle, Snap Angle, Increase/Decrease Side +pub fn update_radius_sign(end: DVec2, start: DVec2, layer: LayerNodeIdentifier, document: &DocumentMessageHandler, responses: &mut VecDeque) { + let sign_num = if end[1] > start[1] { 1. } else { -1. }; + let new_layer = NodeGraphLayer::new(layer, &document.network_interface); + + if new_layer.find_input("Regular Polygon", 1).unwrap_or(&TaggedValue::U32(0)).to_u32() % 2 == 1 { + let Some(polygon_node_id) = new_layer.upstream_node_id_from_name("Regular Polygon") else { return }; + + responses.add(NodeGraphMessage::SetInput { + input_connector: InputConnector::node(polygon_node_id, 2), + input: NodeInput::value(TaggedValue::F64(sign_num * 0.5), false), + }); + return; + } + + if new_layer.find_input("Star", 1).unwrap_or(&TaggedValue::U32(0)).to_u32() % 2 == 1 { + let Some(star_node_id) = new_layer.upstream_node_id_from_name("Star") else { return }; + + responses.add(NodeGraphMessage::SetInput { + input_connector: InputConnector::node(star_node_id, 2), + input: NodeInput::value(TaggedValue::F64(sign_num * 0.5), false), + }); + responses.add(NodeGraphMessage::SetInput { + input_connector: InputConnector::node(star_node_id, 3), + input: NodeInput::value(TaggedValue::F64(sign_num * 0.25), false), + }); + } +} + +pub fn transform_cage_overlays(document: &DocumentMessageHandler, tool_data: &mut ShapeToolData, overlay_context: &mut OverlayContext) { + let mut transform = document + .network_interface + .selected_nodes() + .selected_visible_and_unlocked_layers(&document.network_interface) + .find(|layer| !document.network_interface.is_artboard(&layer.to_node(), &[])) + .map(|layer| document.metadata().transform_to_viewport_with_first_transform_node_if_group(layer, &document.network_interface)) + .unwrap_or_default(); + + // Check if the matrix is not invertible + let mut transform_tampered = false; + if transform.matrix2.determinant() == 0. { + transform.matrix2 += DMat2::IDENTITY * 1e-4; // TODO: Is this the cleanest way to handle this? + transform_tampered = true; + } + + let bounds = document + .network_interface + .selected_nodes() + .selected_visible_and_unlocked_layers(&document.network_interface) + .filter(|layer| !document.network_interface.is_artboard(&layer.to_node(), &[])) + .filter_map(|layer| { + document + .metadata() + .bounding_box_with_transform(layer, transform.inverse() * document.metadata().transform_to_viewport(layer)) + }) + .reduce(graphene_std::renderer::Quad::combine_bounds); + + if let Some(bounds) = bounds { + let bounding_box_manager = tool_data.bounding_box_manager.get_or_insert(BoundingBoxManager::default()); + + bounding_box_manager.bounds = bounds; + bounding_box_manager.transform = transform; + bounding_box_manager.transform_tampered = transform_tampered; + bounding_box_manager.render_overlays(overlay_context, true); + } else { + tool_data.bounding_box_manager.take(); + } +} + +pub fn anchor_overlays(document: &DocumentMessageHandler, overlay_context: &mut OverlayContext) { + for layer in document.network_interface.selected_nodes().selected_layers(document.metadata()) { + let Some(vector_data) = document.network_interface.compute_modified_vector(layer) else { continue }; + let transform = document.metadata().transform_to_viewport(layer); + + overlay_context.outline_vector(&vector_data, transform); + + for (_, &position) in vector_data.point_domain.ids().iter().zip(vector_data.point_domain.positions()) { + overlay_context.manipulator_anchor(transform.transform_point2(position), false, None); + } + } +} + +/// Extract the node input values of Star. +/// Returns an option of (sides, radius1, radius2). +pub fn extract_star_parameters(layer: Option, document: &DocumentMessageHandler) -> Option<(u32, f64, f64)> { + let node_inputs = NodeGraphLayer::new(layer?, &document.network_interface).find_node_inputs("Star")?; + + let (Some(&TaggedValue::U32(sides)), Some(&TaggedValue::F64(radius_1)), Some(&TaggedValue::F64(radius_2))) = + (node_inputs.get(1)?.as_value(), node_inputs.get(2)?.as_value(), node_inputs.get(3)?.as_value()) + else { + return None; + }; + + Some((sides, radius_1, radius_2)) +} + +/// Extract the node input values of Polygon. +/// Returns an option of (sides, radius). +pub fn extract_polygon_parameters(layer: Option, document: &DocumentMessageHandler) -> Option<(u32, f64)> { + let node_inputs = NodeGraphLayer::new(layer?, &document.network_interface).find_node_inputs("Regular Polygon")?; + + let (Some(&TaggedValue::U32(n)), Some(&TaggedValue::F64(radius))) = (node_inputs.get(1)?.as_value(), node_inputs.get(2)?.as_value()) else { + return None; + }; + + Some((n, radius)) +} + +/// Calculate the viewport position of as a star vertex given its index +pub fn star_vertex_position(viewport: DAffine2, vertex_index: i32, n: u32, radius1: f64, radius2: f64) -> DVec2 { + let angle = ((vertex_index as f64) * PI) / (n as f64); + let radius = if vertex_index % 2 == 0 { radius1 } else { radius2 }; + + viewport.transform_point2(DVec2 { + x: radius * angle.sin(), + y: -radius * angle.cos(), + }) +} + +/// Calculate the viewport position of a polygon vertex given its index +pub fn polygon_vertex_position(viewport: DAffine2, vertex_index: i32, n: u32, radius: f64) -> DVec2 { + let angle = ((vertex_index as f64) * TAU) / (n as f64); + + viewport.transform_point2(DVec2 { + x: radius * angle.sin(), + y: -radius * angle.cos(), + }) +} + +/// Outlines the geometric shape made by star-node +pub fn star_outline(layer: Option, document: &DocumentMessageHandler, overlay_context: &mut OverlayContext) { + let Some(layer) = layer else { return }; + let Some((sides, radius1, radius2)) = extract_star_parameters(Some(layer), document) else { + return; + }; + + let viewport = document.metadata().transform_to_viewport(layer); + + let points = sides as u64; + let diameter: f64 = radius1 * 2.; + let inner_diameter = radius2 * 2.; + + let subpath: Vec = vec![ClickTargetType::Subpath(Subpath::new_star_polygon(DVec2::splat(-diameter), points, diameter, inner_diameter))]; + + overlay_context.outline(subpath.iter(), viewport, None); +} + +/// Outlines the geometric shape made by polygon-node +pub fn polygon_outline(layer: Option, document: &DocumentMessageHandler, overlay_context: &mut OverlayContext) { + let Some(layer) = layer else { return }; + let Some((sides, radius)) = extract_polygon_parameters(Some(layer), document) else { + return; + }; + + let viewport = document.metadata().transform_to_viewport(layer); + + let points = sides as u64; + let radius: f64 = radius * 2.; + + let subpath: Vec = vec![ClickTargetType::Subpath(Subpath::new_regular_polygon(DVec2::splat(-radius), points, radius))]; + + overlay_context.outline(subpath.iter(), viewport, None); +} + +/// Check if the the cursor is inside the geometric star shape made by the Star node without any upstream node modifications +pub fn inside_star(viewport: DAffine2, n: u32, radius1: f64, radius2: f64, mouse_position: DVec2) -> bool { + let mut paths = Vec::new(); + + for i in 0..2 * n { + let new_point = dvec2_to_point(star_vertex_position(viewport, i as i32, n, radius1, radius2)); + + if i == 0 { + paths.push(PathEl::MoveTo(new_point)); + } else { + paths.push(PathEl::LineTo(new_point)); + } + } + + paths.push(PathEl::ClosePath); + + let bez_path = BezPath::from_vec(paths); + let (shape, bbox) = (bez_path.clone(), bez_path.bounding_box()); + + if bbox.x0 > mouse_position.x || bbox.y0 > mouse_position.y || bbox.x1 < mouse_position.x || bbox.y1 < mouse_position.y { + return false; + } + + let winding = shape.winding(dvec2_to_point(mouse_position)); + + // Non-zero fill rule + winding != 0 +} + +/// Check if the the cursor is inside the geometric polygon shape made by the Polygon node without any upstream node modifications +pub fn inside_polygon(viewport: DAffine2, n: u32, radius: f64, mouse_position: DVec2) -> bool { + let mut paths = Vec::new(); + + for i in 0..n { + let new_point = dvec2_to_point(polygon_vertex_position(viewport, i as i32, n, radius)); + + if i == 0 { + paths.push(PathEl::MoveTo(new_point)); + } else { + paths.push(PathEl::LineTo(new_point)); + } + } + + paths.push(PathEl::ClosePath); + + let bez_path = BezPath::from_vec(paths); + let (shape, bbox) = (bez_path.clone(), bez_path.bounding_box()); + + if bbox.x0 > mouse_position.x || bbox.y0 > mouse_position.y || bbox.x1 < mouse_position.x || bbox.y1 < mouse_position.y { + return false; + } + + let winding = shape.winding(dvec2_to_point(mouse_position)); + + // Non-zero fill rule + winding != 0 +} + +pub fn draw_snapping_ticks(snap_radii: &[f64], direction: DVec2, viewport: DAffine2, angle: f64, overlay_context: &mut OverlayContext) { + for &snapped_radius in snap_radii { + let Some(tick_direction) = direction.perp().try_normalize() else { + return; + }; + + let tick_position = viewport.transform_point2(DVec2 { + x: snapped_radius * angle.sin(), + y: -snapped_radius * angle.cos(), + }); + + overlay_context.line(tick_position, tick_position + tick_direction * 5., None, Some(2.)); + overlay_context.line(tick_position, tick_position - tick_direction * 5., None, Some(2.)); + } +} diff --git a/editor/src/messages/tool/common_functionality/shapes/star_shape.rs b/editor/src/messages/tool/common_functionality/shapes/star_shape.rs new file mode 100644 index 0000000000000000000000000000000000000000..653b22f3bafcdfc6264873161eb3e5261311bba5 --- /dev/null +++ b/editor/src/messages/tool/common_functionality/shapes/star_shape.rs @@ -0,0 +1,158 @@ +use super::shape_utility::{ShapeToolModifierKey, update_radius_sign}; +use super::*; +use crate::messages::portfolio::document::graph_operation::utility_types::TransformIn; +use crate::messages::portfolio::document::node_graph::document_node_definitions::resolve_document_node_type; +use crate::messages::portfolio::document::overlays::utility_types::OverlayContext; +use crate::messages::portfolio::document::utility_types::document_metadata::LayerNodeIdentifier; +use crate::messages::portfolio::document::utility_types::network_interface::{InputConnector, NodeTemplate}; +use crate::messages::tool::common_functionality::gizmos::shape_gizmos::number_of_points_dial::{NumberOfPointsDial, NumberOfPointsDialState}; +use crate::messages::tool::common_functionality::gizmos::shape_gizmos::point_radius_handle::{PointRadiusHandle, PointRadiusHandleState}; +use crate::messages::tool::common_functionality::graph_modification_utils; +use crate::messages::tool::common_functionality::shape_editor::ShapeState; +use crate::messages::tool::common_functionality::shapes::shape_utility::{ShapeGizmoHandler, star_outline}; +use crate::messages::tool::tool_messages::tool_prelude::*; +use core::f64; +use glam::DAffine2; +use graph_craft::document::NodeInput; +use graph_craft::document::value::TaggedValue; +use std::collections::VecDeque; + +#[derive(Clone, Debug, Default)] +pub struct StarGizmoHandler { + number_of_points_dial: NumberOfPointsDial, + point_radius_handle: PointRadiusHandle, +} + +impl ShapeGizmoHandler for StarGizmoHandler { + fn is_any_gizmo_hovered(&self) -> bool { + self.number_of_points_dial.is_hovering() || self.point_radius_handle.hovered() + } + + fn handle_state(&mut self, selected_star_layer: LayerNodeIdentifier, mouse_position: DVec2, document: &DocumentMessageHandler, responses: &mut VecDeque) { + self.number_of_points_dial.handle_actions(selected_star_layer, mouse_position, document, responses); + self.point_radius_handle.handle_actions(selected_star_layer, document, mouse_position, responses); + } + + fn handle_click(&mut self) { + if self.number_of_points_dial.is_hovering() { + self.number_of_points_dial.update_state(NumberOfPointsDialState::Dragging); + return; + } + + if self.point_radius_handle.hovered() { + self.point_radius_handle.update_state(PointRadiusHandleState::Dragging); + } + } + + fn handle_update(&mut self, drag_start: DVec2, document: &DocumentMessageHandler, input: &InputPreprocessorMessageHandler, responses: &mut VecDeque) { + if self.number_of_points_dial.is_dragging() { + self.number_of_points_dial.update_number_of_sides(document, input, responses, drag_start); + } + + if self.point_radius_handle.is_dragging_or_snapped() { + self.point_radius_handle.update_inner_radius(document, input, responses, drag_start); + } + } + + fn overlays( + &self, + document: &DocumentMessageHandler, + selected_star_layer: Option, + input: &InputPreprocessorMessageHandler, + shape_editor: &mut &mut ShapeState, + mouse_position: DVec2, + overlay_context: &mut OverlayContext, + ) { + self.number_of_points_dial.overlays(document, selected_star_layer, shape_editor, mouse_position, overlay_context); + self.point_radius_handle.overlays(selected_star_layer, document, input, mouse_position, overlay_context); + + star_outline(selected_star_layer, document, overlay_context); + } + + fn dragging_overlays( + &self, + document: &DocumentMessageHandler, + input: &InputPreprocessorMessageHandler, + shape_editor: &mut &mut ShapeState, + mouse_position: DVec2, + overlay_context: &mut OverlayContext, + ) { + if self.number_of_points_dial.is_dragging() { + self.number_of_points_dial.overlays(document, None, shape_editor, mouse_position, overlay_context); + } + + if self.point_radius_handle.is_dragging_or_snapped() { + self.point_radius_handle.overlays(None, document, input, mouse_position, overlay_context); + } + } + + fn cleanup(&mut self) { + self.number_of_points_dial.cleanup(); + self.point_radius_handle.cleanup(); + } +} + +#[derive(Default)] +pub struct Star; + +impl Star { + pub fn create_node(vertices: u32) -> NodeTemplate { + let node_type = resolve_document_node_type("Star").expect("Star node can't be found"); + node_type.node_template_input_override([ + None, + Some(NodeInput::value(TaggedValue::U32(vertices), false)), + Some(NodeInput::value(TaggedValue::F64(0.5), false)), + Some(NodeInput::value(TaggedValue::F64(0.25), false)), + ]) + } + + pub fn update_shape( + document: &DocumentMessageHandler, + ipp: &InputPreprocessorMessageHandler, + layer: LayerNodeIdentifier, + shape_tool_data: &mut ShapeToolData, + modifier: ShapeToolModifierKey, + responses: &mut VecDeque, + ) { + let [center, lock_ratio, _, _] = modifier; + + if let Some([start, end]) = shape_tool_data.data.calculate_points(document, ipp, center, lock_ratio) { + // TODO: We need to determine how to allow the polygon node to make irregular shapes + update_radius_sign(end, start, layer, document, responses); + + let dimensions = (start - end).abs(); + + // We keep the smaller dimension's scale at 1 and scale the other dimension accordingly + let mut scale = DVec2::ONE; + let radius: f64; + if dimensions.x > dimensions.y { + scale.x = dimensions.x / dimensions.y; + radius = dimensions.y / 2.; + } else { + scale.y = dimensions.y / dimensions.x; + radius = dimensions.x / 2.; + } + + let Some(node_id) = graph_modification_utils::get_star_id(layer, &document.network_interface) else { + return; + }; + + responses.add(NodeGraphMessage::SetInput { + input_connector: InputConnector::node(node_id, 2), + input: NodeInput::value(TaggedValue::F64(radius), false), + }); + + responses.add(NodeGraphMessage::SetInput { + input_connector: InputConnector::node(node_id, 3), + input: NodeInput::value(TaggedValue::F64(radius / 2.), false), + }); + + responses.add(GraphOperationMessage::TransformSet { + layer, + transform: DAffine2::from_scale_angle_translation(scale, 0., (start + end) / 2.), + transform_in: TransformIn::Viewport, + skip_rerender: false, + }); + } + } +} diff --git a/editor/src/messages/tool/common_functionality/snapping.rs b/editor/src/messages/tool/common_functionality/snapping.rs new file mode 100644 index 0000000000000000000000000000000000000000..63319b32a09c27e2782b4a2833fc8fcc6f848ef9 --- /dev/null +++ b/editor/src/messages/tool/common_functionality/snapping.rs @@ -0,0 +1,509 @@ +mod alignment_snapper; +mod distribution_snapper; +mod grid_snapper; +mod layer_snapper; +mod snap_results; + +use crate::consts::{COLOR_OVERLAY_BLUE, COLOR_OVERLAY_LABEL_BACKGROUND, COLOR_OVERLAY_WHITE}; +use crate::messages::portfolio::document::overlays::utility_types::{OverlayContext, Pivot}; +use crate::messages::portfolio::document::utility_types::document_metadata::LayerNodeIdentifier; +use crate::messages::portfolio::document::utility_types::misc::{GridSnapTarget, PathSnapTarget, SnapTarget}; +use crate::messages::prelude::*; +pub use alignment_snapper::*; +use bezier_rs::TValue; +pub use distribution_snapper::*; +use glam::{DAffine2, DVec2}; +use graphene_std::renderer::Quad; +use graphene_std::renderer::Rect; +use graphene_std::vector::NoHashBuilder; +use graphene_std::vector::PointId; +pub use grid_snapper::*; +pub use layer_snapper::*; +pub use snap_results::*; +use std::cmp::Ordering; + +/// Configuration for the relevant snap type +#[derive(Debug, Clone, Copy, Default)] +pub struct SnapTypeConfiguration { + pub only_path: bool, + pub use_existing_candidates: bool, + pub accept_distribution: bool, + pub bbox: Option, +} + +/// Handles snapping and snap overlays +#[derive(Debug, Clone, Default)] +pub struct SnapManager { + indicator: Option, + layer_snapper: LayerSnapper, + grid_snapper: GridSnapper, + alignment_snapper: AlignmentSnapper, + distribution_snapper: DistributionSnapper, + candidates: Option>, + alignment_candidates: Option>, +} + +#[derive(Clone, Copy, Debug, Default)] +pub enum SnapConstraint { + #[default] + None, + Line { + origin: DVec2, + direction: DVec2, + }, + Direction(DVec2), + Circle { + center: DVec2, + radius: f64, + }, +} +impl SnapConstraint { + pub fn projection(&self, point: DVec2) -> DVec2 { + match *self { + Self::Line { origin, direction } if direction != DVec2::ZERO => (point - origin).project_onto(direction) + origin, + Self::Circle { center, radius } => { + let from_center = point - center; + let distance = from_center.length(); + if distance > 0. { + center + radius * from_center / distance + } else { + // Point is exactly at the center, so project right + center + DVec2::new(radius, 0.) + } + } + _ => point, + } + } + pub fn direction(&self) -> DVec2 { + match *self { + Self::Line { direction, .. } | Self::Direction(direction) => direction, + _ => DVec2::ZERO, + } + } +} +pub fn snap_tolerance(document: &DocumentMessageHandler) -> f64 { + document.snapping_state.tolerance / document.document_ptz.zoom() +} + +fn compare_points(a: &&SnappedPoint, b: &&SnappedPoint) -> Ordering { + if (a.target.bounding_box() && !b.target.bounding_box()) || (a.at_intersection && !b.at_intersection) || (a.source.bounding_box() && !b.source.bounding_box()) { + Ordering::Greater + } else if (!a.target.bounding_box() && b.target.bounding_box()) || (!a.at_intersection && b.at_intersection) || (!a.source.bounding_box() && b.source.bounding_box()) { + Ordering::Less + } else { + a.distance.partial_cmp(&b.distance).unwrap() + } +} + +fn find_align(a: &SnappedPoint, b: &SnappedPoint) -> Ordering { + (a.distance, a.distance_to_align_target).partial_cmp(&(b.distance, b.distance_to_align_target)).unwrap() +} + +fn get_closest_point(points: Vec) -> Option { + let mut best_not_align = None; + let mut best_align = None; + for point in points { + if !point.align() && !best_not_align.as_ref().is_some_and(|best| compare_points(&best, &&point).is_ge()) { + best_not_align = Some(point); + } else if point.align() && !best_align.as_ref().is_some_and(|best| find_align(best, &point).is_ge()) { + best_align = Some(point) + } + } + match (best_not_align, best_align) { + (None, None) => None, + (Some(result), None) | (None, Some(result)) => Some(result), + (Some(mut result), Some(align)) => { + let SnapTarget::DistributeEvenly(distribution) = result.target else { return Some(result) }; + if distribution.is_x() && align.alignment_target_horizontal.is_some() { + result.snapped_point_document.y = align.snapped_point_document.y; + result.alignment_target_horizontal = align.alignment_target_horizontal; + } + if distribution.is_y() && align.alignment_target_vertical.is_some() { + result.snapped_point_document.x = align.snapped_point_document.x; + result.alignment_target_vertical = align.alignment_target_vertical; + } + + Some(result) + } + } +} +fn get_closest_curve(curves: &[SnappedCurve], exclude_paths: bool) -> Option<&SnappedPoint> { + let keep_curve = |curve: &&SnappedCurve| !exclude_paths || curve.point.target != SnapTarget::Path(PathSnapTarget::AlongPath); + curves.iter().filter(keep_curve).map(|curve| &curve.point).min_by(compare_points) +} +fn get_closest_line(lines: &[SnappedLine]) -> Option<&SnappedPoint> { + lines.iter().map(|curve| &curve.point).min_by(compare_points) +} +fn get_closest_intersection(snap_to: DVec2, curves: &[SnappedCurve]) -> Option { + let mut best = None; + for curve_i in curves { + for curve_j in curves { + if curve_i.start == curve_j.start && curve_i.layer == curve_j.layer { + continue; + } + for curve_i_t in curve_i.document_curve.intersections(&curve_j.document_curve, None, None) { + let snapped_point_document = curve_i.document_curve.evaluate(TValue::Parametric(curve_i_t)); + let distance = snap_to.distance(snapped_point_document); + let i_closer = curve_i.point.distance < curve_j.point.distance; + let close = if i_closer { curve_i } else { curve_j }; + let far = if i_closer { curve_j } else { curve_i }; + if !best.as_ref().is_some_and(|best: &SnappedPoint| best.distance < distance) { + best = Some(SnappedPoint { + snapped_point_document, + distance, + target: SnapTarget::Path(PathSnapTarget::IntersectionPoint), + tolerance: close.point.tolerance, + outline_layers: [Some(close.layer), Some(far.layer)], + source: close.point.source, + at_intersection: true, + constrained: true, + ..Default::default() + }) + } + } + } + } + best +} +fn get_grid_intersection(snap_to: DVec2, lines: &[SnappedLine]) -> Option { + let mut best = None; + for line_i in lines { + for line_j in lines { + if let Some(snapped_point_document) = Quad::intersect_rays(line_i.point.snapped_point_document, line_i.direction, line_j.point.snapped_point_document, line_j.direction) { + let distance = snap_to.distance(snapped_point_document); + if !best.as_ref().is_some_and(|best: &SnappedPoint| best.distance < distance) { + best = Some(SnappedPoint { + snapped_point_document, + distance, + target: SnapTarget::Grid(GridSnapTarget::Intersection), + tolerance: line_i.point.tolerance, + source: line_i.point.source, + at_intersection: true, + constrained: true, + ..Default::default() + }) + } + } + } + } + best +} + +#[derive(Default, Clone, Debug)] +pub struct SnapCache { + pub manipulators: HashMap, NoHashBuilder>, + pub unselected: Vec, +} + +#[derive(Clone)] +pub struct SnapData<'a> { + pub document: &'a DocumentMessageHandler, + pub input: &'a InputPreprocessorMessageHandler, + pub ignore: &'a [LayerNodeIdentifier], + pub node_snap_cache: Option<&'a SnapCache>, + pub candidates: Option<&'a Vec>, + pub alignment_candidates: Option<&'a Vec>, +} +impl<'a> SnapData<'a> { + pub fn new(document: &'a DocumentMessageHandler, input: &'a InputPreprocessorMessageHandler) -> Self { + Self::ignore(document, input, &[]) + } + pub fn ignore(document: &'a DocumentMessageHandler, input: &'a InputPreprocessorMessageHandler, ignore: &'a [LayerNodeIdentifier]) -> Self { + Self { + document, + input, + ignore, + candidates: None, + alignment_candidates: None, + node_snap_cache: None, + } + } + pub fn new_snap_cache(document: &'a DocumentMessageHandler, input: &'a InputPreprocessorMessageHandler, snap_cache: &'a SnapCache) -> Self { + Self { + node_snap_cache: Some(snap_cache), + ..Self::new(document, input) + } + } + fn get_candidates(&self) -> &[LayerNodeIdentifier] { + self.candidates.map_or([].as_slice(), |candidates| candidates.as_slice()) + } + fn ignore_bounds(&self, layer: LayerNodeIdentifier) -> bool { + self.node_snap_cache.is_some_and(|cache| cache.manipulators.contains_key(&layer)) + } + fn ignore_manipulator(&self, layer: LayerNodeIdentifier, target: PointId) -> bool { + self.node_snap_cache.and_then(|cache| cache.manipulators.get(&layer)).is_some_and(|points| points.contains(&target)) + } + fn has_manipulators(&self) -> bool { + self.node_snap_cache.is_some_and(|cache| !cache.manipulators.is_empty()) + } +} +impl SnapManager { + pub fn update_indicator(&mut self, snapped_point: SnappedPoint) { + self.indicator = snapped_point.is_snapped().then_some(snapped_point); + } + pub fn clear_indicator(&mut self) { + self.indicator = None; + } + pub fn preview_draw(&mut self, snap_data: &SnapData, mouse: DVec2) { + let point = SnapCandidatePoint::handle(snap_data.document.metadata().document_to_viewport.inverse().transform_point2(mouse)); + let snapped = self.free_snap(snap_data, &point, SnapTypeConfiguration::default()); + self.update_indicator(snapped); + } + + pub fn indicator_pos(&self) -> Option { + self.indicator.as_ref().map(|point| point.snapped_point_document) + } + + fn find_best_snap(snap_data: &mut SnapData, point: &SnapCandidatePoint, snap_results: SnapResults, constrained: bool, off_screen: bool, to_path: bool) -> SnappedPoint { + let mut snapped_points = Vec::new(); + let document = snap_data.document; + + if let Some(closest_point) = get_closest_point(snap_results.points) { + snapped_points.push(closest_point); + } + let exclude_paths = !document.snapping_state.target_enabled(SnapTarget::Path(PathSnapTarget::AlongPath)); + if let Some(closest_curve) = get_closest_curve(&snap_results.curves, exclude_paths) { + snapped_points.push(closest_curve.clone()); + } + + if document.snapping_state.target_enabled(SnapTarget::Grid(GridSnapTarget::Line)) { + if let Some(closest_line) = get_closest_line(&snap_results.grid_lines) { + snapped_points.push(closest_line.clone()); + } + } + + if !constrained { + if document.snapping_state.target_enabled(SnapTarget::Path(PathSnapTarget::IntersectionPoint)) { + if let Some(closest_curves_intersection) = get_closest_intersection(point.document_point, &snap_results.curves) { + snapped_points.push(closest_curves_intersection); + } + } + if document.snapping_state.target_enabled(SnapTarget::Grid(GridSnapTarget::Intersection)) { + if let Some(closest_grid_intersection) = get_grid_intersection(point.document_point, &snap_results.grid_lines) { + snapped_points.push(closest_grid_intersection); + } + } + } + + if to_path { + snapped_points.retain(|i| matches!(i.target, SnapTarget::Path(_))); + } + + let mut best_point = None; + + for point in snapped_points { + let viewport_point = document.metadata().document_to_viewport.transform_point2(point.snapped_point_document); + let on_screen = viewport_point.cmpgt(DVec2::ZERO).all() && viewport_point.cmplt(snap_data.input.viewport_bounds.size()).all(); + if !on_screen && !off_screen { + continue; + } + if point.distance > point.tolerance { + continue; + } + if best_point.as_ref().is_some_and(|best: &SnappedPoint| point.other_snap_better(best)) { + continue; + } + best_point = Some(point); + } + + best_point.unwrap_or(SnappedPoint::infinite_snap(point.document_point)) + } + + fn add_candidates(&mut self, layer: LayerNodeIdentifier, snap_data: &SnapData, quad: Quad) { + let document = snap_data.document; + + if !document.network_interface.is_visible(&layer.to_node(), &[]) { + return; + } + if snap_data.ignore.contains(&layer) { + return; + } + if layer.has_children(document.metadata()) { + for layer in layer.children(document.metadata()) { + self.add_candidates(layer, snap_data, quad); + } + return; + } + let Some(bounds) = document.metadata().bounding_box_with_transform(layer, DAffine2::IDENTITY) else { + return; + }; + let layer_bounds = document.metadata().transform_to_document(layer) * Quad::from_box(bounds); + let screen_bounds = document.metadata().document_to_viewport.inverse() * Quad::from_box([DVec2::ZERO, snap_data.input.viewport_bounds.size()]); + if screen_bounds.intersects(layer_bounds) { + if self.alignment_candidates.as_ref().is_none_or(|candidates| candidates.len() <= 100) { + self.alignment_candidates.get_or_insert_with(Vec::new).push(layer); + } + if quad.intersects(layer_bounds) && self.candidates.as_ref().is_none_or(|candidates| candidates.len() <= 10) { + self.candidates.get_or_insert_with(Vec::new).push(layer); + } + } + } + + fn find_candidates(&mut self, snap_data: &SnapData, point: &SnapCandidatePoint, bbox: Option) { + let document = snap_data.document; + let offset = snap_tolerance(document); + let quad = bbox.map_or_else(|| Quad::from_square(point.document_point, offset), |quad| Quad::from_box(quad.0).inflate(offset)); + + self.candidates = None; + self.alignment_candidates = None; + for layer in LayerNodeIdentifier::ROOT_PARENT.children(document.metadata()) { + self.add_candidates(layer, snap_data, quad); + } + + if self.alignment_candidates.as_ref().is_some_and(|candidates| candidates.len() > crate::consts::MAX_ALIGNMENT_CANDIDATES) { + warn!("Alignment candidate overflow"); + } + if self.candidates.as_ref().is_some_and(|candidates| candidates.len() > crate::consts::MAX_SNAP_CANDIDATES) { + warn!("Snap candidate overflow"); + } + } + + pub fn free_snap(&mut self, snap_data: &SnapData, point: &SnapCandidatePoint, config: SnapTypeConfiguration) -> SnappedPoint { + if !point.document_point.is_finite() { + warn!("Snapping non-finite position"); + return SnappedPoint::infinite_snap(DVec2::ZERO); + } + + let mut snap_results = SnapResults::default(); + if !config.use_existing_candidates { + self.candidates = None; + } + + let mut snap_data = snap_data.clone(); + if snap_data.candidates.is_none() { + self.find_candidates(&snap_data, point, config.bbox); + } + snap_data.candidates = self.candidates.as_ref(); + snap_data.alignment_candidates = self.alignment_candidates.as_ref(); + + self.layer_snapper.free_snap(&mut snap_data, point, &mut snap_results, config); + self.grid_snapper.free_snap(&mut snap_data, point, &mut snap_results); + self.alignment_snapper.free_snap(&mut snap_data, point, &mut snap_results, config); + self.distribution_snapper.free_snap(&mut snap_data, point, &mut snap_results, config); + + Self::find_best_snap(&mut snap_data, point, snap_results, false, false, config.only_path) + } + + pub fn constrained_snap(&mut self, snap_data: &SnapData, point: &SnapCandidatePoint, constraint: SnapConstraint, config: SnapTypeConfiguration) -> SnappedPoint { + if !point.document_point.is_finite() { + warn!("Snapping non-finite position"); + return SnappedPoint::infinite_snap(DVec2::ZERO); + } + + let mut snap_results = SnapResults::default(); + if !config.use_existing_candidates { + self.candidates = None; + } + + let mut snap_data = snap_data.clone(); + if snap_data.candidates.is_none() { + self.find_candidates(&snap_data, point, config.bbox); + } + snap_data.candidates = self.candidates.as_ref(); + snap_data.alignment_candidates = self.alignment_candidates.as_ref(); + + self.layer_snapper.constrained_snap(&mut snap_data, point, &mut snap_results, constraint, config); + self.grid_snapper.constrained_snap(&mut snap_data, point, &mut snap_results, constraint); + self.alignment_snapper.constrained_snap(&mut snap_data, point, &mut snap_results, constraint, config); + self.distribution_snapper.constrained_snap(&mut snap_data, point, &mut snap_results, constraint, config); + + Self::find_best_snap(&mut snap_data, point, snap_results, true, false, config.only_path) + } + + fn alignment_x_overlay(boxes: &VecDeque, transform: DAffine2, overlay_context: &mut OverlayContext) { + let y_size = transform.inverse().transform_vector2(DVec2::Y * 8.).length(); + for (&first, &second) in boxes.iter().zip(boxes.iter().skip(1)) { + let bottom = first.center().y < second.center().y + y_size; + let y = if bottom { first.max() } else { first.min() }.y; + let start = DVec2::new(first.max().x, y); + let end = DVec2::new(second.min().x, y); + let signed_size = if bottom { y_size } else { -y_size }; + overlay_context.line(transform.transform_point2(start), transform.transform_point2(start + DVec2::Y * signed_size), None, None); + overlay_context.line(transform.transform_point2(end), transform.transform_point2(end + DVec2::Y * signed_size), None, None); + overlay_context.line( + transform.transform_point2(start + DVec2::Y * signed_size / 2.), + transform.transform_point2(end + DVec2::Y * signed_size / 2.), + None, + None, + ); + } + } + + fn alignment_y_overlay(boxes: &VecDeque, transform: DAffine2, overlay_context: &mut OverlayContext) { + let x_size = transform.inverse().transform_vector2(DVec2::X * 8.).length(); + for (&first, &second) in boxes.iter().zip(boxes.iter().skip(1)) { + let right = first.center().x < second.center().x + x_size; + let x = if right { first.max() } else { first.min() }.x; + let start = DVec2::new(x, first.max().y); + let end = DVec2::new(x, second.min().y); + let signed_size = if right { x_size } else { -x_size }; + overlay_context.line(transform.transform_point2(start), transform.transform_point2(start + DVec2::X * signed_size), None, None); + overlay_context.line(transform.transform_point2(end), transform.transform_point2(end + DVec2::X * signed_size), None, None); + overlay_context.line( + transform.transform_point2(start + DVec2::X * signed_size / 2.), + transform.transform_point2(end + DVec2::X * signed_size / 2.), + None, + None, + ); + } + } + + pub fn draw_overlays(&mut self, snap_data: SnapData, overlay_context: &mut OverlayContext) { + let to_viewport = snap_data.document.metadata().document_to_viewport; + if let Some(ind) = &self.indicator { + for layer in &ind.outline_layers { + let &Some(layer) = layer else { continue }; + overlay_context.outline( + snap_data.document.metadata().layer_with_free_points_outline(layer), + snap_data.document.metadata().transform_to_viewport(layer), + None, + ); + } + if let Some(quad) = ind.target_bounds { + overlay_context.quad(to_viewport * quad, None, None); + } + let viewport = to_viewport.transform_point2(ind.snapped_point_document); + + Self::alignment_x_overlay(&ind.distribution_boxes_horizontal, to_viewport, overlay_context); + Self::alignment_y_overlay(&ind.distribution_boxes_vertical, to_viewport, overlay_context); + + let align = [ind.alignment_target_horizontal, ind.alignment_target_vertical].map(|target| target.map(|target| to_viewport.transform_point2(target))); + let any_align = align.iter().flatten().next().is_some(); + for &target in align.iter().flatten() { + overlay_context.line(viewport, target, None, None); + } + for &target in align.iter().flatten() { + overlay_context.manipulator_handle(target, false, None); + } + if any_align { + overlay_context.manipulator_handle(viewport, false, None); + } + + if !any_align && ind.distribution_equal_distance_horizontal.is_none() && ind.distribution_equal_distance_vertical.is_none() { + let text = format!("[{}] from [{}]", ind.target, ind.source); + let transform = DAffine2::from_translation(viewport - DVec2::new(0., 4.)); + overlay_context.text(&text, COLOR_OVERLAY_WHITE, Some(COLOR_OVERLAY_LABEL_BACKGROUND), transform, 4., [Pivot::Start, Pivot::End]); + overlay_context.square(viewport, Some(4.), Some(COLOR_OVERLAY_BLUE), Some(COLOR_OVERLAY_BLUE)); + } + } + } + + /// Removes snap target data and overlays. Call this when snapping is done. + pub fn cleanup(&mut self, responses: &mut VecDeque) { + self.candidates = None; + self.indicator = None; + responses.add(OverlaysMessage::Draw); + } +} + +/// Converts a bounding box into a set of points for snapping +/// +/// Puts a point in the middle of each edge (top, bottom, left, right) +pub fn expand_bounds([bound1, bound2]: [DVec2; 2]) -> [DVec2; 4] { + [ + DVec2::new((bound1.x + bound2.x) / 2., bound1.y), + DVec2::new((bound1.x + bound2.x) / 2., bound2.y), + DVec2::new(bound1.x, (bound1.y + bound2.y) / 2.), + DVec2::new(bound2.x, (bound1.y + bound2.y) / 2.), + ] +} diff --git a/editor/src/messages/tool/common_functionality/snapping/alignment_snapper.rs b/editor/src/messages/tool/common_functionality/snapping/alignment_snapper.rs new file mode 100644 index 0000000000000000000000000000000000000000..4d5645e539a2c725372ce1e6eb57421e71d1db50 --- /dev/null +++ b/editor/src/messages/tool/common_functionality/snapping/alignment_snapper.rs @@ -0,0 +1,210 @@ +use super::*; +use crate::messages::portfolio::document::utility_types::misc::*; +use glam::{DAffine2, DVec2}; +use graphene_std::renderer::Quad; + +#[derive(Clone, Debug, Default)] +pub struct AlignmentSnapper { + bounding_box_points: Vec, +} + +impl AlignmentSnapper { + pub fn collect_bounding_box_points(&mut self, snap_data: &mut SnapData, first_point: bool) { + if !first_point { + return; + } + + let document = snap_data.document; + + self.bounding_box_points.clear(); + if !document.snapping_state.bounding_box.align_with_edges { + return; + } + + for layer in document.metadata().all_layers() { + if !document.network_interface.is_artboard(&layer.to_node(), &[]) || snap_data.ignore.contains(&layer) { + continue; + } + + if document.snapping_state.target_enabled(SnapTarget::Artboard(ArtboardSnapTarget::CornerPoint)) { + let Some(bounds) = document.metadata().bounding_box_with_transform(layer, document.metadata().transform_to_document(layer)) else { + continue; + }; + + get_bbox_points(Quad::from_box(bounds), &mut self.bounding_box_points, BBoxSnapValues::ALIGN_ARTBOARD, document); + } + } + for &layer in snap_data.alignment_candidates.map_or([].as_slice(), |candidates| candidates.as_slice()) { + if snap_data.ignore_bounds(layer) { + continue; + } + let Some(bounds) = document.metadata().bounding_box_with_transform(layer, DAffine2::IDENTITY) else { + continue; + }; + + let quad = document.metadata().transform_to_document(layer) * Quad::from_box(bounds); + let values = BBoxSnapValues::ALIGN_BOUNDING_BOX; + get_bbox_points(quad, &mut self.bounding_box_points, values, document); + } + } + + pub fn snap_bbox_points(&mut self, snap_data: &mut SnapData, point: &SnapCandidatePoint, snap_results: &mut SnapResults, constraint: SnapConstraint, config: SnapTypeConfiguration) { + self.collect_bounding_box_points(snap_data, !config.use_existing_candidates); + let unselected_geometry = if snap_data.document.snapping_state.target_enabled(SnapTarget::Alignment(AlignmentSnapTarget::AlignWithAnchorPoint)) { + snap_data.node_snap_cache.map(|cache| cache.unselected.as_slice()).unwrap_or(&[]) + } else { + &[] + }; + + // TODO: snap handle points + let document = snap_data.document; + let tolerance = snap_tolerance(document); + let tolerance_squared = tolerance.powi(2); + let mut snap_x: Option = None; + let mut snap_y: Option = None; + + for target_point in self.bounding_box_points.iter().chain(unselected_geometry) { + let target_position = target_point.document_point; + + // Perpendicular snap for line's endpoints + if let Some(quad) = target_point.quad.map(|q| q.0) { + if quad[0] == quad[3] && quad[1] == quad[2] && quad[0] == target_point.document_point { + let [p1, p2, ..] = quad; + let Some(direction) = (p2 - p1).try_normalize() else { return }; + let normal = DVec2::new(-direction.y, direction.x); + + for endpoint in [p1, p2] { + if let Some(perpendicular_snap) = Quad::intersect_rays(point.document_point, direction, endpoint, normal) { + let distance_squared = point.document_point.distance_squared(perpendicular_snap); + if distance_squared < tolerance_squared { + let distance = distance_squared.sqrt(); + let distance_to_align_target = perpendicular_snap.distance_squared(endpoint).sqrt(); + + let snap_point = SnappedPoint { + snapped_point_document: perpendicular_snap, + source: point.source, + target: SnapTarget::Alignment(AlignmentSnapTarget::PerpendicularToEndpoint), + target_bounds: Some(Quad(quad)), + distance, + tolerance, + distance_to_align_target, + fully_constrained: false, + at_intersection: true, + alignment_target_horizontal: Some(endpoint), + ..Default::default() + }; + snap_results.points.push(snap_point); + } + } + } + } + } + let [point_on_x, point_on_y] = if let SnapConstraint::Line { origin, direction } = constraint { + [ + Quad::intersect_rays(target_point.document_point, DVec2::Y, origin, direction), + Quad::intersect_rays(target_point.document_point, DVec2::X, origin, direction), + ] + } else { + let Some(quad) = target_point.quad.map(|quad| quad.0) else { continue }; + let edges = [quad[1] - quad[0], quad[3] - quad[0]]; + edges.map(|edge| edge.try_normalize().map(|edge| (point.document_point - target_position).project_onto(edge) + target_position)) + }; + + let target_path = matches!(target_point.target, SnapTarget::Path(_)); + let updated_target = if target_path { + SnapTarget::Alignment(AlignmentSnapTarget::AlignWithAnchorPoint) + } else { + target_point.target + }; + + if let Some(point_on_x) = point_on_x { + let distance_to_snapped = point.document_point.distance(point_on_x); + let distance_to_align_target = point_on_x.distance(target_position); + if distance_to_snapped < tolerance && snap_x.as_ref().is_none_or(|point| distance_to_align_target < point.distance_to_align_target) { + snap_x = Some(SnappedPoint { + snapped_point_document: point_on_x, + source: point.source, // TODO(0Hypercube): map source + target: updated_target, + target_bounds: target_point.quad, + distance: distance_to_snapped, + tolerance, + distance_to_align_target, + alignment_target_horizontal: Some(target_position), + fully_constrained: true, + at_intersection: matches!(constraint, SnapConstraint::Line { .. }), + ..Default::default() + }); + } + } + if let Some(point_on_y) = point_on_y { + let distance_to_snapped = point.document_point.distance(point_on_y); + let distance_to_align_target = point_on_y.distance(target_position); + if distance_to_snapped < tolerance && snap_y.as_ref().is_none_or(|point| distance_to_align_target < point.distance_to_align_target) { + snap_y = Some(SnappedPoint { + snapped_point_document: point_on_y, + source: point.source, // TODO(0Hypercube): map source + target: updated_target, + target_bounds: target_point.quad, + distance: distance_to_snapped, + tolerance, + distance_to_align_target, + alignment_target_vertical: Some(target_position), + fully_constrained: true, + at_intersection: matches!(constraint, SnapConstraint::Line { .. }), + ..Default::default() + }); + } + } + } + + match (snap_x, snap_y) { + (Some(snap_x), Some(snap_y)) if !matches!(constraint, SnapConstraint::Line { .. }) => { + let intersection = DVec2::new(snap_y.snapped_point_document.x, snap_x.snapped_point_document.y); + let distance = intersection.distance(point.document_point); + + if distance >= tolerance { + snap_results.points.push(if snap_x.distance < snap_y.distance { snap_x } else { snap_y }); + return; + } + + snap_results.points.push(SnappedPoint { + snapped_point_document: intersection, + source: point.source, // TODO: map source + target: SnapTarget::Alignment(AlignmentSnapTarget::IntersectionPoint), + target_bounds: snap_x.target_bounds, + distance, + tolerance, + alignment_target_horizontal: snap_x.alignment_target_horizontal, + alignment_target_vertical: snap_y.alignment_target_vertical, + constrained: true, + at_intersection: true, + ..Default::default() + }); + } + (Some(snap_x), Some(snap_y)) => snap_results.points.push(if snap_x.distance < snap_y.distance { snap_x } else { snap_y }), + (Some(snap_x), _) => snap_results.points.push(snap_x), + (_, Some(snap_y)) => snap_results.points.push(snap_y), + _ => {} + } + } + + pub fn free_snap(&mut self, snap_data: &mut SnapData, point: &SnapCandidatePoint, snap_results: &mut SnapResults, config: SnapTypeConfiguration) { + let is_bbox = matches!(point.source, SnapSource::BoundingBox(_)); + let is_path = matches!(point.source, SnapSource::Path(_)); + let path_selected = snap_data.has_manipulators(); + + if is_bbox || (is_path && path_selected) || (is_path && point.alignment) { + self.snap_bbox_points(snap_data, point, snap_results, SnapConstraint::None, config); + } + } + + pub fn constrained_snap(&mut self, snap_data: &mut SnapData, point: &SnapCandidatePoint, snap_results: &mut SnapResults, constraint: SnapConstraint, config: SnapTypeConfiguration) { + let is_bbox = matches!(point.source, SnapSource::BoundingBox(_)); + let is_path = matches!(point.source, SnapSource::Path(_)); + let path_selected = snap_data.has_manipulators(); + + if is_bbox || (is_path && path_selected) || (is_path && point.alignment) { + self.snap_bbox_points(snap_data, point, snap_results, constraint, config); + } + } +} diff --git a/editor/src/messages/tool/common_functionality/snapping/distribution_snapper.rs b/editor/src/messages/tool/common_functionality/snapping/distribution_snapper.rs new file mode 100644 index 0000000000000000000000000000000000000000..1622effaf96b949b7f7ad00a2a2b1915f1bd16f5 --- /dev/null +++ b/editor/src/messages/tool/common_functionality/snapping/distribution_snapper.rs @@ -0,0 +1,702 @@ +use super::*; +use crate::messages::portfolio::document::utility_types::document_metadata::LayerNodeIdentifier; +use crate::messages::portfolio::document::utility_types::misc::*; +use glam::DVec2; +use graphene_std::renderer::Quad; +use std::collections::VecDeque; + +#[derive(Clone, Debug, Default)] +pub struct DistributionSnapper { + right: Vec, + left: Vec, + down: Vec, + up: Vec, +} + +#[cfg_attr(test, derive(Debug, PartialEq))] +pub struct DistributionMatch { + pub equal: f64, + pub first: f64, +} + +fn dist_right(a: Rect, b: Rect) -> f64 { + -a.max().x + b.min().x +} +fn dist_left(a: Rect, b: Rect) -> f64 { + a.min().x - b.max().x +} +fn dist_down(a: Rect, b: Rect) -> f64 { + -a.max().y + b.min().y +} +fn dist_up(a: Rect, b: Rect) -> f64 { + a.min().y - b.max().y +} + +impl DistributionSnapper { + fn add_bounds(&mut self, layer: LayerNodeIdentifier, snap_data: &mut SnapData, bbox_to_snap: Rect, max_extent: f64) { + let document = snap_data.document; + + let Some(bounds) = document.metadata().bounding_box_with_transform(layer, document.metadata().transform_to_document(layer)) else { + return; + }; + let bounds = Rect::from_box(bounds); + if bounds.intersects(bbox_to_snap) { + return; + } + + let difference = bounds.center() - bbox_to_snap.center(); + + let x_bounds = bbox_to_snap.expand_by(max_extent, 0.); + let y_bounds = bbox_to_snap.expand_by(0., max_extent); + + if x_bounds.intersects(bounds) { + if difference.x > 0. { + self.right.push(bounds); + } else { + self.left.push(bounds); + } + } else if y_bounds.intersects(bounds) { + if difference.y > 0. { + self.down.push(bounds); + } else { + self.up.push(bounds); + } + } + } + + pub fn collect_bounding_box_points(&mut self, snap_data: &mut SnapData, first_point: bool, bbox_to_snap: Rect) { + if !first_point { + return; + } + + let document = snap_data.document; + + self.right.clear(); + self.left.clear(); + self.down.clear(); + self.up.clear(); + + let screen_bounds = (document.metadata().document_to_viewport.inverse() * Quad::from_box([DVec2::ZERO, snap_data.input.viewport_bounds.size()])).bounding_box(); + let max_extent = (screen_bounds[1] - screen_bounds[0]).abs().max_element(); + + // Collect artboard bounds + for layer in document.metadata().all_layers() { + if document.network_interface.is_artboard(&layer.to_node(), &[]) && !snap_data.ignore.contains(&layer) { + self.add_bounds(layer, snap_data, bbox_to_snap, max_extent); + } + } + + // Collect alignment candidate bounds + for &layer in snap_data.alignment_candidates.map_or([].as_slice(), |candidates| candidates.as_slice()) { + if !snap_data.ignore_bounds(layer) { + self.add_bounds(layer, snap_data, bbox_to_snap, max_extent); + } + } + + // Sort and merge intersecting rectangles + self.right.sort_unstable_by(|a, b| a.center().x.total_cmp(&b.center().x)); + self.left.sort_unstable_by(|a, b| b.center().x.total_cmp(&a.center().x)); + self.down.sort_unstable_by(|a, b| a.center().y.total_cmp(&b.center().y)); + self.up.sort_unstable_by(|a, b| b.center().y.total_cmp(&a.center().y)); + + Self::merge_intersecting(&mut self.right); + Self::merge_intersecting(&mut self.left); + Self::merge_intersecting(&mut self.down); + Self::merge_intersecting(&mut self.up); + } + + fn merge_intersecting(rectangles: &mut Vec) { + let mut index = 0; + while index < rectangles.len() { + let insert_index = index; + let mut obelisk = rectangles[index]; + + while index + 1 < rectangles.len() && rectangles[index].intersects(rectangles[index + 1]) { + index += 1; + obelisk = Rect::combine_bounds(obelisk, rectangles[index]); + } + + if index > insert_index { + rectangles.insert(insert_index, obelisk); + index += 1; + } + + index += 1; + } + } + + fn exact_further_matches(source: Rect, rectangles: &[Rect], dist_fn: fn(Rect, Rect) -> f64, first_dist: f64, depth: u8) -> VecDeque { + if rectangles.is_empty() || depth > 10 { + return VecDeque::from([source]); + } + + for (index, &rect) in rectangles.iter().enumerate() { + let next_dist = dist_fn(source, rect); + + if (first_dist - next_dist).abs() < 5e-5 * depth as f64 { + let mut results = Self::exact_further_matches(rect, &rectangles[(index + 1)..], dist_fn, first_dist, depth + 1); + results.push_front(source); + return results; + } + } + + VecDeque::from([source]) + } + + fn matches_within_tolerance(source: Rect, rectangles: &[Rect], tolerance: f64, dist_fn: fn(Rect, Rect) -> f64, first_dist: f64) -> Option<(f64, VecDeque)> { + for (index, &rect) in rectangles.iter().enumerate() { + let next_dist = dist_fn(source, rect); + + if (first_dist - next_dist).abs() < tolerance { + let this_dist = next_dist; + let results = Self::exact_further_matches(rect, &rectangles[(index + 1)..], dist_fn, this_dist, 2); + return Some((this_dist, results)); + } + } + + None + } + + fn top_level_matches(source: Rect, rectangles: &[Rect], tolerance: f64, dist_fn: fn(Rect, Rect) -> f64) -> (Option, VecDeque) { + if rectangles.is_empty() { + return (None, VecDeque::new()); + } + + let mut best: Option<(DistributionMatch, Rect, VecDeque)> = None; + for (index, &rect) in rectangles.iter().enumerate() { + let first_dist = dist_fn(source, rect); + + let Some((equal_dist, results)) = Self::matches_within_tolerance(rect, &rectangles[(index + 1)..], tolerance, dist_fn, first_dist) else { + continue; + }; + if best.as_ref().is_some_and(|(_, _, best)| best.len() >= results.len()) { + continue; + } + + best = Some((DistributionMatch { first: first_dist, equal: equal_dist }, rect, results)); + } + + if let Some((dist, rect, mut results)) = best { + results.push_front(rect); + (Some(dist), results) + } else { + (None, VecDeque::from([rectangles[0]])) + } + } + + fn snap_bbox_points(&self, tolerance: f64, point: &SnapCandidatePoint, snap_results: &mut SnapResults, constraint: SnapConstraint, bounds: Rect) { + let mut consider_x = true; + let mut consider_y = true; + + if let SnapConstraint::Line { direction, .. } = constraint { + let direction = direction.normalize_or_zero(); + consider_x = direction.x != 0.; + consider_y = direction.y != 0.; + } + + let mut snap_x: Option = None; + let mut snap_y: Option = None; + + self.horizontal_snap(consider_x, bounds, tolerance, &mut snap_x, point); + self.vertical_snap(consider_y, bounds, tolerance, &mut snap_y, point); + + match (snap_x, snap_y) { + (Some(x), Some(y)) => { + let x_bounds = Rect::from_box(x.source_bounds.unwrap_or_default().bounding_box()); + let y_bounds = Rect::from_box(y.source_bounds.unwrap_or_default().bounding_box()); + let final_bounds = Rect::from_box([0, 1].map(|index| DVec2::new(x_bounds[index].x, y_bounds[index].y))); + + let mut final_point = x; + final_point.snapped_point_document += y.snapped_point_document - point.document_point; + final_point.source_bounds = Some(final_bounds.into()); + final_point.target = SnapTarget::DistributeEvenly(DistributionSnapTarget::XY); + final_point.distribution_boxes_vertical = y.distribution_boxes_vertical; + final_point.distribution_equal_distance_vertical = y.distribution_equal_distance_vertical; + final_point.distance = (final_point.distance * final_point.distance + y.distance * y.distance).sqrt(); + snap_results.points.push(final_point); + } + (Some(x), None) => snap_results.points.push(x), + (None, Some(y)) => snap_results.points.push(y), + (None, None) => {} + } + } + + fn horizontal_snap(&self, consider_x: bool, bounds: Rect, tolerance: f64, snap_x: &mut Option, point: &SnapCandidatePoint) { + if !consider_x { + return; + } + + // Try right distribution first + if !self.right.is_empty() { + let (equal_dist, mut vec_right) = Self::top_level_matches(bounds, &self.right, tolerance, dist_right); + if let Some(distances) = equal_dist { + let translation = DVec2::X * (distances.first - distances.equal); + vec_right.push_front(bounds.translate(translation)); + + // Find matching left distribution + for &left in Self::exact_further_matches(bounds.translate(translation), &self.left, dist_left, distances.equal, 2).iter().skip(1) { + vec_right.push_front(left); + } + + // Adjust bounds to maintain alignment + if vec_right.len() > 1 { + vec_right[0][0].y = vec_right[0][0].y.min(vec_right[1][1].y); + vec_right[0][1].y = vec_right[0][1].y.min(vec_right[1][1].y); + } + + *snap_x = Some(SnappedPoint::distribute(point, DistributionSnapTarget::Right, vec_right, distances, bounds, translation, tolerance)); + return; + } + } + + // Try left distribution if right didn't work + if !self.left.is_empty() { + let (equal_dist, mut vec_left) = Self::top_level_matches(bounds, &self.left, tolerance, dist_left); + if let Some(distances) = equal_dist { + let translation = -DVec2::X * (distances.first - distances.equal); + vec_left.make_contiguous().reverse(); + vec_left.push_back(bounds.translate(translation)); + + // Find matching right distribution + for &right in Self::exact_further_matches(bounds.translate(translation), &self.right, dist_right, distances.equal, 2).iter().skip(1) { + vec_left.push_back(right); + } + + *snap_x = Some(SnappedPoint::distribute(point, DistributionSnapTarget::Left, vec_left, distances, bounds, translation, tolerance)); + return; + } + } + + // Try center distribution if both sides exist + if !self.left.is_empty() && !self.right.is_empty() { + let target_x = (self.right[0].min() + self.left[0].max()).x / 2.; + let offset = target_x - bounds.center().x; + + if offset.abs() < tolerance { + let translation = DVec2::X * offset; + let equal = bounds.translate(translation).min().x - self.left[0].max().x; + let first = equal + offset; + let distances = DistributionMatch { first, equal }; + + let mut boxes = VecDeque::from([self.left[0], bounds.translate(translation), self.right[0]]); + + // Adjust bounds to maintain alignment + if boxes.len() > 1 { + boxes[1][0].y = boxes[1][0].y.min(boxes[0][1].y); + boxes[1][1].y = boxes[1][1].y.min(boxes[0][1].y); + } + + *snap_x = Some(SnappedPoint::distribute(point, DistributionSnapTarget::X, boxes, distances, bounds, translation, tolerance)); + } + } + } + + fn vertical_snap(&self, consider_y: bool, bounds: Rect, tolerance: f64, snap_y: &mut Option, point: &SnapCandidatePoint) { + if !consider_y { + return; + } + + // Try down distribution first + if !self.down.is_empty() { + let (equal_dist, mut vec_down) = Self::top_level_matches(bounds, &self.down, tolerance, dist_down); + if let Some(distances) = equal_dist { + let translation = DVec2::Y * (distances.first - distances.equal); + vec_down.push_front(bounds.translate(translation)); + + // Find matching up distribution + for &up in Self::exact_further_matches(bounds.translate(translation), &self.up, dist_up, distances.equal, 2).iter().skip(1) { + vec_down.push_front(up); + } + + // Adjust bounds to maintain alignment + if vec_down.len() > 1 { + vec_down[0][0].x = vec_down[0][0].x.min(vec_down[1][1].x); + vec_down[0][1].x = vec_down[0][1].x.min(vec_down[1][1].x); + } + + *snap_y = Some(SnappedPoint::distribute(point, DistributionSnapTarget::Down, vec_down, distances, bounds, translation, tolerance)); + return; + } + } + + // Try up distribution if down didn't work + if !self.up.is_empty() { + let (equal_dist, mut vec_up) = Self::top_level_matches(bounds, &self.up, tolerance, dist_up); + if let Some(distances) = equal_dist { + let translation = -DVec2::Y * (distances.first - distances.equal); + vec_up.make_contiguous().reverse(); + vec_up.push_back(bounds.translate(translation)); + + // Find matching down distribution + for &down in Self::exact_further_matches(bounds.translate(translation), &self.down, dist_down, distances.equal, 2).iter().skip(1) { + vec_up.push_back(down); + } + + *snap_y = Some(SnappedPoint::distribute(point, DistributionSnapTarget::Up, vec_up, distances, bounds, translation, tolerance)); + return; + } + } + + // Try center distribution if both sides exist + if !self.up.is_empty() && !self.down.is_empty() { + let target_y = (self.down[0].min() + self.up[0].max()).y / 2.; + let offset = target_y - bounds.center().y; + + if offset.abs() < tolerance { + let translation = DVec2::Y * offset; + let equal = bounds.translate(translation).min().y - self.up[0].max().y; + let first = equal + offset; + let distances = DistributionMatch { first, equal }; + + let mut boxes = VecDeque::from([self.up[0], bounds.translate(translation), self.down[0]]); + + // Adjust bounds to maintain alignment + if boxes.len() > 1 { + boxes[1][0].x = boxes[1][0].x.min(boxes[0][1].x); + boxes[1][1].x = boxes[1][1].x.min(boxes[0][1].x); + } + + *snap_y = Some(SnappedPoint::distribute(point, DistributionSnapTarget::Y, boxes, distances, bounds, translation, tolerance)); + } + } + } + + pub fn free_snap(&mut self, snap_data: &mut SnapData, point: &SnapCandidatePoint, snap_results: &mut SnapResults, config: SnapTypeConfiguration) { + let Some(bounds) = config.bbox else { return }; + if !snap_data.document.snapping_state.bounding_box.distribute_evenly { + return; + } + + self.collect_bounding_box_points(snap_data, config.accept_distribution, bounds); + self.snap_bbox_points(snap_tolerance(snap_data.document), point, snap_results, SnapConstraint::None, bounds); + } + + pub fn constrained_snap(&mut self, snap_data: &mut SnapData, point: &SnapCandidatePoint, snap_results: &mut SnapResults, constraint: SnapConstraint, config: SnapTypeConfiguration) { + let Some(bounds) = config.bbox else { return }; + if !snap_data.document.snapping_state.bounding_box.distribute_evenly { + return; + } + + self.collect_bounding_box_points(snap_data, config.accept_distribution, bounds); + self.snap_bbox_points(snap_tolerance(snap_data.document), point, snap_results, constraint, bounds); + } +} + +#[cfg(test)] +mod tests { + use super::*; + #[test] + fn merge_intersecting_test() { + let mut rectangles = vec![Rect::from_square(DVec2::ZERO, 2.), Rect::from_square(DVec2::new(10., 0.), 2.)]; + DistributionSnapper::merge_intersecting(&mut rectangles); + assert_eq!(rectangles.len(), 2); + + let mut rectangles = vec![ + Rect::from_square(DVec2::ZERO, 2.), + Rect::from_square(DVec2::new(1., 0.), 2.), + Rect::from_square(DVec2::new(10., 0.), 2.), + Rect::from_square(DVec2::new(11., 0.), 2.), + ]; + DistributionSnapper::merge_intersecting(&mut rectangles); + assert_eq!(rectangles.len(), 6); + assert_eq!(rectangles[0], Rect::from_box([DVec2::new(-2., -2.), DVec2::new(3., 2.)])); + assert_eq!(rectangles[3], Rect::from_box([DVec2::new(8., -2.), DVec2::new(13., 2.)])); + } + + #[test] + fn dist_simple_2() { + let rectangles = [10., 20.].map(|x| Rect::from_square(DVec2::new(x, 0.), 2.)); + let source = Rect::from_square(DVec2::new(0.5, 0.), 2.); + let (offset, rectangles) = DistributionSnapper::top_level_matches(source, &rectangles, 1., dist_right); + assert_eq!(offset, Some(DistributionMatch { first: 5.5, equal: 6. })); + assert_eq!(rectangles.len(), 2); + } + + #[test] + fn dist_simple_3() { + let rectangles = [10., 20., 30.].map(|x| Rect::from_square(DVec2::new(x, 0.), 2.)); + let source = Rect::from_square(DVec2::new(0.5, 0.), 2.); + let (offset, rectangles) = DistributionSnapper::top_level_matches(source, &rectangles, 1., dist_right); + assert_eq!(offset, Some(DistributionMatch { first: 5.5, equal: 6. })); + assert_eq!(rectangles.len(), 3); + } + + #[test] + fn dist_out_of_tolerance() { + let rectangles = [10., 20.].map(|x| Rect::from_square(DVec2::new(x, 0.), 2.)); + let source = Rect::from_square(DVec2::new(0.5, 0.), 2.); + let (offset, rectangles) = DistributionSnapper::top_level_matches(source, &rectangles, 0.4, dist_right); + assert_eq!(offset, None); + assert_eq!(rectangles.len(), 1); + } + + #[test] + fn dist_with_nonsense() { + let source = Rect::from_square(DVec2::new(0.5, 0.), 2.); + let rectangles = [2., 10., 15., 20.].map(|x| Rect::from_square(DVec2::new(x, 0.), 2.)); + let (offset, rectangles) = DistributionSnapper::top_level_matches(source, &rectangles, 1., dist_right); + assert_eq!(offset, Some(DistributionMatch { first: 5.5, equal: 6. })); + assert_eq!(rectangles.len(), 2); + } + + #[cfg(test)] + fn assert_boxes_in_order(rectangles: &VecDeque, index: usize) { + for (&first, &second) in rectangles.iter().zip(rectangles.iter().skip(1)) { + assert!(first.max()[index] < second.min()[index], "{first:?} {second:?} {index}") + } + } + + #[test] + fn dist_snap_point_right() { + let dist_snapper = DistributionSnapper { + right: [2., 10., 15., 20.].map(|x| Rect::from_square(DVec2::new(x, 0.), 2.)).to_vec(), + left: [-2.].map(|x| Rect::from_square(DVec2::new(x, 0.), 2.)).to_vec(), + ..Default::default() + }; + let source = Rect::from_square(DVec2::new(0.5, 0.), 2.); + let snap_results = &mut SnapResults::default(); + dist_snapper.snap_bbox_points(1., &SnapCandidatePoint::default(), snap_results, SnapConstraint::None, source); + assert_eq!(snap_results.points.len(), 1); + assert_eq!(snap_results.points[0].distance, 0.5); + assert_eq!(snap_results.points[0].distribution_equal_distance_horizontal, Some(6.)); + let mut expected_box = Rect::from_square(DVec2::new(0., 0.), 2.); + expected_box[0].y = expected_box[0].y.min(dist_snapper.left[0][1].y); + expected_box[1].y = expected_box[1].y.min(dist_snapper.left[0][1].y); + + assert_eq!(snap_results.points[0].distribution_boxes_horizontal.len(), 3); + assert_eq!(snap_results.points[0].distribution_boxes_horizontal[0], expected_box); + assert_boxes_in_order(&snap_results.points[0].distribution_boxes_horizontal, 0); + } + + #[test] + fn dist_snap_point_right_left() { + let dist_snapper = DistributionSnapper { + right: [2., 10., 15., 20.].map(|x| Rect::from_square(DVec2::new(x, 0.), 2.)).to_vec(), + left: [-2., -10., -15., -20.].map(|x| Rect::from_square(DVec2::new(x, 0.), 2.)).to_vec(), + ..Default::default() + }; + + let source = Rect::from_square(DVec2::new(0.5, 0.), 2.); + let snap_results = &mut SnapResults::default(); + dist_snapper.snap_bbox_points(1., &SnapCandidatePoint::default(), snap_results, SnapConstraint::None, source); + + assert_eq!(snap_results.points.len(), 1); + assert_eq!(snap_results.points[0].distance, 0.5); + assert_eq!(snap_results.points[0].distribution_equal_distance_horizontal, Some(6.)); + assert_eq!(snap_results.points[0].distribution_boxes_horizontal.len(), 5); + + let mut expected_left1 = dist_snapper.left[1]; + let mut expected_center = Rect::from_square(DVec2::new(0., 0.), 2.); + + expected_center[0].y = expected_center[0].y.min(dist_snapper.left[1][1].y).min(dist_snapper.right[0][1].y); + expected_center[1].y = expected_center[1].y.min(dist_snapper.left[1][1].y).min(dist_snapper.right[0][1].y); + + expected_left1[0].y = expected_left1[0].y.min(dist_snapper.left[0][1].y).min(expected_center[1].y); + expected_left1[1].y = expected_left1[1].y.min(dist_snapper.left[0][1].y).min(expected_center[1].y); + + assert_eq!(snap_results.points[0].distribution_boxes_horizontal[1], expected_left1); + assert_eq!(snap_results.points[0].distribution_boxes_horizontal[2], expected_center); + assert_boxes_in_order(&snap_results.points[0].distribution_boxes_horizontal, 0); + } + + #[test] + fn dist_snap_point_left() { + let dist_snapper = DistributionSnapper { + left: [-2., -10., -15., -20.].map(|x| Rect::from_square(DVec2::new(x, 0.), 2.)).to_vec(), + ..Default::default() + }; + let source = Rect::from_square(DVec2::new(0.5, 0.), 2.); + let snap_results = &mut SnapResults::default(); + dist_snapper.snap_bbox_points(1., &SnapCandidatePoint::default(), snap_results, SnapConstraint::None, source); + assert_eq!(snap_results.points.len(), 1); + assert_eq!(snap_results.points[0].distance, 0.5); + assert_eq!(snap_results.points[0].distribution_equal_distance_horizontal, Some(6.)); + assert_eq!(snap_results.points[0].distribution_boxes_horizontal.len(), 3); + assert_eq!(snap_results.points[0].distribution_boxes_horizontal[2], Rect::from_square(DVec2::new(0., 0.), 2.)); + assert_boxes_in_order(&snap_results.points[0].distribution_boxes_horizontal, 0); + } + + #[test] + fn dist_snap_point_left_right() { + let dist_snapper = DistributionSnapper { + left: [-2., -10., -15., -20.].map(|x| Rect::from_square(DVec2::new(x, 0.), 2.)).to_vec(), + right: [2., 10., 15.].map(|x| Rect::from_square(DVec2::new(x, 0.), 2.)).to_vec(), + ..Default::default() + }; + let source = Rect::from_square(DVec2::new(0.5, 0.), 2.); + let snap_results = &mut SnapResults::default(); + dist_snapper.snap_bbox_points(1., &SnapCandidatePoint::default(), snap_results, SnapConstraint::None, source); + assert_eq!(snap_results.points.len(), 1); + assert_eq!(snap_results.points[0].distance, 0.5); + assert_eq!(snap_results.points[0].distribution_equal_distance_horizontal, Some(6.)); + assert_eq!(snap_results.points[0].distribution_boxes_horizontal.len(), 4); + assert_eq!(snap_results.points[0].distribution_boxes_horizontal[2], Rect::from_square(DVec2::new(0., 0.), 2.)); + assert_boxes_in_order(&snap_results.points[0].distribution_boxes_horizontal, 0); + } + + #[test] + fn dist_snap_point_center_x() { + let dist_snapper = DistributionSnapper { + left: [-10., -15.].map(|x| Rect::from_square(DVec2::new(x, 0.), 2.)).to_vec(), + right: [10., 15.].map(|x| Rect::from_square(DVec2::new(x, 0.), 2.)).to_vec(), + ..Default::default() + }; + let source = Rect::from_square(DVec2::new(0.5, 0.), 2.); + let snap_results = &mut SnapResults::default(); + dist_snapper.snap_bbox_points(1., &SnapCandidatePoint::default(), snap_results, SnapConstraint::None, source); + assert_eq!(snap_results.points.len(), 1); + assert_eq!(snap_results.points[0].distance, 0.5); + assert_eq!(snap_results.points[0].distribution_equal_distance_horizontal, Some(6.)); + + let mut expected_box = Rect::from_square(DVec2::new(0., 0.), 2.); + expected_box[0].y = expected_box[0].y.min(dist_snapper.left[0][1].y); + expected_box[1].y = expected_box[1].y.min(dist_snapper.left[0][1].y); + + assert_eq!(snap_results.points[0].distribution_boxes_horizontal.len(), 3); + assert_eq!(snap_results.points[0].distribution_boxes_horizontal[1], expected_box); + assert_boxes_in_order(&snap_results.points[0].distribution_boxes_horizontal, 0); + } + + // ---------------------------------- + + #[test] + fn dist_snap_point_down() { + let dist_snapper = DistributionSnapper { + down: [2., 10., 15., 20.].map(|y| Rect::from_square(DVec2::new(0., y), 2.)).to_vec(), + up: [-2.].map(|y| Rect::from_square(DVec2::new(0., y), 2.)).to_vec(), + ..Default::default() + }; + let source = Rect::from_square(DVec2::new(0., 0.5), 2.); + let snap_results = &mut SnapResults::default(); + dist_snapper.snap_bbox_points(1., &SnapCandidatePoint::default(), snap_results, SnapConstraint::None, source); + assert_eq!(snap_results.points.len(), 1); + assert_eq!(snap_results.points[0].distance, 0.5); + assert_eq!(snap_results.points[0].distribution_equal_distance_vertical, Some(6.)); + + let mut expected_box = Rect::from_square(DVec2::new(0., 0.), 2.); + expected_box[0].x = expected_box[0].x.min(dist_snapper.down[0][1].x); + expected_box[1].x = expected_box[1].x.min(dist_snapper.down[0][1].x); + + assert_eq!(snap_results.points[0].distribution_boxes_vertical.len(), 3); + assert_eq!(snap_results.points[0].distribution_boxes_vertical[0], expected_box); + assert_boxes_in_order(&snap_results.points[0].distribution_boxes_vertical, 1); + } + + #[test] + fn dist_snap_point_down_up() { + let dist_snapper = DistributionSnapper { + down: [2., 10., 15., 20.].map(|y| Rect::from_square(DVec2::new(0., y), 2.)).to_vec(), + up: [-2., -10., -15., -20.].map(|y| Rect::from_square(DVec2::new(0., y), 2.)).to_vec(), + ..Default::default() + }; + let source = Rect::from_square(DVec2::new(0., 0.5), 2.); + let snap_results = &mut SnapResults::default(); + dist_snapper.snap_bbox_points(1., &SnapCandidatePoint::default(), snap_results, SnapConstraint::None, source); + + assert_eq!(snap_results.points.len(), 1); + assert_eq!(snap_results.points[0].distance, 0.5); + assert_eq!(snap_results.points[0].distribution_equal_distance_vertical, Some(6.)); + assert_eq!(snap_results.points[0].distribution_boxes_vertical.len(), 5); + + let mut expected_center = Rect::from_square(DVec2::new(0., 0.), 2.); + expected_center[0].x = expected_center[0].x.min(dist_snapper.up[1][1].x).min(dist_snapper.down[0][1].x); + expected_center[1].x = expected_center[1].x.min(dist_snapper.up[1][1].x).min(dist_snapper.down[0][1].x); + + let mut expected_up = Rect::from_square(DVec2::new(0., -10.), 2.); + expected_up[0].x = expected_up[0].x.min(dist_snapper.up[0][1].x).min(expected_center[0].x); + expected_up[1].x = expected_up[1].x.min(dist_snapper.up[0][1].x).min(expected_center[1].x); + + assert_eq!(snap_results.points[0].distribution_boxes_vertical[1], expected_up); + assert_eq!(snap_results.points[0].distribution_boxes_vertical[2], expected_center); + assert_boxes_in_order(&snap_results.points[0].distribution_boxes_vertical, 1); + } + + #[test] + fn dist_snap_point_up() { + let dist_snapper = DistributionSnapper { + up: [-2., -10., -15., -20.].map(|y| Rect::from_square(DVec2::new(0., y), 2.)).to_vec(), + ..Default::default() + }; + let source = Rect::from_square(DVec2::new(0., 0.5), 2.); + let snap_results = &mut SnapResults::default(); + dist_snapper.snap_bbox_points(1., &SnapCandidatePoint::default(), snap_results, SnapConstraint::None, source); + assert_eq!(snap_results.points.len(), 1); + assert_eq!(snap_results.points[0].distance, 0.5); + assert_eq!(snap_results.points[0].distribution_equal_distance_vertical, Some(6.)); + assert_eq!(snap_results.points[0].distribution_boxes_vertical.len(), 3); + assert_eq!(snap_results.points[0].distribution_boxes_vertical[2], Rect::from_square(DVec2::new(0., 0.), 2.)); + assert_boxes_in_order(&snap_results.points[0].distribution_boxes_vertical, 1); + } + + #[test] + fn dist_snap_point_up_down() { + let dist_snapper = DistributionSnapper { + up: [-2., -10., -15., -20.].map(|y| Rect::from_square(DVec2::new(0., y), 2.)).to_vec(), + down: [2., 10., 15.].map(|y| Rect::from_square(DVec2::new(0., y), 2.)).to_vec(), + ..Default::default() + }; + let source = Rect::from_square(DVec2::new(0., 0.5), 2.); + let snap_results = &mut SnapResults::default(); + dist_snapper.snap_bbox_points(1., &SnapCandidatePoint::default(), snap_results, SnapConstraint::None, source); + assert_eq!(snap_results.points.len(), 1); + assert_eq!(snap_results.points[0].distance, 0.5); + assert_eq!(snap_results.points[0].distribution_equal_distance_vertical, Some(6.)); + assert_eq!(snap_results.points[0].distribution_boxes_vertical.len(), 4); + assert_eq!(snap_results.points[0].distribution_boxes_vertical[2], Rect::from_square(DVec2::new(0., 0.), 2.)); + assert_boxes_in_order(&snap_results.points[0].distribution_boxes_vertical, 1); + } + + #[test] + fn dist_snap_point_center_y() { + let dist_snapper = DistributionSnapper { + up: [-10., -15.].map(|y| Rect::from_square(DVec2::new(0., y), 2.)).to_vec(), + down: [10., 15.].map(|y| Rect::from_square(DVec2::new(0., y), 2.)).to_vec(), + ..Default::default() + }; + let source = Rect::from_square(DVec2::new(0., 0.5), 2.); + let snap_results = &mut SnapResults::default(); + dist_snapper.snap_bbox_points(1., &SnapCandidatePoint::default(), snap_results, SnapConstraint::None, source); + + assert_eq!(snap_results.points.len(), 1); + assert_eq!(snap_results.points[0].distance, 0.5); + assert_eq!(snap_results.points[0].distribution_equal_distance_vertical, Some(6.)); + assert_eq!(snap_results.points[0].distribution_boxes_vertical.len(), 3); + + let mut expected_box = Rect::from_square(DVec2::new(0., 0.), 2.); + expected_box[0].x = expected_box[0].x.min(dist_snapper.up[0][1].x).min(dist_snapper.down[0][1].x); + expected_box[1].x = expected_box[1].x.min(dist_snapper.up[0][1].x).min(dist_snapper.down[0][1].x); + + assert_eq!(snap_results.points[0].distribution_boxes_vertical[1], expected_box); + assert_boxes_in_order(&snap_results.points[0].distribution_boxes_vertical, 1); + } + + #[test] + fn dist_snap_point_center_xy() { + let dist_snapper = DistributionSnapper { + up: [-10., -15.].map(|y| Rect::from_square(DVec2::new(0., y), 2.)).to_vec(), + down: [10., 15.].map(|y| Rect::from_square(DVec2::new(0., y), 2.)).to_vec(), + left: [-12., -15.].map(|x| Rect::from_square(DVec2::new(x, 0.), 2.)).to_vec(), + right: [12., 15.].map(|x| Rect::from_square(DVec2::new(x, 0.), 2.)).to_vec(), + ..Default::default() + }; + let source = Rect::from_square(DVec2::new(0.3, 0.4), 2.); + let snap_results = &mut SnapResults::default(); + dist_snapper.snap_bbox_points(1., &SnapCandidatePoint::default(), snap_results, SnapConstraint::None, source); + + assert_eq!(snap_results.points.len(), 1); + assert_eq!(snap_results.points[0].distance, 0.5000000000000001); + assert_eq!(snap_results.points[0].distribution_equal_distance_horizontal, Some(8.)); + assert_eq!(snap_results.points[0].distribution_equal_distance_vertical, Some(6.)); + assert_eq!(snap_results.points[0].distribution_boxes_horizontal.len(), 3); + assert_eq!(snap_results.points[0].distribution_boxes_vertical.len(), 3); + + assert!(snap_results.points[0].distribution_boxes_horizontal[1][0].y <= dist_snapper.left[0][1].y); + assert!(snap_results.points[0].distribution_boxes_horizontal[1][1].y <= dist_snapper.left[0][1].y); + assert!(snap_results.points[0].distribution_boxes_vertical[1][0].x <= dist_snapper.up[0][1].x); + assert!(snap_results.points[0].distribution_boxes_vertical[1][1].x <= dist_snapper.up[0][1].x); + + assert_eq!(Rect::from_box(snap_results.points[0].source_bounds.unwrap().bounding_box()), Rect::from_square(DVec2::new(0., 0.), 2.)); + assert_boxes_in_order(&snap_results.points[0].distribution_boxes_horizontal, 0); + assert_boxes_in_order(&snap_results.points[0].distribution_boxes_vertical, 1); + } +} diff --git a/editor/src/messages/tool/common_functionality/snapping/grid_snapper.rs b/editor/src/messages/tool/common_functionality/snapping/grid_snapper.rs new file mode 100644 index 0000000000000000000000000000000000000000..1c339d435441ae2315f4d5e4ec0c0f64b3ccd2f2 --- /dev/null +++ b/editor/src/messages/tool/common_functionality/snapping/grid_snapper.rs @@ -0,0 +1,181 @@ +use super::*; +use crate::messages::portfolio::document::utility_types::misc::{GridSnapTarget, GridSnapping, GridType, SnapTarget}; +use glam::DVec2; +use graphene_std::renderer::Quad; + +struct Line { + pub point: DVec2, + pub direction: DVec2, +} + +#[derive(Clone, Debug, Default)] + +pub struct GridSnapper; + +impl GridSnapper { + // Rectangular grid has 4 lines around a point, 2 on y axis and 2 on x axis. + fn get_snap_lines_rectangular(&self, document_point: DVec2, snap_data: &mut SnapData, spacing: DVec2) -> Vec { + let document = snap_data.document; + let mut lines = Vec::new(); + + let Some(spacing) = GridSnapping::compute_rectangle_spacing(spacing, &document.document_ptz) else { + return lines; + }; + let origin = document.snapping_state.grid.origin; + for (direction, perpendicular) in [(DVec2::X, DVec2::Y), (DVec2::Y, DVec2::X)] { + lines.push(Line { + direction, + point: perpendicular * (((document_point - origin) / spacing).ceil() * spacing + origin), + }); + lines.push(Line { + direction, + point: perpendicular * (((document_point - origin) / spacing).floor() * spacing + origin), + }); + } + lines + } + + // Isometric grid has 6 lines around a point, 2 y axis, 2 on the angle a, and 2 on the angle b. + fn get_snap_lines_isometric(&self, document_point: DVec2, snap_data: &mut SnapData, y_axis_spacing: f64, angle_a: f64, angle_b: f64) -> Vec { + let document = snap_data.document; + let mut lines = Vec::new(); + + let origin = document.snapping_state.grid.origin; + + let tan_a = angle_a.to_radians().tan(); + let tan_b = angle_b.to_radians().tan(); + let spacing = DVec2::new(y_axis_spacing / (tan_a + tan_b), y_axis_spacing); + let Some(spacing_multiplier) = GridSnapping::compute_isometric_multiplier(y_axis_spacing, tan_a + tan_b, &document.document_ptz) else { + return lines; + }; + let spacing = spacing * spacing_multiplier; + + let x_max = ((document_point.x - origin.x) / spacing.x).ceil() * spacing.x + origin.x; + let x_min = ((document_point.x - origin.x) / spacing.x).floor() * spacing.x + origin.x; + lines.push(Line { + point: DVec2::new(x_max, 0.), + direction: DVec2::Y, + }); + lines.push(Line { + point: DVec2::new(x_min, 0.), + direction: DVec2::Y, + }); + + let y_projected_onto_x = document_point.y + tan_a * (document_point.x - origin.x); + let y_onto_x_max = ((y_projected_onto_x - origin.y) / spacing.y).ceil() * spacing.y + origin.y; + let y_onto_x_min = ((y_projected_onto_x - origin.y) / spacing.y).floor() * spacing.y + origin.y; + lines.push(Line { + point: DVec2::new(origin.x, y_onto_x_max), + direction: DVec2::new(1., -tan_a), + }); + lines.push(Line { + point: DVec2::new(origin.x, y_onto_x_min), + direction: DVec2::new(1., -tan_a), + }); + + let y_projected_onto_z = document_point.y - tan_b * (document_point.x - origin.x); + let y_onto_z_max = ((y_projected_onto_z - origin.y) / spacing.y).ceil() * spacing.y + origin.y; + let y_onto_z_min = ((y_projected_onto_z - origin.y) / spacing.y).floor() * spacing.y + origin.y; + lines.push(Line { + point: DVec2::new(origin.x, y_onto_z_max), + direction: DVec2::new(1., tan_b), + }); + lines.push(Line { + point: DVec2::new(origin.x, y_onto_z_min), + direction: DVec2::new(1., tan_b), + }); + + lines + } + + fn get_snap_lines(&self, document_point: DVec2, snap_data: &mut SnapData) -> Vec { + match snap_data.document.snapping_state.grid.grid_type { + GridType::Rectangular { spacing } => self.get_snap_lines_rectangular(document_point, snap_data, spacing), + GridType::Isometric { y_axis_spacing, angle_a, angle_b } => self.get_snap_lines_isometric(document_point, snap_data, y_axis_spacing, angle_a, angle_b), + } + } + + pub fn free_snap(&mut self, snap_data: &mut SnapData, point: &SnapCandidatePoint, snap_results: &mut SnapResults) { + let lines = self.get_snap_lines(point.document_point, snap_data); + let tolerance = snap_tolerance(snap_data.document); + + for line in lines { + let projected = (point.document_point - line.point).project_onto(line.direction) + line.point; + let distance = point.document_point.distance(projected); + if !distance.is_finite() { + continue; + } + + if distance > tolerance { + continue; + } + + if snap_data.document.snapping_state.target_enabled(SnapTarget::Grid(GridSnapTarget::Line)) + || snap_data.document.snapping_state.target_enabled(SnapTarget::Grid(GridSnapTarget::Intersection)) + { + snap_results.grid_lines.push(SnappedLine { + direction: line.direction, + point: SnappedPoint { + snapped_point_document: projected, + source: point.source, + target: SnapTarget::Grid(GridSnapTarget::Line), + source_bounds: point.quad, + distance, + tolerance, + ..Default::default() + }, + }); + } + + let normal_target = SnapTarget::Grid(GridSnapTarget::LineNormal); + if snap_data.document.snapping_state.target_enabled(normal_target) { + for &neighbor in &point.neighbors { + let projected = (neighbor - line.point).project_onto(line.direction) + line.point; + let distance = point.document_point.distance(projected); + if distance > tolerance { + continue; + } + snap_results.points.push(SnappedPoint { + snapped_point_document: projected, + source: point.source, + source_bounds: point.quad, + target: normal_target, + distance, + tolerance, + ..Default::default() + }) + } + } + } + } + + pub fn constrained_snap(&mut self, snap_data: &mut SnapData, point: &SnapCandidatePoint, snap_results: &mut SnapResults, constraint: SnapConstraint) { + let tolerance = snap_tolerance(snap_data.document); + let projected = constraint.projection(point.document_point); + let lines = self.get_snap_lines(projected, snap_data); + let (constraint_start, constraint_direction) = match constraint { + SnapConstraint::Line { origin, direction } => (origin, direction.normalize_or_zero()), + SnapConstraint::Direction(direction) => (projected, direction.normalize_or_zero()), + _ => unimplemented!(), + }; + for line in lines { + let Some(intersection) = Quad::intersect_rays(line.point, line.direction, constraint_start, constraint_direction) else { + continue; + }; + let distance = intersection.distance(point.document_point); + if distance < tolerance && snap_data.document.snapping_state.target_enabled(SnapTarget::Grid(GridSnapTarget::Line)) { + snap_results.points.push(SnappedPoint { + snapped_point_document: intersection, + source: point.source, + target: SnapTarget::Grid(GridSnapTarget::Line), + at_intersection: false, + constrained: true, + source_bounds: point.quad, + distance, + tolerance, + ..Default::default() + }) + } + } + } +} diff --git a/editor/src/messages/tool/common_functionality/snapping/layer_snapper.rs b/editor/src/messages/tool/common_functionality/snapping/layer_snapper.rs new file mode 100644 index 0000000000000000000000000000000000000000..3a306713571273171374db387095508ac5dcbac9 --- /dev/null +++ b/editor/src/messages/tool/common_functionality/snapping/layer_snapper.rs @@ -0,0 +1,520 @@ +use super::*; +use crate::consts::HIDE_HANDLE_DISTANCE; +use crate::messages::portfolio::document::utility_types::document_metadata::LayerNodeIdentifier; +use crate::messages::portfolio::document::utility_types::misc::*; +use crate::messages::prelude::*; +use bezier_rs::{Bezier, Identifier, Subpath, TValue}; +use glam::{DAffine2, DVec2}; +use graphene_std::math::math_ext::QuadExt; +use graphene_std::renderer::Quad; +use graphene_std::vector::PointId; + +#[derive(Clone, Debug, Default)] +pub struct LayerSnapper { + points_to_snap: Vec, + paths_to_snap: Vec, +} +impl LayerSnapper { + pub fn add_layer_bounds(&mut self, document: &DocumentMessageHandler, layer: LayerNodeIdentifier, target: SnapTarget) { + if !document.snapping_state.target_enabled(target) { + return; + } + + let bounds = if document.network_interface.is_artboard(&layer.to_node(), &[]) { + document + .metadata() + .bounding_box_with_transform(layer, document.metadata().transform_to_document(layer)) + .map(Quad::from_box) + } else { + document + .metadata() + .bounding_box_with_transform(layer, DAffine2::IDENTITY) + .map(|bounds| document.metadata().transform_to_document(layer) * Quad::from_box(bounds)) + }; + let Some(bounds) = bounds else { return }; + + if bounds.0.iter().any(|point| !point.is_finite()) { + return; + } + + for document_curve in bounds.bezier_lines() { + self.paths_to_snap.push(SnapCandidatePath { + document_curve, + layer, + start: PointId::new(), + target, + bounds: Some(bounds), + }); + } + } + + pub fn collect_paths(&mut self, snap_data: &mut SnapData, first_point: bool) { + if !first_point { + return; + } + let document = snap_data.document; + self.paths_to_snap.clear(); + + for layer in document.metadata().all_layers() { + if !document.network_interface.is_artboard(&layer.to_node(), &[]) || snap_data.ignore.contains(&layer) { + continue; + } + self.add_layer_bounds(document, layer, SnapTarget::Artboard(ArtboardSnapTarget::AlongEdge)); + } + for &layer in snap_data.get_candidates() { + let transform = document.metadata().transform_to_document(layer); + if !transform.is_finite() { + continue; + } + + if document.snapping_state.target_enabled(SnapTarget::Path(PathSnapTarget::IntersectionPoint)) || document.snapping_state.target_enabled(SnapTarget::Path(PathSnapTarget::AlongPath)) { + for subpath in document.metadata().layer_outline(layer) { + for (start_index, curve) in subpath.iter().enumerate() { + let document_curve = curve.apply_transformation(|p| transform.transform_point2(p)); + let start = subpath.manipulator_groups()[start_index].id; + if snap_data.ignore_manipulator(layer, start) || snap_data.ignore_manipulator(layer, subpath.manipulator_groups()[(start_index + 1) % subpath.len()].id) { + continue; + } + self.paths_to_snap.push(SnapCandidatePath { + document_curve, + layer, + start, + target: SnapTarget::Path(PathSnapTarget::AlongPath), + bounds: None, + }); + } + } + } + } + } + + pub fn free_snap_paths(&mut self, snap_data: &mut SnapData, point: &SnapCandidatePoint, snap_results: &mut SnapResults, config: SnapTypeConfiguration) { + self.collect_paths(snap_data, !config.use_existing_candidates); + + let document = snap_data.document; + let normals = document.snapping_state.target_enabled(SnapTarget::Path(PathSnapTarget::NormalToPath)); + let tangents = document.snapping_state.target_enabled(SnapTarget::Path(PathSnapTarget::TangentToPath)); + let tolerance = snap_tolerance(document); + + for path in &self.paths_to_snap { + // Skip very short paths + if path.document_curve.start.distance_squared(path.document_curve.end) < tolerance * tolerance * 2. { + continue; + } + let time = path.document_curve.project(point.document_point); + let snapped_point_document = path.document_curve.evaluate(bezier_rs::TValue::Parametric(time)); + + let distance = snapped_point_document.distance(point.document_point); + + if distance < tolerance { + snap_results.curves.push(SnappedCurve { + layer: path.layer, + start: path.start, + document_curve: path.document_curve, + point: SnappedPoint { + snapped_point_document, + target: path.target, + distance, + tolerance, + outline_layers: [path.bounds.is_none().then_some(path.layer), None], + source: point.source, + target_bounds: path.bounds, + ..Default::default() + }, + }); + normals_and_tangents(path, normals, tangents, point, tolerance, snap_results); + } + } + } + + pub fn snap_paths_constrained(&mut self, snap_data: &mut SnapData, point: &SnapCandidatePoint, snap_results: &mut SnapResults, constraint: SnapConstraint, config: SnapTypeConfiguration) { + let document = snap_data.document; + self.collect_paths(snap_data, !config.use_existing_candidates); + + let tolerance = snap_tolerance(document); + let constraint_path = if let SnapConstraint::Circle { center, radius } = constraint { + Subpath::new_ellipse(center - DVec2::splat(radius), center + DVec2::splat(radius)) + } else { + let constrained_point = constraint.projection(point.document_point); + let direction = constraint.direction().normalize_or_zero(); + let start = constrained_point - tolerance * direction; + let end = constrained_point + tolerance * direction; + Subpath::::new_line(start, end) + }; + + for path in &self.paths_to_snap { + for constraint_path in constraint_path.iter() { + for time in path.document_curve.intersections(&constraint_path, None, None) { + let snapped_point_document = path.document_curve.evaluate(bezier_rs::TValue::Parametric(time)); + + let distance = snapped_point_document.distance(point.document_point); + + if distance < tolerance { + snap_results.points.push(SnappedPoint { + snapped_point_document, + target: path.target, + distance, + tolerance, + outline_layers: [path.bounds.is_none().then_some(path.layer), None], + source: point.source, + target_bounds: path.bounds, + at_intersection: true, + ..Default::default() + }); + } + } + } + } + } + + pub fn collect_anchors(&mut self, snap_data: &mut SnapData, first_point: bool) { + if !first_point { + return; + } + let document = snap_data.document; + self.points_to_snap.clear(); + + for layer in document.metadata().all_layers() { + if !document.network_interface.is_artboard(&layer.to_node(), &[]) || snap_data.ignore.contains(&layer) { + continue; + } + if self.points_to_snap.len() >= crate::consts::MAX_LAYER_SNAP_POINTS { + warn!("Snap point overflow; skipping."); + return; + } + + if document.snapping_state.target_enabled(SnapTarget::Artboard(ArtboardSnapTarget::CornerPoint)) { + let Some(bounds) = document + .network_interface + .document_metadata() + .bounding_box_with_transform(layer, document.metadata().transform_to_document(layer)) + else { + continue; + }; + + get_bbox_points(Quad::from_box(bounds), &mut self.points_to_snap, BBoxSnapValues::ARTBOARD, document); + } + } + for &layer in snap_data.get_candidates() { + get_layer_snap_points(layer, snap_data, &mut self.points_to_snap); + + if snap_data.ignore_bounds(layer) { + continue; + } + if self.points_to_snap.len() >= crate::consts::MAX_LAYER_SNAP_POINTS { + warn!("Snap point overflow; skipping."); + return; + } + let Some(bounds) = document.metadata().bounding_box_with_transform(layer, DAffine2::IDENTITY) else { + continue; + }; + let quad = document.metadata().transform_to_document(layer) * Quad::from_box(bounds); + let values = BBoxSnapValues::BOUNDING_BOX; + get_bbox_points(quad, &mut self.points_to_snap, values, document); + } + } + + pub fn snap_anchors(&mut self, snap_data: &mut SnapData, point: &SnapCandidatePoint, snap_results: &mut SnapResults, c: SnapConstraint, constrained_point: DVec2) { + let mut best = None; + for candidate in &self.points_to_snap { + // Candidate is not on constraint + if !candidate.document_point.abs_diff_eq(c.projection(candidate.document_point), 1e-5) { + continue; + } + let distance = candidate.document_point.distance(constrained_point); + let tolerance = snap_tolerance(snap_data.document); + + let candidate_better = |best: &SnappedPoint| { + if best.snapped_point_document.abs_diff_eq(candidate.document_point, 1e-5) { + !candidate.target.bounding_box() + } else { + distance < best.distance + } + }; + if distance < tolerance && (best.is_none() || best.as_ref().is_some_and(candidate_better)) { + best = Some(SnappedPoint { + snapped_point_document: candidate.document_point, + source: point.source, + target: candidate.target, + distance, + tolerance, + constrained: true, + target_bounds: candidate.quad, + outline_layers: [candidate.outline_layer, None], + ..Default::default() + }); + } + } + if let Some(result) = best { + snap_results.points.push(result); + } + } + + pub fn free_snap(&mut self, snap_data: &mut SnapData, point: &SnapCandidatePoint, snap_results: &mut SnapResults, config: SnapTypeConfiguration) { + self.collect_anchors(snap_data, !config.use_existing_candidates); + self.snap_anchors(snap_data, point, snap_results, SnapConstraint::None, point.document_point); + self.free_snap_paths(snap_data, point, snap_results, config); + } + + pub fn constrained_snap(&mut self, snap_data: &mut SnapData, point: &SnapCandidatePoint, snap_results: &mut SnapResults, constraint: SnapConstraint, config: SnapTypeConfiguration) { + self.collect_anchors(snap_data, !config.use_existing_candidates); + self.snap_anchors(snap_data, point, snap_results, constraint, constraint.projection(point.document_point)); + self.snap_paths_constrained(snap_data, point, snap_results, constraint, config); + } +} + +fn normals_and_tangents(path: &SnapCandidatePath, normals: bool, tangents: bool, point: &SnapCandidatePoint, tolerance: f64, snap_results: &mut SnapResults) { + if normals && path.bounds.is_none() { + for &neighbor in &point.neighbors { + for t in path.document_curve.normals_to_point(neighbor) { + let normal_point = path.document_curve.evaluate(TValue::Parametric(t)); + let distance = normal_point.distance(point.document_point); + if distance > tolerance { + continue; + } + snap_results.points.push(SnappedPoint { + snapped_point_document: normal_point, + target: SnapTarget::Path(PathSnapTarget::NormalToPath), + distance, + tolerance, + outline_layers: [Some(path.layer), None], + source: point.source, + constrained: true, + ..Default::default() + }); + } + } + } + if tangents && path.bounds.is_none() { + for &neighbor in &point.neighbors { + for t in path.document_curve.tangents_to_point(neighbor) { + let tangent_point = path.document_curve.evaluate(TValue::Parametric(t)); + let distance = tangent_point.distance(point.document_point); + if distance > tolerance { + continue; + } + snap_results.points.push(SnappedPoint { + snapped_point_document: tangent_point, + target: SnapTarget::Path(PathSnapTarget::TangentToPath), + distance, + tolerance, + outline_layers: [Some(path.layer), None], + source: point.source, + constrained: true, + ..Default::default() + }); + } + } + } +} + +#[derive(Clone, Debug)] +struct SnapCandidatePath { + document_curve: Bezier, + layer: LayerNodeIdentifier, + start: PointId, + target: SnapTarget, + bounds: Option, +} + +#[derive(Clone, Debug, Default)] +pub struct SnapCandidatePoint { + pub document_point: DVec2, + pub source: SnapSource, + pub target: SnapTarget, + pub quad: Option, + /// This layer is outlined if the snap candidate is used. + pub outline_layer: Option, + pub neighbors: Vec, + pub alignment: bool, +} +impl SnapCandidatePoint { + pub fn new(document_point: DVec2, source: SnapSource, target: SnapTarget, outline_layer: Option) -> Self { + Self::new_quad(document_point, source, target, None, outline_layer, true) + } + + pub fn new_quad(document_point: DVec2, source: SnapSource, target: SnapTarget, quad: Option, outline_layer: Option, alignment: bool) -> Self { + Self { + document_point, + source, + target, + quad, + outline_layer, + alignment, + ..Default::default() + } + } + + pub fn new_source(document_point: DVec2, source: SnapSource) -> Self { + Self::new(document_point, source, SnapTarget::None, None) + } + + pub fn handle(document_point: DVec2) -> Self { + Self::new_source(document_point, SnapSource::Path(PathSnapSource::AnchorPointWithFreeHandles)) + } + + pub fn handle_neighbors(document_point: DVec2, neighbors: impl Into>) -> Self { + let mut point = Self::new_source(document_point, SnapSource::Path(PathSnapSource::AnchorPointWithFreeHandles)); + point.neighbors = neighbors.into(); + point + } +} + +#[derive(Default)] +pub struct BBoxSnapValues { + corner_source: SnapSource, + corner_target: SnapTarget, + edge_source: SnapSource, + edge_target: SnapTarget, + center_source: SnapSource, + center_target: SnapTarget, +} +impl BBoxSnapValues { + pub const BOUNDING_BOX: Self = Self { + corner_source: SnapSource::BoundingBox(BoundingBoxSnapSource::CornerPoint), + corner_target: SnapTarget::BoundingBox(BoundingBoxSnapTarget::CornerPoint), + edge_source: SnapSource::BoundingBox(BoundingBoxSnapSource::EdgeMidpoint), + edge_target: SnapTarget::BoundingBox(BoundingBoxSnapTarget::EdgeMidpoint), + center_source: SnapSource::BoundingBox(BoundingBoxSnapSource::CenterPoint), + center_target: SnapTarget::BoundingBox(BoundingBoxSnapTarget::CenterPoint), + }; + + pub const ARTBOARD: Self = Self { + corner_source: SnapSource::Artboard(ArtboardSnapSource::CornerPoint), + corner_target: SnapTarget::Artboard(ArtboardSnapTarget::CornerPoint), + edge_source: SnapSource::None, + edge_target: SnapTarget::None, + center_source: SnapSource::Artboard(ArtboardSnapSource::CenterPoint), + center_target: SnapTarget::Artboard(ArtboardSnapTarget::CenterPoint), + }; + + pub const ALIGN_BOUNDING_BOX: Self = Self { + corner_source: SnapSource::Alignment(AlignmentSnapSource::BoundingBoxCornerPoint), + corner_target: SnapTarget::Alignment(AlignmentSnapTarget::BoundingBoxCornerPoint), + edge_source: SnapSource::None, + edge_target: SnapTarget::None, + center_source: SnapSource::Alignment(AlignmentSnapSource::BoundingBoxCenterPoint), + center_target: SnapTarget::Alignment(AlignmentSnapTarget::BoundingBoxCenterPoint), + }; + + pub const ALIGN_ARTBOARD: Self = Self { + corner_source: SnapSource::Alignment(AlignmentSnapSource::ArtboardCornerPoint), + corner_target: SnapTarget::Alignment(AlignmentSnapTarget::ArtboardCornerPoint), + edge_source: SnapSource::None, + edge_target: SnapTarget::None, + center_source: SnapSource::Alignment(AlignmentSnapSource::ArtboardCenterPoint), + center_target: SnapTarget::Alignment(AlignmentSnapTarget::ArtboardCenterPoint), + }; +} + +pub fn get_bbox_points(quad: Quad, points: &mut Vec, values: BBoxSnapValues, document: &DocumentMessageHandler) { + for index in 0..4 { + let start = quad.0[index]; + let end = quad.0[(index + 1) % 4]; + if document.snapping_state.target_enabled(values.corner_target) { + points.push(SnapCandidatePoint::new_quad(start, values.corner_source, values.corner_target, Some(quad), None, false)); + } + if document.snapping_state.target_enabled(values.edge_target) { + points.push(SnapCandidatePoint::new_quad((start + end) / 2., values.edge_source, values.edge_target, Some(quad), None, false)); + } + } + + if document.snapping_state.target_enabled(values.center_target) { + points.push(SnapCandidatePoint::new_quad(quad.center(), values.center_source, values.center_target, Some(quad), None, false)); + } +} + +fn handle_not_under(to_document: DAffine2) -> impl Fn(&DVec2) -> bool { + move |&offset: &DVec2| to_document.transform_vector2(offset).length_squared() >= HIDE_HANDLE_DISTANCE * HIDE_HANDLE_DISTANCE +} + +fn subpath_anchor_snap_points(layer: LayerNodeIdentifier, subpath: &Subpath, snap_data: &SnapData, points: &mut Vec, to_document: DAffine2) { + let document = snap_data.document; + + // Midpoints of linear segments + if document.snapping_state.target_enabled(SnapTarget::Path(PathSnapTarget::LineMidpoint)) { + for (index, curve) in subpath.iter().enumerate() { + if snap_data.ignore_manipulator(layer, subpath.manipulator_groups()[index].id) || snap_data.ignore_manipulator(layer, subpath.manipulator_groups()[(index + 1) % subpath.len()].id) { + continue; + } + if points.len() >= crate::consts::MAX_LAYER_SNAP_POINTS { + return; + } + + let in_handle = curve.handle_start().map(|handle| handle - curve.start).filter(handle_not_under(to_document)); + let out_handle = curve.handle_end().map(|handle| handle - curve.end).filter(handle_not_under(to_document)); + if in_handle.is_none() && out_handle.is_none() { + points.push(SnapCandidatePoint::new( + to_document.transform_point2(curve.start() * 0.5 + curve.end * 0.5), + SnapSource::Path(PathSnapSource::LineMidpoint), + SnapTarget::Path(PathSnapTarget::LineMidpoint), + Some(layer), + )); + } + } + } + + // Anchors + for (index, group) in subpath.manipulator_groups().iter().enumerate() { + if snap_data.ignore_manipulator(layer, group.id) { + continue; + } + + if points.len() >= crate::consts::MAX_LAYER_SNAP_POINTS { + return; + } + + let colinear = are_manipulator_handles_colinear(group, to_document, subpath, index); + + // Colinear handles + if colinear && document.snapping_state.target_enabled(SnapTarget::Path(PathSnapTarget::AnchorPointWithColinearHandles)) { + points.push(SnapCandidatePoint::new( + to_document.transform_point2(group.anchor), + SnapSource::Path(PathSnapSource::AnchorPointWithColinearHandles), + SnapTarget::Path(PathSnapTarget::AnchorPointWithColinearHandles), + Some(layer), + )); + } + // Free handles + else if !colinear && document.snapping_state.target_enabled(SnapTarget::Path(PathSnapTarget::AnchorPointWithFreeHandles)) { + points.push(SnapCandidatePoint::new( + to_document.transform_point2(group.anchor), + SnapSource::Path(PathSnapSource::AnchorPointWithFreeHandles), + SnapTarget::Path(PathSnapTarget::AnchorPointWithFreeHandles), + Some(layer), + )); + } + } +} + +pub fn are_manipulator_handles_colinear(group: &bezier_rs::ManipulatorGroup, to_document: DAffine2, subpath: &Subpath, index: usize) -> bool { + let anchor = group.anchor; + let handle_in = group.in_handle.map(|handle| anchor - handle).filter(handle_not_under(to_document)); + let handle_out = group.out_handle.map(|handle| handle - anchor).filter(handle_not_under(to_document)); + let anchor_is_endpoint = !subpath.closed() && (index == 0 || index == subpath.len() - 1); + + // Unless this is an endpoint, check if both handles are colinear (within an angular epsilon) + !anchor_is_endpoint && handle_in.is_some_and(|handle_in| handle_out.is_some_and(|handle_out| handle_in.angle_to(handle_out) < 1e-5)) +} + +pub fn get_layer_snap_points(layer: LayerNodeIdentifier, snap_data: &SnapData, points: &mut Vec) { + let document = snap_data.document; + + if document.network_interface.is_artboard(&layer.to_node(), &[]) { + return; + } + if points.len() >= crate::consts::MAX_LAYER_SNAP_POINTS { + return; + } + + if layer.has_children(document.metadata()) { + for child in layer.descendants(document.metadata()) { + get_layer_snap_points(child, snap_data, points); + } + } else if document.metadata().layer_outline(layer).next().is_some() { + let to_document = document.metadata().transform_to_document(layer); + for subpath in document.metadata().layer_outline(layer) { + subpath_anchor_snap_points(layer, subpath, snap_data, points, to_document); + } + } +} diff --git a/editor/src/messages/tool/common_functionality/snapping/snap_results.rs b/editor/src/messages/tool/common_functionality/snapping/snap_results.rs new file mode 100644 index 0000000000000000000000000000000000000000..3ab53e4dd7e2e0ffef7d30d0ab11bed9fa2799c7 --- /dev/null +++ b/editor/src/messages/tool/common_functionality/snapping/snap_results.rs @@ -0,0 +1,124 @@ +use super::DistributionMatch; +use crate::messages::portfolio::document::utility_types::document_metadata::LayerNodeIdentifier; +use crate::messages::portfolio::document::utility_types::misc::{DistributionSnapTarget, SnapSource, SnapTarget}; +use crate::messages::tool::common_functionality::snapping::SnapCandidatePoint; +use bezier_rs::Bezier; +use glam::DVec2; +use graphene_std::renderer::Quad; +use graphene_std::renderer::Rect; +use graphene_std::vector::PointId; +use std::collections::VecDeque; + +#[derive(Clone, Debug, Default)] +pub struct SnapResults { + pub points: Vec, + pub grid_lines: Vec, + pub curves: Vec, +} +#[derive(Default, Debug, Clone)] +pub struct SnappedPoint { + pub snapped_point_document: DVec2, + pub source: SnapSource, + pub target: SnapTarget, + pub at_intersection: bool, + pub constrained: bool, // Found when looking for constrained + pub fully_constrained: bool, + pub target_bounds: Option, + pub source_bounds: Option, + /// These layer(s) are outlined in the overlays when the snap is used. + pub outline_layers: [Option; 2], + pub distance: f64, + pub tolerance: f64, + pub distribution_boxes_horizontal: VecDeque, + pub distribution_equal_distance_horizontal: Option, + pub distribution_boxes_vertical: VecDeque, + pub distribution_equal_distance_vertical: Option, + pub distance_to_align_target: f64, // If aligning so that the top is aligned but the X pos is 200 from the target, this is 200. + pub alignment_target_horizontal: Option, + pub alignment_target_vertical: Option, +} +impl SnappedPoint { + pub fn align(&self) -> bool { + self.alignment_target_horizontal.is_some() || self.alignment_target_vertical.is_some() + } + pub fn infinite_snap(snapped_point_document: DVec2) -> Self { + Self { + snapped_point_document, + distance: f64::INFINITY, + ..Default::default() + } + } + pub fn from_source_point(snapped_point_document: DVec2, source: SnapSource) -> Self { + Self { + snapped_point_document, + source, + ..Default::default() + } + } + pub fn distribute(point: &SnapCandidatePoint, target: DistributionSnapTarget, boxes: VecDeque, distances: DistributionMatch, bounds: Rect, translation: DVec2, tolerance: f64) -> Self { + let is_x = target.is_x(); + + let [distribution_boxes_horizontal, distribution_boxes_vertical] = if is_x { [boxes, Default::default()] } else { [Default::default(), boxes] }; + Self { + snapped_point_document: point.document_point + translation, + source: point.source, + target: SnapTarget::DistributeEvenly(target), + distribution_boxes_horizontal, + distribution_equal_distance_horizontal: is_x.then_some(distances.equal), + distribution_boxes_vertical, + distribution_equal_distance_vertical: (!is_x).then_some(distances.equal), + distance: (distances.first - distances.equal).abs(), + constrained: true, + source_bounds: Some(bounds.translate(translation).into()), + tolerance, + ..Default::default() + } + } + pub fn other_snap_better(&self, other: &Self) -> bool { + if self.distance.is_finite() && !other.distance.is_finite() { + return false; + } + if !self.distance.is_finite() && other.distance.is_finite() { + return true; + } + + let my_dist = self.distance; + let other_dist = other.distance; + + // Prevent flickering when two points are equally close + let bias = 1e-2; + + // Prefer closest + let other_closer = other_dist < my_dist + bias; + + // We should prefer the most constrained option (e.g. intersection > path) + let other_more_constrained = other.constrained && !self.constrained; + let self_more_constrained = self.constrained && !other.constrained; + + let both_align = other.align() && self.align(); + let other_better_align = !other.align() && self.align() || (both_align && !self.source.center() && other.source.center()); + let self_better_align = !self.align() && other.align() || (both_align && !other.source.center() && self.source.center()); + + // Prefer nodes to intersections if both are at the same position + let constrained_at_same_pos = other.constrained && self.constrained && self.snapped_point_document.abs_diff_eq(other.snapped_point_document, 1.); + let other_better_constraint = constrained_at_same_pos && self.at_intersection && !other.at_intersection; + let self_better_constraint = constrained_at_same_pos && other.at_intersection && !self.at_intersection; + + (other_closer || other_more_constrained || other_better_align || other_better_constraint) && !self_more_constrained && !self_better_align && !self_better_constraint + } + pub fn is_snapped(&self) -> bool { + self.distance.is_finite() + } +} +#[derive(Clone, Debug, Default)] +pub struct SnappedLine { + pub point: SnappedPoint, + pub direction: DVec2, +} +#[derive(Clone, Debug)] +pub struct SnappedCurve { + pub layer: LayerNodeIdentifier, + pub start: PointId, + pub point: SnappedPoint, + pub document_curve: Bezier, +} diff --git a/editor/src/messages/tool/common_functionality/transformation_cage.rs b/editor/src/messages/tool/common_functionality/transformation_cage.rs new file mode 100644 index 0000000000000000000000000000000000000000..cb5ce0e91f6e800319b3a50d0b695ec5db15ac92 --- /dev/null +++ b/editor/src/messages/tool/common_functionality/transformation_cage.rs @@ -0,0 +1,869 @@ +use super::snapping::{self, SnapCandidatePoint, SnapConstraint, SnapData, SnapManager, SnappedPoint}; +use crate::consts::{ + BOUNDS_ROTATE_THRESHOLD, BOUNDS_SELECT_THRESHOLD, COLOR_OVERLAY_WHITE, MAX_LENGTH_FOR_NO_WIDTH_OR_HEIGHT, MAXIMUM_ALT_SCALE_FACTOR, MIN_LENGTH_FOR_CORNERS_VISIBILITY, + MIN_LENGTH_FOR_EDGE_RESIZE_PRIORITY_OVER_CORNERS, MIN_LENGTH_FOR_MIDPOINT_VISIBILITY, MIN_LENGTH_FOR_RESIZE_TO_INCLUDE_INTERIOR, MIN_LENGTH_FOR_SKEW_TRIANGLE_VISIBILITY, RESIZE_HANDLE_SIZE, + SELECTION_DRAG_ANGLE, SKEW_TRIANGLE_OFFSET, SKEW_TRIANGLE_SIZE, +}; +use crate::messages::frontend::utility_types::MouseCursorIcon; +use crate::messages::portfolio::document::overlays::utility_types::OverlayContext; +use crate::messages::portfolio::document::utility_types::transformation::OriginalTransforms; +use crate::messages::prelude::*; +use crate::messages::tool::common_functionality::compass_rose::Axis; +use crate::messages::tool::common_functionality::snapping::SnapTypeConfiguration; +use glam::{DAffine2, DMat2, DVec2}; +use graphene_std::renderer::Quad; +use graphene_std::renderer::Rect; + +/// (top, bottom, left, right) +pub type EdgeBool = (bool, bool, bool, bool); + +pub struct SizeSnapData<'a> { + pub manager: &'a mut SnapManager, + pub points: &'a mut Vec, + pub snap_data: SnapData<'a>, +} + +/// Contains the edges that are being dragged along with the original bounds. +#[derive(Clone, Debug, Default)] +pub struct SelectedEdges { + pub bounds: [DVec2; 2], + pub top: bool, + pub bottom: bool, + pub left: bool, + pub right: bool, + // Aspect ratio in the form of width/height, so x:1 = width:height + aspect_ratio: f64, +} + +/// The different possible configurations for how the transform cage is presently viewed, depending on its per-axis sizes and the level of zoom. +/// See doc comments in each variant for a diagram of the configuration. +#[derive(Clone, Debug, Default, PartialEq)] +enum TransformCageSizeCategory { + #[default] + /// - ![Diagram](https://files.keavon.com/-/OrganicHelplessWalleye/capture.png) + Full, + /// - ![Diagram](https://files.keavon.com/-/AnyGoldenrodHawk/capture.png) + ReducedLandscape, + /// - ![Diagram](https://files.keavon.com/-/DarkslategrayAcidicFirebelliedtoad/capture.png) + ReducedPortrait, + /// - ![Diagram](https://files.keavon.com/-/GlisteningComplexSeagull/capture.png) + ReducedBoth, + /// - ![Diagram](https://files.keavon.com/-/InconsequentialCharmingLynx/capture.png) + Narrow, + /// - ![Diagram](https://files.keavon.com/-/OpenPaleturquoiseArthropods/capture.png) + Flat, + /// A single point in space with no width or height. + Point, +} + +impl SelectedEdges { + pub fn new(top: bool, bottom: bool, left: bool, right: bool, bounds: [DVec2; 2]) -> Self { + let size = (bounds[0] - bounds[1]).abs(); + let aspect_ratio = size.x / size.y; + Self { + top, + bottom, + left, + right, + bounds, + aspect_ratio, + } + } + + /// Calculate the pivot for the operation (the opposite point to the edge dragged) + pub fn calculate_pivot(&self) -> DVec2 { + self.pivot_from_bounds(self.bounds[0], self.bounds[1]) + } + + fn pivot_from_bounds(&self, min: DVec2, max: DVec2) -> DVec2 { + let x = if self.left { + max.x + } else if self.right { + min.x + } else { + (min.x + max.x) / 2. + }; + + let y = if self.top { + max.y + } else if self.bottom { + min.y + } else { + (min.y + max.y) / 2. + }; + + DVec2::new(x, y) + } + + /// Computes the new bounds with the given mouse move and modifier keys + pub fn new_size(&self, mouse: DVec2, transform: DAffine2, center_around: Option, constrain: bool, snap: Option) -> (DVec2, DVec2) { + let mouse = transform.inverse().transform_point2(mouse); + + let mut min = self.bounds[0]; + let mut max = self.bounds[1]; + + if self.top { + min.y = mouse.y; + } else if self.bottom { + max.y = mouse.y; + } + if self.left { + min.x = mouse.x; + } else if self.right { + max.x = mouse.x; + } + + let mut pivot = self.pivot_from_bounds(min, max); + + // Alt: Scaling around the pivot + if let Some(center_around) = center_around { + let center_around = transform.inverse().transform_point2(center_around); + + let calculate_distance = |moving_opposite_to_drag: &mut f64, center: f64, dragging: f64, original_dragging: f64, current_side: bool| { + if !current_side { + return true; + } + + // The motion of the user's cursor by an `x` pixel offset results in `x * scale_factor` pixels of offset on the other side + let scale_factor = (center - *moving_opposite_to_drag) / (center - original_dragging); + let new_distance = center - scale_factor * (center - dragging); + + // Ignore the Alt key press and scale the dragged edge normally + if !new_distance.is_finite() || scale_factor.abs() > MAXIMUM_ALT_SCALE_FACTOR { + // Don't go on to check the other sides since this side is already invalid, so Alt-dragging is disabled and updating the pivot would be incorrect + return false; + } + + *moving_opposite_to_drag = new_distance; + + true + }; + + // Update the value of the first argument through mutation, and if we make it through all of them without + // encountering a case where the pivot is too near the edge, we also update the pivot so scaling occurs around it + if calculate_distance(&mut max.y, center_around.y, min.y, self.bounds[0].y, self.top) + && calculate_distance(&mut min.y, center_around.y, max.y, self.bounds[1].y, self.bottom) + && calculate_distance(&mut max.x, center_around.x, min.x, self.bounds[0].x, self.left) + && calculate_distance(&mut min.x, center_around.x, max.x, self.bounds[1].x, self.right) + { + pivot = center_around; + } + } + + // Shift: Aspect ratio constraint + if constrain { + let size = max - min; + let min_pivot = (pivot - min) / size; + let new_size = match ((self.top || self.bottom), (self.left || self.right)) { + (true, true) => DVec2::new(size.x, size.x / self.aspect_ratio).abs().max(DVec2::new(size.y * self.aspect_ratio, size.y).abs()) * size.signum(), + (true, false) => DVec2::new(size.y * self.aspect_ratio, size.y), + (false, true) => DVec2::new(size.x, size.x / self.aspect_ratio), + _ => size, + }; + let delta_size = new_size - size; + min -= delta_size * min_pivot; + max = min + new_size; + } + + if let Some(SizeSnapData { manager, points, snap_data }) = snap { + let view_to_doc = snap_data.document.metadata().document_to_viewport.inverse(); + let bounds_to_doc = view_to_doc * transform; + let mut best_snap = SnappedPoint::infinite_snap(pivot); + let mut best_scale_factor = DVec2::ONE; + let tolerance = snapping::snap_tolerance(snap_data.document); + + let bbox = Some(Rect::from_box((bounds_to_doc * Quad::from_box([min, max])).bounding_box())); + for (index, point) in points.iter_mut().enumerate() { + let config = SnapTypeConfiguration { + bbox, + use_existing_candidates: index != 0, + ..Default::default() + }; + + let old_position = point.document_point; + let bounds_space = bounds_to_doc.inverse().transform_point2(point.document_point); + let normalized = (bounds_space - self.bounds[0]) / (self.bounds[1] - self.bounds[0]); + let updated = normalized * (max - min) + min; + point.document_point = bounds_to_doc.transform_point2(updated); + let mut snapped = if constrain { + let constraint = SnapConstraint::Line { + origin: point.document_point, + direction: (point.document_point - bounds_to_doc.transform_point2(pivot)).normalize_or_zero(), + }; + manager.constrained_snap(&snap_data, point, constraint, config) + } else if !(self.top || self.bottom) || !(self.left || self.right) { + let axis = if !(self.top || self.bottom) { DVec2::X } else { DVec2::Y }; + let constraint = SnapConstraint::Line { + origin: point.document_point, + direction: bounds_to_doc.transform_vector2(axis), + }; + manager.constrained_snap(&snap_data, point, constraint, config) + } else { + manager.free_snap(&snap_data, point, config) + }; + point.document_point = old_position; + + if !snapped.is_snapped() { + continue; + } + let snapped_bounds = bounds_to_doc.inverse().transform_point2(snapped.snapped_point_document); + + let new_from_pivot = snapped_bounds - pivot; // The new vector from the snapped point to the pivot + let original_from_pivot = updated - pivot; // The original vector from the point to the pivot + let mut scale_factor = new_from_pivot / original_from_pivot; + + // Constrain should always scale by the same factor in x and y + if constrain { + // When the point is on the pivot, we simply copy the other axis. + if original_from_pivot.x.abs() < 1e-5 { + scale_factor.x = scale_factor.y; + } else if original_from_pivot.y.abs() < 1e-5 { + scale_factor.y = scale_factor.x; + } + + debug_assert!((scale_factor.x - scale_factor.y).abs() < 1e-5); + } + + if !(self.left || self.right || constrain) { + scale_factor.x = 1. + } + if !(self.top || self.bottom || constrain) { + scale_factor.y = 1. + } + + snapped.distance = bounds_to_doc.transform_vector2((max - min) * (scale_factor - DVec2::ONE)).length(); + if snapped.distance > tolerance || !snapped.distance.is_finite() { + continue; + } + if best_snap.other_snap_better(&snapped) { + best_snap = snapped; + best_scale_factor = scale_factor; + } + } + manager.update_indicator(best_snap); + + min = pivot - (pivot - min) * best_scale_factor; + max = pivot - (pivot - max) * best_scale_factor; + } + + (min, max - min) + } + + /// Calculates the required scaling to resize the bounding box + pub fn bounds_to_scale_transform(&self, position: DVec2, size: DVec2) -> (DAffine2, DVec2) { + let old_size = self.bounds[1] - self.bounds[0]; + let mut enlargement_factor = size / old_size; + if !enlargement_factor.x.is_finite() || old_size.x.abs() < f64::EPSILON * 1000. { + enlargement_factor.x = 1.; + } + if !enlargement_factor.y.is_finite() || old_size.y.abs() < f64::EPSILON * 1000. { + enlargement_factor.y = 1.; + } + let mut pivot = (self.bounds[0] * enlargement_factor - position) / (enlargement_factor - DVec2::ONE); + if !pivot.x.is_finite() { + pivot.x = 0.; + } + if !pivot.y.is_finite() { + pivot.y = 0.; + } + (DAffine2::from_scale(enlargement_factor), pivot) + } + + pub fn skew_transform(&self, mouse: DVec2, to_viewport_transform: DAffine2, free_movement: bool) -> DAffine2 { + // Skip if the matrix is singular + if !to_viewport_transform.matrix2.determinant().recip().is_finite() { + return DAffine2::IDENTITY; + } + + let opposite = self.pivot_from_bounds(self.bounds[0], self.bounds[1]); + let dragging_point = self.pivot_from_bounds(self.bounds[1], self.bounds[0]); + + let viewport_dragging_point = to_viewport_transform.transform_point2(dragging_point); + let parallel_to_x = self.top || self.bottom; + let parallel_to_y = !parallel_to_x && (self.left || self.right); + + let drag_vector = mouse - viewport_dragging_point; + let document_drag_vector = to_viewport_transform.inverse().transform_vector2(drag_vector); + + let bounds = (self.bounds[1] - self.bounds[0]).abs(); + let sign = if self.top || self.left { -1. } else { 1. }; + let signed_bounds = sign * bounds; + + let scale_factor = if parallel_to_x { signed_bounds.y.recip() } else { signed_bounds.x.recip() }; + let scaled_document_drag = document_drag_vector * scale_factor; + + let skew = DAffine2::from_mat2(DMat2::from_cols_array(&[ + 1. + if parallel_to_y && free_movement { scaled_document_drag.x } else { 0. }, + if parallel_to_y { scaled_document_drag.y } else { 0. }, + if parallel_to_x { scaled_document_drag.x } else { 0. }, + 1. + if parallel_to_x && free_movement { scaled_document_drag.y } else { 0. }, + ])); + + DAffine2::from_translation(opposite) * skew * DAffine2::from_translation(-opposite) + } +} + +/// Aligns the mouse position to the closest axis +pub fn axis_align_drag(axis_align: bool, axis: Axis, position: DVec2, start: DVec2) -> DVec2 { + if axis_align { + let mouse_position = position - start; + let snap_resolution = SELECTION_DRAG_ANGLE.to_radians(); + let angle = -mouse_position.angle_to(DVec2::X); + let snapped_angle = (angle / snap_resolution).round() * snap_resolution; + let axis_vector = DVec2::from_angle(snapped_angle); + if snapped_angle.is_finite() { + start + axis_vector * mouse_position.dot(axis_vector).abs() + } else { + start + } + } else if axis.is_constraint() { + let mouse_position = position - start; + let axis_vector: DVec2 = axis.into(); + start + axis_vector * mouse_position.dot(axis_vector) + } else { + position + } +} + +/// Snaps a dragging event from the artboard or select tool +pub fn snap_drag(start: DVec2, current: DVec2, snap_to_axis: bool, axis: Axis, snap_data: SnapData, snap_manager: &mut SnapManager, candidates: &[SnapCandidatePoint]) -> DVec2 { + let mouse_position = axis_align_drag(snap_to_axis, axis, snap_data.input.mouse.position, start); + let document = snap_data.document; + let total_mouse_delta_document = document.metadata().document_to_viewport.inverse().transform_vector2(mouse_position - start); + let mouse_delta_document = document.metadata().document_to_viewport.inverse().transform_vector2(mouse_position - current); + let mut offset = mouse_delta_document; + let mut best_snap = SnappedPoint::infinite_snap(document.metadata().document_to_viewport.inverse().transform_point2(mouse_position)); + + let bbox = Rect::point_iter(candidates.iter().map(|candidate| candidate.document_point + total_mouse_delta_document)); + + for (index, point) in candidates.iter().enumerate() { + let config = SnapTypeConfiguration { + bbox, + accept_distribution: true, + use_existing_candidates: index != 0, + ..Default::default() + }; + + let mut point = point.clone(); + point.document_point += total_mouse_delta_document; + + let constrained_along_axis = snap_to_axis || axis.is_constraint(); + let snapped = if constrained_along_axis { + let constraint = SnapConstraint::Line { + origin: point.document_point, + direction: total_mouse_delta_document.try_normalize().unwrap_or(DVec2::X), + }; + snap_manager.constrained_snap(&snap_data, &point, constraint, config) + } else { + snap_manager.free_snap(&snap_data, &point, config) + }; + + if best_snap.other_snap_better(&snapped) { + offset = snapped.snapped_point_document - point.document_point + mouse_delta_document; + best_snap = snapped; + } + } + + snap_manager.update_indicator(best_snap); + + document.metadata().document_to_viewport.transform_vector2(offset) +} + +/// Contains info on the overlays for the bounding box and transform handles +#[derive(Clone, Debug, Default)] +pub struct BoundingBoxManager { + /// The corners of the box. Transform with original_bound_transform to get viewport co-ordinates. + pub bounds: [DVec2; 2], + /// The transform to viewport space for the bounds co-ordinates when the bounds were last updated. + pub transform: DAffine2, + /// Whether the transform is actually singular but adjusted to not be so. + pub transform_tampered: bool, + /// The transform to viewport space for the bounds co-ordinates when the transformation was started. + pub original_bound_transform: DAffine2, + pub selected_edges: Option, + pub original_transforms: OriginalTransforms, + pub opposite_pivot: DVec2, + pub center_of_transformation: DVec2, +} + +impl BoundingBoxManager { + /// Calculates the transformed handle positions based on the bounding box and the transform + pub fn evaluate_transform_handle_positions(&self) -> [DVec2; 8] { + let (left, top): (f64, f64) = self.bounds[0].into(); + let (right, bottom): (f64, f64) = self.bounds[1].into(); + [ + DVec2::new(left, top), + DVec2::new(left, (top + bottom) / 2.), + DVec2::new(left, bottom), + DVec2::new((left + right) / 2., top), + DVec2::new((left + right) / 2., bottom), + DVec2::new(right, top), + DVec2::new(right, (top + bottom) / 2.), + DVec2::new(right, bottom), + ] + } + + pub fn get_closest_edge(&self, edges: EdgeBool, cursor: DVec2) -> EdgeBool { + if !edges.0 && !edges.1 && !edges.2 && !edges.3 { + return (false, false, false, false); + } + + let cursor = self.transform.inverse().transform_point2(cursor); + let min = self.bounds[0].min(self.bounds[1]); + let max = self.bounds[0].max(self.bounds[1]); + + let distances = [ + edges.0.then(|| (cursor - DVec2::new(cursor.x, min.y)).length_squared()), + edges.1.then(|| (cursor - DVec2::new(cursor.x, max.y)).length_squared()), + edges.2.then(|| (cursor - DVec2::new(min.x, cursor.y)).length_squared()), + edges.3.then(|| (cursor - DVec2::new(max.x, cursor.y)).length_squared()), + ]; + + let min_distance = distances.iter().filter_map(|&x| x).min_by(|a, b| a.partial_cmp(b).unwrap()); + + match min_distance { + Some(min) => ( + edges.0 && distances[0].is_some_and(|d| (d - min).abs() < f64::EPSILON), + edges.1 && distances[1].is_some_and(|d| (d - min).abs() < f64::EPSILON), + edges.2 && distances[2].is_some_and(|d| (d - min).abs() < f64::EPSILON), + edges.3 && distances[3].is_some_and(|d| (d - min).abs() < f64::EPSILON), + ), + None => (false, false, false, false), + } + } + + pub fn check_skew_handle(&self, cursor: DVec2, edge: EdgeBool) -> bool { + let Some([start, end]) = self.edge_endpoints_vector_from_edge_bool(edge) else { return false }; + if (end - start).length_squared() < MIN_LENGTH_FOR_SKEW_TRIANGLE_VISIBILITY.powi(2) { + return false; + }; + + let edge_dir = (end - start).normalize(); + let mid = start.midpoint(end); + + for direction in [-edge_dir, edge_dir] { + let base = mid + direction * (3. + SKEW_TRIANGLE_OFFSET + SKEW_TRIANGLE_SIZE / 2.); + let extension = cursor - base; + let along_edge = extension.dot(edge_dir).abs(); + let along_perp = extension.perp_dot(edge_dir).abs(); + + if along_edge <= SKEW_TRIANGLE_SIZE / 2. && along_perp <= BOUNDS_SELECT_THRESHOLD { + return true; + } + } + false + } + + pub fn edge_endpoints_vector_from_edge_bool(&self, edges: EdgeBool) -> Option<[DVec2; 2]> { + let quad = self.transform * Quad::from_box(self.bounds); + let category = self.overlay_display_category(); + + if matches!( + category, + TransformCageSizeCategory::Full | TransformCageSizeCategory::Narrow | TransformCageSizeCategory::ReducedLandscape + ) { + if edges.0 { + return Some([quad.top_left(), quad.top_right()]); + } + if edges.1 { + return Some([quad.bottom_left(), quad.bottom_right()]); + } + } + + if matches!( + category, + TransformCageSizeCategory::Full | TransformCageSizeCategory::Narrow | TransformCageSizeCategory::ReducedPortrait + ) { + if edges.2 { + return Some([quad.top_left(), quad.bottom_left()]); + } + if edges.3 { + return Some([quad.top_right(), quad.bottom_right()]); + } + } + None + } + + pub fn render_skew_gizmos(&mut self, overlay_context: &mut OverlayContext, hover_edge: EdgeBool) { + let mut draw_edge_triangles = |start: DVec2, end: DVec2| { + if (end - start).length() < MIN_LENGTH_FOR_SKEW_TRIANGLE_VISIBILITY { + return; + } + + let edge_dir = (end - start).normalize(); + let mid = end.midpoint(start); + + for edge in [edge_dir, -edge_dir] { + overlay_context.draw_triangle(mid + edge * (3. + SKEW_TRIANGLE_OFFSET), edge, SKEW_TRIANGLE_SIZE, None, None); + } + }; + + if let Some([start, end]) = self.edge_endpoints_vector_from_edge_bool(hover_edge) { + draw_edge_triangles(start, end); + } + } + + pub fn over_extended_edge_midpoint(&self, mouse: DVec2, hover_edge: EdgeBool) -> bool { + const HALF_WIDTH_OUTER_RECT: f64 = RESIZE_HANDLE_SIZE / 2. + SKEW_TRIANGLE_OFFSET + SKEW_TRIANGLE_SIZE; + const HALF_WIDTH_INNER_RECT: f64 = SKEW_TRIANGLE_OFFSET + RESIZE_HANDLE_SIZE / 2.; + + const INNER_QUAD_CORNER: DVec2 = DVec2::new(HALF_WIDTH_INNER_RECT, RESIZE_HANDLE_SIZE / 2.); + const FULL_QUAD_CORNER: DVec2 = DVec2::new(HALF_WIDTH_OUTER_RECT, BOUNDS_SELECT_THRESHOLD); + + let quad = self.transform * Quad::from_box(self.bounds); + + let Some([start, end]) = self.edge_endpoints_vector_from_edge_bool(hover_edge) else { + return false; + }; + if (end - start).length() < MIN_LENGTH_FOR_SKEW_TRIANGLE_VISIBILITY { + return false; + } + + let angle; + let is_compact; + if hover_edge.0 || hover_edge.1 { + angle = (quad.top_left() - quad.top_right()).to_angle(); + is_compact = (quad.top_left() - quad.bottom_left()).length_squared() < MIN_LENGTH_FOR_RESIZE_TO_INCLUDE_INTERIOR.powi(2); + } else if hover_edge.2 || hover_edge.3 { + angle = (quad.top_left() - quad.bottom_left()).to_angle(); + is_compact = (quad.top_left() - quad.top_right()).length_squared() < MIN_LENGTH_FOR_RESIZE_TO_INCLUDE_INTERIOR.powi(2); + } else { + return false; + }; + + let has_triangle_hover = self.check_skew_handle(mouse, hover_edge); + let point = start.midpoint(end); + + if is_compact { + let upper_rect = DAffine2::from_angle_translation(angle, point) * Quad::from_box([-FULL_QUAD_CORNER.with_y(0.), FULL_QUAD_CORNER]); + let inter_triangle_quad = DAffine2::from_angle_translation(angle, point) * Quad::from_box([-INNER_QUAD_CORNER, INNER_QUAD_CORNER]); + + upper_rect.contains(mouse) || has_triangle_hover || inter_triangle_quad.contains(mouse) + } else { + let rect = DAffine2::from_angle_translation(angle, point) * Quad::from_box([-FULL_QUAD_CORNER, FULL_QUAD_CORNER]); + + rect.contains(mouse) || has_triangle_hover + } + } + + pub fn render_quad(&self, overlay_context: &mut OverlayContext) { + let quad = self.transform * Quad::from_box(self.bounds); + + // Draw the bounding box rectangle + overlay_context.quad(quad, None, None); + } + + /// Update the position of the bounding box and transform handles + pub fn render_overlays(&mut self, overlay_context: &mut OverlayContext, render_quad: bool) { + let quad = self.transform * Quad::from_box(self.bounds); + let category = self.overlay_display_category(); + + let horizontal_edges = [quad.top_right().midpoint(quad.bottom_right()), quad.bottom_left().midpoint(quad.top_left())]; + let vertical_edges = [quad.top_left().midpoint(quad.top_right()), quad.bottom_right().midpoint(quad.bottom_left())]; + + if render_quad { + self.render_quad(overlay_context); + } + + let mut draw_handle = |point: DVec2, angle: f64| { + let quad = DAffine2::from_angle_translation(angle, point) * Quad::from_box([DVec2::splat(-RESIZE_HANDLE_SIZE / 2.), DVec2::splat(RESIZE_HANDLE_SIZE / 2.)]); + overlay_context.quad(quad, None, Some(COLOR_OVERLAY_WHITE)); + }; + + let horizontal_angle = (quad.top_left() - quad.bottom_left()).to_angle(); + let vertical_angle = (quad.top_left() - quad.top_right()).to_angle(); + + // Draw the horizontal midpoint drag handles + if matches!( + category, + TransformCageSizeCategory::Full | TransformCageSizeCategory::Narrow | TransformCageSizeCategory::ReducedLandscape + ) { + for point in horizontal_edges { + draw_handle(point, horizontal_angle); + } + } + + // Draw the vertical midpoint drag handles + if matches!( + category, + TransformCageSizeCategory::Full | TransformCageSizeCategory::Narrow | TransformCageSizeCategory::ReducedPortrait + ) { + for point in vertical_edges { + draw_handle(point, vertical_angle); + } + } + + let angle = quad + .edges() + .map(|[x, y]| x.distance_squared(y)) + .into_iter() + .reduce(|horizontal_distance, vertical_distance| if horizontal_distance > vertical_distance { horizontal_angle } else { vertical_angle }) + .unwrap_or_default(); + + // Draw the corner drag handles + if matches!( + category, + TransformCageSizeCategory::Full | TransformCageSizeCategory::ReducedBoth | TransformCageSizeCategory::ReducedLandscape | TransformCageSizeCategory::ReducedPortrait + ) { + for point in quad.0 { + draw_handle(point, angle); + } + } + + // Draw the flat line endpoint drag handles + if category == TransformCageSizeCategory::Flat { + draw_handle(self.transform.transform_point2(self.bounds[0]), angle); + draw_handle(self.transform.transform_point2(self.bounds[1]), angle); + } + } + + /// Find the [`TransformCageSizeCategory`] of this bounding box based on size thresholds. + fn overlay_display_category(&self) -> TransformCageSizeCategory { + let quad = self.transform * Quad::from_box(self.bounds); + + // Check if the bounds are essentially the same because the width and height are smaller than MAX_LENGTH_FOR_NO_WIDTH_OR_HEIGHT + if self.is_bounds_point() { + return TransformCageSizeCategory::Point; + } + + // Check if the area is essentially zero because either the width or height is smaller than MAX_LENGTH_FOR_NO_WIDTH_OR_HEIGHT + if self.is_bounds_flat() { + return TransformCageSizeCategory::Flat; + } + + let vertical_length = (quad.top_left() - quad.top_right()).length_squared(); + let horizontal_length = (quad.bottom_left() - quad.top_left()).length_squared(); + let corners_visible = vertical_length >= MIN_LENGTH_FOR_CORNERS_VISIBILITY.powi(2) && horizontal_length >= MIN_LENGTH_FOR_CORNERS_VISIBILITY.powi(2); + + if corners_visible { + let vertical_edge_visible = vertical_length > MIN_LENGTH_FOR_MIDPOINT_VISIBILITY.powi(2); + let horizontal_edge_visible = horizontal_length > MIN_LENGTH_FOR_MIDPOINT_VISIBILITY.powi(2); + + return match (vertical_edge_visible, horizontal_edge_visible) { + (true, true) => TransformCageSizeCategory::Full, + (true, false) => TransformCageSizeCategory::ReducedPortrait, + (false, true) => TransformCageSizeCategory::ReducedLandscape, + (false, false) => TransformCageSizeCategory::ReducedBoth, + }; + } + + TransformCageSizeCategory::Narrow + } + + /// Determine if these bounds are flat ([`TransformCageSizeCategory::Flat`]), which means that the width and/or height is essentially zero and the bounds are a line with effectively no area. This can happen on actual lines (axis-aligned, i.e. drawn horizontally or vertically) or when an element is scaled to zero in X or Y. A flat transform cage can still be rotated by a transformation, but its local space remains flat. + fn is_bounds_flat(&self) -> bool { + (self.bounds[0] - self.bounds[1]).abs().cmple(DVec2::splat(MAX_LENGTH_FOR_NO_WIDTH_OR_HEIGHT)).any() + } + + /// Determine if these bounds are point ([`TransformCageSizeCategory::Point`]), which means that the width and height are essentially zero and the bounds are a point with no area. This can happen on points when an element is scaled to zero in both X and Y, or if an element is just a single anchor point. A point transform cage cannot be rotated by a transformation, and its local space remains a point. + fn is_bounds_point(&self) -> bool { + (self.bounds[0] - self.bounds[1]).abs().cmple(DVec2::splat(MAX_LENGTH_FOR_NO_WIDTH_OR_HEIGHT)).all() + } + + /// Determine if the given point in viewport space falls within the bounds of `self`. + fn is_contained_in_bounds(&self, point: DVec2) -> bool { + let document_point = self.transform.inverse().transform_point2(point); + Quad::from_box(self.bounds).contains(document_point) + } + + /// Compute the threshold in viewport space. This only works with affine transforms as it assumes lines remain parallel. + fn compute_viewport_threshold(&self, scalar: f64) -> [f64; 2] { + let inverse = self.transform.inverse(); + + let viewport_x = self.transform.transform_vector2(DVec2::X).normalize_or_zero() * scalar; + let viewport_y = self.transform.transform_vector2(DVec2::Y).normalize_or_zero() * scalar; + + let threshold_x = inverse.transform_vector2(viewport_x).length(); + let threshold_y = inverse.transform_vector2(viewport_y).length(); + + [threshold_x, threshold_y] + } + + /// Check if the user has selected the edge for dragging. + /// + /// Returns which edge in the order: + /// + /// `top, bottom, left, right` + pub fn check_selected_edges(&self, cursor: DVec2) -> Option { + let cursor = self.transform.inverse().transform_point2(cursor); + + let min = self.bounds[0].min(self.bounds[1]); + let max = self.bounds[0].max(self.bounds[1]); + + let [threshold_x, threshold_y] = self.compute_viewport_threshold(BOUNDS_SELECT_THRESHOLD); + let [corner_min_x, corner_min_y] = self.compute_viewport_threshold(MIN_LENGTH_FOR_CORNERS_VISIBILITY); + let [edge_min_x, edge_min_y] = self.compute_viewport_threshold(MIN_LENGTH_FOR_RESIZE_TO_INCLUDE_INTERIOR); + let [midpoint_threshold_x, midpoint_threshold_y] = self.compute_viewport_threshold(MIN_LENGTH_FOR_EDGE_RESIZE_PRIORITY_OVER_CORNERS); + + if (min.x - cursor.x < threshold_x && min.y - cursor.y < threshold_y) && (cursor.x - max.x < threshold_x && cursor.y - max.y < threshold_y) { + let mut top = (cursor.y - min.y).abs() < threshold_y; + let mut bottom = (max.y - cursor.y).abs() < threshold_y; + let mut left = (cursor.x - min.x).abs() < threshold_x; + let mut right = (max.x - cursor.x).abs() < threshold_x; + + let width = max.x - min.x; + let height = max.y - min.y; + + if (left || right) && (top || bottom) { + let horizontal_midpoint_x = (min.x + max.x) / 2.; + let vertical_midpoint_y = (min.y + max.y) / 2.; + + if (cursor.x - horizontal_midpoint_x).abs() < midpoint_threshold_x { + left = false; + right = false; + } else if (cursor.y - vertical_midpoint_y).abs() < midpoint_threshold_y { + top = false; + bottom = false; + } + } + + if width < edge_min_x || height <= edge_min_y { + if self.transform_tampered { + return None; + } + + if min.x < cursor.x && cursor.x < max.x && cursor.y < max.y && cursor.y > min.y { + return None; + } + + // Prioritize single axis transformations on very small bounds + if height < corner_min_y && (left || right) { + top = false; + bottom = false; + } + if width < corner_min_x && (top || bottom) { + left = false; + right = false; + } + + // On bounds with no width/height, disallow transformation in the relevant axis + if width < MAX_LENGTH_FOR_NO_WIDTH_OR_HEIGHT { + left = false; + right = false; + } + if height < MAX_LENGTH_FOR_NO_WIDTH_OR_HEIGHT { + top = false; + bottom = false; + } + } + + if top || bottom || left || right { + return Some((top, bottom, left, right)); + } + } + + None + } + + /// Check if the user is rotating with the bounds + pub fn check_rotate(&self, cursor: DVec2) -> bool { + if self.is_contained_in_bounds(cursor) { + return false; + } + let [threshold_x, threshold_y] = self.compute_viewport_threshold(BOUNDS_ROTATE_THRESHOLD); + let cursor = self.transform.inverse().transform_point2(cursor); + + let flat = self.is_bounds_flat(); + let point = self.is_bounds_point(); + let within_square_bounds = |center: &DVec2| center.x - threshold_x < cursor.x && cursor.x < center.x + threshold_x && center.y - threshold_y < cursor.y && cursor.y < center.y + threshold_y; + if point { + false + } else if flat { + [self.bounds[0], self.bounds[1]].iter().any(within_square_bounds) + } else { + self.evaluate_transform_handle_positions().iter().any(within_square_bounds) + } + } + + /// Gets the required mouse cursor to show resizing bounds or optionally rotation + pub fn get_cursor(&self, input: &InputPreprocessorMessageHandler, rotate: bool, dragging_bounds: bool, skew_edge: Option) -> MouseCursorIcon { + let edges = self.check_selected_edges(input.mouse.position); + + let is_near_square = edges.is_some_and(|hover_edge| self.over_extended_edge_midpoint(input.mouse.position, hover_edge)); + if dragging_bounds && is_near_square { + if let Some(skew_edge) = skew_edge { + if self.check_skew_handle(input.mouse.position, skew_edge) { + if skew_edge.0 || skew_edge.1 { + return MouseCursorIcon::EWResize; + } else if skew_edge.2 || skew_edge.3 { + return MouseCursorIcon::NSResize; + } + } + }; + } + + match edges { + Some((top, bottom, left, right)) => match (top, bottom, left, right) { + (true, _, false, false) | (_, true, false, false) => MouseCursorIcon::NSResize, + (false, false, true, _) | (false, false, _, true) => MouseCursorIcon::EWResize, + (true, _, true, _) | (_, true, _, true) => MouseCursorIcon::NWSEResize, + (true, _, _, true) | (_, true, true, _) => MouseCursorIcon::NESWResize, + _ => MouseCursorIcon::Default, + }, + _ if rotate && self.check_rotate(input.mouse.position) => MouseCursorIcon::Rotate, + _ => MouseCursorIcon::Default, + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn skew_transform_singular() { + for edge in [ + SelectedEdges::new(true, false, false, false, [DVec2::NEG_ONE, DVec2::ONE]), + SelectedEdges::new(false, true, false, false, [DVec2::NEG_ONE, DVec2::ONE]), + SelectedEdges::new(false, false, true, false, [DVec2::NEG_ONE, DVec2::ONE]), + SelectedEdges::new(false, false, false, true, [DVec2::NEG_ONE, DVec2::ONE]), + ] { + // The determinant is 0. + let transform = DAffine2::from_cols_array(&[2.; 6]); + // This shouldn't panic. We don't really care about the behavior in this test. + let _ = edge.skew_transform(DVec2::new(1.5, 1.5), transform, false); + } + } + + #[test] + fn skew_transform_correct() { + for edge in [ + SelectedEdges::new(true, false, false, false, [DVec2::NEG_ONE, DVec2::ONE]), + SelectedEdges::new(false, true, false, false, [DVec2::NEG_ONE, DVec2::ONE]), + SelectedEdges::new(false, false, true, false, [DVec2::NEG_ONE, DVec2::ONE]), + SelectedEdges::new(false, false, false, true, [DVec2::NEG_ONE, DVec2::ONE]), + ] { + // Random transform with det != 0. + let to_viewport_transform = DAffine2::from_cols_array(&[2., 1., 0., 1., 2., 3.]); + // Random mouse position. + let mouse = DVec2::new(1.5, 1.5); + let final_transform = edge.skew_transform(mouse, to_viewport_transform, false); + + // This is the current handle that goes under the mouse. + let opposite = edge.pivot_from_bounds(edge.bounds[0], edge.bounds[1]); + let dragging_point = edge.pivot_from_bounds(edge.bounds[1], edge.bounds[0]); + + let viewport_dragging_point = to_viewport_transform.transform_point2(dragging_point); + let parallel_to_x = edge.top || edge.bottom; + let parallel_to_y = !parallel_to_x && (edge.left || edge.right); + + let drag_vector = mouse - viewport_dragging_point; + let document_drag_vector = to_viewport_transform.inverse().transform_vector2(drag_vector); + + let sign = if edge.top || edge.left { -1. } else { 1. }; + let scale_factor = (edge.bounds[1] - edge.bounds[0])[parallel_to_x as usize].abs().recip() * sign; + let scaled_document_drag = document_drag_vector * scale_factor; + + let skew = DAffine2::from_mat2(DMat2::from_cols_array(&[ + 1., + if parallel_to_y { scaled_document_drag.y } else { 0. }, + if parallel_to_x { scaled_document_drag.x } else { 0. }, + 1., + ])); + + let constructed_transform = DAffine2::from_translation(opposite) * skew * DAffine2::from_translation(-opposite); + + assert_eq!(constructed_transform, final_transform); + } + } +} diff --git a/editor/src/messages/tool/common_functionality/utility_functions.rs b/editor/src/messages/tool/common_functionality/utility_functions.rs new file mode 100644 index 0000000000000000000000000000000000000000..23829271b0e2ffe52686368486b715699ce9e633 --- /dev/null +++ b/editor/src/messages/tool/common_functionality/utility_functions.rs @@ -0,0 +1,590 @@ +use super::snapping::{SnapCandidatePoint, SnapData, SnapManager}; +use super::transformation_cage::{BoundingBoxManager, SizeSnapData}; +use crate::consts::ROTATE_INCREMENT; +use crate::messages::portfolio::document::utility_types::document_metadata::LayerNodeIdentifier; +use crate::messages::portfolio::document::utility_types::transformation::Selected; +use crate::messages::prelude::*; +use crate::messages::tool::common_functionality::graph_modification_utils::get_text; +use crate::messages::tool::common_functionality::transformation_cage::SelectedEdges; +use crate::messages::tool::tool_messages::path_tool::PathOverlayMode; +use crate::messages::tool::utility_types::ToolType; +use bezier_rs::{Bezier, BezierHandles}; +use glam::{DAffine2, DVec2}; +use graphene_std::renderer::Quad; +use graphene_std::text::{FontCache, load_font}; +use graphene_std::vector::{HandleExt, HandleId, ManipulatorPointId, PointId, SegmentId, VectorData, VectorModificationType}; +use kurbo::{CubicBez, Line, ParamCurveExtrema, PathSeg, Point, QuadBez}; + +/// Determines if a path should be extended. Goal in viewport space. Returns the path and if it is extending from the start, if applicable. +pub fn should_extend( + document: &DocumentMessageHandler, + goal: DVec2, + tolerance: f64, + layers: impl Iterator, + preferences: &PreferencesMessageHandler, +) -> Option<(LayerNodeIdentifier, PointId, DVec2)> { + closest_point(document, goal, tolerance, layers, |_| false, preferences) +} + +/// Determine the closest point to the goal point under max_distance. +/// Additionally exclude checking closeness to the point which given to exclude() returns true. +pub fn closest_point( + document: &DocumentMessageHandler, + goal: DVec2, + max_distance: f64, + layers: impl Iterator, + exclude: T, + preferences: &PreferencesMessageHandler, +) -> Option<(LayerNodeIdentifier, PointId, DVec2)> +where + T: Fn(PointId) -> bool, +{ + let mut best = None; + let mut best_distance_squared = max_distance * max_distance; + for layer in layers { + let viewspace = document.metadata().transform_to_viewport(layer); + let Some(vector_data) = document.network_interface.compute_modified_vector(layer) else { + continue; + }; + for id in vector_data.extendable_points(preferences.vector_meshes) { + if exclude(id) { + continue; + } + let Some(point) = vector_data.point_domain.position_from_id(id) else { continue }; + + let distance_squared = viewspace.transform_point2(point).distance_squared(goal); + + if distance_squared < best_distance_squared { + best = Some((layer, id, point)); + best_distance_squared = distance_squared; + } + } + } + + best +} + +/// Calculates the bounding box of the layer's text, based on the settings for max width and height specified in the typesetting config. +pub fn text_bounding_box(layer: LayerNodeIdentifier, document: &DocumentMessageHandler, font_cache: &FontCache) -> Quad { + let Some((text, font, typesetting)) = get_text(layer, &document.network_interface) else { + return Quad::from_box([DVec2::ZERO, DVec2::ZERO]); + }; + + let font_data = font_cache.get(font).map(|data| load_font(data)); + let far = graphene_std::text::bounding_box(text, font_data, typesetting, false); + + Quad::from_box([DVec2::ZERO, far]) +} + +pub fn calculate_segment_angle(anchor: PointId, segment: SegmentId, vector_data: &VectorData, prefer_handle_direction: bool) -> Option { + let is_start = |point: PointId, segment: SegmentId| vector_data.segment_start_from_id(segment) == Some(point); + let anchor_position = vector_data.point_domain.position_from_id(anchor)?; + let end_handle = ManipulatorPointId::EndHandle(segment).get_position(vector_data); + let start_handle = ManipulatorPointId::PrimaryHandle(segment).get_position(vector_data); + + let start_point = if is_start(anchor, segment) { + vector_data.segment_end_from_id(segment).and_then(|id| vector_data.point_domain.position_from_id(id)) + } else { + vector_data.segment_start_from_id(segment).and_then(|id| vector_data.point_domain.position_from_id(id)) + }; + + let required_handle = if is_start(anchor, segment) { + start_handle + .filter(|&handle| prefer_handle_direction && handle != anchor_position) + .or(end_handle.filter(|&handle| Some(handle) != start_point)) + .or(start_point) + } else { + end_handle + .filter(|&handle| prefer_handle_direction && handle != anchor_position) + .or(start_handle.filter(|&handle| Some(handle) != start_point)) + .or(start_point) + }; + + required_handle.map(|handle| -(handle - anchor_position).angle_to(DVec2::X)) +} + +pub fn adjust_handle_colinearity(handle: HandleId, anchor_position: DVec2, target_control_point: DVec2, vector_data: &VectorData, layer: LayerNodeIdentifier, responses: &mut VecDeque) { + let Some(other_handle) = vector_data.other_colinear_handle(handle) else { return }; + let Some(handle_position) = other_handle.to_manipulator_point().get_position(vector_data) else { + return; + }; + let Some(direction) = (anchor_position - target_control_point).try_normalize() else { return }; + + let new_relative_position = (handle_position - anchor_position).length() * direction; + let modification_type = other_handle.set_relative_position(new_relative_position); + + responses.add(GraphOperationMessage::Vector { layer, modification_type }); +} + +pub fn restore_previous_handle_position( + handle: HandleId, + original_c: DVec2, + anchor_position: DVec2, + vector_data: &VectorData, + layer: LayerNodeIdentifier, + responses: &mut VecDeque, +) -> Option { + let other_handle = vector_data.other_colinear_handle(handle)?; + let handle_position = other_handle.to_manipulator_point().get_position(vector_data)?; + let direction = (anchor_position - original_c).try_normalize()?; + + let old_relative_position = (handle_position - anchor_position).length() * direction; + let modification_type = other_handle.set_relative_position(old_relative_position); + responses.add(GraphOperationMessage::Vector { layer, modification_type }); + + let handles = [handle, other_handle]; + let modification_type = VectorModificationType::SetG1Continuous { handles, enabled: false }; + responses.add(GraphOperationMessage::Vector { layer, modification_type }); + + Some(other_handle) +} + +pub fn restore_g1_continuity( + handle: HandleId, + other_handle: HandleId, + control_point: DVec2, + anchor_position: DVec2, + vector_data: &VectorData, + layer: LayerNodeIdentifier, + responses: &mut VecDeque, +) { + let Some(handle_position) = other_handle.to_manipulator_point().get_position(vector_data) else { + return; + }; + let Some(direction) = (anchor_position - control_point).try_normalize() else { return }; + + let new_relative_position = (handle_position - anchor_position).length() * direction; + let modification_type = other_handle.set_relative_position(new_relative_position); + responses.add(GraphOperationMessage::Vector { layer, modification_type }); + + let handles = [handle, other_handle]; + let modification_type = VectorModificationType::SetG1Continuous { handles, enabled: true }; + responses.add(GraphOperationMessage::Vector { layer, modification_type }); +} + +/// Check whether a point is visible in the current overlay mode. +pub fn is_visible_point( + manipulator_point_id: ManipulatorPointId, + vector_data: &VectorData, + path_overlay_mode: PathOverlayMode, + frontier_handles_info: Option>>, + selected_segments: Vec, + selected_points: &HashSet, +) -> bool { + match manipulator_point_id { + ManipulatorPointId::Anchor(_) => true, + ManipulatorPointId::EndHandle(segment_id) | ManipulatorPointId::PrimaryHandle(segment_id) => { + match (path_overlay_mode, selected_points.len() == 1) { + (PathOverlayMode::AllHandles, _) => true, + (PathOverlayMode::SelectedPointHandles, _) | (PathOverlayMode::FrontierHandles, true) => { + if selected_segments.contains(&segment_id) { + return true; + } + + // Either the segment is a part of selected segments or the opposite handle is a part of existing selection + let Some(handle_pair) = manipulator_point_id.get_handle_pair(vector_data) else { return false }; + let other_handle = handle_pair[1].to_manipulator_point(); + + // Return whether the list of selected points contain the other handle + selected_points.contains(&other_handle) + } + (PathOverlayMode::FrontierHandles, false) => { + let Some(anchor) = manipulator_point_id.get_anchor(vector_data) else { + warn!("No anchor for selected handle"); + return false; + }; + let Some(frontier_handles) = &frontier_handles_info else { + warn!("No frontier handles info provided"); + return false; + }; + + frontier_handles.get(&segment_id).map(|anchors| anchors.contains(&anchor)).unwrap_or_default() + } + } + } + } +} + +/// Function to find the bounding box of bezier (uses method from kurbo) +pub fn calculate_bezier_bbox(bezier: Bezier) -> [DVec2; 2] { + let start = Point::new(bezier.start.x, bezier.start.y); + let end = Point::new(bezier.end.x, bezier.end.y); + let bbox = match bezier.handles { + BezierHandles::Cubic { handle_start, handle_end } => { + let p1 = Point::new(handle_start.x, handle_start.y); + let p2 = Point::new(handle_end.x, handle_end.y); + CubicBez::new(start, p1, p2, end).bounding_box() + } + BezierHandles::Quadratic { handle } => { + let p1 = Point::new(handle.x, handle.y); + QuadBez::new(start, p1, end).bounding_box() + } + BezierHandles::Linear => Line::new(start, end).bounding_box(), + }; + [DVec2::new(bbox.x0, bbox.y0), DVec2::new(bbox.x1, bbox.y1)] +} + +pub fn is_intersecting(bezier: Bezier, quad: [DVec2; 2], transform: DAffine2) -> bool { + let to_layerspace = transform.inverse(); + let quad = [to_layerspace.transform_point2(quad[0]), to_layerspace.transform_point2(quad[1])]; + let start = Point::new(bezier.start.x, bezier.start.y); + let end = Point::new(bezier.end.x, bezier.end.y); + let segment = match bezier.handles { + BezierHandles::Cubic { handle_start, handle_end } => { + let p1 = Point::new(handle_start.x, handle_start.y); + let p2 = Point::new(handle_end.x, handle_end.y); + PathSeg::Cubic(CubicBez::new(start, p1, p2, end)) + } + BezierHandles::Quadratic { handle } => { + let p1 = Point::new(handle.x, handle.y); + PathSeg::Quad(QuadBez::new(start, p1, end)) + } + BezierHandles::Linear => PathSeg::Line(Line::new(start, end)), + }; + + // Create a list of all the sides + let sides = [ + Line::new((quad[0].x, quad[0].y), (quad[1].x, quad[0].y)), + Line::new((quad[0].x, quad[0].y), (quad[0].x, quad[1].y)), + Line::new((quad[1].x, quad[1].y), (quad[1].x, quad[0].y)), + Line::new((quad[1].x, quad[1].y), (quad[0].x, quad[1].y)), + ]; + + let mut is_intersecting = false; + for line in sides { + let intersections = segment.intersect_line(line); + let mut intersects = false; + for intersection in intersections { + if intersection.line_t <= 1. && intersection.line_t >= 0. && intersection.segment_t <= 1. && intersection.segment_t >= 0. { + // There is a valid intersection point + intersects = true; + break; + } + } + if intersects { + is_intersecting = true; + break; + } + } + is_intersecting +} + +#[allow(clippy::too_many_arguments)] +pub fn resize_bounds( + document: &DocumentMessageHandler, + responses: &mut VecDeque, + bounds: &mut BoundingBoxManager, + dragging_layers: &mut Vec, + snap_manager: &mut SnapManager, + snap_candidates: &mut Vec, + input: &InputPreprocessorMessageHandler, + center: bool, + constrain: bool, + tool: ToolType, +) { + if let Some(movement) = &mut bounds.selected_edges { + let center = center.then_some(bounds.center_of_transformation); + let snap = Some(SizeSnapData { + manager: snap_manager, + points: snap_candidates, + snap_data: SnapData::ignore(document, input, dragging_layers), + }); + let (position, size) = movement.new_size(input.mouse.position, bounds.original_bound_transform, center, constrain, snap); + let (delta, mut pivot) = movement.bounds_to_scale_transform(position, size); + + let pivot_transform = DAffine2::from_translation(pivot); + let transformation = pivot_transform * delta * pivot_transform.inverse(); + + dragging_layers.retain(|layer| { + if *layer != LayerNodeIdentifier::ROOT_PARENT { + document.network_interface.document_network().nodes.contains_key(&layer.to_node()) + } else { + log::error!("ROOT_PARENT should not be part of layers_dragging"); + false + } + }); + + let mut selected = Selected::new(&mut bounds.original_transforms, &mut pivot, dragging_layers, responses, &document.network_interface, None, &tool, None); + selected.apply_transformation(bounds.original_bound_transform * transformation * bounds.original_bound_transform.inverse(), None); + } +} + +#[allow(clippy::too_many_arguments)] +pub fn rotate_bounds( + document: &DocumentMessageHandler, + responses: &mut VecDeque, + bounds: &mut BoundingBoxManager, + dragging_layers: &mut Vec, + drag_start: DVec2, + mouse_position: DVec2, + snap_angle: bool, + tool: ToolType, +) { + let angle = { + let start_offset = drag_start - bounds.center_of_transformation; + let end_offset = mouse_position - bounds.center_of_transformation; + start_offset.angle_to(end_offset) + }; + + let snapped_angle = if snap_angle { + let snap_resolution = ROTATE_INCREMENT.to_radians(); + (angle / snap_resolution).round() * snap_resolution + } else { + angle + }; + + let delta = DAffine2::from_angle(snapped_angle); + + dragging_layers.retain(|layer| { + if *layer != LayerNodeIdentifier::ROOT_PARENT { + document.network_interface.document_network().nodes.contains_key(&layer.to_node()) + } else { + log::error!("ROOT_PARENT should not be part of replacement_selected_layers"); + false + } + }); + + let mut selected = Selected::new( + &mut bounds.original_transforms, + &mut bounds.center_of_transformation, + dragging_layers, + responses, + &document.network_interface, + None, + &tool, + None, + ); + selected.update_transforms(delta, None, None); +} + +pub fn skew_bounds( + document: &DocumentMessageHandler, + responses: &mut VecDeque, + bounds: &mut BoundingBoxManager, + free_movement: bool, + layers: &mut Vec, + mouse_position: DVec2, + tool: ToolType, +) { + if let Some(movement) = &mut bounds.selected_edges { + let mut pivot = DVec2::ZERO; + + let transformation = movement.skew_transform(mouse_position, bounds.original_bound_transform, free_movement); + + layers.retain(|layer| { + if *layer != LayerNodeIdentifier::ROOT_PARENT { + document.network_interface.document_network().nodes.contains_key(&layer.to_node()) + } else { + log::error!("ROOT_PARENT should not be part of layers_dragging"); + false + } + }); + + let mut selected = Selected::new(&mut bounds.original_transforms, &mut pivot, layers, responses, &document.network_interface, None, &tool, None); + selected.apply_transformation(bounds.original_bound_transform * transformation * bounds.original_bound_transform.inverse(), None); + } +} + +// TODO: Replace returned tuple (where at most 1 element is true at a time) with an enum. +/// Returns the tuple (resize, rotate, skew). +pub fn transforming_transform_cage( + document: &DocumentMessageHandler, + mut bounding_box_manager: &mut Option, + input: &InputPreprocessorMessageHandler, + responses: &mut VecDeque, + layers_dragging: &mut Vec, +) -> (bool, bool, bool) { + let dragging_bounds = bounding_box_manager.as_mut().and_then(|bounding_box| { + let edges = bounding_box.check_selected_edges(input.mouse.position); + + bounding_box.selected_edges = edges.map(|(top, bottom, left, right)| { + let selected_edges = SelectedEdges::new(top, bottom, left, right, bounding_box.bounds); + bounding_box.opposite_pivot = selected_edges.calculate_pivot(); + selected_edges + }); + + edges + }); + + let rotating_bounds = bounding_box_manager.as_ref().map(|bounding_box| bounding_box.check_rotate(input.mouse.position)).unwrap_or_default(); + + let selected: Vec<_> = document.network_interface.selected_nodes().selected_visible_and_unlocked_layers(&document.network_interface).collect(); + + let is_flat_layer = bounding_box_manager.as_ref().map(|bounding_box_manager| bounding_box_manager.transform_tampered).unwrap_or(true); + + if dragging_bounds.is_some() && !is_flat_layer { + responses.add(DocumentMessage::StartTransaction); + + *layers_dragging = selected; + + if let Some(bounds) = &mut bounding_box_manager { + bounds.original_bound_transform = bounds.transform; + + layers_dragging.retain(|layer| { + if *layer != LayerNodeIdentifier::ROOT_PARENT { + document.network_interface.document_network().nodes.contains_key(&layer.to_node()) + } else { + log::error!("ROOT_PARENT should not be part of layers_dragging"); + false + } + }); + + let mut selected = Selected::new( + &mut bounds.original_transforms, + &mut bounds.center_of_transformation, + layers_dragging, + responses, + &document.network_interface, + None, + &ToolType::Select, + None, + ); + bounds.center_of_transformation = selected.mean_average_of_pivots(); + + // Check if we're hovering over a skew triangle + let edges = bounds.check_selected_edges(input.mouse.position); + if let Some(edges) = edges { + let closest_edge = bounds.get_closest_edge(edges, input.mouse.position); + if bounds.check_skew_handle(input.mouse.position, closest_edge) { + // No resize or rotate, just skew + return (false, false, true); + } + } + } + + // Just resize, no rotate or skew + return (true, false, false); + } + + if rotating_bounds { + responses.add(DocumentMessage::StartTransaction); + + if let Some(bounds) = &mut bounding_box_manager { + layers_dragging.retain(|layer| { + if *layer != LayerNodeIdentifier::ROOT_PARENT { + document.network_interface.document_network().nodes.contains_key(&layer.to_node()) + } else { + log::error!("ROOT_PARENT should not be part of layers_dragging"); + false + } + }); + + let mut selected = Selected::new( + &mut bounds.original_transforms, + &mut bounds.center_of_transformation, + &selected, + responses, + &document.network_interface, + None, + &ToolType::Select, + None, + ); + + bounds.center_of_transformation = selected.mean_average_of_pivots(); + } + + *layers_dragging = selected; + + // No resize or skew, just rotate + return (false, true, false); + } + + // No resize, rotate, or skew + (false, false, false) +} + +/// Calculates similarity metric between new bezier curve and two old beziers by using sampled points. +#[allow(clippy::too_many_arguments)] +pub fn log_optimization(a: f64, b: f64, p1: DVec2, p3: DVec2, d1: DVec2, d2: DVec2, points1: &[DVec2], n: usize) -> f64 { + let start_handle_length = a.exp(); + let end_handle_length = b.exp(); + + // Compute the handle positions of new bezier curve + let c1 = p1 + d1 * start_handle_length; + let c2 = p3 + d2 * end_handle_length; + + let new_curve = Bezier::from_cubic_coordinates(p1.x, p1.y, c1.x, c1.y, c2.x, c2.y, p3.x, p3.y); + + // Sample 2*n points from new curve and get the L2 metric between all of points + let points = new_curve.compute_lookup_table(Some(2 * n), None).collect::>(); + + let dist = points1.iter().zip(points.iter()).map(|(p1, p2)| (p1.x - p2.x).powi(2) + (p1.y - p2.y).powi(2)).sum::(); + + dist / (2 * n) as f64 +} + +/// Calculates optimal handle lengths with adam optimization. +#[allow(clippy::too_many_arguments)] +pub fn find_two_param_best_approximate(p1: DVec2, p3: DVec2, d1: DVec2, d2: DVec2, min_len1: f64, min_len2: f64, farther_segment: Bezier, other_segment: Bezier) -> (DVec2, DVec2) { + let h = 1e-6; + let tol = 1e-6; + let max_iter = 200; + + let mut a = (5_f64).ln(); + let mut b = (5_f64).ln(); + + let mut m_a = 0.; + let mut v_a = 0.; + let mut m_b = 0.; + let mut v_b = 0.; + + let initial_alpha = 0.05; + let decay_rate: f64 = 0.99; + + let beta1 = 0.9; + let beta2 = 0.999; + let epsilon = 1e-8; + + let n = 20; + + let farther_segment = if farther_segment.start.distance(p1) >= f64::EPSILON { + farther_segment.reverse() + } else { + farther_segment + }; + + let other_segment = if other_segment.end.distance(p3) >= f64::EPSILON { other_segment.reverse() } else { other_segment }; + + // Now we sample points proportional to the lengths of the beziers + let l1 = farther_segment.length(None); + let l2 = other_segment.length(None); + let ratio = l1 / (l1 + l2); + let n_points1 = ((2 * n) as f64 * ratio).floor() as usize; + let mut points1 = farther_segment.compute_lookup_table(Some(n_points1), None).collect::>(); + let mut points2 = other_segment.compute_lookup_table(Some(n), None).collect::>(); + points1.append(&mut points2); + + let f = |a: f64, b: f64| -> f64 { log_optimization(a, b, p1, p3, d1, d2, &points1, n) }; + + for t in 1..=max_iter { + let dfa = (f(a + h, b) - f(a - h, b)) / (2. * h); + let dfb = (f(a, b + h) - f(a, b - h)) / (2. * h); + + m_a = beta1 * m_a + (1. - beta1) * dfa; + m_b = beta1 * m_b + (1. - beta1) * dfb; + + v_a = beta2 * v_a + (1. - beta2) * dfa * dfa; + v_b = beta2 * v_b + (1. - beta2) * dfb * dfb; + + let m_a_hat = m_a / (1. - beta1.powi(t)); + let v_a_hat = v_a / (1. - beta2.powi(t)); + let m_b_hat = m_b / (1. - beta1.powi(t)); + let v_b_hat = v_b / (1. - beta2.powi(t)); + + let alpha_t = initial_alpha * decay_rate.powi(t); + + // Update log-lengths + a -= alpha_t * m_a_hat / (v_a_hat.sqrt() + epsilon); + b -= alpha_t * m_b_hat / (v_b_hat.sqrt() + epsilon); + + // Convergence check + if dfa.abs() < tol && dfb.abs() < tol { + break; + } + } + + let len1 = a.exp().max(min_len1); + let len2 = b.exp().max(min_len2); + + (d1 * len1, d2 * len2) +} diff --git a/editor/src/messages/tool/mod.rs b/editor/src/messages/tool/mod.rs new file mode 100644 index 0000000000000000000000000000000000000000..ca03f01e8b7260cd275a6dfb5d0f203934bc927f --- /dev/null +++ b/editor/src/messages/tool/mod.rs @@ -0,0 +1,14 @@ +mod tool_message; +mod tool_message_handler; + +pub mod common_functionality; +pub mod tool_messages; +pub mod transform_layer; +pub mod utility_types; + +#[doc(inline)] +pub use tool_message::{ToolMessage, ToolMessageDiscriminant}; +#[doc(inline)] +pub use tool_message_handler::{ToolMessageData, ToolMessageHandler}; +#[doc(inline)] +pub use transform_layer::{TransformLayerMessage, TransformLayerMessageDiscriminant}; diff --git a/editor/src/messages/tool/tool_message.rs b/editor/src/messages/tool/tool_message.rs new file mode 100644 index 0000000000000000000000000000000000000000..c281149a4274422ad485d38198a52f4a5fd161d5 --- /dev/null +++ b/editor/src/messages/tool/tool_message.rs @@ -0,0 +1,97 @@ +use super::utility_types::ToolType; +use crate::messages::preferences::SelectionMode; +use crate::messages::prelude::*; +use graphene_std::raster::color::Color; + +#[impl_message(Message, Tool)] +#[derive(PartialEq, Clone, Debug, serde::Serialize, serde::Deserialize)] +pub enum ToolMessage { + // Sub-messages + #[child] + TransformLayer(TransformLayerMessage), + + #[child] + Select(SelectToolMessage), + #[child] + Artboard(ArtboardToolMessage), + #[child] + Navigate(NavigateToolMessage), + #[child] + Eyedropper(EyedropperToolMessage), + #[child] + Fill(FillToolMessage), + #[child] + Gradient(GradientToolMessage), + + #[child] + Path(PathToolMessage), + #[child] + Pen(PenToolMessage), + #[child] + Freehand(FreehandToolMessage), + #[child] + Spline(SplineToolMessage), + #[child] + Shape(ShapeToolMessage), + #[child] + Text(TextToolMessage), + + #[child] + Brush(BrushToolMessage), + // // #[child] + // Heal(HealToolMessage), + // // #[child] + // Clone(CloneToolMessage), + // // #[child] + // Patch(PatchToolMessage), + // // #[child] + // Relight(RelightToolMessage), + // // #[child] + // Detail(DetailToolMessage), + + // Messages + + // General tools + ActivateToolSelect, + ActivateToolArtboard, + ActivateToolNavigate, + ActivateToolEyedropper, + ActivateToolFill, + ActivateToolGradient, + // Vector tools + ActivateToolPath, + ActivateToolPen, + ActivateToolFreehand, + ActivateToolSpline, + ActivateToolShapeLine, + ActivateToolShapeRectangle, + ActivateToolShapeEllipse, + ActivateToolShape, + ActivateToolText, + // Raster tools + ActivateToolBrush, + + ActivateTool { + tool_type: ToolType, + }, + DeactivateTools, + InitTools, + PreUndo, + Redo, + RefreshToolOptions, + ResetColors, + SelectWorkingColor { + color: Color, + primary: bool, + }, + SelectRandomWorkingColor { + primary: bool, + }, + SwapColors, + Undo, + UpdateCursor, + UpdateHints, + UpdateSelectionMode { + selection_mode: SelectionMode, + }, +} diff --git a/editor/src/messages/tool/tool_message_handler.rs b/editor/src/messages/tool/tool_message_handler.rs new file mode 100644 index 0000000000000000000000000000000000000000..9413495488abe5107588c16cb584e220fa483939 --- /dev/null +++ b/editor/src/messages/tool/tool_message_handler.rs @@ -0,0 +1,357 @@ +use super::common_functionality::shape_editor::ShapeState; +use super::common_functionality::shapes::shape_utility::ShapeType::{self, Ellipse, Line, Rectangle}; +use super::utility_types::{ToolActionHandlerData, ToolFsmState, tool_message_to_tool_type}; +use crate::application::generate_uuid; +use crate::messages::layout::utility_types::widget_prelude::*; +use crate::messages::portfolio::document::overlays::utility_types::OverlayProvider; +use crate::messages::portfolio::utility_types::PersistentData; +use crate::messages::prelude::*; +use crate::messages::tool::utility_types::ToolType; +use crate::node_graph_executor::NodeGraphExecutor; +use graphene_std::raster::color::Color; + +const ARTBOARD_OVERLAY_PROVIDER: OverlayProvider = |context| DocumentMessage::DrawArtboardOverlays(context).into(); + +pub struct ToolMessageData<'a> { + pub document_id: DocumentId, + pub document: &'a mut DocumentMessageHandler, + pub input: &'a InputPreprocessorMessageHandler, + pub persistent_data: &'a PersistentData, + pub node_graph: &'a NodeGraphExecutor, + pub preferences: &'a PreferencesMessageHandler, +} + +#[derive(Debug, Default)] +pub struct ToolMessageHandler { + pub tool_state: ToolFsmState, + pub transform_layer_handler: TransformLayerMessageHandler, + pub shape_editor: ShapeState, + pub tool_is_active: bool, +} + +impl MessageHandler> for ToolMessageHandler { + fn process_message(&mut self, message: ToolMessage, responses: &mut VecDeque, data: ToolMessageData) { + let ToolMessageData { + document_id, + document, + input, + persistent_data, + node_graph, + preferences, + } = data; + let font_cache = &persistent_data.font_cache; + + match message { + // Messages + ToolMessage::TransformLayer(message) => self + .transform_layer_handler + .process_message(message, responses, (document, input, &self.tool_state.tool_data, &mut self.shape_editor)), + + ToolMessage::ActivateToolSelect => responses.add_front(ToolMessage::ActivateTool { tool_type: ToolType::Select }), + ToolMessage::ActivateToolArtboard => responses.add_front(ToolMessage::ActivateTool { tool_type: ToolType::Artboard }), + ToolMessage::ActivateToolNavigate => responses.add_front(ToolMessage::ActivateTool { tool_type: ToolType::Navigate }), + ToolMessage::ActivateToolEyedropper => responses.add_front(ToolMessage::ActivateTool { tool_type: ToolType::Eyedropper }), + ToolMessage::ActivateToolText => responses.add_front(ToolMessage::ActivateTool { tool_type: ToolType::Text }), + ToolMessage::ActivateToolFill => responses.add_front(ToolMessage::ActivateTool { tool_type: ToolType::Fill }), + ToolMessage::ActivateToolGradient => responses.add_front(ToolMessage::ActivateTool { tool_type: ToolType::Gradient }), + + ToolMessage::ActivateToolPath => responses.add_front(ToolMessage::ActivateTool { tool_type: ToolType::Path }), + ToolMessage::ActivateToolPen => responses.add_front(ToolMessage::ActivateTool { tool_type: ToolType::Pen }), + ToolMessage::ActivateToolFreehand => responses.add_front(ToolMessage::ActivateTool { tool_type: ToolType::Freehand }), + ToolMessage::ActivateToolSpline => responses.add_front(ToolMessage::ActivateTool { tool_type: ToolType::Spline }), + ToolMessage::ActivateToolShape => { + if self.tool_state.tool_data.active_shape_type.is_some() { + self.tool_state.tool_data.active_shape_type = None; + self.tool_state.tool_data.active_tool_type = ToolType::Shape; + } + responses.add_front(ToolMessage::ActivateTool { tool_type: ToolType::Shape }); + responses.add(ShapeToolMessage::SetShape(ShapeType::Polygon)); + responses.add(ShapeToolMessage::HideShapeTypeWidget(false)) + } + ToolMessage::ActivateToolBrush => responses.add_front(ToolMessage::ActivateTool { tool_type: ToolType::Brush }), + ToolMessage::ActivateToolShapeLine | ToolMessage::ActivateToolShapeRectangle | ToolMessage::ActivateToolShapeEllipse => { + let shape = match message { + ToolMessage::ActivateToolShapeLine => Line, + ToolMessage::ActivateToolShapeRectangle => Rectangle, + ToolMessage::ActivateToolShapeEllipse => Ellipse, + _ => unreachable!(), + }; + + self.tool_state.tool_data.active_shape_type = Some(shape.tool_type()); + responses.add_front(ToolMessage::ActivateTool { tool_type: ToolType::Shape }); + responses.add(ShapeToolMessage::HideShapeTypeWidget(true)); + responses.add(ShapeToolMessage::SetShape(shape)); + } + ToolMessage::ActivateTool { tool_type } => { + let tool_data = &mut self.tool_state.tool_data; + let old_tool = tool_data.active_tool_type.get_tool(); + let tool_type = tool_type.get_tool(); + + responses.add(ToolMessage::RefreshToolOptions); + tool_data.send_layout(responses, LayoutTarget::ToolShelf); + + // Do nothing if switching to the same tool + if self.tool_is_active && tool_type == old_tool { + return; + } + + if tool_type != ToolType::Shape { + tool_data.active_shape_type = None; + } + + self.tool_is_active = true; + + // Send the old and new tools a transition to their FSM Abort states + let mut send_abort_to_tool = |old_tool: ToolType, new_tool: ToolType, update_hints_and_cursor: bool| { + if let Some(tool) = tool_data.tools.get_mut(&new_tool) { + let mut data = ToolActionHandlerData { + document, + document_id, + global_tool_data: &self.tool_state.document_tool_data, + input, + font_cache, + shape_editor: &mut self.shape_editor, + node_graph, + preferences, + }; + + if let Some(tool_abort_message) = tool.event_to_message_map().tool_abort { + tool.process_message(tool_abort_message, responses, &mut data); + } + + if update_hints_and_cursor { + if self.transform_layer_handler.is_transforming() { + self.transform_layer_handler.hints(responses); + } else { + tool.process_message(ToolMessage::UpdateHints, responses, &mut data); + } + tool.process_message(ToolMessage::UpdateCursor, responses, &mut data); + } + } + + if matches!(old_tool, ToolType::Path | ToolType::Select) { + responses.add(TransformLayerMessage::CancelTransformOperation); + } + }; + + send_abort_to_tool(old_tool, tool_type, true); + send_abort_to_tool(old_tool, old_tool, false); + + // Unsubscribe old tool from the broadcaster + tool_data.tools.get(&tool_type).unwrap().deactivate(responses); + + // Store the new active tool + tool_data.active_tool_type = tool_type; + + // Subscribe new tool + tool_data.tools.get(&tool_type).unwrap().activate(responses); + + // Send the SelectionChanged message to the active tool, this will ensure the selection is updated + responses.add(BroadcastEvent::SelectionChanged); + + // Update the working colors for the active tool + responses.add(BroadcastEvent::WorkingColorChanged); + + // Send tool options to the frontend + responses.add(ToolMessage::RefreshToolOptions); + + // Notify the frontend about the new active tool to be displayed + tool_data.send_layout(responses, LayoutTarget::ToolShelf); + } + ToolMessage::DeactivateTools => { + let tool_data = &mut self.tool_state.tool_data; + tool_data.tools.get(&tool_data.active_tool_type).unwrap().deactivate(responses); + + // Unsubscribe the transform layer to selection change events + let message = Box::new(TransformLayerMessage::SelectionChanged.into()); + let on = BroadcastEvent::SelectionChanged; + responses.add(BroadcastMessage::UnsubscribeEvent { message, on }); + + responses.add(OverlaysMessage::RemoveProvider(ARTBOARD_OVERLAY_PROVIDER)); + + responses.add(FrontendMessage::UpdateInputHints { hint_data: Default::default() }); + responses.add(FrontendMessage::UpdateMouseCursor { cursor: Default::default() }); + + self.tool_is_active = false; + } + ToolMessage::InitTools => { + // Subscribe the transform layer to selection change events + responses.add(BroadcastMessage::SubscribeEvent { + on: BroadcastEvent::SelectionChanged, + send: Box::new(TransformLayerMessage::SelectionChanged.into()), + }); + + self.tool_is_active = true; + + let tool_data = &mut self.tool_state.tool_data; + let document_data = &self.tool_state.document_tool_data; + let active_tool = &tool_data.active_tool_type; + + // Subscribe tool to broadcast messages + tool_data.tools.get(active_tool).unwrap().activate(responses); + + // Register initial properties + tool_data.tools.get(active_tool).unwrap().send_layout(responses, LayoutTarget::ToolOptions); + + // Notify the frontend about the initial active tool + tool_data.send_layout(responses, LayoutTarget::ToolShelf); + + // Notify the frontend about the initial working colors + document_data.update_working_colors(responses); + + let mut data = ToolActionHandlerData { + document, + document_id, + global_tool_data: &self.tool_state.document_tool_data, + input, + font_cache, + shape_editor: &mut self.shape_editor, + node_graph, + preferences, + }; + + // Set initial hints and cursor + tool_data.active_tool_mut().process_message(ToolMessage::UpdateHints, responses, &mut data); + tool_data.active_tool_mut().process_message(ToolMessage::UpdateCursor, responses, &mut data); + + responses.add(OverlaysMessage::AddProvider(ARTBOARD_OVERLAY_PROVIDER)); + } + ToolMessage::PreUndo => { + let tool_data = &mut self.tool_state.tool_data; + if tool_data.active_tool_type != ToolType::Pen { + responses.add(BroadcastEvent::ToolAbort); + } + } + ToolMessage::Redo => { + let tool_data = &mut self.tool_state.tool_data; + if tool_data.active_tool_type == ToolType::Pen { + responses.add(PenToolMessage::Redo); + } + } + ToolMessage::RefreshToolOptions => { + let tool_data = &mut self.tool_state.tool_data; + tool_data.tools.get(&tool_data.active_tool_type).unwrap().send_layout(responses, LayoutTarget::ToolOptions); + } + ToolMessage::ResetColors => { + let document_data = &mut self.tool_state.document_tool_data; + + document_data.primary_color = Color::BLACK; + document_data.secondary_color = Color::WHITE; + + document_data.update_working_colors(responses); // TODO: Make this an event + } + ToolMessage::SelectRandomWorkingColor { primary } => { + // Select a random working color (RGBA) based on an UUID + let document_data = &mut self.tool_state.document_tool_data; + + let random_number = generate_uuid(); + let r = (random_number >> 16) as u8; + let g = (random_number >> 8) as u8; + let b = random_number as u8; + let random_color = Color::from_rgba8_srgb(r, g, b, 255); + + if primary { + document_data.primary_color = random_color; + } else { + document_data.secondary_color = random_color; + } + + document_data.update_working_colors(responses); // TODO: Make this an event + } + ToolMessage::SelectWorkingColor { color, primary } => { + let document_data = &mut self.tool_state.document_tool_data; + + if primary { + document_data.primary_color = color; + } else { + document_data.secondary_color = color; + } + + document_data.update_working_colors(responses); // TODO: Make this an event + } + ToolMessage::SwapColors => { + let document_data = &mut self.tool_state.document_tool_data; + + std::mem::swap(&mut document_data.primary_color, &mut document_data.secondary_color); + + document_data.update_working_colors(responses); // TODO: Make this an event + } + ToolMessage::Undo => { + let tool_data = &mut self.tool_state.tool_data; + if tool_data.active_tool_type == ToolType::Pen { + responses.add(PenToolMessage::Undo); + } + } + + // Sub-messages + tool_message => { + let tool_type = match &tool_message { + ToolMessage::UpdateCursor | ToolMessage::UpdateHints => self.tool_state.tool_data.active_tool_type, + tool_message => tool_message_to_tool_type(tool_message), + }; + let tool_data = &mut self.tool_state.tool_data; + + if let Some(tool) = tool_data.tools.get_mut(&tool_type) { + let graph_view_overlay_open = document.graph_view_overlay_open(); + + if tool_type == tool_data.active_tool_type { + let mut data = ToolActionHandlerData { + document, + document_id, + global_tool_data: &self.tool_state.document_tool_data, + input, + font_cache, + shape_editor: &mut self.shape_editor, + node_graph, + preferences, + }; + if matches!(tool_message, ToolMessage::UpdateHints) { + if graph_view_overlay_open { + // When graph view is open, forward the hint update to the node graph handler + responses.add(NodeGraphMessage::UpdateHints); + } else if self.transform_layer_handler.is_transforming() { + self.transform_layer_handler.hints(responses); + } else { + tool.process_message(ToolMessage::UpdateHints, responses, &mut data) + } + } else { + tool.process_message(tool_message, responses, &mut data); + } + } + } + } + } + } + + fn actions(&self) -> ActionList { + let mut list = actions!(ToolMessageDiscriminant; + ActivateToolSelect, + ActivateToolArtboard, + ActivateToolNavigate, + ActivateToolEyedropper, + ActivateToolFill, + ActivateToolGradient, + + ActivateToolPath, + ActivateToolPen, + ActivateToolFreehand, + ActivateToolSpline, + ActivateToolShapeLine, + ActivateToolShapeRectangle, + ActivateToolShapeEllipse, + ActivateToolShape, + ActivateToolText, + + ActivateToolBrush, + + SelectRandomWorkingColor, + ResetColors, + SwapColors, + Undo, + ); + list.extend(self.tool_state.tool_data.active_tool().actions()); + list.extend(self.transform_layer_handler.actions()); + + list + } +} diff --git a/editor/src/messages/tool/tool_messages/artboard_tool.rs b/editor/src/messages/tool/tool_messages/artboard_tool.rs new file mode 100644 index 0000000000000000000000000000000000000000..d72e28df51f8c246f4fce94976c8d6eaec18e660 --- /dev/null +++ b/editor/src/messages/tool/tool_messages/artboard_tool.rs @@ -0,0 +1,661 @@ +use super::tool_prelude::*; +use crate::messages::portfolio::document::graph_operation::utility_types::TransformIn; +use crate::messages::portfolio::document::overlays::utility_types::OverlayContext; +use crate::messages::portfolio::document::utility_types::document_metadata::LayerNodeIdentifier; +use crate::messages::tool::common_functionality::auto_panning::AutoPanning; +use crate::messages::tool::common_functionality::compass_rose::Axis; +use crate::messages::tool::common_functionality::resize::Resize; +use crate::messages::tool::common_functionality::snapping; +use crate::messages::tool::common_functionality::snapping::SnapCandidatePoint; +use crate::messages::tool::common_functionality::snapping::SnapData; +use crate::messages::tool::common_functionality::snapping::SnapManager; +use crate::messages::tool::common_functionality::transformation_cage::*; +use graph_craft::document::NodeId; +use graphene_std::renderer::Quad; + +#[derive(Default)] +pub struct ArtboardTool { + fsm_state: ArtboardToolFsmState, + data: ArtboardToolData, +} + +#[impl_message(Message, ToolMessage, Artboard)] +#[derive(PartialEq, Clone, Debug, serde::Serialize, serde::Deserialize, specta::Type)] +pub enum ArtboardToolMessage { + // Standard messages + Abort, + Overlays(OverlayContext), + + // Tool-specific messages + UpdateSelectedArtboard, + DeleteSelected, + NudgeSelected { delta_x: f64, delta_y: f64, resize: Key, resize_opposite_corner: Key }, + PointerDown, + PointerMove { constrain_axis_or_aspect: Key, center: Key }, + PointerOutsideViewport { constrain_axis_or_aspect: Key, center: Key }, + PointerUp, +} + +impl ToolMetadata for ArtboardTool { + fn icon_name(&self) -> String { + "GeneralArtboardTool".into() + } + fn tooltip(&self) -> String { + "Artboard Tool".into() + } + fn tool_type(&self) -> crate::messages::tool::utility_types::ToolType { + ToolType::Artboard + } +} + +impl<'a> MessageHandler> for ArtboardTool { + fn process_message(&mut self, message: ToolMessage, responses: &mut VecDeque, tool_data: &mut ToolActionHandlerData<'a>) { + self.fsm_state.process_event(message, &mut self.data, tool_data, &(), responses, false); + } + + fn actions(&self) -> ActionList { + let mut common = actions!(ArtboardToolMessageDiscriminant; + DeleteSelected, + NudgeSelected, + PointerMove, + ); + + let additional = match self.fsm_state { + ArtboardToolFsmState::Ready { .. } => actions!(ArtboardToolMessageDiscriminant; PointerDown), + _ => actions!(ArtboardToolMessageDiscriminant; PointerUp, Abort), + }; + common.extend(additional); + + common + } +} + +impl LayoutHolder for ArtboardTool { + fn layout(&self) -> Layout { + Layout::WidgetLayout(WidgetLayout::default()) + } +} + +impl ToolTransition for ArtboardTool { + fn event_to_message_map(&self) -> EventToMessageMap { + EventToMessageMap { + tool_abort: Some(ArtboardToolMessage::Abort.into()), + overlay_provider: Some(|overlay_context| ArtboardToolMessage::Overlays(overlay_context).into()), + ..Default::default() + } + } +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +enum ArtboardToolFsmState { + Ready { hovered: bool }, + Drawing, + ResizingBounds, + Dragging, +} + +impl Default for ArtboardToolFsmState { + fn default() -> Self { + Self::Ready { hovered: false } + } +} + +#[derive(Clone, Debug, Default)] +struct ArtboardToolData { + bounding_box_manager: Option, + selected_artboard: Option, + snap_manager: SnapManager, + cursor: MouseCursorIcon, + drag_start: DVec2, + drag_current: DVec2, + auto_panning: AutoPanning, + snap_candidates: Vec, + dragging_current_artboard_location: glam::IVec2, + draw: Resize, +} + +impl ArtboardToolData { + fn get_snap_candidates(&mut self, document: &DocumentMessageHandler, _input: &InputPreprocessorMessageHandler) { + self.snap_candidates.clear(); + + let Some(layer) = self.selected_artboard else { return }; + + if let Some(bounds) = document.metadata().bounding_box_with_transform(layer, document.metadata().transform_to_document(layer)) { + snapping::get_bbox_points(Quad::from_box(bounds), &mut self.snap_candidates, snapping::BBoxSnapValues::ARTBOARD, document); + } + } + + fn check_dragging_bounds(&mut self, cursor: DVec2) -> Option<(bool, bool, bool, bool)> { + let bounding_box = self.bounding_box_manager.as_mut()?; + let edges = bounding_box.check_selected_edges(cursor)?; + let (top, bottom, left, right) = edges; + let selected_edges = SelectedEdges::new(top, bottom, left, right, bounding_box.bounds); + bounding_box.opposite_pivot = selected_edges.calculate_pivot(); + bounding_box.selected_edges = Some(selected_edges); + + Some(edges) + } + + fn start_resizing(&mut self, _selected_edges: (bool, bool, bool, bool), _document: &DocumentMessageHandler, _input: &InputPreprocessorMessageHandler) { + if let Some(bounds) = &mut self.bounding_box_manager { + bounds.center_of_transformation = bounds.transform.transform_point2((bounds.bounds[0] + bounds.bounds[1]) / 2.); + self.dragging_current_artboard_location = bounds.bounds[0].round().as_ivec2(); + } + } + + fn hovered_artboard(document: &DocumentMessageHandler, input: &InputPreprocessorMessageHandler) -> Option { + document.click_xray(input).find(|&layer| document.network_interface.is_artboard(&layer.to_node(), &[])) + } + + fn select_artboard(&mut self, document: &DocumentMessageHandler, input: &InputPreprocessorMessageHandler, responses: &mut VecDeque) -> bool { + if let Some(intersection) = Self::hovered_artboard(document, input) { + self.selected_artboard = Some(intersection); + + if let Some(bounds) = document.metadata().bounding_box_document(intersection) { + let bounding_box_manager = self.bounding_box_manager.get_or_insert(BoundingBoxManager::default()); + bounding_box_manager.bounds = bounds; + bounding_box_manager.transform = document.metadata().document_to_viewport; + } + + responses.add_front(NodeGraphMessage::SelectedNodesSet { nodes: vec![intersection.to_node()] }); + + true + } else { + self.selected_artboard = None; + + responses.add(PropertiesPanelMessage::Clear); + + false + } + } + + fn resize_artboard(&mut self, responses: &mut VecDeque, document: &DocumentMessageHandler, input: &InputPreprocessorMessageHandler, from_center: bool, constrain_square: bool) { + let Some(bounds) = &self.bounding_box_manager else { + return; + }; + let Some(movement) = &bounds.selected_edges else { + return; + }; + if self.selected_artboard.unwrap() == LayerNodeIdentifier::ROOT_PARENT { + log::error!("Selected artboard cannot be ROOT_PARENT"); + return; + } + + let center = from_center.then_some(bounds.center_of_transformation); + let ignore = self.selected_artboard.map_or(Vec::new(), |layer| vec![layer]); + let snap = Some(SizeSnapData { + manager: &mut self.snap_manager, + points: &mut self.snap_candidates, + snap_data: SnapData::ignore(document, input, &ignore), + }); + let (min, size) = movement.new_size(input.mouse.position, bounds.transform, center, constrain_square, snap); + let max = min + size; + let position = min.min(max); + let size = (max - min).abs(); + + responses.add(GraphOperationMessage::ResizeArtboard { + layer: self.selected_artboard.unwrap(), + location: position.round().as_ivec2(), + dimensions: size.round().as_ivec2(), + }); + + let translation = position.round().as_ivec2() - self.dragging_current_artboard_location; + self.dragging_current_artboard_location = position.round().as_ivec2(); + for child in self.selected_artboard.unwrap().children(document.metadata()) { + let local_translation = document.metadata().downstream_transform_to_document(child).inverse().transform_vector2(-translation.as_dvec2()); + responses.add(GraphOperationMessage::TransformChange { + layer: child, + transform: DAffine2::from_translation(local_translation), + transform_in: TransformIn::Local, + skip_rerender: false, + }); + } + } +} + +impl Fsm for ArtboardToolFsmState { + type ToolData = ArtboardToolData; + type ToolOptions = (); + + fn transition(self, event: ToolMessage, tool_data: &mut Self::ToolData, tool_action_data: &mut ToolActionHandlerData, _tool_options: &(), responses: &mut VecDeque) -> Self { + let ToolActionHandlerData { document, input, .. } = tool_action_data; + + let hovered = ArtboardToolData::hovered_artboard(document, input).is_some(); + + let ToolMessage::Artboard(event) = event else { return self }; + match (self, event) { + (state, ArtboardToolMessage::Overlays(mut overlay_context)) => { + let display_transform_cage = overlay_context.visibility_settings.transform_cage(); + if display_transform_cage && state != ArtboardToolFsmState::Drawing { + if let Some(bounds) = tool_data.selected_artboard.and_then(|layer| document.metadata().bounding_box_document(layer)) { + let bounding_box_manager = tool_data.bounding_box_manager.get_or_insert(BoundingBoxManager::default()); + bounding_box_manager.bounds = bounds; + bounding_box_manager.transform = document.metadata().document_to_viewport; + + bounding_box_manager.render_overlays(&mut overlay_context, true); + } + } else { + tool_data.bounding_box_manager.take(); + } + + tool_data.snap_manager.draw_overlays(SnapData::new(document, input), &mut overlay_context); + + self + } + (ArtboardToolFsmState::Ready { .. }, ArtboardToolMessage::PointerDown) => { + let to_viewport = document.metadata().document_to_viewport; + let to_document = to_viewport.inverse(); + tool_data.drag_start = to_document.transform_point2(input.mouse.position); + tool_data.drag_current = to_document.transform_point2(input.mouse.position); + + let state = if let Some(selected_edges) = tool_data.check_dragging_bounds(input.mouse.position) { + tool_data.start_resizing(selected_edges, document, input); + tool_data.get_snap_candidates(document, input); + ArtboardToolFsmState::ResizingBounds + } else if tool_data.select_artboard(document, input, responses) { + tool_data.get_snap_candidates(document, input); + ArtboardToolFsmState::Dragging + } else { + tool_data.draw.start(document, input); + + ArtboardToolFsmState::Drawing + }; + responses.add(DocumentMessage::StartTransaction); + state + } + (ArtboardToolFsmState::ResizingBounds, ArtboardToolMessage::PointerMove { constrain_axis_or_aspect, center }) => { + let from_center = input.keyboard.get(center as usize); + let constrain_square = input.keyboard.get(constrain_axis_or_aspect as usize); + tool_data.resize_artboard(responses, document, input, from_center, constrain_square); + + // Auto-panning + let messages = [ + ArtboardToolMessage::PointerOutsideViewport { constrain_axis_or_aspect, center }.into(), + ArtboardToolMessage::PointerMove { constrain_axis_or_aspect, center }.into(), + ]; + tool_data.auto_panning.setup_by_mouse_position(input, &messages, responses); + + ArtboardToolFsmState::ResizingBounds + } + (ArtboardToolFsmState::Dragging, ArtboardToolMessage::PointerMove { constrain_axis_or_aspect, center }) => { + if let Some(bounds) = &mut tool_data.bounding_box_manager { + let axis_align = input.keyboard.get(constrain_axis_or_aspect as usize); + + let ignore = tool_data.selected_artboard.map_or(Vec::new(), |layer| vec![layer]); + let snap_data = SnapData::ignore(document, input, &ignore); + let document_to_viewport = document.metadata().document_to_viewport; + let [start, current] = [tool_data.drag_start, tool_data.drag_current].map(|point| document_to_viewport.transform_point2(point)); + let mouse_delta = snap_drag(start, current, axis_align, Axis::None, snap_data, &mut tool_data.snap_manager, &tool_data.snap_candidates); + + let size = bounds.bounds[1] - bounds.bounds[0]; + let position = bounds.bounds[0] + bounds.transform.inverse().transform_vector2(mouse_delta); + + if tool_data.selected_artboard.unwrap() == LayerNodeIdentifier::ROOT_PARENT { + log::error!("Selected artboard cannot be ROOT_PARENT"); + return ArtboardToolFsmState::Ready { hovered }; + } + responses.add(GraphOperationMessage::ResizeArtboard { + layer: tool_data.selected_artboard.unwrap(), + location: position.round().as_ivec2(), + dimensions: size.round().as_ivec2(), + }); + + // The second term is added to prevent the slow change in position due to rounding errors. + tool_data.drag_current += (document_to_viewport.inverse() * bounds.transform).transform_vector2(position.round() - bounds.bounds[0]); + + // Update bounds if another `PointerMove` message comes before `ResizeArtboard` is finished. + bounds.bounds[0] = position.round(); + bounds.bounds[1] = position.round() + size.round(); + + // Auto-panning + let messages = [ + ArtboardToolMessage::PointerOutsideViewport { constrain_axis_or_aspect, center }.into(), + ArtboardToolMessage::PointerMove { constrain_axis_or_aspect, center }.into(), + ]; + tool_data.auto_panning.setup_by_mouse_position(input, &messages, responses); + } + ArtboardToolFsmState::Dragging + } + (ArtboardToolFsmState::Drawing, ArtboardToolMessage::PointerMove { constrain_axis_or_aspect, center }) => { + let [start, end] = tool_data.draw.calculate_points_ignore_layer(document, input, center, constrain_axis_or_aspect, true); + let viewport_to_document = document.metadata().document_to_viewport.inverse(); + let [start, end] = [start, end].map(|point| viewport_to_document.transform_point2(point)); + if let Some(artboard) = tool_data.selected_artboard { + assert_ne!(artboard, LayerNodeIdentifier::ROOT_PARENT, "Selected artboard cannot be ROOT_PARENT"); + + responses.add(GraphOperationMessage::ResizeArtboard { + layer: artboard, + location: start.min(end).round().as_ivec2(), + dimensions: (start.round() - end.round()).abs().as_ivec2(), + }); + } else { + let id = NodeId::new(); + + tool_data.selected_artboard = Some(LayerNodeIdentifier::new_unchecked(id)); + + responses.add(GraphOperationMessage::NewArtboard { + id, + artboard: graphene_std::Artboard { + graphic_group: graphene_std::GraphicGroupTable::default(), + label: String::from("Artboard"), + location: start.min(end).round().as_ivec2(), + dimensions: (start.round() - end.round()).abs().as_ivec2(), + background: graphene_std::Color::WHITE, + clip: false, + }, + }) + } + + // Auto-panning + let messages = [ + ArtboardToolMessage::PointerOutsideViewport { constrain_axis_or_aspect, center }.into(), + ArtboardToolMessage::PointerMove { constrain_axis_or_aspect, center }.into(), + ]; + tool_data.auto_panning.setup_by_mouse_position(input, &messages, responses); + + ArtboardToolFsmState::Drawing + } + + (ArtboardToolFsmState::Ready { .. }, ArtboardToolMessage::PointerMove { .. }) => { + let mut cursor = tool_data + .bounding_box_manager + .as_ref() + .map_or(MouseCursorIcon::Default, |bounds| bounds.get_cursor(input, false, false, None)); + + if cursor == MouseCursorIcon::Default && !hovered { + tool_data.snap_manager.preview_draw(&SnapData::new(document, input), input.mouse.position); + responses.add(OverlaysMessage::Draw); + cursor = MouseCursorIcon::Crosshair; + } else { + tool_data.snap_manager.cleanup(responses); + } + + if tool_data.cursor != cursor { + tool_data.cursor = cursor; + responses.add(FrontendMessage::UpdateMouseCursor { cursor }); + } + + ArtboardToolFsmState::Ready { hovered } + } + (ArtboardToolFsmState::ResizingBounds, ArtboardToolMessage::PointerOutsideViewport { .. }) => { + // Auto-panning + let _ = tool_data.auto_panning.shift_viewport(input, responses); + + ArtboardToolFsmState::ResizingBounds + } + (ArtboardToolFsmState::Dragging, ArtboardToolMessage::PointerOutsideViewport { .. }) => { + // Auto-panning + tool_data.auto_panning.shift_viewport(input, responses); + + ArtboardToolFsmState::Dragging + } + (ArtboardToolFsmState::Drawing, ArtboardToolMessage::PointerOutsideViewport { .. }) => { + // Auto-panning + tool_data.auto_panning.shift_viewport(input, responses); + + ArtboardToolFsmState::Drawing + } + (state, ArtboardToolMessage::PointerOutsideViewport { constrain_axis_or_aspect, center }) => { + // Auto-panning + let messages = [ + ArtboardToolMessage::PointerOutsideViewport { constrain_axis_or_aspect, center }.into(), + ArtboardToolMessage::PointerMove { constrain_axis_or_aspect, center }.into(), + ]; + tool_data.auto_panning.stop(&messages, responses); + + state + } + (ArtboardToolFsmState::Drawing | ArtboardToolFsmState::ResizingBounds | ArtboardToolFsmState::Dragging, ArtboardToolMessage::PointerUp) => { + responses.add(DocumentMessage::EndTransaction); + + tool_data.snap_manager.cleanup(responses); + + if let Some(bounds) = &mut tool_data.bounding_box_manager { + bounds.original_transforms.clear(); + } + + responses.add(OverlaysMessage::Draw); + + ArtboardToolFsmState::Ready { hovered } + } + (_, ArtboardToolMessage::UpdateSelectedArtboard) => { + tool_data.selected_artboard = document + .network_interface + .selected_nodes() + .selected_layers(document.metadata()) + .find(|layer| document.network_interface.is_artboard(&layer.to_node(), &[])); + self + } + (_, ArtboardToolMessage::DeleteSelected) => { + tool_data.selected_artboard.take(); + responses.add(DocumentMessage::DeleteSelectedLayers); + + ArtboardToolFsmState::Ready { hovered } + } + ( + _, + ArtboardToolMessage::NudgeSelected { + delta_x, + delta_y, + resize, + resize_opposite_corner, + }, + ) => { + let Some(bounds) = &mut tool_data.bounding_box_manager else { + return ArtboardToolFsmState::Ready { hovered }; + }; + let Some(selected_artboard) = tool_data.selected_artboard else { + return ArtboardToolFsmState::Ready { hovered }; + }; + if selected_artboard == LayerNodeIdentifier::ROOT_PARENT { + log::error!("Selected artboard cannot be ROOT_PARENT"); + return ArtboardToolFsmState::Ready { hovered }; + } + + let resize = input.keyboard.key(resize); + let resize_opposite_corner = input.keyboard.key(resize_opposite_corner); + let [existing_top_left, existing_bottom_right] = bounds.bounds; + + // Nudge translation without resizing + if !resize { + let delta = DVec2::from_angle(-document.document_ptz.tilt()).rotate(DVec2::new(delta_x, delta_y)); + + responses.add(GraphOperationMessage::ResizeArtboard { + layer: selected_artboard, + location: DVec2::new(existing_top_left.x + delta.x, existing_top_left.y + delta.y).round().as_ivec2(), + dimensions: (existing_bottom_right - existing_top_left).round().as_ivec2(), + }); + + return ArtboardToolFsmState::Ready { hovered }; + } + + // Swap and negate coordinates as needed to match the resize direction that's closest to the current tilt angle + let tilt = (document.document_ptz.tilt() + std::f64::consts::TAU) % std::f64::consts::TAU; + let (delta_x, delta_y, opposite_x, opposite_y) = match ((tilt + std::f64::consts::FRAC_PI_4) / std::f64::consts::FRAC_PI_2).floor() as i32 % 4 { + 0 => (delta_x, delta_y, false, false), + 1 => (delta_y, -delta_x, false, true), + 2 => (-delta_x, -delta_y, true, true), + 3 => (-delta_y, delta_x, true, false), + _ => unreachable!(), + }; + + let size = existing_bottom_right - existing_top_left; + let enlargement = DVec2::new( + if resize_opposite_corner != opposite_x { -delta_x } else { delta_x }, + if resize_opposite_corner != opposite_y { -delta_y } else { delta_y }, + ); + let enlargement_factor = (enlargement + size) / size; + + let position = DVec2::new( + existing_top_left.x + if resize_opposite_corner != opposite_x { delta_x } else { 0. }, + existing_top_left.y + if resize_opposite_corner != opposite_y { delta_y } else { 0. }, + ); + let mut pivot = (existing_top_left * enlargement_factor - position) / (enlargement_factor - DVec2::ONE); + if !pivot.x.is_finite() { + pivot.x = 0.; + } + if !pivot.y.is_finite() { + pivot.y = 0.; + } + let scale = DAffine2::from_scale(enlargement_factor); + let pivot = DAffine2::from_translation(pivot); + let transformation = pivot * scale * pivot.inverse(); + let document_to_viewport = document.navigation_handler.calculate_offset_transform(input.viewport_bounds.center(), &document.document_ptz); + let to = document_to_viewport.inverse() * document.metadata().downstream_transform_to_viewport(selected_artboard); + let original_transform = document.metadata().upstream_transform(selected_artboard.to_node()); + let new = to.inverse() * transformation * to * original_transform; + + responses.add(GraphOperationMessage::ResizeArtboard { + layer: selected_artboard, + location: position.round().as_ivec2(), + dimensions: new.transform_vector2(existing_bottom_right - existing_top_left).round().as_ivec2(), + }); + + ArtboardToolFsmState::Ready { hovered } + } + (ArtboardToolFsmState::Dragging | ArtboardToolFsmState::Drawing | ArtboardToolFsmState::ResizingBounds, ArtboardToolMessage::Abort) => { + responses.add(DocumentMessage::AbortTransaction); + + tool_data.snap_manager.cleanup(responses); + responses.add(OverlaysMessage::Draw); + + ArtboardToolFsmState::Ready { hovered } + } + _ => self, + } + } + + fn update_hints(&self, responses: &mut VecDeque) { + let hint_data = match self { + ArtboardToolFsmState::Ready { .. } => HintData(vec![ + HintGroup(vec![HintInfo::mouse(MouseMotion::LmbDrag, "Draw Artboard")]), + HintGroup(vec![HintInfo::mouse(MouseMotion::LmbDrag, "Move Artboard")]), + HintGroup(vec![HintInfo::keys([Key::Backspace], "Delete Artboard")]), + ]), + ArtboardToolFsmState::Dragging => HintData(vec![ + HintGroup(vec![HintInfo::mouse(MouseMotion::Rmb, ""), HintInfo::keys([Key::Escape], "Cancel").prepend_slash()]), + HintGroup(vec![HintInfo::keys([Key::Shift], "Constrain to Axis")]), + ]), + ArtboardToolFsmState::Drawing => HintData(vec![ + HintGroup(vec![HintInfo::mouse(MouseMotion::Rmb, ""), HintInfo::keys([Key::Escape], "Cancel").prepend_slash()]), + HintGroup(vec![HintInfo::keys([Key::Shift], "Constrain Square"), HintInfo::keys([Key::Alt], "From Center")]), + ]), + ArtboardToolFsmState::ResizingBounds => HintData(vec![ + HintGroup(vec![HintInfo::mouse(MouseMotion::Rmb, ""), HintInfo::keys([Key::Escape], "Cancel").prepend_slash()]), + HintGroup(vec![HintInfo::keys([Key::Shift], "Preserve Aspect Ratio"), HintInfo::keys([Key::Alt], "From Center")]), + ]), + }; + + responses.add(FrontendMessage::UpdateInputHints { hint_data }); + } + + fn update_cursor(&self, responses: &mut VecDeque) { + if let Self::Ready { hovered: false } = self { + responses.add(FrontendMessage::UpdateMouseCursor { cursor: MouseCursorIcon::Crosshair }); + } else { + responses.add(FrontendMessage::UpdateMouseCursor { cursor: MouseCursorIcon::Default }); + } + } +} + +#[cfg(test)] +mod test_artboard { + pub use crate::test_utils::test_prelude::*; + + async fn get_artboards(editor: &mut EditorTestUtils) -> Vec { + let instrumented = match editor.eval_graph().await { + Ok(instrumented) => instrumented, + Err(e) => panic!("Failed to evaluate graph: {}", e), + }; + instrumented.grab_all_input::(&editor.runtime).collect() + } + + #[tokio::test] + async fn artboard_draw_simple() { + let mut editor = EditorTestUtils::create(); + editor.new_document().await; + editor.drag_tool(ToolType::Artboard, 10.1, 10.8, 19.9, 0.2, ModifierKeys::empty()).await; + + let artboards = get_artboards(&mut editor).await; + + assert_eq!(artboards.len(), 1); + assert_eq!(artboards[0].location, IVec2::new(10, 0)); + assert_eq!(artboards[0].dimensions, IVec2::new(10, 11)); + } + + #[tokio::test] + async fn artboard_draw_square() { + let mut editor = EditorTestUtils::create(); + editor.new_document().await; + editor.drag_tool(ToolType::Artboard, 10., 10., -10., 11., ModifierKeys::SHIFT).await; + + let artboards = get_artboards(&mut editor).await; + assert_eq!(artboards.len(), 1); + assert_eq!(artboards[0].location, IVec2::new(-10, 10)); + assert_eq!(artboards[0].dimensions, IVec2::new(20, 20)); + } + + #[tokio::test] + async fn artboard_draw_square_rotated() { + let mut editor = EditorTestUtils::create(); + editor.new_document().await; + editor + .handle_message(NavigationMessage::CanvasTiltSet { + // 45 degree rotation of content clockwise + angle_radians: f64::consts::FRAC_PI_4, + }) + .await; + // Viewport coordinates + editor.drag_tool(ToolType::Artboard, 0., 0., 0., 10., ModifierKeys::SHIFT).await; + + let artboards = get_artboards(&mut editor).await; + assert_eq!(artboards.len(), 1); + assert_eq!(artboards[0].location, IVec2::new(0, 0)); + let desired_size = DVec2::splat(f64::consts::FRAC_1_SQRT_2 * 10.); + assert_eq!(artboards[0].dimensions, desired_size.round().as_ivec2()); + } + + #[tokio::test] + async fn artboard_draw_center_square_rotated() { + let mut editor = EditorTestUtils::create(); + + editor.new_document().await; + editor + .handle_message(NavigationMessage::CanvasTiltSet { + // 45 degree rotation of content clockwise + angle_radians: f64::consts::FRAC_PI_4, + }) + .await; + // Viewport coordinates + editor.drag_tool(ToolType::Artboard, 0., 0., 0., 10., ModifierKeys::SHIFT | ModifierKeys::ALT).await; + + let artboards = get_artboards(&mut editor).await; + assert_eq!(artboards.len(), 1); + assert_eq!(artboards[0].location, DVec2::splat(f64::consts::FRAC_1_SQRT_2 * -10.).as_ivec2()); + let desired_size = DVec2::splat(f64::consts::FRAC_1_SQRT_2 * 20.); + assert_eq!(artboards[0].dimensions, desired_size.round().as_ivec2()); + } + + #[tokio::test] + async fn artboard_delete() { + let mut editor = EditorTestUtils::create(); + + editor.new_document().await; + editor.drag_tool(ToolType::Artboard, 10.1, 10.8, 19.9, 0.2, ModifierKeys::default()).await; + editor.press(Key::Delete, ModifierKeys::default()).await; + + let artboards = get_artboards(&mut editor).await; + assert_eq!(artboards.len(), 0); + } + + #[tokio::test] + async fn artboard_cancel() { + let mut editor = EditorTestUtils::create(); + + editor.new_document().await; + + editor.drag_tool_cancel_rmb(ToolType::Artboard).await; + let artboards = get_artboards(&mut editor).await; + assert_eq!(artboards.len(), 0); + } +} diff --git a/editor/src/messages/tool/tool_messages/brush_tool.rs b/editor/src/messages/tool/tool_messages/brush_tool.rs new file mode 100644 index 0000000000000000000000000000000000000000..b468603989f5771c8a776a2cecff6e8abfe0e9b4 --- /dev/null +++ b/editor/src/messages/tool/tool_messages/brush_tool.rs @@ -0,0 +1,460 @@ +use super::tool_prelude::*; +use crate::consts::DEFAULT_BRUSH_SIZE; +use crate::messages::portfolio::document::graph_operation::transform_utils::{get_current_normalized_pivot, get_current_transform}; +use crate::messages::portfolio::document::node_graph::document_node_definitions::resolve_document_node_type; +use crate::messages::portfolio::document::utility_types::document_metadata::LayerNodeIdentifier; +use crate::messages::portfolio::document::utility_types::network_interface::FlowType; +use crate::messages::tool::common_functionality::color_selector::{ToolColorOptions, ToolColorType}; +use graph_craft::document::NodeId; +use graph_craft::document::value::TaggedValue; +use graphene_std::Color; +use graphene_std::brush::brush_stroke::{BrushInputSample, BrushStroke, BrushStyle}; +use graphene_std::raster::BlendMode; + +const BRUSH_MAX_SIZE: f64 = 5000.; + +#[derive(PartialEq, Copy, Clone, Debug, serde::Serialize, serde::Deserialize, specta::Type)] +pub enum DrawMode { + Draw = 0, + Erase, + Restore, +} + +#[derive(Default)] +pub struct BrushTool { + fsm_state: BrushToolFsmState, + data: BrushToolData, + options: BrushOptions, +} + +pub struct BrushOptions { + legacy_warning_was_shown: bool, + diameter: f64, + hardness: f64, + flow: f64, + spacing: f64, + color: ToolColorOptions, + blend_mode: BlendMode, + draw_mode: DrawMode, +} + +impl Default for BrushOptions { + fn default() -> Self { + Self { + legacy_warning_was_shown: false, + diameter: DEFAULT_BRUSH_SIZE, + hardness: 0., + flow: 100., + spacing: 20., + color: ToolColorOptions::default(), + blend_mode: BlendMode::Normal, + draw_mode: DrawMode::Draw, + } + } +} + +#[impl_message(Message, ToolMessage, Brush)] +#[derive(PartialEq, Clone, Debug, serde::Serialize, serde::Deserialize, specta::Type)] +pub enum BrushToolMessage { + // Standard messages + Abort, + WorkingColorChanged, + + // Tool-specific messages + DragStart, + DragStop, + PointerMove, + UpdateOptions(BrushToolMessageOptionsUpdate), +} + +#[derive(PartialEq, Clone, Debug, serde::Serialize, serde::Deserialize, specta::Type)] +pub enum BrushToolMessageOptionsUpdate { + BlendMode(BlendMode), + ChangeDiameter(f64), + Color(Option), + ColorType(ToolColorType), + Diameter(f64), + DrawMode(DrawMode), + Flow(f64), + Hardness(f64), + Spacing(f64), + WorkingColors(Option, Option), + NoDisplayLegacyWarning, +} + +#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)] +enum BrushToolFsmState { + #[default] + Ready, + Drawing, +} + +impl ToolMetadata for BrushTool { + fn icon_name(&self) -> String { + "RasterBrushTool".into() + } + fn tooltip(&self) -> String { + "Brush Tool".into() + } + fn tool_type(&self) -> crate::messages::tool::utility_types::ToolType { + ToolType::Brush + } +} + +impl LayoutHolder for BrushTool { + fn layout(&self) -> Layout { + let mut widgets = vec![ + NumberInput::new(Some(self.options.diameter)) + .label("Diameter") + .min(1.) + .max(BRUSH_MAX_SIZE) /* Anything bigger would cause the application to be unresponsive and eventually die */ + .unit(" px") + .on_update(|number_input: &NumberInput| BrushToolMessage::UpdateOptions(BrushToolMessageOptionsUpdate::Diameter(number_input.value.unwrap())).into()) + .widget_holder(), + Separator::new(SeparatorType::Related).widget_holder(), + NumberInput::new(Some(self.options.hardness)) + .label("Hardness") + .min(0.) + .max(100.) + .mode_range() + .unit("%") + .on_update(|number_input: &NumberInput| BrushToolMessage::UpdateOptions(BrushToolMessageOptionsUpdate::Hardness(number_input.value.unwrap())).into()) + .widget_holder(), + Separator::new(SeparatorType::Related).widget_holder(), + NumberInput::new(Some(self.options.flow)) + .label("Flow") + .min(1.) + .max(100.) + .mode_range() + .unit("%") + .on_update(|number_input: &NumberInput| BrushToolMessage::UpdateOptions(BrushToolMessageOptionsUpdate::Flow(number_input.value.unwrap())).into()) + .widget_holder(), + Separator::new(SeparatorType::Related).widget_holder(), + NumberInput::new(Some(self.options.spacing)) + .label("Spacing") + .min(1.) + .max(100.) + .mode_range() + .unit("%") + .on_update(|number_input: &NumberInput| BrushToolMessage::UpdateOptions(BrushToolMessageOptionsUpdate::Spacing(number_input.value.unwrap())).into()) + .widget_holder(), + ]; + + widgets.push(Separator::new(SeparatorType::Unrelated).widget_holder()); + + let draw_mode_entries: Vec<_> = [DrawMode::Draw, DrawMode::Erase, DrawMode::Restore] + .into_iter() + .map(|draw_mode| RadioEntryData::new(format!("{draw_mode:?}")).on_update(move |_| BrushToolMessage::UpdateOptions(BrushToolMessageOptionsUpdate::DrawMode(draw_mode)).into())) + .collect(); + widgets.push(RadioInput::new(draw_mode_entries).selected_index(Some(self.options.draw_mode as u32)).widget_holder()); + + widgets.push(Separator::new(SeparatorType::Unrelated).widget_holder()); + + widgets.append(&mut self.options.color.create_widgets( + "Color", + false, + |_| BrushToolMessage::UpdateOptions(BrushToolMessageOptionsUpdate::Color(None)).into(), + |color_type: ToolColorType| WidgetCallback::new(move |_| BrushToolMessage::UpdateOptions(BrushToolMessageOptionsUpdate::ColorType(color_type.clone())).into()), + |color: &ColorInput| BrushToolMessage::UpdateOptions(BrushToolMessageOptionsUpdate::Color(color.value.as_solid().map(|color| color.to_linear_srgb()))).into(), + )); + + widgets.push(Separator::new(SeparatorType::Related).widget_holder()); + + let blend_mode_entries: Vec> = BlendMode::list() + .iter() + .map(|group| { + group + .iter() + .map(|blend_mode| { + MenuListEntry::new(format!("{blend_mode:?}")) + .label(blend_mode.to_string()) + .on_commit(|_| BrushToolMessage::UpdateOptions(BrushToolMessageOptionsUpdate::BlendMode(*blend_mode)).into()) + }) + .collect() + }) + .collect(); + widgets.push( + DropdownInput::new(blend_mode_entries) + .selected_index(self.options.blend_mode.index_in_list().map(|index| index as u32)) + .tooltip("The blend mode used with the background when performing a brush stroke. Only used in draw mode.") + .disabled(self.options.draw_mode != DrawMode::Draw) + .widget_holder(), + ); + + Layout::WidgetLayout(WidgetLayout::new(vec![LayoutGroup::Row { widgets }])) + } +} + +impl<'a> MessageHandler> for BrushTool { + fn process_message(&mut self, message: ToolMessage, responses: &mut VecDeque, tool_data: &mut ToolActionHandlerData<'a>) { + let ToolMessage::Brush(BrushToolMessage::UpdateOptions(action)) = message else { + self.fsm_state.process_event(message, &mut self.data, tool_data, &self.options, responses, true); + return; + }; + match action { + BrushToolMessageOptionsUpdate::BlendMode(blend_mode) => self.options.blend_mode = blend_mode, + BrushToolMessageOptionsUpdate::ChangeDiameter(change) => { + let needs_rounding = ((self.options.diameter + change.abs() / 2.) % change.abs() - change.abs() / 2.).abs() > 0.5; + if needs_rounding && change > 0. { + self.options.diameter = (self.options.diameter / change.abs()).ceil() * change.abs(); + } else if needs_rounding && change < 0. { + self.options.diameter = (self.options.diameter / change.abs()).floor() * change.abs(); + } else { + self.options.diameter = (self.options.diameter / change.abs()).round() * change.abs() + change; + } + self.options.diameter = self.options.diameter.max(1.); + self.send_layout(responses, LayoutTarget::ToolOptions); + } + BrushToolMessageOptionsUpdate::Diameter(diameter) => self.options.diameter = diameter, + BrushToolMessageOptionsUpdate::DrawMode(draw_mode) => self.options.draw_mode = draw_mode, + BrushToolMessageOptionsUpdate::Hardness(hardness) => self.options.hardness = hardness, + BrushToolMessageOptionsUpdate::Flow(flow) => self.options.flow = flow, + BrushToolMessageOptionsUpdate::Spacing(spacing) => self.options.spacing = spacing, + BrushToolMessageOptionsUpdate::Color(color) => { + self.options.color.custom_color = color; + self.options.color.color_type = ToolColorType::Custom; + } + BrushToolMessageOptionsUpdate::ColorType(color_type) => self.options.color.color_type = color_type, + BrushToolMessageOptionsUpdate::WorkingColors(primary, secondary) => { + self.options.color.primary_working_color = primary; + self.options.color.secondary_working_color = secondary; + } + BrushToolMessageOptionsUpdate::NoDisplayLegacyWarning => self.options.legacy_warning_was_shown = true, + } + + self.send_layout(responses, LayoutTarget::ToolOptions); + } + + fn actions(&self) -> ActionList { + match self.fsm_state { + BrushToolFsmState::Ready => actions!(BrushToolMessageDiscriminant; + DragStart, + DragStop, + UpdateOptions, + ), + BrushToolFsmState::Drawing => actions!(BrushToolMessageDiscriminant; + DragStop, + PointerMove, + Abort, + UpdateOptions, + ), + } + } +} + +impl ToolTransition for BrushTool { + fn event_to_message_map(&self) -> EventToMessageMap { + EventToMessageMap { + tool_abort: Some(BrushToolMessage::Abort.into()), + working_color_changed: Some(BrushToolMessage::WorkingColorChanged.into()), + ..Default::default() + } + } +} + +#[derive(Clone, Debug, Default)] +struct BrushToolData { + strokes: Vec, + layer: Option, + transform: DAffine2, +} + +impl BrushToolData { + fn load_existing_strokes(&mut self, document: &DocumentMessageHandler) -> Option { + self.transform = DAffine2::IDENTITY; + + if document.network_interface.selected_nodes().selected_layers(document.metadata()).count() != 1 { + return None; + } + let layer = document.network_interface.selected_nodes().selected_layers(document.metadata()).next()?; + + self.layer = Some(layer); + for node_id in document.network_interface.upstream_flow_back_from_nodes(vec![layer.to_node()], &[], FlowType::HorizontalFlow) { + let Some(node) = document.network_interface.document_network().nodes.get(&node_id) else { + continue; + }; + let Some(reference) = document.network_interface.reference(&node_id, &[]) else { + continue; + }; + + if *reference == Some("Brush".to_string()) && node_id != layer.to_node() { + let points_input = node.inputs.get(1)?; + let Some(TaggedValue::BrushStrokes(strokes)) = points_input.as_value() else { continue }; + self.strokes.clone_from(strokes); + + return Some(layer); + } + + if *reference == Some("Transform".to_string()) { + let upstream = document.metadata().upstream_transform(node_id); + let pivot = DAffine2::from_translation(upstream.transform_point2(get_current_normalized_pivot(&node.inputs))); + self.transform = pivot * get_current_transform(&node.inputs) * pivot.inverse() * self.transform; + } + } + + self.transform = DAffine2::IDENTITY; + None + } + + fn update_strokes(&self, responses: &mut VecDeque) { + let Some(layer) = self.layer else { return }; + let strokes = self.strokes.clone(); + responses.add(GraphOperationMessage::Brush { layer, strokes }); + } +} + +impl Fsm for BrushToolFsmState { + type ToolData = BrushToolData; + type ToolOptions = BrushOptions; + + fn transition(self, event: ToolMessage, tool_data: &mut Self::ToolData, tool_action_data: &mut ToolActionHandlerData, tool_options: &Self::ToolOptions, responses: &mut VecDeque) -> Self { + let ToolActionHandlerData { + document, global_tool_data, input, .. + } = tool_action_data; + + if !tool_options.legacy_warning_was_shown { + responses.add(DialogMessage::DisplayDialogError { + title: "Unsupported tool".into(), + description: " + The current Brush tool is a legacy feature with\n\ + significant quality and performance limitations.\n\ + It will be replaced soon by a new implementation.\n\ + " + .trim() + .into(), + }); + responses.add(BrushToolMessage::UpdateOptions(BrushToolMessageOptionsUpdate::NoDisplayLegacyWarning)); + } + + let ToolMessage::Brush(event) = event else { return self }; + match (self, event) { + (BrushToolFsmState::Ready, BrushToolMessage::DragStart) => { + responses.add(DocumentMessage::StartTransaction); + let loaded_layer = tool_data.load_existing_strokes(document); + + if let Some(layer) = loaded_layer { + let pos = document + .network_interface + .document_metadata() + .downstream_transform_to_viewport(layer) + .inverse() + .transform_point2(input.mouse.position); + let layer_position = tool_data.transform.inverse().transform_point2(pos); + let layer_document_scale = document.metadata().downstream_transform_to_viewport(layer) * tool_data.transform; + + // TODO: Also scale it based on the input image ('Background' input). + // TODO: Resizing the input image results in a different brush size from the chosen diameter. + let layer_scale = 0.0001_f64 // Safety against division by zero + .max((layer_document_scale.matrix2 * glam::DVec2::X).length()) + .max((layer_document_scale.matrix2 * glam::DVec2::Y).length()); + + // Start a new stroke with a single sample + let blend_mode = match tool_options.draw_mode { + DrawMode::Draw => tool_options.blend_mode, + DrawMode::Erase => BlendMode::Erase, + DrawMode::Restore => BlendMode::Restore, + }; + tool_data.strokes.push(BrushStroke { + trace: vec![BrushInputSample { position: layer_position }], + style: BrushStyle { + color: tool_options.color.active_color().unwrap_or_default(), + diameter: tool_options.diameter / layer_scale, + hardness: tool_options.hardness, + flow: tool_options.flow, + spacing: tool_options.spacing, + blend_mode, + }, + }); + + tool_data.update_strokes(responses); + BrushToolFsmState::Drawing + } + // Create the new layer, wait for the render output to return its transform, and then create the rest of the layer + else { + new_brush_layer(document, responses); + responses.add(NodeGraphMessage::RunDocumentGraph); + responses.add(Message::StartBuffer); + responses.add(BrushToolMessage::DragStart); + BrushToolFsmState::Ready + } + } + + (BrushToolFsmState::Drawing, BrushToolMessage::PointerMove) => { + if let Some(layer) = tool_data.layer { + if let Some(stroke) = tool_data.strokes.last_mut() { + let layer_position = document + .network_interface + .document_metadata() + .downstream_transform_to_viewport(layer) + .inverse() + .transform_point2(input.mouse.position); + let layer_position = tool_data.transform.inverse().transform_point2(layer_position); + + stroke.trace.push(BrushInputSample { position: layer_position }) + } + } + tool_data.update_strokes(responses); + + BrushToolFsmState::Drawing + } + + (BrushToolFsmState::Drawing, BrushToolMessage::DragStop) => { + if !tool_data.strokes.is_empty() { + responses.add(DocumentMessage::EndTransaction); + } else { + responses.add(DocumentMessage::AbortTransaction); + } + tool_data.strokes.clear(); + + BrushToolFsmState::Ready + } + (BrushToolFsmState::Drawing, BrushToolMessage::Abort) => { + responses.add(DocumentMessage::AbortTransaction); + tool_data.strokes.clear(); + + BrushToolFsmState::Ready + } + (_, BrushToolMessage::WorkingColorChanged) => { + responses.add(BrushToolMessage::UpdateOptions(BrushToolMessageOptionsUpdate::WorkingColors( + Some(global_tool_data.primary_color), + Some(global_tool_data.secondary_color), + ))); + self + } + _ => self, + } + } + + fn update_hints(&self, responses: &mut VecDeque) { + let hint_data = match self { + BrushToolFsmState::Ready => HintData(vec![ + HintGroup(vec![HintInfo::mouse(MouseMotion::LmbDrag, "Draw")]), + HintGroup(vec![HintInfo::multi_keys([[Key::BracketLeft], [Key::BracketRight]], "Shrink/Grow Brush")]), + ]), + BrushToolFsmState::Drawing => HintData(vec![HintGroup(vec![HintInfo::mouse(MouseMotion::Rmb, ""), HintInfo::keys([Key::Escape], "Cancel").prepend_slash()])]), + }; + + responses.add(FrontendMessage::UpdateInputHints { hint_data }); + } + + fn update_cursor(&self, responses: &mut VecDeque) { + responses.add(FrontendMessage::UpdateMouseCursor { cursor: MouseCursorIcon::Default }); + } +} + +fn new_brush_layer(document: &DocumentMessageHandler, responses: &mut VecDeque) -> LayerNodeIdentifier { + responses.add(DocumentMessage::DeselectAllLayers); + + let brush_node = resolve_document_node_type("Brush").expect("Brush node does not exist").default_node_template(); + + let id = NodeId::new(); + responses.add(GraphOperationMessage::NewCustomLayer { + id, + nodes: vec![(NodeId(0), brush_node)], + parent: document.new_layer_parent(true), + insert_index: 0, + }); + responses.add(NodeGraphMessage::SelectedNodesSet { nodes: vec![id] }); + + LayerNodeIdentifier::new_unchecked(id) +} diff --git a/editor/src/messages/tool/tool_messages/eyedropper_tool.rs b/editor/src/messages/tool/tool_messages/eyedropper_tool.rs new file mode 100644 index 0000000000000000000000000000000000000000..3b3f324972f56e255b8e3e0f36ca1886e3726575 --- /dev/null +++ b/editor/src/messages/tool/tool_messages/eyedropper_tool.rs @@ -0,0 +1,166 @@ +use super::tool_prelude::*; +use crate::messages::tool::utility_types::DocumentToolData; + +#[derive(Default)] +pub struct EyedropperTool { + fsm_state: EyedropperToolFsmState, + data: EyedropperToolData, +} + +#[impl_message(Message, ToolMessage, Eyedropper)] +#[derive(PartialEq, Eq, Clone, Debug, Hash, serde::Serialize, serde::Deserialize, specta::Type)] +pub enum EyedropperToolMessage { + // Standard messages + Abort, + + // Tool-specific messages + SamplePrimaryColorBegin, + SamplePrimaryColorEnd, + PointerMove, + SampleSecondaryColorBegin, + SampleSecondaryColorEnd, +} + +impl ToolMetadata for EyedropperTool { + fn icon_name(&self) -> String { + "GeneralEyedropperTool".into() + } + fn tooltip(&self) -> String { + "Eyedropper Tool".into() + } + fn tool_type(&self) -> crate::messages::tool::utility_types::ToolType { + ToolType::Eyedropper + } +} + +impl LayoutHolder for EyedropperTool { + fn layout(&self) -> Layout { + Layout::WidgetLayout(WidgetLayout::default()) + } +} + +impl<'a> MessageHandler> for EyedropperTool { + fn process_message(&mut self, message: ToolMessage, responses: &mut VecDeque, tool_data: &mut ToolActionHandlerData<'a>) { + self.fsm_state.process_event(message, &mut self.data, tool_data, &(), responses, true); + } + + advertise_actions!(EyedropperToolMessageDiscriminant; + SamplePrimaryColorBegin, + SamplePrimaryColorEnd, + SampleSecondaryColorBegin, + SampleSecondaryColorEnd, + PointerMove, + Abort, + ); +} + +impl ToolTransition for EyedropperTool { + fn event_to_message_map(&self) -> EventToMessageMap { + EventToMessageMap { + tool_abort: Some(EyedropperToolMessage::Abort.into()), + working_color_changed: Some(EyedropperToolMessage::PointerMove.into()), + ..Default::default() + } + } +} + +#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)] +enum EyedropperToolFsmState { + #[default] + Ready, + SamplingPrimary, + SamplingSecondary, +} + +#[derive(Clone, Debug, Default)] +struct EyedropperToolData {} + +impl Fsm for EyedropperToolFsmState { + type ToolData = EyedropperToolData; + type ToolOptions = (); + + fn transition(self, event: ToolMessage, _tool_data: &mut Self::ToolData, tool_action_data: &mut ToolActionHandlerData, _tool_options: &(), responses: &mut VecDeque) -> Self { + let ToolActionHandlerData { global_tool_data, input, .. } = tool_action_data; + + let ToolMessage::Eyedropper(event) = event else { return self }; + match (self, event) { + // Ready -> Sampling + (EyedropperToolFsmState::Ready, mouse_down) if matches!(mouse_down, EyedropperToolMessage::SamplePrimaryColorBegin | EyedropperToolMessage::SampleSecondaryColorBegin) => { + update_cursor_preview(responses, input, global_tool_data, None); + + if mouse_down == EyedropperToolMessage::SamplePrimaryColorBegin { + EyedropperToolFsmState::SamplingPrimary + } else { + EyedropperToolFsmState::SamplingSecondary + } + } + // Sampling -> Sampling + (EyedropperToolFsmState::SamplingPrimary | EyedropperToolFsmState::SamplingSecondary, EyedropperToolMessage::PointerMove) => { + if input.viewport_bounds.in_bounds(input.mouse.position) { + update_cursor_preview(responses, input, global_tool_data, None); + } else { + disable_cursor_preview(responses); + } + + self + } + // Sampling -> Ready + (EyedropperToolFsmState::SamplingPrimary, EyedropperToolMessage::SamplePrimaryColorEnd) | (EyedropperToolFsmState::SamplingSecondary, EyedropperToolMessage::SampleSecondaryColorEnd) => { + let set_color_choice = if self == EyedropperToolFsmState::SamplingPrimary { "Primary" } else { "Secondary" }.to_string(); + update_cursor_preview(responses, input, global_tool_data, Some(set_color_choice)); + disable_cursor_preview(responses); + + EyedropperToolFsmState::Ready + } + // Any -> Ready + (_, EyedropperToolMessage::Abort) => { + disable_cursor_preview(responses); + + EyedropperToolFsmState::Ready + } + // Ready -> Ready + _ => self, + } + } + + fn update_hints(&self, responses: &mut VecDeque) { + let hint_data = match self { + EyedropperToolFsmState::Ready => HintData(vec![HintGroup(vec![ + HintInfo::mouse(MouseMotion::Lmb, "Sample to Primary"), + HintInfo::keys_and_mouse([Key::Shift], MouseMotion::Lmb, "Sample to Secondary"), + ])]), + EyedropperToolFsmState::SamplingPrimary | EyedropperToolFsmState::SamplingSecondary => { + HintData(vec![HintGroup(vec![HintInfo::mouse(MouseMotion::Rmb, ""), HintInfo::keys([Key::Escape], "Cancel").prepend_slash()])]) + } + }; + + responses.add(FrontendMessage::UpdateInputHints { hint_data }); + } + + fn update_cursor(&self, responses: &mut VecDeque) { + let cursor = match *self { + EyedropperToolFsmState::Ready => MouseCursorIcon::Default, + EyedropperToolFsmState::SamplingPrimary | EyedropperToolFsmState::SamplingSecondary => MouseCursorIcon::None, + }; + + responses.add(FrontendMessage::UpdateMouseCursor { cursor }); + } +} + +fn disable_cursor_preview(responses: &mut VecDeque) { + responses.add(FrontendMessage::UpdateEyedropperSamplingState { + mouse_position: None, + primary_color: "".into(), + secondary_color: "".into(), + set_color_choice: None, + }); +} + +fn update_cursor_preview(responses: &mut VecDeque, input: &InputPreprocessorMessageHandler, global_tool_data: &DocumentToolData, set_color_choice: Option) { + responses.add(FrontendMessage::UpdateEyedropperSamplingState { + mouse_position: Some(input.mouse.position.into()), + primary_color: "#".to_string() + global_tool_data.primary_color.to_rgb_hex_srgb().as_str(), + secondary_color: "#".to_string() + global_tool_data.secondary_color.to_rgb_hex_srgb().as_str(), + set_color_choice, + }); +} diff --git a/editor/src/messages/tool/tool_messages/fill_tool.rs b/editor/src/messages/tool/tool_messages/fill_tool.rs new file mode 100644 index 0000000000000000000000000000000000000000..5aeb063d876c86aa040e0d06bcd0167bad1550a0 --- /dev/null +++ b/editor/src/messages/tool/tool_messages/fill_tool.rs @@ -0,0 +1,213 @@ +use super::tool_prelude::*; +use crate::messages::portfolio::document::overlays::utility_types::OverlayContext; +use crate::messages::tool::common_functionality::graph_modification_utils::NodeGraphLayer; +use graphene_std::vector::style::Fill; + +#[derive(Default)] +pub struct FillTool { + fsm_state: FillToolFsmState, +} + +#[impl_message(Message, ToolMessage, Fill)] +#[derive(PartialEq, Clone, Debug, Hash, serde::Serialize, serde::Deserialize, specta::Type)] +pub enum FillToolMessage { + // Standard messages + Abort, + WorkingColorChanged, + Overlays(OverlayContext), + + // Tool-specific messages + PointerMove, + PointerUp, + FillPrimaryColor, + FillSecondaryColor, +} + +impl ToolMetadata for FillTool { + fn icon_name(&self) -> String { + "GeneralFillTool".into() + } + fn tooltip(&self) -> String { + "Fill Tool".into() + } + fn tool_type(&self) -> crate::messages::tool::utility_types::ToolType { + ToolType::Fill + } +} + +impl LayoutHolder for FillTool { + fn layout(&self) -> Layout { + Layout::WidgetLayout(WidgetLayout::default()) + } +} + +impl<'a> MessageHandler> for FillTool { + fn process_message(&mut self, message: ToolMessage, responses: &mut VecDeque, tool_data: &mut ToolActionHandlerData<'a>) { + self.fsm_state.process_event(message, &mut (), tool_data, &(), responses, true); + } + fn actions(&self) -> ActionList { + match self.fsm_state { + FillToolFsmState::Ready => actions!(FillToolMessageDiscriminant; + FillPrimaryColor, + FillSecondaryColor, + PointerMove, + ), + FillToolFsmState::Filling => actions!(FillToolMessageDiscriminant; + PointerMove, + PointerUp, + Abort, + ), + } + } +} + +impl ToolTransition for FillTool { + fn event_to_message_map(&self) -> EventToMessageMap { + EventToMessageMap { + tool_abort: Some(FillToolMessage::Abort.into()), + working_color_changed: Some(FillToolMessage::WorkingColorChanged.into()), + overlay_provider: Some(|overlay_context| FillToolMessage::Overlays(overlay_context).into()), + ..Default::default() + } + } +} + +#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)] +enum FillToolFsmState { + #[default] + Ready, + // Implemented as a fake dragging state that can be used to abort unwanted fills + Filling, +} + +impl Fsm for FillToolFsmState { + type ToolData = (); + type ToolOptions = (); + + fn transition(self, event: ToolMessage, _tool_data: &mut Self::ToolData, handler_data: &mut ToolActionHandlerData, _tool_options: &Self::ToolOptions, responses: &mut VecDeque) -> Self { + let ToolActionHandlerData { + document, global_tool_data, input, .. + } = handler_data; + + let ToolMessage::Fill(event) = event else { return self }; + match (self, event) { + (_, FillToolMessage::Overlays(mut overlay_context)) => { + // Choose the working color to preview + let use_secondary = input.keyboard.get(Key::Shift as usize); + let preview_color = if use_secondary { global_tool_data.secondary_color } else { global_tool_data.primary_color }; + + // Get the layer the user is hovering over + if let Some(layer) = document.click(input) { + overlay_context.fill_path_pattern(document.metadata().layer_outline(layer), document.metadata().transform_to_viewport(layer), &preview_color); + } + + self + } + (_, FillToolMessage::PointerMove | FillToolMessage::WorkingColorChanged) => { + // Generate the hover outline + responses.add(OverlaysMessage::Draw); + self + } + (FillToolFsmState::Ready, color_event) => { + let Some(layer_identifier) = document.click(input) else { + return self; + }; + // If the layer is a raster layer, don't fill it, wait till the flood fill tool is implemented + if NodeGraphLayer::is_raster_layer(layer_identifier, &mut document.network_interface) { + return self; + } + let fill = match color_event { + FillToolMessage::FillPrimaryColor => Fill::Solid(global_tool_data.primary_color.to_gamma_srgb()), + FillToolMessage::FillSecondaryColor => Fill::Solid(global_tool_data.secondary_color.to_gamma_srgb()), + _ => return self, + }; + + responses.add(DocumentMessage::AddTransaction); + responses.add(GraphOperationMessage::FillSet { layer: layer_identifier, fill }); + + FillToolFsmState::Filling + } + (FillToolFsmState::Filling, FillToolMessage::PointerUp) => FillToolFsmState::Ready, + (FillToolFsmState::Filling, FillToolMessage::Abort) => { + responses.add(DocumentMessage::AbortTransaction); + + FillToolFsmState::Ready + } + _ => self, + } + } + + fn update_hints(&self, responses: &mut VecDeque) { + let hint_data = match self { + FillToolFsmState::Ready => HintData(vec![HintGroup(vec![ + HintInfo::mouse(MouseMotion::Lmb, "Fill with Primary"), + HintInfo::keys([Key::Shift], "Fill with Secondary").prepend_plus(), + ])]), + FillToolFsmState::Filling => HintData(vec![HintGroup(vec![HintInfo::mouse(MouseMotion::Rmb, ""), HintInfo::keys([Key::Escape], "Cancel").prepend_slash()])]), + }; + + responses.add(FrontendMessage::UpdateInputHints { hint_data }); + } + + fn update_cursor(&self, responses: &mut VecDeque) { + responses.add(FrontendMessage::UpdateMouseCursor { cursor: MouseCursorIcon::Default }); + } +} + +#[cfg(test)] +mod test_fill { + pub use crate::test_utils::test_prelude::*; + use graphene_std::vector::fill; + use graphene_std::vector::style::Fill; + + async fn get_fills(editor: &mut EditorTestUtils) -> Vec { + let instrumented = match editor.eval_graph().await { + Ok(instrumented) => instrumented, + Err(e) => panic!("Failed to evaluate graph: {e}"), + }; + + instrumented.grab_all_input::>(&editor.runtime).collect() + } + + #[tokio::test] + async fn ignore_artboard() { + let mut editor = EditorTestUtils::create(); + editor.new_document().await; + editor.drag_tool(ToolType::Artboard, 0., 0., 100., 100., ModifierKeys::empty()).await; + editor.click_tool(ToolType::Fill, MouseKeys::LEFT, DVec2::new(2., 2.), ModifierKeys::empty()).await; + assert!(get_fills(&mut editor,).await.is_empty()); + } + + #[tokio::test] + async fn ignore_raster() { + let mut editor = EditorTestUtils::create(); + editor.new_document().await; + editor.create_raster_image(Image::new(100, 100, Color::WHITE), Some((0., 0.))).await; + editor.click_tool(ToolType::Fill, MouseKeys::LEFT, DVec2::new(2., 2.), ModifierKeys::empty()).await; + assert!(get_fills(&mut editor,).await.is_empty()); + } + + #[tokio::test] + async fn primary() { + let mut editor = EditorTestUtils::create(); + editor.new_document().await; + editor.drag_tool(ToolType::Rectangle, 0., 0., 100., 100., ModifierKeys::empty()).await; + editor.select_primary_color(Color::GREEN).await; + editor.click_tool(ToolType::Fill, MouseKeys::LEFT, DVec2::new(2., 2.), ModifierKeys::empty()).await; + let fills = get_fills(&mut editor).await; + assert_eq!(fills.len(), 1); + assert_eq!(fills[0].as_solid().unwrap().to_rgba8_srgb(), Color::GREEN.to_rgba8_srgb()); + } + + #[tokio::test] + async fn secondary() { + let mut editor = EditorTestUtils::create(); + editor.new_document().await; + editor.drag_tool(ToolType::Rectangle, 0., 0., 100., 100., ModifierKeys::empty()).await; + editor.select_secondary_color(Color::YELLOW).await; + editor.click_tool(ToolType::Fill, MouseKeys::LEFT, DVec2::new(2., 2.), ModifierKeys::SHIFT).await; + let fills = get_fills(&mut editor).await; + assert_eq!(fills.len(), 1); + assert_eq!(fills[0].as_solid().unwrap().to_rgba8_srgb(), Color::YELLOW.to_rgba8_srgb()); + } +} diff --git a/editor/src/messages/tool/tool_messages/freehand_tool.rs b/editor/src/messages/tool/tool_messages/freehand_tool.rs new file mode 100644 index 0000000000000000000000000000000000000000..e2abddef2a0dd5cba2127b52fa3e480b66854683 --- /dev/null +++ b/editor/src/messages/tool/tool_messages/freehand_tool.rs @@ -0,0 +1,722 @@ +use super::tool_prelude::*; +use crate::consts::DEFAULT_STROKE_WIDTH; +use crate::messages::portfolio::document::node_graph::document_node_definitions::resolve_document_node_type; +use crate::messages::portfolio::document::overlays::utility_functions::path_endpoint_overlays; +use crate::messages::portfolio::document::overlays::utility_types::OverlayContext; +use crate::messages::portfolio::document::utility_types::document_metadata::LayerNodeIdentifier; +use crate::messages::tool::common_functionality::color_selector::{ToolColorOptions, ToolColorType}; +use crate::messages::tool::common_functionality::graph_modification_utils; +use crate::messages::tool::common_functionality::utility_functions::should_extend; +use glam::DVec2; +use graph_craft::document::NodeId; +use graphene_std::Color; +use graphene_std::vector::VectorModificationType; +use graphene_std::vector::{PointId, SegmentId}; + +#[derive(Default)] +pub struct FreehandTool { + fsm_state: FreehandToolFsmState, + data: FreehandToolData, + options: FreehandOptions, +} + +pub struct FreehandOptions { + line_weight: f64, + fill: ToolColorOptions, + stroke: ToolColorOptions, +} + +impl Default for FreehandOptions { + fn default() -> Self { + Self { + line_weight: DEFAULT_STROKE_WIDTH, + fill: ToolColorOptions::new_none(), + stroke: ToolColorOptions::new_primary(), + } + } +} + +#[impl_message(Message, ToolMessage, Freehand)] +#[derive(PartialEq, Clone, Debug, serde::Serialize, serde::Deserialize, specta::Type)] +pub enum FreehandToolMessage { + // Standard messages + Overlays(OverlayContext), + Abort, + WorkingColorChanged, + + // Tool-specific messages + DragStart { append_to_selected: Key }, + DragStop, + PointerMove, + UpdateOptions(FreehandOptionsUpdate), +} + +#[derive(PartialEq, Clone, Debug, serde::Serialize, serde::Deserialize, specta::Type)] +pub enum FreehandOptionsUpdate { + FillColor(Option), + FillColorType(ToolColorType), + LineWeight(f64), + StrokeColor(Option), + StrokeColorType(ToolColorType), + WorkingColors(Option, Option), +} + +#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)] +enum FreehandToolFsmState { + #[default] + Ready, + Drawing, +} + +impl ToolMetadata for FreehandTool { + fn icon_name(&self) -> String { + "VectorFreehandTool".into() + } + fn tooltip(&self) -> String { + "Freehand Tool".into() + } + fn tool_type(&self) -> crate::messages::tool::utility_types::ToolType { + ToolType::Freehand + } +} + +fn create_weight_widget(line_weight: f64) -> WidgetHolder { + NumberInput::new(Some(line_weight)) + .unit(" px") + .label("Weight") + .min(1.) + .max((1_u64 << f64::MANTISSA_DIGITS) as f64) + .on_update(|number_input: &NumberInput| FreehandToolMessage::UpdateOptions(FreehandOptionsUpdate::LineWeight(number_input.value.unwrap())).into()) + .widget_holder() +} + +impl LayoutHolder for FreehandTool { + fn layout(&self) -> Layout { + let mut widgets = self.options.fill.create_widgets( + "Fill", + true, + |_| FreehandToolMessage::UpdateOptions(FreehandOptionsUpdate::FillColor(None)).into(), + |color_type: ToolColorType| WidgetCallback::new(move |_| FreehandToolMessage::UpdateOptions(FreehandOptionsUpdate::FillColorType(color_type.clone())).into()), + |color: &ColorInput| FreehandToolMessage::UpdateOptions(FreehandOptionsUpdate::FillColor(color.value.as_solid().map(|color| color.to_linear_srgb()))).into(), + ); + + widgets.push(Separator::new(SeparatorType::Unrelated).widget_holder()); + + widgets.append(&mut self.options.stroke.create_widgets( + "Stroke", + true, + |_| FreehandToolMessage::UpdateOptions(FreehandOptionsUpdate::StrokeColor(None)).into(), + |color_type: ToolColorType| WidgetCallback::new(move |_| FreehandToolMessage::UpdateOptions(FreehandOptionsUpdate::StrokeColorType(color_type.clone())).into()), + |color: &ColorInput| FreehandToolMessage::UpdateOptions(FreehandOptionsUpdate::StrokeColor(color.value.as_solid().map(|color| color.to_linear_srgb()))).into(), + )); + widgets.push(Separator::new(SeparatorType::Unrelated).widget_holder()); + widgets.push(create_weight_widget(self.options.line_weight)); + + Layout::WidgetLayout(WidgetLayout::new(vec![LayoutGroup::Row { widgets }])) + } +} + +impl<'a> MessageHandler> for FreehandTool { + fn process_message(&mut self, message: ToolMessage, responses: &mut VecDeque, tool_data: &mut ToolActionHandlerData<'a>) { + let ToolMessage::Freehand(FreehandToolMessage::UpdateOptions(action)) = message else { + self.fsm_state.process_event(message, &mut self.data, tool_data, &self.options, responses, true); + return; + }; + match action { + FreehandOptionsUpdate::FillColor(color) => { + self.options.fill.custom_color = color; + self.options.fill.color_type = ToolColorType::Custom; + } + FreehandOptionsUpdate::FillColorType(color_type) => self.options.fill.color_type = color_type, + FreehandOptionsUpdate::LineWeight(line_weight) => self.options.line_weight = line_weight, + FreehandOptionsUpdate::StrokeColor(color) => { + self.options.stroke.custom_color = color; + self.options.stroke.color_type = ToolColorType::Custom; + } + FreehandOptionsUpdate::StrokeColorType(color_type) => self.options.stroke.color_type = color_type, + FreehandOptionsUpdate::WorkingColors(primary, secondary) => { + self.options.stroke.primary_working_color = primary; + self.options.stroke.secondary_working_color = secondary; + self.options.fill.primary_working_color = primary; + self.options.fill.secondary_working_color = secondary; + } + } + + self.send_layout(responses, LayoutTarget::ToolOptions); + } + + fn actions(&self) -> ActionList { + match self.fsm_state { + FreehandToolFsmState::Ready => actions!(FreehandToolMessageDiscriminant; + DragStart, + DragStop, + ), + FreehandToolFsmState::Drawing => actions!(FreehandToolMessageDiscriminant; + DragStop, + PointerMove, + Abort, + ), + } + } +} + +impl ToolTransition for FreehandTool { + fn event_to_message_map(&self) -> EventToMessageMap { + EventToMessageMap { + overlay_provider: Some(|overlay_context: OverlayContext| FreehandToolMessage::Overlays(overlay_context).into()), + tool_abort: Some(FreehandToolMessage::Abort.into()), + working_color_changed: Some(FreehandToolMessage::WorkingColorChanged.into()), + ..Default::default() + } + } +} + +#[derive(Clone, Debug, Default)] +struct FreehandToolData { + end_point: Option<(DVec2, PointId)>, + dragged: bool, + weight: f64, + layer: Option, +} + +impl Fsm for FreehandToolFsmState { + type ToolData = FreehandToolData; + type ToolOptions = FreehandOptions; + + fn transition(self, event: ToolMessage, tool_data: &mut Self::ToolData, tool_action_data: &mut ToolActionHandlerData, tool_options: &Self::ToolOptions, responses: &mut VecDeque) -> Self { + let ToolActionHandlerData { + document, + global_tool_data, + input, + shape_editor, + preferences, + .. + } = tool_action_data; + + let ToolMessage::Freehand(event) = event else { return self }; + match (self, event) { + (_, FreehandToolMessage::Overlays(mut overlay_context)) => { + path_endpoint_overlays(document, shape_editor, &mut overlay_context, tool_action_data.preferences); + + self + } + (FreehandToolFsmState::Ready, FreehandToolMessage::DragStart { append_to_selected }) => { + responses.add(DocumentMessage::StartTransaction); + + tool_data.dragged = false; + tool_data.end_point = None; + tool_data.weight = tool_options.line_weight; + + // Extend an endpoint of the selected path + let selected_nodes = document.network_interface.selected_nodes(); + let tolerance = crate::consts::SNAP_POINT_TOLERANCE; + if let Some((layer, point, position)) = should_extend(document, input.mouse.position, tolerance, selected_nodes.selected_layers(document.metadata()), preferences) { + tool_data.layer = Some(layer); + tool_data.end_point = Some((position, point)); + + extend_path_with_next_segment(tool_data, position, true, responses); + + return FreehandToolFsmState::Drawing; + } + + if input.keyboard.key(append_to_selected) { + let mut selected_layers_except_artboards = selected_nodes.selected_layers_except_artboards(&document.network_interface); + let existing_layer = selected_layers_except_artboards.next().filter(|_| selected_layers_except_artboards.next().is_none()); + if let Some(layer) = existing_layer { + tool_data.layer = Some(layer); + + let transform = document.metadata().transform_to_viewport(layer); + let position = transform.inverse().transform_point2(input.mouse.position); + + extend_path_with_next_segment(tool_data, position, false, responses); + + return FreehandToolFsmState::Drawing; + } + } + + responses.add(DocumentMessage::DeselectAllLayers); + + let parent = document.new_layer_bounding_artboard(input); + + let node_type = resolve_document_node_type("Path").expect("Path node does not exist"); + let node = node_type.default_node_template(); + let nodes = vec![(NodeId(0), node)]; + + let layer = graph_modification_utils::new_custom(NodeId::new(), nodes, parent, responses); + responses.add(Message::StartBuffer); + tool_options.fill.apply_fill(layer, responses); + tool_options.stroke.apply_stroke(tool_data.weight, layer, responses); + tool_data.layer = Some(layer); + + FreehandToolFsmState::Drawing + } + (FreehandToolFsmState::Drawing, FreehandToolMessage::PointerMove) => { + if let Some(layer) = tool_data.layer { + let transform = document.metadata().transform_to_viewport(layer); + let position = transform.inverse().transform_point2(input.mouse.position); + + extend_path_with_next_segment(tool_data, position, true, responses); + } + + FreehandToolFsmState::Drawing + } + (FreehandToolFsmState::Drawing, FreehandToolMessage::DragStop) => { + if tool_data.dragged { + responses.add(DocumentMessage::CommitTransaction); + } else { + responses.add(DocumentMessage::EndTransaction); + } + + tool_data.end_point = None; + tool_data.layer = None; + + FreehandToolFsmState::Ready + } + (FreehandToolFsmState::Drawing, FreehandToolMessage::Abort) => { + responses.add(DocumentMessage::AbortTransaction); + tool_data.layer = None; + tool_data.end_point = None; + + FreehandToolFsmState::Ready + } + (_, FreehandToolMessage::WorkingColorChanged) => { + responses.add(FreehandToolMessage::UpdateOptions(FreehandOptionsUpdate::WorkingColors( + Some(global_tool_data.primary_color), + Some(global_tool_data.secondary_color), + ))); + self + } + _ => self, + } + } + + fn update_hints(&self, responses: &mut VecDeque) { + let hint_data = match self { + FreehandToolFsmState::Ready => HintData(vec![HintGroup(vec![ + HintInfo::mouse(MouseMotion::LmbDrag, "Draw Polyline"), + // TODO: Only show this if a single layer is selected and it's of a valid type (e.g. a vector path but not raster or artboard) + HintInfo::keys([Key::Shift], "Append to Selected Layer").prepend_plus(), + ])]), + FreehandToolFsmState::Drawing => HintData(vec![HintGroup(vec![HintInfo::mouse(MouseMotion::Rmb, ""), HintInfo::keys([Key::Escape], "Cancel").prepend_slash()])]), + }; + + responses.add(FrontendMessage::UpdateInputHints { hint_data }); + } + + fn update_cursor(&self, responses: &mut VecDeque) { + responses.add(FrontendMessage::UpdateMouseCursor { cursor: MouseCursorIcon::Default }); + } +} + +fn extend_path_with_next_segment(tool_data: &mut FreehandToolData, position: DVec2, extend: bool, responses: &mut VecDeque) { + if !tool_data.end_point.is_none_or(|(last_pos, _)| position != last_pos) || !position.is_finite() { + return; + } + + let Some(layer) = tool_data.layer else { return }; + + let id = PointId::generate(); + responses.add(GraphOperationMessage::Vector { + layer, + modification_type: VectorModificationType::InsertPoint { id, position }, + }); + + if extend { + if let Some((_, previous_position)) = tool_data.end_point { + let next_id = SegmentId::generate(); + let points = [previous_position, id]; + + responses.add(GraphOperationMessage::Vector { + layer, + modification_type: VectorModificationType::InsertSegment { + id: next_id, + points, + handles: [None, None], + }, + }); + } + } + + tool_data.dragged = true; + tool_data.end_point = Some((position, id)); +} + +#[cfg(test)] +mod test_freehand { + use crate::messages::input_mapper::utility_types::input_mouse::{EditorMouseState, MouseKeys, ScrollDelta}; + use crate::messages::portfolio::document::graph_operation::utility_types::TransformIn; + use crate::messages::tool::common_functionality::graph_modification_utils::get_stroke_width; + use crate::messages::tool::tool_messages::freehand_tool::FreehandOptionsUpdate; + use crate::test_utils::test_prelude::*; + use glam::{DAffine2, DVec2}; + use graphene_std::vector::VectorData; + + async fn get_vector_data(editor: &mut EditorTestUtils) -> Vec<(VectorData, DAffine2)> { + let document = editor.active_document(); + let layers = document.metadata().all_layers(); + + layers + .filter_map(|layer| { + let vector_data = document.network_interface.compute_modified_vector(layer)?; + let transform = document.metadata().transform_to_viewport(layer); + Some((vector_data, transform)) + }) + .collect() + } + + fn verify_path_points(vector_data_list: &[(VectorData, DAffine2)], expected_captured_points: &[DVec2], tolerance: f64) -> Result<(), String> { + if vector_data_list.len() == 0 { + return Err("No vector data found after drawing".to_string()); + } + + let path_data = vector_data_list.iter().find(|(data, _)| data.point_domain.ids().len() > 0).ok_or("Could not find path data")?; + + let (vector_data, transform) = path_data; + let point_count = vector_data.point_domain.ids().len(); + let segment_count = vector_data.segment_domain.ids().len(); + + let actual_positions: Vec = vector_data + .point_domain + .ids() + .iter() + .filter_map(|&point_id| { + let position = vector_data.point_domain.position_from_id(point_id)?; + Some(transform.transform_point2(position)) + }) + .collect(); + + if segment_count != point_count - 1 { + return Err(format!("Expected segments to be one less than points, got {} segments for {} points", segment_count, point_count)); + } + + if point_count != expected_captured_points.len() { + return Err(format!("Expected {} points, got {}", expected_captured_points.len(), point_count)); + } + + for (i, (&expected, &actual)) in expected_captured_points.iter().zip(actual_positions.iter()).enumerate() { + let distance = (expected - actual).length(); + if distance >= tolerance { + return Err(format!("Point {} position mismatch: expected {:?}, got {:?} (distance: {})", i, expected, actual, distance)); + } + } + + Ok(()) + } + + #[tokio::test] + async fn test_freehand_transformed_artboard() { + let mut editor = EditorTestUtils::create(); + editor.new_document().await; + + editor.drag_tool(ToolType::Artboard, 0., 0., 500., 500., ModifierKeys::empty()).await; + + let metadata = editor.active_document().metadata(); + let artboard = metadata.all_layers().next().unwrap(); + + editor + .handle_message(GraphOperationMessage::TransformSet { + layer: artboard, + transform: DAffine2::from_scale_angle_translation(DVec2::new(1.5, 0.8), 0.3, DVec2::new(10., -5.)), + transform_in: TransformIn::Local, + skip_rerender: false, + }) + .await; + + editor.select_tool(ToolType::Freehand).await; + + let mouse_points = [DVec2::new(150., 100.), DVec2::new(200., 150.), DVec2::new(250., 130.), DVec2::new(300., 170.)]; + + // Expected points that will actually be captured by the tool + let expected_captured_points = &mouse_points[1..]; + editor.drag_path(&mouse_points, ModifierKeys::empty()).await; + + let vector_data_list = get_vector_data(&mut editor).await; + verify_path_points(&vector_data_list, expected_captured_points, 1.).expect("Path points verification failed"); + } + + #[tokio::test] + async fn test_extend_existing_path() { + let mut editor = EditorTestUtils::create(); + editor.new_document().await; + + let initial_points = [DVec2::new(100., 100.), DVec2::new(200., 200.), DVec2::new(300., 100.)]; + + editor.select_tool(ToolType::Freehand).await; + + let first_point = initial_points[0]; + editor.move_mouse(first_point.x, first_point.y, ModifierKeys::empty(), MouseKeys::empty()).await; + editor.left_mousedown(first_point.x, first_point.y, ModifierKeys::empty()).await; + + for &point in &initial_points[1..] { + editor.move_mouse(point.x, point.y, ModifierKeys::empty(), MouseKeys::LEFT).await; + } + + let last_initial_point = initial_points[initial_points.len() - 1]; + editor + .mouseup( + EditorMouseState { + editor_position: last_initial_point, + mouse_keys: MouseKeys::empty(), + scroll_delta: ScrollDelta::default(), + }, + ModifierKeys::empty(), + ) + .await; + + let initial_vector_data = get_vector_data(&mut editor).await; + assert!(!initial_vector_data.is_empty(), "No vector data found after initial drawing"); + + let (initial_data, transform) = &initial_vector_data[0]; + let initial_point_count = initial_data.point_domain.ids().len(); + let initial_segment_count = initial_data.segment_domain.ids().len(); + + assert!(initial_point_count >= 2, "Expected at least 2 points in initial path, found {}", initial_point_count); + assert_eq!( + initial_segment_count, + initial_point_count - 1, + "Expected {} segments in initial path, found {}", + initial_point_count - 1, + initial_segment_count + ); + + let extendable_points = initial_data.extendable_points(false).collect::>(); + assert!(!extendable_points.is_empty(), "No extendable points found in the path"); + + let endpoint_id = extendable_points[0]; + let endpoint_pos_option = initial_data.point_domain.position_from_id(endpoint_id); + assert!(endpoint_pos_option.is_some(), "Could not find position for endpoint"); + + let endpoint_pos = endpoint_pos_option.unwrap(); + let endpoint_viewport_pos = transform.transform_point2(endpoint_pos); + + assert!(endpoint_viewport_pos.is_finite(), "Endpoint position is not finite"); + + let extension_points = [DVec2::new(400., 200.), DVec2::new(500., 100.)]; + + let layer_node_id = { + let document = editor.active_document(); + let layer = document.metadata().all_layers().next().unwrap(); + layer.to_node() + }; + + editor.handle_message(NodeGraphMessage::SelectedNodesSet { nodes: vec![layer_node_id] }).await; + + editor.select_tool(ToolType::Freehand).await; + + editor.move_mouse(endpoint_viewport_pos.x, endpoint_viewport_pos.y, ModifierKeys::empty(), MouseKeys::empty()).await; + editor.left_mousedown(endpoint_viewport_pos.x, endpoint_viewport_pos.y, ModifierKeys::empty()).await; + + for &point in &extension_points { + editor.move_mouse(point.x, point.y, ModifierKeys::empty(), MouseKeys::LEFT).await; + } + + let last_extension_point = extension_points[extension_points.len() - 1]; + editor + .mouseup( + EditorMouseState { + editor_position: last_extension_point, + mouse_keys: MouseKeys::empty(), + scroll_delta: ScrollDelta::default(), + }, + ModifierKeys::empty(), + ) + .await; + + let extended_vector_data = get_vector_data(&mut editor).await; + assert!(!extended_vector_data.is_empty(), "No vector data found after extension"); + + let (extended_data, _) = &extended_vector_data[0]; + let extended_point_count = extended_data.point_domain.ids().len(); + let extended_segment_count = extended_data.segment_domain.ids().len(); + + assert!( + extended_point_count > initial_point_count, + "Expected more points after extension, initial: {}, after extension: {}", + initial_point_count, + extended_point_count + ); + + assert_eq!( + extended_segment_count, + extended_point_count - 1, + "Expected segments to be one less than points, points: {}, segments: {}", + extended_point_count, + extended_segment_count + ); + + let layer_count = { + let document = editor.active_document(); + document.metadata().all_layers().count() + }; + assert_eq!(layer_count, 1, "Expected only one layer after extending path"); + } + + #[tokio::test] + async fn test_append_to_selected_layer_with_shift() { + let mut editor = EditorTestUtils::create(); + editor.new_document().await; + + editor.select_tool(ToolType::Freehand).await; + + let initial_points = [DVec2::new(100., 100.), DVec2::new(200., 200.), DVec2::new(300., 100.)]; + + let first_point = initial_points[0]; + editor.move_mouse(first_point.x, first_point.y, ModifierKeys::empty(), MouseKeys::empty()).await; + editor.left_mousedown(first_point.x, first_point.y, ModifierKeys::empty()).await; + + for &point in &initial_points[1..] { + editor.move_mouse(point.x, point.y, ModifierKeys::empty(), MouseKeys::LEFT).await; + } + + let last_initial_point = initial_points[initial_points.len() - 1]; + editor + .mouseup( + EditorMouseState { + editor_position: last_initial_point, + mouse_keys: MouseKeys::empty(), + scroll_delta: ScrollDelta::default(), + }, + ModifierKeys::empty(), + ) + .await; + + let initial_vector_data = get_vector_data(&mut editor).await; + assert!(!initial_vector_data.is_empty(), "No vector data found after initial drawing"); + + let (initial_data, _) = &initial_vector_data[0]; + let initial_point_count = initial_data.point_domain.ids().len(); + let initial_segment_count = initial_data.segment_domain.ids().len(); + + let existing_layer_id = { + let document = editor.active_document(); + let layer = document.metadata().all_layers().next().unwrap(); + layer + }; + + editor + .handle_message(NodeGraphMessage::SelectedNodesSet { + nodes: vec![existing_layer_id.to_node()], + }) + .await; + + let second_path_points = [DVec2::new(400., 100.), DVec2::new(500., 200.), DVec2::new(600., 100.)]; + + let first_second_point = second_path_points[0]; + editor.move_mouse(first_second_point.x, first_second_point.y, ModifierKeys::SHIFT, MouseKeys::empty()).await; + + editor + .mousedown( + EditorMouseState { + editor_position: first_second_point, + mouse_keys: MouseKeys::LEFT, + scroll_delta: ScrollDelta::default(), + }, + ModifierKeys::SHIFT, + ) + .await; + + for &point in &second_path_points[1..] { + editor.move_mouse(point.x, point.y, ModifierKeys::SHIFT, MouseKeys::LEFT).await; + } + + let last_second_point = second_path_points[second_path_points.len() - 1]; + editor + .mouseup( + EditorMouseState { + editor_position: last_second_point, + mouse_keys: MouseKeys::empty(), + scroll_delta: ScrollDelta::default(), + }, + ModifierKeys::SHIFT, + ) + .await; + + let final_vector_data = get_vector_data(&mut editor).await; + assert!(!final_vector_data.is_empty(), "No vector data found after second drawing"); + + // Verify we still have only one layer + let layer_count = { + let document = editor.active_document(); + document.metadata().all_layers().count() + }; + assert_eq!(layer_count, 1, "Expected only one layer after drawing with Shift key"); + + let (final_data, _) = &final_vector_data[0]; + let final_point_count = final_data.point_domain.ids().len(); + let final_segment_count = final_data.segment_domain.ids().len(); + + assert!( + final_point_count > initial_point_count, + "Expected more points after appending to layer, initial: {}, after append: {}", + initial_point_count, + final_point_count + ); + + let expected_new_points = second_path_points.len(); + let expected_new_segments = expected_new_points - 1; + + assert_eq!( + final_point_count, + initial_point_count + expected_new_points, + "Expected {} total points after append", + initial_point_count + expected_new_points + ); + + assert_eq!( + final_segment_count, + initial_segment_count + expected_new_segments, + "Expected {} total segments after append", + initial_segment_count + expected_new_segments + ); + } + + #[tokio::test] + async fn test_line_weight_affects_stroke_width() { + let mut editor = EditorTestUtils::create(); + editor.new_document().await; + + editor.select_tool(ToolType::Freehand).await; + + let custom_line_weight = 5.; + editor + .handle_message(ToolMessage::Freehand(FreehandToolMessage::UpdateOptions(FreehandOptionsUpdate::LineWeight(custom_line_weight)))) + .await; + + let points = [DVec2::new(100., 100.), DVec2::new(200., 200.), DVec2::new(300., 100.)]; + + let first_point = points[0]; + editor.move_mouse(first_point.x, first_point.y, ModifierKeys::empty(), MouseKeys::empty()).await; + editor.left_mousedown(first_point.x, first_point.y, ModifierKeys::empty()).await; + + for &point in &points[1..] { + editor.move_mouse(point.x, point.y, ModifierKeys::empty(), MouseKeys::LEFT).await; + } + + let last_point = points[points.len() - 1]; + editor + .mouseup( + EditorMouseState { + editor_position: last_point, + mouse_keys: MouseKeys::empty(), + scroll_delta: ScrollDelta::default(), + }, + ModifierKeys::empty(), + ) + .await; + + let document = editor.active_document(); + let layer = document.metadata().all_layers().next().unwrap(); + + let stroke_width = get_stroke_width(layer, &document.network_interface); + + assert!(stroke_width.is_some(), "Stroke width should be available on the created path"); + + assert_eq!( + stroke_width.unwrap(), + custom_line_weight, + "Stroke width should match the custom line weight (expected {}, got {})", + custom_line_weight, + stroke_width.unwrap() + ); + } +} diff --git a/editor/src/messages/tool/tool_messages/gradient_tool.rs b/editor/src/messages/tool/tool_messages/gradient_tool.rs new file mode 100644 index 0000000000000000000000000000000000000000..030da8ec1d03b344d8273c25ce3a69e7cebff303 --- /dev/null +++ b/editor/src/messages/tool/tool_messages/gradient_tool.rs @@ -0,0 +1,911 @@ +use super::tool_prelude::*; +use crate::consts::{LINE_ROTATE_SNAP_ANGLE, MANIPULATOR_GROUP_MARKER_SIZE, SELECTION_THRESHOLD}; +use crate::messages::portfolio::document::overlays::utility_types::OverlayContext; +use crate::messages::portfolio::document::utility_types::document_metadata::LayerNodeIdentifier; +use crate::messages::tool::common_functionality::auto_panning::AutoPanning; +use crate::messages::tool::common_functionality::graph_modification_utils::{NodeGraphLayer, get_gradient}; +use crate::messages::tool::common_functionality::snapping::SnapManager; +use graphene_std::vector::style::{Fill, Gradient, GradientType}; + +#[derive(Default)] +pub struct GradientTool { + fsm_state: GradientToolFsmState, + data: GradientToolData, + options: GradientOptions, +} + +#[derive(Default)] +pub struct GradientOptions { + gradient_type: GradientType, +} + +#[impl_message(Message, ToolMessage, Gradient)] +#[derive(PartialEq, Clone, Debug, Hash, serde::Serialize, serde::Deserialize, specta::Type)] +pub enum GradientToolMessage { + // Standard messages + Abort, + Overlays(OverlayContext), + + // Tool-specific messages + DeleteStop, + InsertStop, + PointerDown, + PointerMove { constrain_axis: Key }, + PointerOutsideViewport { constrain_axis: Key }, + PointerUp, + UpdateOptions(GradientOptionsUpdate), +} + +#[derive(PartialEq, Eq, Clone, Debug, Hash, serde::Serialize, serde::Deserialize, specta::Type)] +pub enum GradientOptionsUpdate { + Type(GradientType), +} + +impl ToolMetadata for GradientTool { + fn icon_name(&self) -> String { + "GeneralGradientTool".into() + } + fn tooltip(&self) -> String { + "Gradient Tool".into() + } + fn tool_type(&self) -> crate::messages::tool::utility_types::ToolType { + ToolType::Gradient + } +} + +impl<'a> MessageHandler> for GradientTool { + fn process_message(&mut self, message: ToolMessage, responses: &mut VecDeque, tool_data: &mut ToolActionHandlerData<'a>) { + let ToolMessage::Gradient(GradientToolMessage::UpdateOptions(action)) = message else { + self.fsm_state.process_event(message, &mut self.data, tool_data, &self.options, responses, false); + return; + }; + match action { + GradientOptionsUpdate::Type(gradient_type) => { + self.options.gradient_type = gradient_type; + // Update the selected gradient if it exists + if let Some(selected_gradient) = &mut self.data.selected_gradient { + // Check if the current layer is a raster layer + if let Some(layer) = selected_gradient.layer { + if NodeGraphLayer::is_raster_layer(layer, &mut tool_data.document.network_interface) { + return; // Don't proceed if it's a raster layer + } + selected_gradient.gradient.gradient_type = gradient_type; + selected_gradient.render_gradient(responses); + } + } + } + } + } + + advertise_actions!(GradientToolMessageDiscriminant; + PointerDown, + PointerUp, + PointerMove, + Abort, + InsertStop, + DeleteStop, + ); +} + +impl LayoutHolder for GradientTool { + fn layout(&self) -> Layout { + let gradient_type = RadioInput::new(vec![ + RadioEntryData::new("Linear") + .label("Linear") + .tooltip("Linear gradient") + .on_update(move |_| GradientToolMessage::UpdateOptions(GradientOptionsUpdate::Type(GradientType::Linear)).into()), + RadioEntryData::new("Radial") + .label("Radial") + .tooltip("Radial gradient") + .on_update(move |_| GradientToolMessage::UpdateOptions(GradientOptionsUpdate::Type(GradientType::Radial)).into()), + ]) + .selected_index(Some((self.selected_gradient().unwrap_or(self.options.gradient_type) == GradientType::Radial) as u32)) + .widget_holder(); + + Layout::WidgetLayout(WidgetLayout::new(vec![LayoutGroup::Row { widgets: vec![gradient_type] }])) + } +} + +#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)] +enum GradientToolFsmState { + #[default] + Ready, + Drawing, +} + +/// Computes the transform from gradient space to viewport space (where gradient space is 0..1) +fn gradient_space_transform(layer: LayerNodeIdentifier, document: &DocumentMessageHandler) -> DAffine2 { + let bounds = document.metadata().nonzero_bounding_box(layer); + let bound_transform = DAffine2::from_scale_angle_translation(bounds[1] - bounds[0], 0., bounds[0]); + + let multiplied = document.metadata().transform_to_viewport(layer); + + multiplied * bound_transform +} + +#[derive(PartialEq, Eq, Clone, Copy, Debug, Default)] +pub enum GradientDragTarget { + Start, + #[default] + End, + Step(usize), +} + +/// Contains information about the selected gradient handle +#[derive(Clone, Debug, Default)] +struct SelectedGradient { + layer: Option, + transform: DAffine2, + gradient: Gradient, + dragging: GradientDragTarget, +} + +impl SelectedGradient { + pub fn new(gradient: Gradient, layer: LayerNodeIdentifier, document: &DocumentMessageHandler) -> Self { + let transform = gradient_space_transform(layer, document); + Self { + layer: Some(layer), + transform, + gradient, + dragging: GradientDragTarget::End, + } + } + + pub fn with_gradient_start(mut self, start: DVec2) -> Self { + self.gradient.start = self.transform.inverse().transform_point2(start); + self + } + + pub fn update_gradient(&mut self, mut mouse: DVec2, responses: &mut VecDeque, snap_rotate: bool, gradient_type: GradientType) { + self.gradient.gradient_type = gradient_type; + + if snap_rotate && matches!(self.dragging, GradientDragTarget::End | GradientDragTarget::Start) { + let point = if self.dragging == GradientDragTarget::Start { + self.transform.transform_point2(self.gradient.end) + } else { + self.transform.transform_point2(self.gradient.start) + }; + + let delta = point - mouse; + + let length = delta.length(); + let mut angle = -delta.angle_to(DVec2::X); + + let snap_resolution = LINE_ROTATE_SNAP_ANGLE.to_radians(); + angle = (angle / snap_resolution).round() * snap_resolution; + + let rotated = DVec2::new(length * angle.cos(), length * angle.sin()); + mouse = point - rotated; + } + + let transformed_mouse = self.transform.inverse().transform_point2(mouse); + + match self.dragging { + GradientDragTarget::Start => self.gradient.start = transformed_mouse, + GradientDragTarget::End => self.gradient.end = transformed_mouse, + GradientDragTarget::Step(s) => { + let (start, end) = (self.transform.transform_point2(self.gradient.start), self.transform.transform_point2(self.gradient.end)); + + // Calculate the new position by finding the closest point on the line + let new_pos = ((end - start).angle_to(mouse - start)).cos() * start.distance(mouse) / start.distance(end); + + // Should not go off end but can swap + let clamped = new_pos.clamp(0., 1.); + self.gradient.stops.get_mut(s).unwrap().0 = clamped; + let new_pos = self.gradient.stops[s]; + + self.gradient.stops.sort(); + self.dragging = GradientDragTarget::Step(self.gradient.stops.iter().position(|x| *x == new_pos).unwrap()); + } + } + self.render_gradient(responses); + } + + /// Update the layer fill to the current gradient + pub fn render_gradient(&mut self, responses: &mut VecDeque) { + self.gradient.transform = self.transform; + if let Some(layer) = self.layer { + responses.add(GraphOperationMessage::FillSet { + layer, + fill: Fill::Gradient(self.gradient.clone()), + }); + } + } +} + +impl GradientTool { + /// Get the gradient type of the selected gradient (if it exists) + pub fn selected_gradient(&self) -> Option { + self.data.selected_gradient.as_ref().map(|selected| selected.gradient.gradient_type) + } +} + +impl ToolTransition for GradientTool { + fn event_to_message_map(&self) -> EventToMessageMap { + EventToMessageMap { + tool_abort: Some(GradientToolMessage::Abort.into()), + overlay_provider: Some(|overlay_context| GradientToolMessage::Overlays(overlay_context).into()), + ..Default::default() + } + } +} + +#[derive(Clone, Debug, Default)] +struct GradientToolData { + selected_gradient: Option, + snap_manager: SnapManager, + drag_start: DVec2, + auto_panning: AutoPanning, +} + +impl Fsm for GradientToolFsmState { + type ToolData = GradientToolData; + type ToolOptions = GradientOptions; + + fn transition(self, event: ToolMessage, tool_data: &mut Self::ToolData, tool_action_data: &mut ToolActionHandlerData, tool_options: &Self::ToolOptions, responses: &mut VecDeque) -> Self { + let ToolActionHandlerData { + document, global_tool_data, input, .. + } = tool_action_data; + + let ToolMessage::Gradient(event) = event else { return self }; + match (self, event) { + (_, GradientToolMessage::Overlays(mut overlay_context)) => { + let selected = tool_data.selected_gradient.as_ref(); + + for layer in document.network_interface.selected_nodes().selected_visible_layers(&document.network_interface) { + let Some(gradient) = get_gradient(layer, &document.network_interface) else { continue }; + let transform = gradient_space_transform(layer, document); + let dragging = selected + .filter(|selected| selected.layer.is_some_and(|selected_layer| selected_layer == layer)) + .map(|selected| selected.dragging); + + let Gradient { start, end, stops, .. } = gradient; + let (start, end) = (transform.transform_point2(start), transform.transform_point2(end)); + + overlay_context.line(start, end, None, None); + overlay_context.manipulator_handle(start, dragging == Some(GradientDragTarget::Start), None); + overlay_context.manipulator_handle(end, dragging == Some(GradientDragTarget::End), None); + + for (index, (position, _)) in stops.into_iter().enumerate() { + if position.abs() < f64::EPSILON * 1000. || (1. - position).abs() < f64::EPSILON * 1000. { + continue; + } + + overlay_context.manipulator_handle(start.lerp(end, position), dragging == Some(GradientDragTarget::Step(index)), None); + } + } + + self + } + (GradientToolFsmState::Ready, GradientToolMessage::DeleteStop) => { + let Some(selected_gradient) = &mut tool_data.selected_gradient else { + return self; + }; + + // Skip if invalid gradient + if selected_gradient.gradient.stops.len() < 2 { + return self; + } + + responses.add(DocumentMessage::AddTransaction); + + // Remove the selected point + match selected_gradient.dragging { + GradientDragTarget::Start => { + selected_gradient.gradient.stops.remove(0); + } + GradientDragTarget::End => { + let _ = selected_gradient.gradient.stops.pop(); + } + GradientDragTarget::Step(index) => { + selected_gradient.gradient.stops.remove(index); + } + }; + + // The gradient has only one point and so should become a fill + if selected_gradient.gradient.stops.len() == 1 { + if let Some(layer) = selected_gradient.layer { + responses.add(GraphOperationMessage::FillSet { + layer, + fill: Fill::Solid(selected_gradient.gradient.stops[0].1), + }); + } + return self; + } + + // Find the minimum and maximum positions + let min_position = selected_gradient.gradient.stops.iter().map(|(pos, _)| *pos).reduce(f64::min).expect("No min"); + let max_position = selected_gradient.gradient.stops.iter().map(|(pos, _)| *pos).reduce(f64::max).expect("No max"); + + // Recompute the start and end position of the gradient (in viewport transform) + let transform = selected_gradient.transform; + let (start, end) = (transform.transform_point2(selected_gradient.gradient.start), transform.transform_point2(selected_gradient.gradient.end)); + let (new_start, new_end) = (start.lerp(end, min_position), start.lerp(end, max_position)); + selected_gradient.gradient.start = transform.inverse().transform_point2(new_start); + selected_gradient.gradient.end = transform.inverse().transform_point2(new_end); + + // Remap the positions + for (position, _) in selected_gradient.gradient.stops.iter_mut() { + *position = (*position - min_position) / (max_position - min_position); + } + + // Render the new gradient + selected_gradient.render_gradient(responses); + + self + } + (_, GradientToolMessage::InsertStop) => { + for layer in document.network_interface.selected_nodes().selected_visible_layers(&document.network_interface) { + let Some(mut gradient) = get_gradient(layer, &document.network_interface) else { continue }; + // TODO: This transform is incorrect. I think this is since it is based on the Footprint which has not been updated yet + let transform = gradient_space_transform(layer, document); + let mouse = input.mouse.position; + let (start, end) = (transform.transform_point2(gradient.start), transform.transform_point2(gradient.end)); + + // Compute the distance from the mouse to the gradient line in viewport space + let distance = (end - start).angle_to(mouse - start).sin() * (mouse - start).length(); + + // If click is on the line then insert point + if distance < (SELECTION_THRESHOLD * 2.) { + // Try and insert the new stop + if let Some(index) = gradient.insert_stop(mouse, transform) { + responses.add(DocumentMessage::AddTransaction); + + let mut selected_gradient = SelectedGradient::new(gradient, layer, document); + + // Select the new point + selected_gradient.dragging = GradientDragTarget::Step(index); + + // Update the layer fill + selected_gradient.render_gradient(responses); + + tool_data.selected_gradient = Some(selected_gradient); + + break; + } + } + } + + self + } + (GradientToolFsmState::Ready, GradientToolMessage::PointerDown) => { + let mouse = input.mouse.position; + tool_data.drag_start = mouse; + let tolerance = (MANIPULATOR_GROUP_MARKER_SIZE * 2.).powi(2); + + let mut dragging = false; + for layer in document.network_interface.selected_nodes().selected_visible_layers(&document.network_interface) { + let Some(gradient) = get_gradient(layer, &document.network_interface) else { continue }; + let transform = gradient_space_transform(layer, document); + // Check for dragging step + for (index, (pos, _)) in gradient.stops.iter().enumerate() { + let pos = transform.transform_point2(gradient.start.lerp(gradient.end, *pos)); + if pos.distance_squared(mouse) < tolerance { + dragging = true; + tool_data.selected_gradient = Some(SelectedGradient { + layer: Some(layer), + transform, + gradient: gradient.clone(), + dragging: GradientDragTarget::Step(index), + }) + } + } + + // Check dragging start or end handle + for (pos, dragging_target) in [(gradient.start, GradientDragTarget::Start), (gradient.end, GradientDragTarget::End)] { + let pos = transform.transform_point2(pos); + if pos.distance_squared(mouse) < tolerance { + dragging = true; + tool_data.selected_gradient = Some(SelectedGradient { + layer: Some(layer), + transform, + gradient: gradient.clone(), + dragging: dragging_target, + }) + } + } + } + + let gradient_state = if dragging { + GradientToolFsmState::Drawing + } else { + let selected_layer = document.click(input); + + // Apply the gradient to the selected layer + if let Some(layer) = selected_layer { + // Add check for raster layer + if NodeGraphLayer::is_raster_layer(layer, &mut document.network_interface) { + return GradientToolFsmState::Ready; + } + if !document.network_interface.selected_nodes().selected_layers_contains(layer, document.metadata()) { + let nodes = vec![layer.to_node()]; + + responses.add(NodeGraphMessage::SelectedNodesSet { nodes }); + } + + // Use the already existing gradient if it exists + let gradient = if let Some(gradient) = get_gradient(layer, &document.network_interface) { + gradient.clone() + } else { + // Generate a new gradient + Gradient::new( + DVec2::ZERO, + global_tool_data.secondary_color, + DVec2::ONE, + global_tool_data.primary_color, + DAffine2::IDENTITY, + tool_options.gradient_type, + ) + }; + let selected_gradient = SelectedGradient::new(gradient, layer, document).with_gradient_start(input.mouse.position); + + tool_data.selected_gradient = Some(selected_gradient); + + GradientToolFsmState::Drawing + } else { + GradientToolFsmState::Ready + } + }; + responses.add(DocumentMessage::StartTransaction); + gradient_state + } + (GradientToolFsmState::Drawing, GradientToolMessage::PointerMove { constrain_axis }) => { + if let Some(selected_gradient) = &mut tool_data.selected_gradient { + let mouse = input.mouse.position; // tool_data.snap_manager.snap_position(responses, document, input.mouse.position); + selected_gradient.update_gradient(mouse, responses, input.keyboard.get(constrain_axis as usize), selected_gradient.gradient.gradient_type); + } + + // Auto-panning + let messages = [ + GradientToolMessage::PointerOutsideViewport { constrain_axis }.into(), + GradientToolMessage::PointerMove { constrain_axis }.into(), + ]; + tool_data.auto_panning.setup_by_mouse_position(input, &messages, responses); + + GradientToolFsmState::Drawing + } + (GradientToolFsmState::Drawing, GradientToolMessage::PointerOutsideViewport { .. }) => { + // Auto-panning + if let Some(shift) = tool_data.auto_panning.shift_viewport(input, responses) { + if let Some(selected_gradient) = &mut tool_data.selected_gradient { + selected_gradient.transform.translation += shift; + } + } + + GradientToolFsmState::Drawing + } + (state, GradientToolMessage::PointerOutsideViewport { constrain_axis }) => { + // Auto-panning + let messages = [ + GradientToolMessage::PointerOutsideViewport { constrain_axis }.into(), + GradientToolMessage::PointerMove { constrain_axis }.into(), + ]; + tool_data.auto_panning.stop(&messages, responses); + + state + } + (GradientToolFsmState::Drawing, GradientToolMessage::PointerUp) => { + input.mouse.finish_transaction(tool_data.drag_start, responses); + tool_data.snap_manager.cleanup(responses); + let was_dragging = tool_data.selected_gradient.is_some(); + + if !was_dragging { + if let Some(selected_layer) = document.click(input) { + if let Some(gradient) = get_gradient(selected_layer, &document.network_interface) { + tool_data.selected_gradient = Some(SelectedGradient::new(gradient, selected_layer, document)); + } + } + } + GradientToolFsmState::Ready + } + + (GradientToolFsmState::Drawing, GradientToolMessage::Abort) => { + responses.add(DocumentMessage::AbortTransaction); + tool_data.snap_manager.cleanup(responses); + responses.add(OverlaysMessage::Draw); + + GradientToolFsmState::Ready + } + (_, GradientToolMessage::Abort) => GradientToolFsmState::Ready, + _ => self, + } + } + + fn update_hints(&self, responses: &mut VecDeque) { + let hint_data = match self { + GradientToolFsmState::Ready => HintData(vec![HintGroup(vec![ + HintInfo::mouse(MouseMotion::LmbDrag, "Draw Gradient"), + HintInfo::keys([Key::Shift], "15° Increments").prepend_plus(), + ])]), + GradientToolFsmState::Drawing => HintData(vec![ + HintGroup(vec![HintInfo::mouse(MouseMotion::Rmb, ""), HintInfo::keys([Key::Escape], "Cancel").prepend_slash()]), + HintGroup(vec![HintInfo::keys([Key::Shift], "15° Increments")]), + ]), + }; + + responses.add(FrontendMessage::UpdateInputHints { hint_data }); + } + + fn update_cursor(&self, responses: &mut VecDeque) { + responses.add(FrontendMessage::UpdateMouseCursor { cursor: MouseCursorIcon::Default }); + } +} + +#[cfg(test)] +mod test_gradient { + use crate::messages::input_mapper::utility_types::input_mouse::EditorMouseState; + use crate::messages::input_mapper::utility_types::input_mouse::ScrollDelta; + use crate::messages::portfolio::document::graph_operation::utility_types::TransformIn; + use crate::messages::portfolio::document::utility_types::misc::GroupFolderType; + pub use crate::test_utils::test_prelude::*; + use glam::DAffine2; + use graphene_std::vector::fill; + use graphene_std::vector::style::Fill; + use graphene_std::vector::style::Gradient; + + use super::gradient_space_transform; + + async fn get_fills(editor: &mut EditorTestUtils) -> Vec<(Fill, DAffine2)> { + let instrumented = match editor.eval_graph().await { + Ok(instrumented) => instrumented, + Err(e) => panic!("Failed to evaluate graph: {}", e), + }; + + let document = editor.active_document(); + let layers = document.metadata().all_layers(); + layers + .filter_map(|layer| { + let fill = instrumented.grab_input_from_layer::>(layer, &document.network_interface, &editor.runtime)?; + let transform = gradient_space_transform(layer, document); + Some((fill, transform)) + }) + .collect() + } + + async fn get_gradient(editor: &mut EditorTestUtils) -> (Gradient, DAffine2) { + let fills = get_fills(editor).await; + assert_eq!(fills.len(), 1, "Expected 1 gradient fill, found {}", fills.len()); + + let (fill, transform) = fills.first().unwrap(); + let gradient = fill.as_gradient().expect("Expected gradient fill type"); + + (gradient.clone(), transform.clone()) + } + + fn assert_stops_at_positions(actual_positions: &[f64], expected_positions: &[f64], tolerance: f64) { + assert_eq!( + actual_positions.len(), + expected_positions.len(), + "Expected {} stops, found {}", + expected_positions.len(), + actual_positions.len() + ); + + for (i, (actual, expected)) in actual_positions.iter().zip(expected_positions.iter()).enumerate() { + assert!((actual - expected).abs() < tolerance, "Stop {}: Expected position near {}, got {}", i, expected, actual); + } + } + + #[tokio::test] + async fn ignore_artboard() { + let mut editor = EditorTestUtils::create(); + editor.new_document().await; + editor.drag_tool(ToolType::Artboard, 0., 0., 100., 100., ModifierKeys::empty()).await; + editor.drag_tool(ToolType::Gradient, 2., 2., 4., 4., ModifierKeys::empty()).await; + assert!(get_fills(&mut editor).await.is_empty()); + } + + #[tokio::test] + async fn ignore_raster() { + let mut editor = EditorTestUtils::create(); + editor.new_document().await; + editor.create_raster_image(Image::new(100, 100, Color::WHITE), Some((0., 0.))).await; + editor.drag_tool(ToolType::Gradient, 2., 2., 4., 4., ModifierKeys::empty()).await; + assert!(get_fills(&mut editor).await.is_empty()); + } + + #[tokio::test] + async fn simple_draw() { + let mut editor = EditorTestUtils::create(); + editor.new_document().await; + editor.drag_tool(ToolType::Rectangle, -5., -3., 100., 100., ModifierKeys::empty()).await; + editor.select_primary_color(Color::GREEN).await; + editor.select_secondary_color(Color::BLUE).await; + editor.drag_tool(ToolType::Gradient, 2., 3., 24., 4., ModifierKeys::empty()).await; + + let (gradient, transform) = get_gradient(&mut editor).await; + + // Gradient goes from secondary color to primary color + let stops = gradient.stops.iter().map(|stop| (stop.0, stop.1.to_rgba8_srgb())).collect::>(); + assert_eq!(stops, vec![(0., Color::BLUE.to_rgba8_srgb()), (1., Color::GREEN.to_rgba8_srgb())]); + assert!(transform.transform_point2(gradient.start).abs_diff_eq(DVec2::new(2., 3.), 1e-10)); + assert!(transform.transform_point2(gradient.end).abs_diff_eq(DVec2::new(24., 4.), 1e-10)); + } + + #[tokio::test] + async fn snap_simple_draw() { + let mut editor = EditorTestUtils::create(); + editor.new_document().await; + editor + .handle_message(NavigationMessage::CanvasTiltSet { + angle_radians: f64::consts::FRAC_PI_8, + }) + .await; + let start = DVec2::new(0., 0.); + let end = DVec2::new(24., 4.); + editor.drag_tool(ToolType::Rectangle, -5., -3., 100., 100., ModifierKeys::empty()).await; + editor.drag_tool(ToolType::Gradient, start.x, start.y, end.x, end.y, ModifierKeys::SHIFT).await; + + let (gradient, transform) = get_gradient(&mut editor).await; + + assert!(transform.transform_point2(gradient.start).abs_diff_eq(start, 1e-10)); + + // 15 degrees from horizontal + let angle = f64::to_radians(15.); + let direction = DVec2::new(angle.cos(), angle.sin()); + let expected = start + direction * (end - start).length(); + assert!(transform.transform_point2(gradient.end).abs_diff_eq(expected, 1e-10)); + } + + #[tokio::test] + async fn transformed_draw() { + let mut editor = EditorTestUtils::create(); + editor.new_document().await; + editor + .handle_message(NavigationMessage::CanvasTiltSet { + angle_radians: f64::consts::FRAC_PI_8, + }) + .await; + editor.drag_tool(ToolType::Rectangle, -5., -3., 100., 100., ModifierKeys::empty()).await; + + // Group rectangle + let group_folder_type = GroupFolderType::Layer; + editor.handle_message(DocumentMessage::GroupSelectedLayers { group_folder_type }).await; + let metadata = editor.active_document().metadata(); + let mut layers = metadata.all_layers(); + let folder = layers.next().unwrap(); + let rectangle = layers.next().unwrap(); + assert_eq!(rectangle.parent(metadata), Some(folder)); + // Transform the group + editor + .handle_message(GraphOperationMessage::TransformSet { + layer: folder, + transform: DAffine2::from_scale_angle_translation(DVec2::new(1., 2.), 0., -DVec2::X * 10.), + transform_in: TransformIn::Local, + skip_rerender: false, + }) + .await; + + editor.drag_tool(ToolType::Gradient, 2., 3., 24., 4., ModifierKeys::empty()).await; + + let (gradient, transform) = get_gradient(&mut editor).await; + + assert!(transform.transform_point2(gradient.start).abs_diff_eq(DVec2::new(2., 3.), 1e-10)); + assert!(transform.transform_point2(gradient.end).abs_diff_eq(DVec2::new(24., 4.), 1e-10)); + } + + #[tokio::test] + async fn double_click_insert_stop() { + let mut editor = EditorTestUtils::create(); + editor.new_document().await; + + editor.drag_tool(ToolType::Rectangle, -5., -3., 100., 100., ModifierKeys::empty()).await; + editor.select_primary_color(Color::GREEN).await; + editor.select_secondary_color(Color::BLUE).await; + editor.drag_tool(ToolType::Gradient, 0., 0., 100., 0., ModifierKeys::empty()).await; + + // Get initial gradient state (should have 2 stops) + let (initial_gradient, _) = get_gradient(&mut editor).await; + assert_eq!(initial_gradient.stops.len(), 2, "Expected 2 stops, found {}", initial_gradient.stops.len()); + + editor.select_tool(ToolType::Gradient).await; + editor.double_click(DVec2::new(50., 0.)).await; + + // Check that a new stop has been added + let (updated_gradient, _) = get_gradient(&mut editor).await; + assert_eq!(updated_gradient.stops.len(), 3, "Expected 3 stops, found {}", updated_gradient.stops.len()); + + let positions: Vec = updated_gradient.stops.iter().map(|(pos, _)| *pos).collect(); + assert!( + positions.iter().any(|pos| (pos - 0.5).abs() < 0.1), + "Expected to find a stop near position 0.5, but found: {:?}", + positions + ); + } + + #[tokio::test] + async fn dragging_endpoint_sets_correct_point() { + let mut editor = EditorTestUtils::create(); + editor.new_document().await; + + editor.handle_message(NavigationMessage::CanvasZoomSet { zoom_factor: 2. }).await; + + editor.drag_tool(ToolType::Rectangle, -5., -3., 100., 100., ModifierKeys::empty()).await; + + let document = editor.active_document(); + let selected_layer = document.network_interface.selected_nodes().selected_layers(document.metadata()).next().unwrap(); + editor + .handle_message(GraphOperationMessage::TransformSet { + layer: selected_layer, + transform: DAffine2::from_scale_angle_translation(DVec2::new(1.5, 0.8), 0.3, DVec2::new(10., -5.)), + transform_in: TransformIn::Local, + skip_rerender: false, + }) + .await; + + editor.select_primary_color(Color::GREEN).await; + editor.select_secondary_color(Color::BLUE).await; + + editor.drag_tool(ToolType::Gradient, 0., 0., 100., 0., ModifierKeys::empty()).await; + + // Get the initial gradient state + let (initial_gradient, transform) = get_gradient(&mut editor).await; + assert_eq!(initial_gradient.stops.len(), 2, "Expected 2 stops, found {}", initial_gradient.stops.len()); + + // Verify initial gradient endpoints in viewport space + let initial_start = transform.transform_point2(initial_gradient.start); + let initial_end = transform.transform_point2(initial_gradient.end); + assert!(initial_start.abs_diff_eq(DVec2::new(0., 0.), 1e-10)); + assert!(initial_end.abs_diff_eq(DVec2::new(100., 0.), 1e-10)); + + editor.select_tool(ToolType::Gradient).await; + + // Simulate dragging the end point to a new position (100, 50) + let start_pos = DVec2::new(100., 0.); + let end_pos = DVec2::new(100., 50.); + + editor.move_mouse(start_pos.x, start_pos.y, ModifierKeys::empty(), MouseKeys::empty()).await; + editor.left_mousedown(start_pos.x, start_pos.y, ModifierKeys::empty()).await; + editor.move_mouse(end_pos.x, end_pos.y, ModifierKeys::empty(), MouseKeys::LEFT).await; + editor + .mouseup( + EditorMouseState { + editor_position: end_pos, + mouse_keys: MouseKeys::empty(), + scroll_delta: ScrollDelta::default(), + }, + ModifierKeys::empty(), + ) + .await; + + // Check the updated gradient + let (updated_gradient, transform) = get_gradient(&mut editor).await; + + // Verify the start point hasn't changed + let updated_start = transform.transform_point2(updated_gradient.start); + assert!(updated_start.abs_diff_eq(DVec2::new(0., 0.), 1e-10)); + + // Verify the end point has been updated to the new position + let updated_end = transform.transform_point2(updated_gradient.end); + assert!(updated_end.abs_diff_eq(DVec2::new(100., 50.), 1e-10), "Expected end point at (100, 50), got {:?}", updated_end); + } + + #[tokio::test] + async fn dragging_stop_reorders_gradient() { + let mut editor = EditorTestUtils::create(); + editor.new_document().await; + + editor.drag_tool(ToolType::Rectangle, -5., -3., 100., 100., ModifierKeys::empty()).await; + editor.select_primary_color(Color::GREEN).await; + editor.select_secondary_color(Color::BLUE).await; + editor.drag_tool(ToolType::Gradient, 0., 0., 100., 0., ModifierKeys::empty()).await; + + editor.select_tool(ToolType::Gradient).await; + + // Add a middle stop at 50% + editor.double_click(DVec2::new(50., 0.)).await; + + let (initial_gradient, _) = get_gradient(&mut editor).await; + assert_eq!(initial_gradient.stops.len(), 3, "Expected 3 stops, found {}", initial_gradient.stops.len()); + + // Verify initial stop positions and colors + let mut stops = initial_gradient.stops.clone(); + stops.sort_by(|a, b| a.0.partial_cmp(&b.0).unwrap()); + + let positions: Vec = stops.iter().map(|(pos, _)| *pos).collect(); + assert_stops_at_positions(&positions, &[0., 0.5, 1.], 0.1); + + let middle_color = stops[1].1.to_rgba8_srgb(); + + // Simulate dragging the middle stop to position 0.8 + let click_position = DVec2::new(50., 0.); + editor + .mousedown( + EditorMouseState { + editor_position: click_position, + mouse_keys: MouseKeys::LEFT, + scroll_delta: ScrollDelta::default(), + }, + ModifierKeys::empty(), + ) + .await; + + let drag_position = DVec2::new(80., 0.); + editor.move_mouse(drag_position.x, drag_position.y, ModifierKeys::empty(), MouseKeys::LEFT).await; + + editor + .mouseup( + EditorMouseState { + editor_position: drag_position, + mouse_keys: MouseKeys::empty(), + scroll_delta: ScrollDelta::default(), + }, + ModifierKeys::empty(), + ) + .await; + + let (updated_gradient, _) = get_gradient(&mut editor).await; + assert_eq!(updated_gradient.stops.len(), 3, "Expected 3 stops after dragging, found {}", updated_gradient.stops.len()); + + // Verify updated stop positions and colors + let mut updated_stops = updated_gradient.stops.clone(); + updated_stops.sort_by(|a, b| a.0.partial_cmp(&b.0).unwrap()); + + // Check positions are now correctly ordered + let updated_positions: Vec = updated_stops.iter().map(|(pos, _)| *pos).collect(); + assert_stops_at_positions(&updated_positions, &[0., 0.8, 1.], 0.1); + + // Colors should maintain their associations with the stop points + assert_eq!(updated_stops[0].1.to_rgba8_srgb(), Color::BLUE.to_rgba8_srgb()); + assert_eq!(updated_stops[1].1.to_rgba8_srgb(), middle_color); + assert_eq!(updated_stops[2].1.to_rgba8_srgb(), Color::GREEN.to_rgba8_srgb()); + } + + #[tokio::test] + async fn select_and_delete_removes_stop() { + let mut editor = EditorTestUtils::create(); + editor.new_document().await; + + editor.drag_tool(ToolType::Rectangle, -5., -3., 100., 100., ModifierKeys::empty()).await; + editor.select_primary_color(Color::GREEN).await; + editor.select_secondary_color(Color::BLUE).await; + editor.drag_tool(ToolType::Gradient, 0., 0., 100., 0., ModifierKeys::empty()).await; + + // Get initial gradient state (should have 2 stops) + let (initial_gradient, _) = get_gradient(&mut editor).await; + assert_eq!(initial_gradient.stops.len(), 2, "Expected 2 stops, found {}", initial_gradient.stops.len()); + + editor.select_tool(ToolType::Gradient).await; + + // Add two middle stops + editor.double_click(DVec2::new(25., 0.)).await; + editor.double_click(DVec2::new(75., 0.)).await; + + let (updated_gradient, _) = get_gradient(&mut editor).await; + assert_eq!(updated_gradient.stops.len(), 4, "Expected 4 stops, found {}", updated_gradient.stops.len()); + + let positions: Vec = updated_gradient.stops.iter().map(|(pos, _)| *pos).collect(); + + // Use helper function to verify positions + assert_stops_at_positions(&positions, &[0., 0.25, 0.75, 1.], 0.05); + + // Select the stop at position 0.75 and delete it + let position2 = DVec2::new(75., 0.); + editor.move_mouse(position2.x, position2.y, ModifierKeys::empty(), MouseKeys::empty()).await; + editor.left_mousedown(position2.x, position2.y, ModifierKeys::empty()).await; + editor + .mouseup( + EditorMouseState { + editor_position: position2, + mouse_keys: MouseKeys::empty(), + scroll_delta: ScrollDelta::default(), + }, + ModifierKeys::empty(), + ) + .await; + + editor.press(Key::Delete, ModifierKeys::empty()).await; + + // Verify we now have 3 stops + let (final_gradient, _) = get_gradient(&mut editor).await; + assert_eq!(final_gradient.stops.len(), 3, "Expected 3 stops after deletion, found {}", final_gradient.stops.len()); + + let final_positions: Vec = final_gradient.stops.iter().map(|(pos, _)| *pos).collect(); + + // Verify final positions with helper function + assert_stops_at_positions(&final_positions, &[0., 0.25, 1.], 0.05); + + // Additional verification that 0.75 stop is gone + assert!(!final_positions.iter().any(|pos| (pos - 0.75).abs() < 0.05), "Stop at position 0.75 should have been deleted"); + } +} diff --git a/editor/src/messages/tool/tool_messages/mod.rs b/editor/src/messages/tool/tool_messages/mod.rs new file mode 100644 index 0000000000000000000000000000000000000000..b95d9c3938ad976efe87cf9d7e89864e1597c67f --- /dev/null +++ b/editor/src/messages/tool/tool_messages/mod.rs @@ -0,0 +1,23 @@ +pub mod artboard_tool; +pub mod brush_tool; +pub mod eyedropper_tool; +pub mod fill_tool; +pub mod freehand_tool; +pub mod gradient_tool; +pub mod navigate_tool; +pub mod path_tool; +pub mod pen_tool; +pub mod select_tool; +pub mod shape_tool; +pub mod spline_tool; +pub mod text_tool; + +pub mod tool_prelude { + pub use crate::messages::frontend::utility_types::MouseCursorIcon; + pub use crate::messages::input_mapper::utility_types::input_keyboard::{Key, MouseMotion}; + pub use crate::messages::layout::utility_types::widget_prelude::*; + pub use crate::messages::prelude::*; + pub use crate::messages::tool::utility_types::{EventToMessageMap, Fsm, ToolActionHandlerData, ToolMetadata, ToolTransition, ToolType}; + pub use crate::messages::tool::utility_types::{HintData, HintGroup, HintInfo}; + pub use glam::{DAffine2, DVec2}; +} diff --git a/editor/src/messages/tool/tool_messages/navigate_tool.rs b/editor/src/messages/tool/tool_messages/navigate_tool.rs new file mode 100644 index 0000000000000000000000000000000000000000..0a76a331dcdf87ab04165b65f3ca9a98936c8e15 --- /dev/null +++ b/editor/src/messages/tool/tool_messages/navigate_tool.rs @@ -0,0 +1,180 @@ +use super::tool_prelude::*; + +#[derive(Default)] +pub struct NavigateTool { + fsm_state: NavigateToolFsmState, + tool_data: NavigateToolData, +} + +#[impl_message(Message, ToolMessage, Navigate)] +#[derive(PartialEq, Eq, Clone, Debug, Hash, serde::Serialize, serde::Deserialize, specta::Type)] +pub enum NavigateToolMessage { + // Standard messages + Abort, + + // Tool-specific messages + PointerUp { zoom_in: bool }, + PointerMove { snap: Key }, + TiltCanvasBegin, + ZoomCanvasBegin, + End, +} + +impl ToolMetadata for NavigateTool { + fn icon_name(&self) -> String { + "GeneralNavigateTool".into() + } + fn tooltip(&self) -> String { + "Navigate Tool".into() + } + fn tool_type(&self) -> crate::messages::tool::utility_types::ToolType { + ToolType::Navigate + } +} + +impl LayoutHolder for NavigateTool { + fn layout(&self) -> Layout { + Layout::WidgetLayout(WidgetLayout::default()) + } +} + +impl<'a> MessageHandler> for NavigateTool { + fn process_message(&mut self, message: ToolMessage, responses: &mut VecDeque, tool_data: &mut ToolActionHandlerData<'a>) { + self.fsm_state.process_event(message, &mut self.tool_data, tool_data, &(), responses, true); + } + + fn actions(&self) -> ActionList { + match self.fsm_state { + NavigateToolFsmState::Ready => actions!(NavigateToolMessageDiscriminant; + TiltCanvasBegin, + ZoomCanvasBegin, + ), + NavigateToolFsmState::Tilting | NavigateToolFsmState::Zooming => actions!(NavigateToolMessageDiscriminant; + PointerMove, + ), + NavigateToolFsmState::ZoomOrClickZooming => actions!(NavigateToolMessageDiscriminant; + PointerUp, + PointerMove, + ), + } + } +} + +impl ToolTransition for NavigateTool { + fn event_to_message_map(&self) -> EventToMessageMap { + EventToMessageMap { + tool_abort: Some(NavigateToolMessage::Abort.into()), + ..Default::default() + } + } +} + +#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)] +enum NavigateToolFsmState { + #[default] + Ready, + Tilting, + ZoomOrClickZooming, + Zooming, +} + +#[derive(Clone, Debug, Default)] +struct NavigateToolData { + drag_start: Option, +} + +impl Fsm for NavigateToolFsmState { + type ToolData = NavigateToolData; + type ToolOptions = (); + + fn transition( + self, + message: ToolMessage, + tool_data: &mut Self::ToolData, + ToolActionHandlerData { input, .. }: &mut ToolActionHandlerData, + _tool_options: &Self::ToolOptions, + responses: &mut VecDeque, + ) -> Self { + let ToolMessage::Navigate(navigate) = message else { return self }; + match navigate { + NavigateToolMessage::PointerUp { zoom_in } => { + if self == NavigateToolFsmState::ZoomOrClickZooming { + // Mouse has not moved from pointerdown to pointerup + if tool_data.drag_start == Some(input.mouse.position) { + responses.add_front(if zoom_in { + NavigationMessage::CanvasZoomIncrease { center_on_mouse: true } + } else { + NavigationMessage::CanvasZoomDecrease { center_on_mouse: true } + }); + } + } else { + responses.add_front(NavigationMessage::EndCanvasPTZ { abort_transform: false }); + } + + tool_data.drag_start = None; + NavigateToolFsmState::Ready + } + NavigateToolMessage::PointerMove { snap } => { + if self == NavigateToolFsmState::ZoomOrClickZooming { + responses.add_front(NavigationMessage::BeginCanvasZoom); + NavigateToolFsmState::Zooming + } else { + responses.add_front(NavigationMessage::PointerMove { snap }); + self + } + } + NavigateToolMessage::TiltCanvasBegin => { + responses.add_front(NavigationMessage::BeginCanvasTilt { was_dispatched_from_menu: false }); + NavigateToolFsmState::Tilting + } + NavigateToolMessage::ZoomCanvasBegin => { + // Wait to decide between zooming and click zooming based on whether the next event is a PointerMove or PointerUp + tool_data.drag_start = Some(input.mouse.position); + NavigateToolFsmState::ZoomOrClickZooming + } + NavigateToolMessage::End => { + tool_data.drag_start = None; + NavigateToolFsmState::Ready + } + NavigateToolMessage::Abort => { + responses.add_front(NavigationMessage::EndCanvasPTZ { abort_transform: false }); + tool_data.drag_start = None; + NavigateToolFsmState::Ready + } + } + } + + fn update_hints(&self, responses: &mut VecDeque) { + let hint_data = match self { + NavigateToolFsmState::Ready | NavigateToolFsmState::ZoomOrClickZooming => HintData(vec![ + HintGroup(vec![ + HintInfo::mouse(MouseMotion::MmbDrag, ""), + HintInfo::keys_and_mouse([Key::Space], MouseMotion::LmbDrag, "Pan").prepend_slash(), + ]), + HintGroup(vec![HintInfo::keys_and_mouse([Key::Alt], MouseMotion::LmbDrag, "Tilt")]), + HintGroup(vec![HintInfo::mouse(MouseMotion::LmbDrag, "Zoom"), HintInfo::keys([Key::Shift], "Increments").prepend_plus()]), + HintGroup(vec![HintInfo::mouse(MouseMotion::Lmb, "Zoom In"), HintInfo::keys([Key::Shift], "Zoom Out").prepend_plus()]), + ]), + NavigateToolFsmState::Tilting => HintData(vec![ + HintGroup(vec![HintInfo::mouse(MouseMotion::Rmb, ""), HintInfo::keys([Key::Escape], "Cancel").prepend_slash()]), + HintGroup(vec![HintInfo::keys([Key::Shift], "15° Increments")]), + ]), + NavigateToolFsmState::Zooming => HintData(vec![ + HintGroup(vec![HintInfo::mouse(MouseMotion::Rmb, ""), HintInfo::keys([Key::Escape], "Cancel").prepend_slash()]), + HintGroup(vec![HintInfo::keys([Key::Shift], "Increments")]), + ]), + }; + + responses.add(FrontendMessage::UpdateInputHints { hint_data }); + } + + fn update_cursor(&self, responses: &mut VecDeque) { + let cursor = match *self { + NavigateToolFsmState::Ready => MouseCursorIcon::ZoomIn, + NavigateToolFsmState::Tilting => MouseCursorIcon::Default, + NavigateToolFsmState::Zooming | NavigateToolFsmState::ZoomOrClickZooming => MouseCursorIcon::ZoomIn, + }; + + responses.add(FrontendMessage::UpdateMouseCursor { cursor }); + } +} diff --git a/editor/src/messages/tool/tool_messages/path_tool.rs b/editor/src/messages/tool/tool_messages/path_tool.rs new file mode 100644 index 0000000000000000000000000000000000000000..ff929ce9bd196092a6da5bf3f3a79740188ddf17 --- /dev/null +++ b/editor/src/messages/tool/tool_messages/path_tool.rs @@ -0,0 +1,2577 @@ +use super::select_tool::extend_lasso; +use super::tool_prelude::*; +use crate::consts::{ + COLOR_OVERLAY_BLUE, COLOR_OVERLAY_GREEN, COLOR_OVERLAY_RED, DRAG_DIRECTION_MODE_DETERMINATION_THRESHOLD, DRAG_THRESHOLD, HANDLE_ROTATE_SNAP_ANGLE, SEGMENT_INSERTION_DISTANCE, + SEGMENT_OVERLAY_SIZE, SELECTION_THRESHOLD, SELECTION_TOLERANCE, +}; +use crate::messages::portfolio::document::overlays::utility_functions::{path_overlays, selected_segments}; +use crate::messages::portfolio::document::overlays::utility_types::{DrawHandles, OverlayContext}; +use crate::messages::portfolio::document::utility_types::document_metadata::{DocumentMetadata, LayerNodeIdentifier}; +use crate::messages::portfolio::document::utility_types::network_interface::NodeNetworkInterface; +use crate::messages::portfolio::document::utility_types::transformation::Axis; +use crate::messages::preferences::SelectionMode; +use crate::messages::tool::common_functionality::auto_panning::AutoPanning; +use crate::messages::tool::common_functionality::shape_editor::{ + ClosestSegment, ManipulatorAngle, OpposingHandleLengths, SelectedPointsInfo, SelectionChange, SelectionShape, SelectionShapeType, ShapeState, +}; +use crate::messages::tool::common_functionality::snapping::{SnapCache, SnapCandidatePoint, SnapConstraint, SnapData, SnapManager}; +use crate::messages::tool::common_functionality::utility_functions::{calculate_segment_angle, find_two_param_best_approximate}; +use bezier_rs::{Bezier, TValue}; +use graphene_std::renderer::Quad; +use graphene_std::vector::{HandleExt, HandleId, NoHashBuilder, SegmentId, VectorData}; +use graphene_std::vector::{ManipulatorPointId, PointId, VectorModificationType}; +use std::vec; + +#[derive(Default)] +pub struct PathTool { + fsm_state: PathToolFsmState, + tool_data: PathToolData, + options: PathToolOptions, +} + +#[derive(Default)] +pub struct PathToolOptions { + path_overlay_mode: PathOverlayMode, + path_editing_mode: PathEditingMode, +} + +#[impl_message(Message, ToolMessage, Path)] +#[derive(PartialEq, Clone, Debug, serde::Serialize, serde::Deserialize, specta::Type)] +pub enum PathToolMessage { + // Standard messages + Abort, + Overlays(OverlayContext), + SelectionChanged, + + // Tool-specific messages + BreakPath, + DeselectAllPoints, + Delete, + DeleteAndBreakPath, + DragStop { + extend_selection: Key, + shrink_selection: Key, + }, + Enter { + extend_selection: Key, + shrink_selection: Key, + }, + Escape, + ClosePath, + FlipSmoothSharp, + GRS { + // Should be `Key::KeyG` (Grab), `Key::KeyR` (Rotate), or `Key::KeyS` (Scale) + key: Key, + }, + ManipulatorMakeHandlesFree, + ManipulatorMakeHandlesColinear, + MouseDown { + extend_selection: Key, + lasso_select: Key, + handle_drag_from_anchor: Key, + drag_restore_handle: Key, + molding_in_segment_edit: Key, + }, + NudgeSelectedPoints { + delta_x: f64, + delta_y: f64, + }, + PointerMove { + equidistant: Key, + toggle_colinear: Key, + move_anchor_with_handles: Key, + snap_angle: Key, + lock_angle: Key, + delete_segment: Key, + break_colinear_molding: Key, + }, + PointerOutsideViewport { + equidistant: Key, + toggle_colinear: Key, + move_anchor_with_handles: Key, + snap_angle: Key, + lock_angle: Key, + delete_segment: Key, + break_colinear_molding: Key, + }, + RightClick, + SelectAllAnchors, + SelectedPointUpdated, + SelectedPointXChanged { + new_x: f64, + }, + SelectedPointYChanged { + new_y: f64, + }, + SwapSelectedHandles, + UpdateOptions(PathOptionsUpdate), + UpdateSelectedPointsStatus { + overlay_context: OverlayContext, + }, +} + +#[derive(PartialEq, Eq, Hash, Copy, Clone, Debug, Default, serde::Serialize, serde::Deserialize, specta::Type)] +pub enum PathOverlayMode { + AllHandles = 0, + #[default] + SelectedPointHandles = 1, + FrontierHandles = 2, +} + +#[derive(PartialEq, Eq, Hash, Copy, Clone, Debug)] +pub struct PathEditingMode { + point_editing_mode: bool, + segment_editing_mode: bool, +} + +impl Default for PathEditingMode { + fn default() -> Self { + Self { + point_editing_mode: true, + segment_editing_mode: false, + } + } +} + +#[derive(PartialEq, Eq, Clone, Debug, Hash, serde::Serialize, serde::Deserialize, specta::Type)] +pub enum PathOptionsUpdate { + OverlayModeType(PathOverlayMode), + PointEditingMode { enabled: bool }, + SegmentEditingMode { enabled: bool }, +} + +impl ToolMetadata for PathTool { + fn icon_name(&self) -> String { + "VectorPathTool".into() + } + fn tooltip(&self) -> String { + "Path Tool".into() + } + fn tool_type(&self) -> crate::messages::tool::utility_types::ToolType { + ToolType::Path + } +} + +impl LayoutHolder for PathTool { + fn layout(&self) -> Layout { + let coordinates = self.tool_data.selection_status.as_one().as_ref().map(|point| point.coordinates); + let (x, y) = coordinates.map(|point| (Some(point.x), Some(point.y))).unwrap_or((None, None)); + + let selection_status = &self.tool_data.selection_status; + let manipulator_angle = selection_status.angle(); + + let x_location = NumberInput::new(x) + .unit(" px") + .label("X") + .min_width(120) + .disabled(x.is_none()) + .min(-((1_u64 << f64::MANTISSA_DIGITS) as f64)) + .max((1_u64 << f64::MANTISSA_DIGITS) as f64) + .on_update(move |number_input: &NumberInput| { + if let Some(new_x) = number_input.value.or(x) { + PathToolMessage::SelectedPointXChanged { new_x }.into() + } else { + Message::NoOp + } + }) + .widget_holder(); + + let y_location = NumberInput::new(y) + .unit(" px") + .label("Y") + .min_width(120) + .disabled(y.is_none()) + .min(-((1_u64 << f64::MANTISSA_DIGITS) as f64)) + .max((1_u64 << f64::MANTISSA_DIGITS) as f64) + .on_update(move |number_input: &NumberInput| { + if let Some(new_y) = number_input.value.or(y) { + PathToolMessage::SelectedPointYChanged { new_y }.into() + } else { + Message::NoOp + } + }) + .widget_holder(); + + let related_seperator = Separator::new(SeparatorType::Related).widget_holder(); + let unrelated_seperator = Separator::new(SeparatorType::Unrelated).widget_holder(); + + let colinear_handles_tooltip = "Keep both handles unbent, each 180° apart, when moving either"; + let colinear_handles_state = manipulator_angle.and_then(|angle| match angle { + ManipulatorAngle::Colinear => Some(true), + ManipulatorAngle::Free => Some(false), + ManipulatorAngle::Mixed => None, + }) + // TODO: Remove `unwrap_or_default` once checkboxes are capable of displaying a mixed state + .unwrap_or_default(); + let mut checkbox_id = CheckboxId::default(); + let colinear_handle_checkbox = CheckboxInput::new(colinear_handles_state) + .disabled(!self.tool_data.can_toggle_colinearity) + .on_update(|&CheckboxInput { checked, .. }| { + if checked { + PathToolMessage::ManipulatorMakeHandlesColinear.into() + } else { + PathToolMessage::ManipulatorMakeHandlesFree.into() + } + }) + .tooltip(colinear_handles_tooltip) + .for_label(checkbox_id.clone()) + .widget_holder(); + let colinear_handles_label = TextLabel::new("Colinear Handles") + .disabled(!self.tool_data.can_toggle_colinearity) + .tooltip(colinear_handles_tooltip) + .for_checkbox(&mut checkbox_id) + .widget_holder(); + + let point_editing_mode = CheckboxInput::new(self.options.path_editing_mode.point_editing_mode) + // TODO(Keavon): Replace with a real icon + .icon("Dot") + .tooltip("Point Editing Mode") + .on_update(|input| PathToolMessage::UpdateOptions(PathOptionsUpdate::PointEditingMode { enabled: input.checked }).into()) + .widget_holder(); + let segment_editing_mode = CheckboxInput::new(self.options.path_editing_mode.segment_editing_mode) + // TODO(Keavon): Replace with a real icon + .icon("Remove") + .tooltip("Segment Editing Mode") + .on_update(|input| PathToolMessage::UpdateOptions(PathOptionsUpdate::SegmentEditingMode { enabled: input.checked }).into()) + .widget_holder(); + + let path_overlay_mode_widget = RadioInput::new(vec![ + RadioEntryData::new("all") + .icon("HandleVisibilityAll") + .tooltip("Show all handles regardless of selection") + .on_update(move |_| PathToolMessage::UpdateOptions(PathOptionsUpdate::OverlayModeType(PathOverlayMode::AllHandles)).into()), + RadioEntryData::new("selected") + .icon("HandleVisibilitySelected") + .tooltip("Show only handles of the segments connected to selected points") + .on_update(move |_| PathToolMessage::UpdateOptions(PathOptionsUpdate::OverlayModeType(PathOverlayMode::SelectedPointHandles)).into()), + RadioEntryData::new("frontier") + .icon("HandleVisibilityFrontier") + .tooltip("Show only handles at the frontiers of the segments connected to selected points") + .on_update(move |_| PathToolMessage::UpdateOptions(PathOptionsUpdate::OverlayModeType(PathOverlayMode::FrontierHandles)).into()), + ]) + .selected_index(Some(self.options.path_overlay_mode as u32)) + .widget_holder(); + + Layout::WidgetLayout(WidgetLayout::new(vec![LayoutGroup::Row { + widgets: vec![ + x_location, + related_seperator.clone(), + y_location, + unrelated_seperator.clone(), + colinear_handle_checkbox, + related_seperator.clone(), + colinear_handles_label, + unrelated_seperator.clone(), + point_editing_mode, + related_seperator.clone(), + segment_editing_mode, + unrelated_seperator, + path_overlay_mode_widget, + ], + }])) + } +} + +impl<'a> MessageHandler> for PathTool { + fn process_message(&mut self, message: ToolMessage, responses: &mut VecDeque, tool_data: &mut ToolActionHandlerData<'a>) { + let updating_point = message == ToolMessage::Path(PathToolMessage::SelectedPointUpdated); + + match message { + ToolMessage::Path(PathToolMessage::UpdateOptions(action)) => match action { + PathOptionsUpdate::OverlayModeType(overlay_mode_type) => { + self.options.path_overlay_mode = overlay_mode_type; + responses.add(OverlaysMessage::Draw); + } + PathOptionsUpdate::PointEditingMode { enabled } => { + self.options.path_editing_mode.point_editing_mode = enabled; + responses.add(OverlaysMessage::Draw); + } + PathOptionsUpdate::SegmentEditingMode { enabled } => { + self.options.path_editing_mode.segment_editing_mode = enabled; + responses.add(OverlaysMessage::Draw); + } + }, + ToolMessage::Path(PathToolMessage::ClosePath) => { + responses.add(DocumentMessage::AddTransaction); + tool_data.shape_editor.close_selected_path(tool_data.document, responses); + responses.add(DocumentMessage::EndTransaction); + responses.add(OverlaysMessage::Draw); + } + ToolMessage::Path(PathToolMessage::SwapSelectedHandles) => { + if tool_data.shape_editor.handle_with_pair_selected(&tool_data.document.network_interface) { + tool_data.shape_editor.alternate_selected_handles(&tool_data.document.network_interface); + responses.add(PathToolMessage::SelectedPointUpdated); + responses.add(FrontendMessage::UpdateMouseCursor { cursor: MouseCursorIcon::None }); + responses.add(OverlaysMessage::Draw); + } + } + _ => { + self.fsm_state.process_event(message, &mut self.tool_data, tool_data, &self.options, responses, true); + } + } + + if updating_point { + self.send_layout(responses, LayoutTarget::ToolOptions); + } + } + + // Different actions depending on state may be wanted: + fn actions(&self) -> ActionList { + match self.fsm_state { + PathToolFsmState::Ready => actions!(PathToolMessageDiscriminant; + FlipSmoothSharp, + MouseDown, + Delete, + NudgeSelectedPoints, + Enter, + SelectAllAnchors, + DeselectAllPoints, + BreakPath, + DeleteAndBreakPath, + ClosePath, + PointerMove, + ), + PathToolFsmState::Dragging(_) => actions!(PathToolMessageDiscriminant; + Escape, + RightClick, + FlipSmoothSharp, + DragStop, + PointerMove, + Delete, + BreakPath, + DeleteAndBreakPath, + SwapSelectedHandles, + ), + PathToolFsmState::Drawing { .. } => actions!(PathToolMessageDiscriminant; + FlipSmoothSharp, + DragStop, + PointerMove, + Delete, + Enter, + BreakPath, + DeleteAndBreakPath, + Escape, + RightClick, + ), + PathToolFsmState::SlidingPoint => actions!(PathToolMessageDiscriminant; + PointerMove, + DragStop, + Escape, + RightClick + ), + PathToolFsmState::MoldingSegment => actions!(PathToolMessageDiscriminant; + PointerMove, + DragStop, + RightClick, + Escape, + ), + } + } +} + +impl ToolTransition for PathTool { + fn event_to_message_map(&self) -> EventToMessageMap { + EventToMessageMap { + tool_abort: Some(PathToolMessage::Abort.into()), + selection_changed: Some(PathToolMessage::SelectionChanged.into()), + overlay_provider: Some(|overlay_context| PathToolMessage::Overlays(overlay_context).into()), + ..Default::default() + } + } +} +#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)] +pub struct DraggingState { + point_select_state: PointSelectState, + colinear: ManipulatorAngle, +} + +#[derive(Clone, Copy, Default, Debug, PartialEq, Eq)] +pub enum PointSelectState { + HandleWithPair, + #[default] + HandleNoPair, + Anchor, +} + +#[derive(Clone, Copy)] +pub struct SlidingSegmentData { + segment_id: SegmentId, + bezier: Bezier, + start: PointId, +} + +#[derive(Clone, Copy)] +pub struct SlidingPointInfo { + anchor: PointId, + layer: LayerNodeIdentifier, + connected_segments: [SlidingSegmentData; 2], +} + +#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)] +enum PathToolFsmState { + #[default] + Ready, + Dragging(DraggingState), + Drawing { + selection_shape: SelectionShapeType, + }, + SlidingPoint, + MoldingSegment, +} + +#[derive(Default)] +struct PathToolData { + snap_manager: SnapManager, + lasso_polygon: Vec, + selection_mode: Option, + drag_start_pos: DVec2, + previous_mouse_position: DVec2, + toggle_colinear_debounce: bool, + opposing_handle_lengths: Option, + /// Describes information about the selected point(s), if any, across one or multiple shapes and manipulator point types (anchor or handle). + /// The available information varies depending on whether `None`, `One`, or `Multiple` points are currently selected. + /// NOTE: It must be updated using `update_selection_status` to ensure `can_toggle_colinearity` stays synchronized with the current selection. + selection_status: SelectionStatus, + /// `true` if we can change the current selection to colinear or not. + can_toggle_colinearity: bool, + segment: Option, + snap_cache: SnapCache, + double_click_handled: bool, + delete_segment_pressed: bool, + auto_panning: AutoPanning, + saved_points_before_anchor_select_toggle: Vec, + select_anchor_toggled: bool, + saved_points_before_handle_drag: Vec, + handle_drag_toggle: bool, + saved_points_before_anchor_convert_smooth_sharp: HashSet, + last_click_time: u64, + dragging_state: DraggingState, + angle: f64, + opposite_handle_position: Option, + last_clicked_point_was_selected: bool, + last_clicked_segment_was_selected: bool, + snapping_axis: Option, + alt_clicked_on_anchor: bool, + alt_dragging_from_anchor: bool, + angle_locked: bool, + temporary_colinear_handles: bool, + molding_info: Option<(DVec2, DVec2)>, + molding_segment: bool, + temporary_adjacent_handles_while_molding: Option<[Option; 2]>, + frontier_handles_info: Option>>, + adjacent_anchor_offset: Option, + sliding_point_info: Option, + started_drawing_from_inside: bool, +} + +impl PathToolData { + fn save_points_before_anchor_toggle(&mut self, points: Vec) -> PathToolFsmState { + self.saved_points_before_anchor_select_toggle = points; + PathToolFsmState::Dragging(self.dragging_state) + } + + fn remove_saved_points(&mut self) { + self.saved_points_before_anchor_select_toggle.clear(); + } + + pub fn selection_quad(&self, metadata: &DocumentMetadata) -> Quad { + let bbox = self.selection_box(metadata); + Quad::from_box(bbox) + } + + pub fn calculate_selection_mode_from_direction(&mut self, metadata: &DocumentMetadata) -> SelectionMode { + let bbox = self.selection_box(metadata); + let above_threshold = bbox[1].distance_squared(bbox[0]) > DRAG_DIRECTION_MODE_DETERMINATION_THRESHOLD.powi(2); + + if self.selection_mode.is_none() && above_threshold { + let mode = if bbox[1].x < bbox[0].x { + SelectionMode::Touched + } else { + // This also covers the case where they're equal: the area is zero, so we use `Enclosed` to ensure the selection ends up empty, as nothing will be enclosed by an empty area + SelectionMode::Enclosed + }; + self.selection_mode = Some(mode); + } + + self.selection_mode.unwrap_or(SelectionMode::Touched) + } + + pub fn selection_box(&self, metadata: &DocumentMetadata) -> [DVec2; 2] { + // Convert previous mouse position to viewport space first + let document_to_viewport = metadata.document_to_viewport; + let previous_mouse = document_to_viewport.transform_point2(self.previous_mouse_position); + if previous_mouse == self.drag_start_pos { + let tolerance = DVec2::splat(SELECTION_TOLERANCE); + [self.drag_start_pos - tolerance, self.drag_start_pos + tolerance] + } else { + [self.drag_start_pos, previous_mouse] + } + } + + fn update_selection_status(&mut self, shape_editor: &mut ShapeState, document: &DocumentMessageHandler) { + let selection_status = get_selection_status(&document.network_interface, shape_editor); + + self.can_toggle_colinearity = match &selection_status { + SelectionStatus::None => false, + SelectionStatus::One(single_selected_point) => { + let vector_data = document.network_interface.compute_modified_vector(single_selected_point.layer).unwrap(); + single_selected_point.id.get_handle_pair(&vector_data).is_some() + } + SelectionStatus::Multiple(_) => true, + }; + self.selection_status = selection_status; + } + + // TODO: This function is for basic point select mode. We definitely need to make a new one for the segment select mode. + #[allow(clippy::too_many_arguments)] + fn mouse_down( + &mut self, + shape_editor: &mut ShapeState, + document: &DocumentMessageHandler, + input: &InputPreprocessorMessageHandler, + responses: &mut VecDeque, + extend_selection: bool, + lasso_select: bool, + handle_drag_from_anchor: bool, + drag_zero_handle: bool, + molding_in_segment_edit: bool, + path_overlay_mode: PathOverlayMode, + segment_editing_mode: bool, + point_editing_mode: bool, + ) -> PathToolFsmState { + self.double_click_handled = false; + self.opposing_handle_lengths = None; + + self.drag_start_pos = input.mouse.position; + + if !self.saved_points_before_anchor_convert_smooth_sharp.is_empty() && (input.time - self.last_click_time > 500) { + self.saved_points_before_anchor_convert_smooth_sharp.clear(); + } + + self.last_click_time = input.time; + + let old_selection = shape_editor.selected_points().cloned().collect::>(); + + // Check if the point is already selected; if not, select the first point within the threshold (in pixels) + // Don't select the points which are not shown currently in PathOverlayMode + if let Some((already_selected, mut selection_info)) = shape_editor.get_point_selection_state( + &document.network_interface, + input.mouse.position, + SELECTION_THRESHOLD, + path_overlay_mode, + self.frontier_handles_info.clone(), + point_editing_mode, + ) { + responses.add(DocumentMessage::StartTransaction); + + self.last_clicked_point_was_selected = already_selected; + + // If the point is already selected and shift (`extend_selection`) is used, keep the selection unchanged. + // Otherwise, select the first point within the threshold. + if !(already_selected && extend_selection) { + if let Some(updated_selection_info) = shape_editor.change_point_selection( + &document.network_interface, + input.mouse.position, + SELECTION_THRESHOLD, + extend_selection, + path_overlay_mode, + self.frontier_handles_info.clone(), + ) { + selection_info = updated_selection_info; + } + } + + if let Some(selected_points) = selection_info { + self.drag_start_pos = input.mouse.position; + + // If selected points contain only handles and there was some selection before, then it is stored and becomes restored upon release + let mut dragging_only_handles = true; + for point in &selected_points.points { + if matches!(point.point_id, ManipulatorPointId::Anchor(_)) { + dragging_only_handles = false; + break; + } + } + if dragging_only_handles && !self.handle_drag_toggle && !old_selection.is_empty() { + self.saved_points_before_handle_drag = old_selection; + } + + if handle_drag_from_anchor { + if let Some((layer, point)) = shape_editor.find_nearest_point_indices(&document.network_interface, input.mouse.position, SELECTION_THRESHOLD) { + // Check that selected point is an anchor + if let (Some(point_id), Some(vector_data)) = (point.as_anchor(), document.network_interface.compute_modified_vector(layer)) { + let handles = vector_data.all_connected(point_id).collect::>(); + self.alt_clicked_on_anchor = true; + for handle in &handles { + let modification_type = handle.set_relative_position(DVec2::ZERO); + responses.add(GraphOperationMessage::Vector { layer, modification_type }); + for &handles in &vector_data.colinear_manipulators { + if handles.contains(handle) { + let modification_type = VectorModificationType::SetG1Continuous { handles, enabled: false }; + responses.add(GraphOperationMessage::Vector { layer, modification_type }); + } + } + } + + let manipulator_point_id = handles[0].to_manipulator_point(); + shape_editor.deselect_all_points(); + shape_editor.select_points_by_manipulator_id(&vec![manipulator_point_id]); + responses.add(PathToolMessage::SelectedPointUpdated); + } + } + } + + if let Some((Some(point), Some(vector_data))) = shape_editor + .find_nearest_point_indices(&document.network_interface, input.mouse.position, SELECTION_THRESHOLD) + .map(|(layer, point)| (point.as_anchor(), document.network_interface.compute_modified_vector(layer))) + { + let handles = vector_data + .all_connected(point) + .filter(|handle| handle.length(&vector_data) < 1e-6) + .map(|handle| handle.to_manipulator_point()) + .collect::>(); + let endpoint = vector_data.extendable_points(false).any(|anchor| point == anchor); + + if drag_zero_handle && (handles.len() == 1 && !endpoint) { + shape_editor.deselect_all_points(); + shape_editor.select_points_by_manipulator_id(&handles); + shape_editor.convert_selected_manipulators_to_colinear_handles(responses, document); + } + } + + self.start_dragging_point(selected_points, input, document, shape_editor); + responses.add(OverlaysMessage::Draw); + } + PathToolFsmState::Dragging(self.dragging_state) + } + // We didn't find a point nearby, so we will see if there is a segment to select or insert a point on + else if let Some(segment) = shape_editor.upper_closest_segment(&document.network_interface, input.mouse.position, SELECTION_THRESHOLD) { + responses.add(DocumentMessage::StartTransaction); + + if segment_editing_mode && !molding_in_segment_edit { + let layer = segment.layer(); + let segment_id = segment.segment(); + let already_selected = shape_editor.selected_shape_state.get(&layer).is_some_and(|state| state.is_segment_selected(segment_id)); + self.last_clicked_segment_was_selected = already_selected; + + if !(already_selected && extend_selection) { + let retain_existing_selection = extend_selection || already_selected; + if !retain_existing_selection { + shape_editor.deselect_all_segments(); + shape_editor.deselect_all_points(); + } + + // Add to selected segments + if let Some(selected_shape_state) = shape_editor.selected_shape_state.get_mut(&layer) { + selected_shape_state.select_segment(segment_id); + } + } + + self.drag_start_pos = input.mouse.position; + + let viewport_to_document = document.metadata().document_to_viewport.inverse(); + self.previous_mouse_position = viewport_to_document.transform_point2(input.mouse.position); + + responses.add(OverlaysMessage::Draw); + PathToolFsmState::Dragging(self.dragging_state) + } else { + let handle1 = ManipulatorPointId::PrimaryHandle(segment.segment()); + let handle2 = ManipulatorPointId::EndHandle(segment.segment()); + if let Some(vector_data) = document.network_interface.compute_modified_vector(segment.layer()) { + if let (Some(pos1), Some(pos2)) = (handle1.get_position(&vector_data), handle2.get_position(&vector_data)) { + self.molding_info = Some((pos1, pos2)) + } + } + PathToolFsmState::MoldingSegment + } + } + // We didn't find a segment, so consider selecting the nearest shape instead and start drawing + else if let Some(layer) = document.click(input) { + shape_editor.deselect_all_points(); + shape_editor.deselect_all_segments(); + if extend_selection { + responses.add(NodeGraphMessage::SelectedNodesAdd { nodes: vec![layer.to_node()] }); + } else { + responses.add(NodeGraphMessage::SelectedNodesSet { nodes: vec![layer.to_node()] }); + } + self.drag_start_pos = input.mouse.position; + self.previous_mouse_position = document.metadata().document_to_viewport.inverse().transform_point2(input.mouse.position); + + self.started_drawing_from_inside = true; + + let selection_shape = if lasso_select { SelectionShapeType::Lasso } else { SelectionShapeType::Box }; + PathToolFsmState::Drawing { selection_shape } + } + // Start drawing + else { + self.drag_start_pos = input.mouse.position; + self.previous_mouse_position = document.metadata().document_to_viewport.inverse().transform_point2(input.mouse.position); + + let selection_shape = if lasso_select { SelectionShapeType::Lasso } else { SelectionShapeType::Box }; + PathToolFsmState::Drawing { selection_shape } + } + } + + fn start_dragging_point(&mut self, selected_points: SelectedPointsInfo, input: &InputPreprocessorMessageHandler, document: &DocumentMessageHandler, shape_editor: &mut ShapeState) { + let mut manipulators = HashMap::with_hasher(NoHashBuilder); + let mut unselected = Vec::new(); + for (&layer, state) in &shape_editor.selected_shape_state { + let Some(vector_data) = document.network_interface.compute_modified_vector(layer) else { + continue; + }; + let transform = document.metadata().transform_to_document(layer); + + let mut layer_manipulators = HashSet::with_hasher(NoHashBuilder); + for point in state.selected_points() { + let Some(anchor) = point.get_anchor(&vector_data) else { continue }; + layer_manipulators.insert(anchor); + let Some([handle1, handle2]) = point.get_handle_pair(&vector_data) else { continue }; + let Some(handle) = point.as_handle() else { continue }; + // Check which handle is selected and which is opposite + let opposite = if handle == handle1 { handle2 } else { handle1 }; + + self.opposite_handle_position = if self.opposite_handle_position.is_none() { + opposite.to_manipulator_point().get_position(&vector_data) + } else { + self.opposite_handle_position + }; + } + for (&id, &position) in vector_data.point_domain.ids().iter().zip(vector_data.point_domain.positions()) { + if layer_manipulators.contains(&id) { + continue; + } + unselected.push(SnapCandidatePoint::handle(transform.transform_point2(position))) + } + if !layer_manipulators.is_empty() { + manipulators.insert(layer, layer_manipulators); + } + } + self.snap_cache = SnapCache { manipulators, unselected }; + + let viewport_to_document = document.metadata().document_to_viewport.inverse(); + self.previous_mouse_position = viewport_to_document.transform_point2(input.mouse.position - selected_points.offset); + } + + fn update_colinear(&mut self, equidistant: bool, toggle_colinear: bool, shape_editor: &mut ShapeState, document: &DocumentMessageHandler, responses: &mut VecDeque) -> bool { + // Check handle colinear state + let is_colinear = self + .selection_status + .angle() + .map(|angle| match angle { + ManipulatorAngle::Colinear => true, + ManipulatorAngle::Free | ManipulatorAngle::Mixed => false, + }) + .unwrap_or(false); + + // Check if the toggle_colinear key has just been pressed + if toggle_colinear && !self.toggle_colinear_debounce { + self.opposing_handle_lengths = None; + if is_colinear { + shape_editor.disable_colinear_handles_state_on_selected(&document.network_interface, responses); + } else { + shape_editor.convert_selected_manipulators_to_colinear_handles(responses, document); + } + self.toggle_colinear_debounce = true; + return true; + } + self.toggle_colinear_debounce = toggle_colinear; + + if equidistant && self.opposing_handle_lengths.is_none() { + if !is_colinear { + // Try to get selected handle info + let Some((_, _, selected_handle_id)) = self.try_get_selected_handle_and_anchor(shape_editor, document) else { + self.opposing_handle_lengths = Some(shape_editor.opposing_handle_lengths(document)); + return false; + }; + + let Some((layer, _)) = shape_editor.selected_shape_state.iter().next() else { + self.opposing_handle_lengths = Some(shape_editor.opposing_handle_lengths(document)); + return false; + }; + + let Some(vector_data) = document.network_interface.compute_modified_vector(*layer) else { + self.opposing_handle_lengths = Some(shape_editor.opposing_handle_lengths(document)); + return false; + }; + + // Check if handle has a pair (to ignore handles of edges of open paths) + if let Some(handle_pair) = selected_handle_id.get_handle_pair(&vector_data) { + let opposite_handle_length = handle_pair.iter().filter(|&&h| h.to_manipulator_point() != selected_handle_id).find_map(|&h| { + let opp_handle_pos = h.to_manipulator_point().get_position(&vector_data)?; + let opp_anchor_id = h.to_manipulator_point().get_anchor(&vector_data)?; + let opp_anchor_pos = vector_data.point_domain.position_from_id(opp_anchor_id)?; + Some((opp_handle_pos - opp_anchor_pos).length()) + }); + + // Make handles colinear if opposite handle is zero length + if opposite_handle_length == Some(0.) { + shape_editor.convert_selected_manipulators_to_colinear_handles(responses, document); + return true; + } + } + } + self.opposing_handle_lengths = Some(shape_editor.opposing_handle_lengths(document)); + } + false + } + + /// Attempts to get a single selected handle. Also retrieves the position of the anchor it is connected to. Used for the purpose of snapping the angle. + fn try_get_selected_handle_and_anchor(&self, shape_editor: &ShapeState, document: &DocumentMessageHandler) -> Option<(DVec2, DVec2, ManipulatorPointId)> { + // Only count selections of a single layer + let (layer, selection) = shape_editor.selected_shape_state.iter().next()?; + + // Do not allow selections of multiple points to count + if selection.selected_points_count() != 1 { + return None; + } + + // Only count selected handles + let selected_handle = selection.selected_points().next()?.as_handle()?; + let handle_id = selected_handle.to_manipulator_point(); + + let layer_to_document = document.metadata().transform_to_document(*layer); + let vector_data = document.network_interface.compute_modified_vector(*layer)?; + + let handle_position_local = selected_handle.to_manipulator_point().get_position(&vector_data)?; + let anchor_id = selected_handle.to_manipulator_point().get_anchor(&vector_data)?; + let anchor_position_local = vector_data.point_domain.position_from_id(anchor_id)?; + + let handle_position_document = layer_to_document.transform_point2(handle_position_local); + let anchor_position_document = layer_to_document.transform_point2(anchor_position_local); + + Some((handle_position_document, anchor_position_document, handle_id)) + } + + #[allow(clippy::too_many_arguments)] + fn calculate_handle_angle( + &mut self, + shape_editor: &mut ShapeState, + document: &DocumentMessageHandler, + responses: &mut VecDeque, + relative_vector: DVec2, + handle_vector: DVec2, + handle_id: ManipulatorPointId, + lock_angle: bool, + snap_angle: bool, + tangent_to_neighboring_tangents: bool, + ) -> f64 { + let current_angle = -handle_vector.angle_to(DVec2::X); + + if let Some((vector_data, layer)) = shape_editor + .selected_shape_state + .iter() + .next() + .and_then(|(layer, _)| document.network_interface.compute_modified_vector(*layer).map(|vector_data| (vector_data, layer))) + { + let adjacent_anchor = check_handle_over_adjacent_anchor(handle_id, &vector_data); + let mut required_angle = None; + + // If the handle is dragged over one of its adjacent anchors while holding down the Ctrl key, compute the angle based on the tangent formed with the neighboring anchor points. + if adjacent_anchor.is_some() && lock_angle && !self.angle_locked { + let anchor = handle_id.get_anchor(&vector_data); + let (angle, anchor_position) = calculate_adjacent_anchor_tangent(handle_id, anchor, adjacent_anchor, &vector_data); + + let layer_to_document = document.metadata().transform_to_document(*layer); + + self.adjacent_anchor_offset = handle_id + .get_anchor_position(&vector_data) + .and_then(|handle_anchor| anchor_position.map(|adjacent_anchor| layer_to_document.transform_point2(adjacent_anchor) - layer_to_document.transform_point2(handle_anchor))); + + required_angle = angle; + } + + // If the handle is dragged near its adjacent anchors while holding down the Ctrl key, compute the angle using the tangent direction of neighboring segments. + if relative_vector.length() < 25. && lock_angle && !self.angle_locked { + required_angle = calculate_lock_angle(self, shape_editor, responses, document, &vector_data, handle_id, tangent_to_neighboring_tangents); + } + + // Finalize and apply angle locking if a valid target angle was determined. + if let Some(angle) = required_angle { + self.angle = angle; + self.angle_locked = true; + return angle; + } + } + + if lock_angle && !self.angle_locked { + self.angle_locked = true; + self.angle = -relative_vector.angle_to(DVec2::X); + return -relative_vector.angle_to(DVec2::X); + } + + // When the angle is locked we use the old angle + if self.angle_locked { + return self.angle; + } + + // Round the angle to the closest increment + let mut handle_angle = current_angle; + if snap_angle && !lock_angle { + let snap_resolution = HANDLE_ROTATE_SNAP_ANGLE.to_radians(); + handle_angle = (handle_angle / snap_resolution).round() * snap_resolution; + } + + self.angle = handle_angle; + + handle_angle + } + + #[allow(clippy::too_many_arguments)] + fn apply_snapping( + &mut self, + handle_direction: DVec2, + new_handle_position: DVec2, + anchor_position: DVec2, + using_angle_constraints: bool, + handle_position: DVec2, + document: &DocumentMessageHandler, + input: &InputPreprocessorMessageHandler, + ) -> DVec2 { + let snap_data = SnapData::new(document, input); + let snap_point = SnapCandidatePoint::handle_neighbors(new_handle_position, [anchor_position]); + + let snap_result = match using_angle_constraints { + true => { + let snap_constraint = SnapConstraint::Line { + origin: anchor_position, + direction: handle_direction.normalize_or_zero(), + }; + + self.snap_manager.constrained_snap(&snap_data, &snap_point, snap_constraint, Default::default()) + } + false => self.snap_manager.free_snap(&snap_data, &snap_point, Default::default()), + }; + + self.snap_manager.update_indicator(snap_result.clone()); + + document.metadata().document_to_viewport.transform_vector2(snap_result.snapped_point_document - handle_position) + } + + fn start_snap_along_axis(&mut self, shape_editor: &mut ShapeState, document: &DocumentMessageHandler, input: &InputPreprocessorMessageHandler, responses: &mut VecDeque) { + // Find the negative delta to take the point to the drag start position + let current_mouse = input.mouse.position; + let drag_start = self.drag_start_pos; + let opposite_delta = drag_start - current_mouse; + + shape_editor.move_selected_points_and_segments(None, document, opposite_delta, false, true, false, None, false, responses); + + // Calculate the projected delta and shift the points along that delta + let delta = current_mouse - drag_start; + let axis = if delta.x.abs() >= delta.y.abs() { Axis::X } else { Axis::Y }; + self.snapping_axis = Some(axis); + let projected_delta = match axis { + Axis::X => DVec2::new(delta.x, 0.), + Axis::Y => DVec2::new(0., delta.y), + _ => DVec2::new(delta.x, 0.), + }; + + shape_editor.move_selected_points_and_segments(None, document, projected_delta, false, true, false, None, false, responses); + } + + fn stop_snap_along_axis(&mut self, shape_editor: &mut ShapeState, document: &DocumentMessageHandler, input: &InputPreprocessorMessageHandler, responses: &mut VecDeque) { + // Calculate the negative delta of the selection and move it back to the drag start + let current_mouse = input.mouse.position; + let drag_start = self.drag_start_pos; + + let opposite_delta = drag_start - current_mouse; + let Some(axis) = self.snapping_axis else { return }; + let opposite_projected_delta = match axis { + Axis::X => DVec2::new(opposite_delta.x, 0.), + Axis::Y => DVec2::new(0., opposite_delta.y), + _ => DVec2::new(opposite_delta.x, 0.), + }; + + shape_editor.move_selected_points_and_segments(None, document, opposite_projected_delta, false, true, false, None, false, responses); + + // Calculate what actually would have been the original delta for the point, and apply that + let delta = current_mouse - drag_start; + + shape_editor.move_selected_points_and_segments(None, document, delta, false, true, false, None, false, responses); + + self.snapping_axis = None; + } + + fn get_normalized_tangent(&mut self, point: PointId, segment: SegmentId, vector_data: &VectorData) -> Option { + let other_point = vector_data.other_point(segment, point)?; + let position = ManipulatorPointId::Anchor(point).get_position(vector_data)?; + + let mut handles = vector_data.all_connected(other_point); + let other_handle = handles.find(|handle| handle.segment == segment)?; + + let target_position = if other_handle.length(vector_data) == 0. { + ManipulatorPointId::Anchor(other_point).get_position(vector_data)? + } else { + other_handle.to_manipulator_point().get_position(vector_data)? + }; + + let tangent_vector = target_position - position; + tangent_vector.try_normalize() + } + + fn update_closest_segment(&mut self, shape_editor: &mut ShapeState, position: DVec2, document: &DocumentMessageHandler, path_overlay_mode: PathOverlayMode) { + // Check if there is no point nearby + if shape_editor + .find_nearest_visible_point_indices(&document.network_interface, position, SELECTION_THRESHOLD, path_overlay_mode, self.frontier_handles_info.clone()) + .is_some() + { + self.segment = None; + } + // If already hovering on a segment, then recalculate its closest point + else if let Some(closest_segment) = &mut self.segment { + closest_segment.update_closest_point(document.metadata(), position); + + if closest_segment.too_far(position, SEGMENT_INSERTION_DISTANCE) { + self.segment = None; + } + } + // If not, check that if there is some closest segment or not + else if let Some(closest_segment) = shape_editor.upper_closest_segment(&document.network_interface, position, SEGMENT_INSERTION_DISTANCE) { + self.segment = Some(closest_segment); + } + } + + fn start_sliding_point(&mut self, shape_editor: &mut ShapeState, document: &DocumentMessageHandler) -> bool { + let single_anchor_selected = shape_editor.selected_points().count() == 1 && shape_editor.selected_points().any(|point| matches!(point, ManipulatorPointId::Anchor(_))); + + if single_anchor_selected { + let Some(anchor) = shape_editor.selected_points().next() else { return false }; + let Some(layer) = document.network_interface.selected_nodes().selected_layers(document.metadata()).next() else { + return false; + }; + let Some(vector_data) = document.network_interface.compute_modified_vector(layer) else { + return false; + }; + + // Check that the handles of anchor point are also colinear + if !vector_data.colinear(*anchor) { + return false; + }; + + let Some(point_id) = anchor.as_anchor() else { return false }; + + let mut connected_segments = [None, None]; + for (segment, bezier, start, end) in vector_data.segment_bezier_iter() { + if start == point_id || end == point_id { + match (connected_segments[0], connected_segments[1]) { + (None, None) => connected_segments[0] = Some(SlidingSegmentData { segment_id: segment, bezier, start }), + (Some(_), None) => connected_segments[1] = Some(SlidingSegmentData { segment_id: segment, bezier, start }), + _ => { + warn!("more than two segments connected to the anchor point"); + return false; + } + } + } + } + let connected_segments = if let [Some(seg1), Some(seg2)] = connected_segments { + [seg1, seg2] + } else { + warn!("expected exactly two connected segments"); + return false; + }; + + self.sliding_point_info = Some(SlidingPointInfo { + anchor: point_id, + layer, + connected_segments, + }); + return true; + } + false + } + + fn slide_point(&mut self, target_position: DVec2, responses: &mut VecDeque, network_interface: &NodeNetworkInterface, shape_editor: &ShapeState) { + let Some(sliding_point_info) = self.sliding_point_info else { return }; + let anchor = sliding_point_info.anchor; + let layer = sliding_point_info.layer; + + let Some(vector_data) = network_interface.compute_modified_vector(layer) else { return }; + let transform = network_interface.document_metadata().transform_to_viewport(layer); + let layer_pos = transform.inverse().transform_point2(target_position); + + let segments = sliding_point_info.connected_segments; + + let t1 = segments[0].bezier.project(layer_pos); + let position1 = segments[0].bezier.evaluate(TValue::Parametric(t1)); + + let t2 = segments[1].bezier.project(layer_pos); + let position2 = segments[1].bezier.evaluate(TValue::Parametric(t2)); + + let (closer_segment, farther_segment, t_value, new_position) = if position2.distance(layer_pos) < position1.distance(layer_pos) { + (segments[1], segments[0], t2, position2) + } else { + (segments[0], segments[1], t1, position1) + }; + + // Move the anchor to the new position + let Some(current_position) = ManipulatorPointId::Anchor(anchor).get_position(&vector_data) else { + return; + }; + let delta = new_position - current_position; + + shape_editor.move_anchor(anchor, &vector_data, delta, layer, None, responses); + + // Make a split at the t_value + let [first, second] = closer_segment.bezier.split(TValue::Parametric(t_value)); + let closer_segment_other_point = if anchor == closer_segment.start { closer_segment.bezier.end } else { closer_segment.bezier.start }; + + let (split_segment, other_segment) = if first.start == closer_segment_other_point { (first, second) } else { (second, first) }; + + // Primary handle maps to primary handle and secondary maps to secondary + let closer_primary_handle = HandleId::primary(closer_segment.segment_id); + let Some(handle_position) = split_segment.handle_start() else { return }; + let relative_position1 = handle_position - split_segment.start; + let modification_type = closer_primary_handle.set_relative_position(relative_position1); + responses.add(GraphOperationMessage::Vector { layer, modification_type }); + + let closer_secondary_handle = HandleId::end(closer_segment.segment_id); + let Some(handle_position) = split_segment.handle_end() else { return }; + let relative_position2 = handle_position - split_segment.end; + let modification_type = closer_secondary_handle.set_relative_position(relative_position2); + responses.add(GraphOperationMessage::Vector { layer, modification_type }); + + let end_handle_direction = if anchor == closer_segment.start { -relative_position1 } else { -relative_position2 }; + + let (farther_other_point, start_handle, end_handle, start_handle_pos) = if anchor == farther_segment.start { + ( + farther_segment.bezier.end, + HandleId::end(farther_segment.segment_id), + HandleId::primary(farther_segment.segment_id), + farther_segment.bezier.handle_end(), + ) + } else { + ( + farther_segment.bezier.start, + HandleId::primary(farther_segment.segment_id), + HandleId::end(farther_segment.segment_id), + farther_segment.bezier.handle_start(), + ) + }; + let Some(start_handle_position) = start_handle_pos else { return }; + let start_handle_direction = start_handle_position - farther_other_point; + + // Get normalized direction vectors, if cubic handle is zero then we consider corresponding tangent + let d1 = start_handle_direction.try_normalize().unwrap_or({ + if anchor == farther_segment.start { + -farther_segment.bezier.tangent(TValue::Parametric(0.99)) + } else { + farther_segment.bezier.tangent(TValue::Parametric(0.01)) + } + }); + + let d2 = end_handle_direction.try_normalize().unwrap_or_default(); + + let min_len1 = start_handle_direction.length() * 0.4; + let min_len2 = end_handle_direction.length() * 0.4; + + let (relative_pos1, relative_pos2) = find_two_param_best_approximate(farther_other_point, new_position, d1, d2, min_len1, min_len2, farther_segment.bezier, other_segment); + + // Now set those handles to these handle lengths keeping the directions d1, d2 + let modification_type = start_handle.set_relative_position(relative_pos1); + responses.add(GraphOperationMessage::Vector { layer, modification_type }); + + let modification_type = end_handle.set_relative_position(relative_pos2); + responses.add(GraphOperationMessage::Vector { layer, modification_type }); + } + + #[allow(clippy::too_many_arguments)] + fn drag( + &mut self, + equidistant: bool, + lock_angle: bool, + snap_angle: bool, + snap_axis: bool, + shape_editor: &mut ShapeState, + document: &DocumentMessageHandler, + input: &InputPreprocessorMessageHandler, + responses: &mut VecDeque, + ) { + // First check if selection is not just a single handle point + let selected_points = shape_editor.selected_points(); + let single_handle_selected = selected_points.count() == 1 + && shape_editor + .selected_points() + .any(|point| matches!(point, ManipulatorPointId::EndHandle(_) | ManipulatorPointId::PrimaryHandle(_))); + + // This is where it starts snapping along axis + if snap_axis && self.snapping_axis.is_none() && !single_handle_selected { + self.start_snap_along_axis(shape_editor, document, input, responses); + } else if !snap_axis && self.snapping_axis.is_some() { + self.stop_snap_along_axis(shape_editor, document, input, responses); + } + + let document_to_viewport = document.metadata().document_to_viewport; + let previous_mouse = document_to_viewport.transform_point2(self.previous_mouse_position); + let current_mouse = input.mouse.position; + let raw_delta = document_to_viewport.inverse().transform_vector2(current_mouse - previous_mouse); + + let snapped_delta = if let Some((handle_position, anchor_position, handle_id)) = self.try_get_selected_handle_and_anchor(shape_editor, document) { + let cursor_position = handle_position + raw_delta; + + let handle_angle = self.calculate_handle_angle( + shape_editor, + document, + responses, + handle_position - anchor_position, + cursor_position - anchor_position, + handle_id, + lock_angle, + snap_angle, + equidistant, + ); + + let adjacent_anchor_offset = self.adjacent_anchor_offset.unwrap_or(DVec2::ZERO); + let constrained_direction = DVec2::new(handle_angle.cos(), handle_angle.sin()); + let projected_length = (cursor_position - anchor_position - adjacent_anchor_offset).dot(constrained_direction); + let constrained_target = anchor_position + adjacent_anchor_offset + constrained_direction * projected_length; + let constrained_delta = constrained_target - handle_position; + + self.apply_snapping( + constrained_direction, + handle_position + constrained_delta, + anchor_position + adjacent_anchor_offset, + lock_angle || snap_angle, + handle_position, + document, + input, + ) + } else { + shape_editor.snap(&mut self.snap_manager, &self.snap_cache, document, input, previous_mouse) + }; + + let handle_lengths = if equidistant { None } else { self.opposing_handle_lengths.take() }; + let opposite = if lock_angle { None } else { self.opposite_handle_position }; + let unsnapped_delta = current_mouse - previous_mouse; + let mut was_alt_dragging = false; + + if self.snapping_axis.is_none() { + if self.alt_clicked_on_anchor && !self.alt_dragging_from_anchor && self.drag_start_pos.distance(input.mouse.position) > DRAG_THRESHOLD { + // Checking which direction the dragging begins + self.alt_dragging_from_anchor = true; + let Some(layer) = document.network_interface.selected_nodes().selected_layers(document.metadata()).next() else { + return; + }; + let Some(vector_data) = document.network_interface.compute_modified_vector(layer) else { return }; + let Some(point_id) = shape_editor.selected_points().next().unwrap().get_anchor(&vector_data) else { + return; + }; + + if vector_data.connected_count(point_id) == 2 { + let connected_segments: Vec = vector_data.all_connected(point_id).collect(); + let segment1 = connected_segments[0]; + let Some(tangent1) = self.get_normalized_tangent(point_id, segment1.segment, &vector_data) else { + return; + }; + let segment2 = connected_segments[1]; + let Some(tangent2) = self.get_normalized_tangent(point_id, segment2.segment, &vector_data) else { + return; + }; + + let delta = input.mouse.position - self.drag_start_pos; + let handle = if delta.dot(tangent1) >= delta.dot(tangent2) { + segment1.to_manipulator_point() + } else { + segment2.to_manipulator_point() + }; + + // Now change the selection to this handle + shape_editor.deselect_all_points(); + shape_editor.select_points_by_manipulator_id(&vec![handle]); + responses.add(PathToolMessage::SelectionChanged); + } + } + + if self.alt_dragging_from_anchor && !equidistant && self.alt_clicked_on_anchor { + was_alt_dragging = true; + self.alt_dragging_from_anchor = false; + self.alt_clicked_on_anchor = false; + } + + let mut skip_opposite = false; + if self.temporary_colinear_handles && !lock_angle { + shape_editor.disable_colinear_handles_state_on_selected(&document.network_interface, responses); + self.temporary_colinear_handles = false; + skip_opposite = true; + } + shape_editor.move_selected_points_and_segments(handle_lengths, document, snapped_delta, equidistant, true, was_alt_dragging, opposite, skip_opposite, responses); + self.previous_mouse_position += document_to_viewport.inverse().transform_vector2(snapped_delta); + } else { + let Some(axis) = self.snapping_axis else { return }; + let projected_delta = match axis { + Axis::X => DVec2::new(unsnapped_delta.x, 0.), + Axis::Y => DVec2::new(0., unsnapped_delta.y), + _ => DVec2::new(unsnapped_delta.x, 0.), + }; + shape_editor.move_selected_points_and_segments(handle_lengths, document, projected_delta, equidistant, true, false, opposite, false, responses); + self.previous_mouse_position += document_to_viewport.inverse().transform_vector2(unsnapped_delta); + } + + // Constantly checking and changing the snapping axis based on current mouse position + if snap_axis && self.snapping_axis.is_some() { + let Some(current_axis) = self.snapping_axis else { return }; + let total_delta = self.drag_start_pos - input.mouse.position; + + if (total_delta.x.abs() > total_delta.y.abs() && current_axis == Axis::Y) || (total_delta.y.abs() > total_delta.x.abs() && current_axis == Axis::X) { + self.stop_snap_along_axis(shape_editor, document, input, responses); + self.start_snap_along_axis(shape_editor, document, input, responses); + } + } + } +} + +impl Fsm for PathToolFsmState { + type ToolData = PathToolData; + type ToolOptions = PathToolOptions; + + fn transition(self, event: ToolMessage, tool_data: &mut Self::ToolData, tool_action_data: &mut ToolActionHandlerData, tool_options: &Self::ToolOptions, responses: &mut VecDeque) -> Self { + let ToolActionHandlerData { document, input, shape_editor, .. } = tool_action_data; + + update_dynamic_hints(self, responses, shape_editor, document, tool_data, tool_options); + + let ToolMessage::Path(event) = event else { return self }; + match (self, event) { + (_, PathToolMessage::SelectionChanged) => { + // Set the newly targeted layers to visible + let target_layers = document.network_interface.selected_nodes().selected_layers(document.metadata()).collect(); + shape_editor.set_selected_layers(target_layers); + + responses.add(OverlaysMessage::Draw); + self + } + (_, PathToolMessage::UpdateSelectedPointsStatus { overlay_context }) => { + let display_anchors = overlay_context.visibility_settings.anchors(); + let display_handles = overlay_context.visibility_settings.handles(); + + shape_editor.update_selected_anchors_status(display_anchors); + shape_editor.update_selected_handles_status(display_handles); + + self + } + (_, PathToolMessage::Overlays(mut overlay_context)) => { + // TODO: find the segment ids of which the selected points are a part of + + match tool_options.path_overlay_mode { + PathOverlayMode::AllHandles => { + path_overlays(document, DrawHandles::All, shape_editor, &mut overlay_context); + tool_data.frontier_handles_info = None; + } + PathOverlayMode::SelectedPointHandles => { + let selected_segments = selected_segments(&document.network_interface, shape_editor); + + path_overlays(document, DrawHandles::SelectedAnchors(selected_segments), shape_editor, &mut overlay_context); + tool_data.frontier_handles_info = None; + } + PathOverlayMode::FrontierHandles => { + let selected_segments = selected_segments(&document.network_interface, shape_editor); + let selected_points = shape_editor.selected_points(); + let selected_anchors = selected_points + .filter_map(|point_id| if let ManipulatorPointId::Anchor(p) = point_id { Some(*p) } else { None }) + .collect::>(); + + // Match the behavior of `PathOverlayMode::SelectedPointHandles` when only one point is selected + if shape_editor.selected_points().count() == 1 { + path_overlays(document, DrawHandles::SelectedAnchors(selected_segments), shape_editor, &mut overlay_context); + } else { + let mut segment_endpoints: HashMap> = HashMap::new(); + + for layer in document.network_interface.selected_nodes().selected_layers(document.metadata()) { + let Some(vector_data) = document.network_interface.compute_modified_vector(layer) else { continue }; + + // The points which are part of only one segment will be rendered + let mut selected_segments_by_point: HashMap> = HashMap::new(); + + for (segment_id, _bezier, start, end) in vector_data.segment_bezier_iter() { + if selected_segments.contains(&segment_id) { + selected_segments_by_point.entry(start).or_default().push(segment_id); + selected_segments_by_point.entry(end).or_default().push(segment_id); + } + } + + for (point, attached_segments) in selected_segments_by_point { + if attached_segments.len() == 1 { + segment_endpoints.entry(attached_segments[0]).or_default().push(point); + } + // Handle the edge case where a point, although not explicitly selected, is shared by two segments. + else if !selected_anchors.contains(&point) { + segment_endpoints.entry(attached_segments[0]).or_default().push(point); + segment_endpoints.entry(attached_segments[1]).or_default().push(point); + } + } + } + + // Caching segment endpoints for use in point selection logic + tool_data.frontier_handles_info = Some(segment_endpoints.clone()); + + // Now frontier anchors can be sent for rendering overlays + path_overlays(document, DrawHandles::FrontierHandles(segment_endpoints), shape_editor, &mut overlay_context); + } + } + } + + match self { + Self::Ready => { + tool_data.update_closest_segment(shape_editor, input.mouse.position, document, tool_options.path_overlay_mode); + + if let Some(closest_segment) = &tool_data.segment { + if tool_options.path_editing_mode.segment_editing_mode { + let transform = document.metadata().transform_to_viewport(closest_segment.layer()); + + overlay_context.outline_overlay_bezier(closest_segment.bezier(), transform); + + // Draw the anchors again + let display_anchors = overlay_context.visibility_settings.anchors(); + if display_anchors { + let start_pos = transform.transform_point2(closest_segment.bezier().start); + let end_pos = transform.transform_point2(closest_segment.bezier().end); + let start_id = closest_segment.points()[0]; + let end_id = closest_segment.points()[1]; + if let Some(shape_state) = shape_editor.selected_shape_state.get_mut(&closest_segment.layer()) { + overlay_context.manipulator_anchor(start_pos, shape_state.is_point_selected(ManipulatorPointId::Anchor(start_id)), None); + overlay_context.manipulator_anchor(end_pos, shape_state.is_point_selected(ManipulatorPointId::Anchor(end_id)), None); + } + } + } else { + let perp = closest_segment.calculate_perp(document); + let point = closest_segment.closest_point(document.metadata()); + + // Draw an X on the segment + if tool_data.delete_segment_pressed { + let angle = 45_f64.to_radians(); + let tilted_line = DVec2::from_angle(angle).rotate(perp); + let tilted_perp = tilted_line.perp(); + + overlay_context.line(point - tilted_line * SEGMENT_OVERLAY_SIZE, point + tilted_line * SEGMENT_OVERLAY_SIZE, Some(COLOR_OVERLAY_BLUE), None); + overlay_context.line(point - tilted_perp * SEGMENT_OVERLAY_SIZE, point + tilted_perp * SEGMENT_OVERLAY_SIZE, Some(COLOR_OVERLAY_BLUE), None); + } + // Draw a line on the segment + else { + overlay_context.line(point - perp * SEGMENT_OVERLAY_SIZE, point + perp * SEGMENT_OVERLAY_SIZE, Some(COLOR_OVERLAY_BLUE), None); + } + } + } + } + Self::Drawing { selection_shape } => { + let mut fill_color = graphene_std::Color::from_rgb_str(COLOR_OVERLAY_BLUE.strip_prefix('#').unwrap()) + .unwrap() + .with_alpha(0.05) + .to_rgba_hex_srgb(); + fill_color.insert(0, '#'); + let fill_color = Some(fill_color.as_str()); + + let selection_mode = match tool_action_data.preferences.get_selection_mode() { + SelectionMode::Directional => tool_data.calculate_selection_mode_from_direction(document.metadata()), + selection_mode => selection_mode, + }; + + let quad = tool_data.selection_quad(document.metadata()); + let polygon = &tool_data.lasso_polygon; + + match (selection_shape, selection_mode, tool_data.started_drawing_from_inside) { + // Don't draw box if it is from inside a shape and selection just began + (SelectionShapeType::Box, SelectionMode::Enclosed, false) => overlay_context.dashed_quad(quad, None, fill_color, Some(4.), Some(4.), Some(0.5)), + (SelectionShapeType::Lasso, SelectionMode::Enclosed, _) => overlay_context.dashed_polygon(polygon, None, fill_color, Some(4.), Some(4.), Some(0.5)), + (SelectionShapeType::Box, _, false) => overlay_context.quad(quad, None, fill_color), + (SelectionShapeType::Lasso, _, _) => overlay_context.polygon(polygon, None, fill_color), + (SelectionShapeType::Box, _, _) => {} + } + } + Self::Dragging(_) => { + tool_data.snap_manager.draw_overlays(SnapData::new(document, input), &mut overlay_context); + + // Draw the snapping axis lines + if tool_data.snapping_axis.is_some() { + let Some(axis) = tool_data.snapping_axis else { return self }; + let origin = tool_data.drag_start_pos; + let viewport_diagonal = input.viewport_bounds.size().length(); + + let faded = |color: &str| { + let mut color = graphene_std::Color::from_rgb_str(color.strip_prefix('#').unwrap()).unwrap().with_alpha(0.25).to_rgba_hex_srgb(); + color.insert(0, '#'); + color + }; + match axis { + Axis::Y => { + overlay_context.line(origin - DVec2::Y * viewport_diagonal, origin + DVec2::Y * viewport_diagonal, Some(COLOR_OVERLAY_GREEN), None); + overlay_context.line(origin - DVec2::X * viewport_diagonal, origin + DVec2::X * viewport_diagonal, Some(&faded(COLOR_OVERLAY_RED)), None); + } + Axis::X | Axis::Both => { + overlay_context.line(origin - DVec2::X * viewport_diagonal, origin + DVec2::X * viewport_diagonal, Some(COLOR_OVERLAY_RED), None); + overlay_context.line(origin - DVec2::Y * viewport_diagonal, origin + DVec2::Y * viewport_diagonal, Some(&faded(COLOR_OVERLAY_GREEN)), None); + } + } + } + } + Self::SlidingPoint => {} + Self::MoldingSegment => {} + } + + responses.add(PathToolMessage::SelectedPointUpdated); + responses.add(PathToolMessage::UpdateSelectedPointsStatus { overlay_context }); + self + } + + // Mouse down + ( + _, + PathToolMessage::MouseDown { + extend_selection, + lasso_select, + handle_drag_from_anchor, + drag_restore_handle, + molding_in_segment_edit, + }, + ) => { + let extend_selection = input.keyboard.get(extend_selection as usize); + let lasso_select = input.keyboard.get(lasso_select as usize); + let handle_drag_from_anchor = input.keyboard.get(handle_drag_from_anchor as usize); + let drag_zero_handle = input.keyboard.get(drag_restore_handle as usize); + let molding_in_segment_edit = input.keyboard.get(molding_in_segment_edit as usize); + + tool_data.selection_mode = None; + tool_data.lasso_polygon.clear(); + + tool_data.mouse_down( + shape_editor, + document, + input, + responses, + extend_selection, + lasso_select, + handle_drag_from_anchor, + drag_zero_handle, + molding_in_segment_edit, + tool_options.path_overlay_mode, + tool_options.path_editing_mode.segment_editing_mode, + tool_options.path_editing_mode.point_editing_mode, + ) + } + ( + PathToolFsmState::Drawing { selection_shape }, + PathToolMessage::PointerMove { + equidistant, + toggle_colinear, + move_anchor_with_handles, + snap_angle, + lock_angle, + delete_segment, + break_colinear_molding, + }, + ) => { + tool_data.previous_mouse_position = document.metadata().document_to_viewport.inverse().transform_point2(input.mouse.position); + tool_data.started_drawing_from_inside = false; + + if selection_shape == SelectionShapeType::Lasso { + extend_lasso(&mut tool_data.lasso_polygon, input.mouse.position); + } + + responses.add(OverlaysMessage::Draw); + + // Auto-panning + let messages = [ + PathToolMessage::PointerOutsideViewport { + equidistant, + toggle_colinear, + move_anchor_with_handles, + snap_angle, + lock_angle, + delete_segment, + break_colinear_molding, + } + .into(), + PathToolMessage::PointerMove { + equidistant, + toggle_colinear, + move_anchor_with_handles, + snap_angle, + lock_angle, + delete_segment, + break_colinear_molding, + } + .into(), + ]; + tool_data.auto_panning.setup_by_mouse_position(input, &messages, responses); + + PathToolFsmState::Drawing { selection_shape } + } + ( + PathToolFsmState::Dragging(_), + PathToolMessage::PointerMove { + equidistant, + toggle_colinear, + move_anchor_with_handles, + snap_angle, + lock_angle, + delete_segment, + break_colinear_molding, + }, + ) => { + let mut selected_only_handles = true; + + let selected_points = shape_editor.selected_points(); + + for point in selected_points { + if matches!(point, ManipulatorPointId::Anchor(_)) { + selected_only_handles = false; + break; + } + } + + if !tool_data.saved_points_before_handle_drag.is_empty() && (tool_data.drag_start_pos.distance(input.mouse.position) > DRAG_THRESHOLD) && (selected_only_handles) { + tool_data.handle_drag_toggle = true; + } + + let anchor_and_handle_toggled = input.keyboard.get(move_anchor_with_handles as usize); + let initial_press = anchor_and_handle_toggled && !tool_data.select_anchor_toggled; + let released_from_toggle = tool_data.select_anchor_toggled && !anchor_and_handle_toggled; + + if initial_press { + responses.add(PathToolMessage::SelectedPointUpdated); + tool_data.select_anchor_toggled = true; + tool_data.save_points_before_anchor_toggle(shape_editor.selected_points().cloned().collect()); + shape_editor.select_handles_and_anchor_connected_to_current_handle(&document.network_interface); + } else if released_from_toggle { + responses.add(PathToolMessage::SelectedPointUpdated); + tool_data.select_anchor_toggled = false; + shape_editor.deselect_all_points(); + shape_editor.select_points_by_manipulator_id(&tool_data.saved_points_before_anchor_select_toggle); + tool_data.remove_saved_points(); + } + + let toggle_colinear_state = input.keyboard.get(toggle_colinear as usize); + let equidistant_state = input.keyboard.get(equidistant as usize); + let lock_angle_state = input.keyboard.get(lock_angle as usize); + let snap_angle_state = input.keyboard.get(snap_angle as usize); + + if !lock_angle_state { + tool_data.angle_locked = false; + tool_data.adjacent_anchor_offset = None; + } + + if !tool_data.update_colinear(equidistant_state, toggle_colinear_state, tool_action_data.shape_editor, tool_action_data.document, responses) { + if snap_angle_state && lock_angle_state && tool_data.start_sliding_point(tool_action_data.shape_editor, tool_action_data.document) { + return PathToolFsmState::SlidingPoint; + } + + tool_data.drag( + equidistant_state, + lock_angle_state, + snap_angle_state, + snap_angle_state, + tool_action_data.shape_editor, + tool_action_data.document, + input, + responses, + ); + } + + // Auto-panning + let messages = [ + PathToolMessage::PointerOutsideViewport { + toggle_colinear, + equidistant, + move_anchor_with_handles, + snap_angle, + lock_angle, + delete_segment, + break_colinear_molding, + } + .into(), + PathToolMessage::PointerMove { + toggle_colinear, + equidistant, + move_anchor_with_handles, + snap_angle, + lock_angle, + delete_segment, + break_colinear_molding, + } + .into(), + ]; + tool_data.auto_panning.setup_by_mouse_position(input, &messages, responses); + + PathToolFsmState::Dragging(tool_data.dragging_state) + } + (PathToolFsmState::SlidingPoint, PathToolMessage::PointerMove { .. }) => { + tool_data.slide_point(input.mouse.position, responses, &document.network_interface, shape_editor); + PathToolFsmState::SlidingPoint + } + (PathToolFsmState::MoldingSegment, PathToolMessage::PointerMove { break_colinear_molding, .. }) => { + if tool_data.drag_start_pos.distance(input.mouse.position) > DRAG_THRESHOLD { + tool_data.molding_segment = true; + } + + let break_colinear_molding = input.keyboard.get(break_colinear_molding as usize); + + // Logic for molding segment + if let Some(segment) = &mut tool_data.segment { + if let Some(molding_segment_handles) = tool_data.molding_info { + tool_data.temporary_adjacent_handles_while_molding = segment.mold_handle_positions( + document, + responses, + molding_segment_handles, + input.mouse.position, + break_colinear_molding, + tool_data.temporary_adjacent_handles_while_molding, + ); + } + } + + PathToolFsmState::MoldingSegment + } + (PathToolFsmState::Ready, PathToolMessage::PointerMove { delete_segment, .. }) => { + tool_data.delete_segment_pressed = input.keyboard.get(delete_segment as usize); + + if !tool_data.saved_points_before_anchor_convert_smooth_sharp.is_empty() { + tool_data.saved_points_before_anchor_convert_smooth_sharp.clear(); + } + + if tool_data.adjacent_anchor_offset.is_some() { + tool_data.adjacent_anchor_offset = None; + } + + responses.add(OverlaysMessage::Draw); + + self + } + (PathToolFsmState::Drawing { selection_shape: selection_type }, PathToolMessage::PointerOutsideViewport { .. }) => { + // Auto-panning + if let Some(offset) = tool_data.auto_panning.shift_viewport(input, responses) { + tool_data.drag_start_pos += offset; + } + + PathToolFsmState::Drawing { selection_shape: selection_type } + } + (PathToolFsmState::Dragging(dragging_state), PathToolMessage::PointerOutsideViewport { .. }) => { + // Auto-panning + if let Some(offset) = tool_data.auto_panning.shift_viewport(input, responses) { + tool_data.drag_start_pos += offset; + } + + PathToolFsmState::Dragging(dragging_state) + } + ( + state, + PathToolMessage::PointerOutsideViewport { + equidistant, + toggle_colinear, + move_anchor_with_handles, + snap_angle, + lock_angle, + delete_segment, + break_colinear_molding, + }, + ) => { + // Auto-panning + let messages = [ + PathToolMessage::PointerOutsideViewport { + equidistant, + toggle_colinear, + move_anchor_with_handles, + snap_angle, + lock_angle, + delete_segment, + break_colinear_molding, + } + .into(), + PathToolMessage::PointerMove { + equidistant, + toggle_colinear, + move_anchor_with_handles, + snap_angle, + lock_angle, + delete_segment, + break_colinear_molding, + } + .into(), + ]; + tool_data.auto_panning.stop(&messages, responses); + + state + } + (PathToolFsmState::Drawing { selection_shape }, PathToolMessage::Enter { extend_selection, shrink_selection }) => { + let extend_selection = input.keyboard.get(extend_selection as usize); + let shrink_selection = input.keyboard.get(shrink_selection as usize); + + let selection_change = if shrink_selection { + SelectionChange::Shrink + } else if extend_selection { + SelectionChange::Extend + } else { + SelectionChange::Clear + }; + + let document_to_viewport = document.metadata().document_to_viewport; + let previous_mouse = document_to_viewport.transform_point2(tool_data.previous_mouse_position); + if tool_data.drag_start_pos == previous_mouse { + responses.add(NodeGraphMessage::SelectedNodesSet { nodes: vec![] }); + } else { + let selection_mode = match tool_action_data.preferences.get_selection_mode() { + SelectionMode::Directional => tool_data.calculate_selection_mode_from_direction(document.metadata()), + selection_mode => selection_mode, + }; + + match selection_shape { + SelectionShapeType::Box => { + let bbox = [tool_data.drag_start_pos, previous_mouse]; + shape_editor.select_all_in_shape( + &document.network_interface, + SelectionShape::Box(bbox), + selection_change, + tool_options.path_overlay_mode, + tool_data.frontier_handles_info.clone(), + tool_options.path_editing_mode.segment_editing_mode, + selection_mode, + ); + } + SelectionShapeType::Lasso => shape_editor.select_all_in_shape( + &document.network_interface, + SelectionShape::Lasso(&tool_data.lasso_polygon), + selection_change, + tool_options.path_overlay_mode, + tool_data.frontier_handles_info.clone(), + tool_options.path_editing_mode.segment_editing_mode, + selection_mode, + ), + } + } + + responses.add(OverlaysMessage::Draw); + + PathToolFsmState::Ready + } + (PathToolFsmState::Dragging { .. }, PathToolMessage::Escape | PathToolMessage::RightClick) => { + if tool_data.handle_drag_toggle && tool_data.drag_start_pos.distance(input.mouse.position) > DRAG_THRESHOLD { + shape_editor.deselect_all_points(); + shape_editor.deselect_all_segments(); + shape_editor.select_points_by_manipulator_id(&tool_data.saved_points_before_handle_drag); + + tool_data.saved_points_before_handle_drag.clear(); + tool_data.handle_drag_toggle = false; + } + tool_data.angle_locked = false; + responses.add(DocumentMessage::AbortTransaction); + tool_data.snap_manager.cleanup(responses); + PathToolFsmState::Ready + } + (PathToolFsmState::Drawing { .. }, PathToolMessage::Escape | PathToolMessage::RightClick) => { + tool_data.snap_manager.cleanup(responses); + PathToolFsmState::Ready + } + (PathToolFsmState::SlidingPoint, PathToolMessage::Escape | PathToolMessage::RightClick) => { + tool_data.sliding_point_info = None; + + responses.add(DocumentMessage::AbortTransaction); + tool_data.snap_manager.cleanup(responses); + + PathToolFsmState::Ready + } + (PathToolFsmState::MoldingSegment, PathToolMessage::Escape | PathToolMessage::RightClick) => { + // Undo the molding and go back to the state before + tool_data.molding_info = None; + tool_data.molding_segment = false; + tool_data.temporary_adjacent_handles_while_molding = None; + + responses.add(DocumentMessage::AbortTransaction); + tool_data.snap_manager.cleanup(responses); + + PathToolFsmState::Ready + } + // Mouse up + (PathToolFsmState::Drawing { selection_shape }, PathToolMessage::DragStop { extend_selection, shrink_selection }) => { + let extend_selection = input.keyboard.get(extend_selection as usize); + let shrink_selection = input.keyboard.get(shrink_selection as usize); + + let select_kind = if shrink_selection { + SelectionChange::Shrink + } else if extend_selection { + SelectionChange::Extend + } else { + SelectionChange::Clear + }; + + let document_to_viewport = document.metadata().document_to_viewport; + let previous_mouse = document_to_viewport.transform_point2(tool_data.previous_mouse_position); + + let selection_mode = match tool_action_data.preferences.get_selection_mode() { + SelectionMode::Directional => tool_data.calculate_selection_mode_from_direction(document.metadata()), + selection_mode => selection_mode, + }; + + if tool_data.drag_start_pos.distance(previous_mouse) < 1e-8 { + // If click happens inside of a shape then don't set selected nodes to empty + if document.click(input).is_none() { + responses.add(NodeGraphMessage::SelectedNodesSet { nodes: vec![] }); + } + } else { + match selection_shape { + SelectionShapeType::Box => { + let bbox = [tool_data.drag_start_pos, previous_mouse]; + shape_editor.select_all_in_shape( + &document.network_interface, + SelectionShape::Box(bbox), + select_kind, + tool_options.path_overlay_mode, + tool_data.frontier_handles_info.clone(), + tool_options.path_editing_mode.segment_editing_mode, + selection_mode, + ); + } + SelectionShapeType::Lasso => shape_editor.select_all_in_shape( + &document.network_interface, + SelectionShape::Lasso(&tool_data.lasso_polygon), + select_kind, + tool_options.path_overlay_mode, + tool_data.frontier_handles_info.clone(), + tool_options.path_editing_mode.segment_editing_mode, + selection_mode, + ), + } + } + responses.add(OverlaysMessage::Draw); + responses.add(PathToolMessage::SelectedPointUpdated); + + PathToolFsmState::Ready + } + (_, PathToolMessage::DragStop { extend_selection, .. }) => { + let extend_selection = input.keyboard.get(extend_selection as usize); + let drag_occurred = tool_data.drag_start_pos.distance(input.mouse.position) > DRAG_THRESHOLD; + + let nearest_point = shape_editor.find_nearest_visible_point_indices( + &document.network_interface, + input.mouse.position, + SELECTION_THRESHOLD, + tool_options.path_overlay_mode, + tool_data.frontier_handles_info.clone(), + ); + + let nearest_segment = tool_data.segment.clone(); + + if let Some(segment) = &mut tool_data.segment { + let segment_mode = tool_options.path_editing_mode.segment_editing_mode; + if !drag_occurred && !tool_data.molding_segment && !segment_mode { + if tool_data.delete_segment_pressed { + if let Some(vector_data) = document.network_interface.compute_modified_vector(segment.layer()) { + shape_editor.dissolve_segment(responses, segment.layer(), &vector_data, segment.segment(), segment.points()); + } + } else { + segment.adjusted_insert_and_select(shape_editor, responses, extend_selection); + } + } + + tool_data.segment = None; + tool_data.molding_info = None; + tool_data.molding_segment = false; + tool_data.temporary_adjacent_handles_while_molding = None; + } + + let segment_mode = tool_options.path_editing_mode.segment_editing_mode; + + if let Some((layer, nearest_point)) = nearest_point { + let clicked_selected = shape_editor.selected_points().any(|&point| nearest_point == point); + if !drag_occurred && extend_selection { + if clicked_selected && tool_data.last_clicked_point_was_selected { + shape_editor.selected_shape_state.entry(layer).or_default().deselect_point(nearest_point); + } else { + shape_editor.selected_shape_state.entry(layer).or_default().select_point(nearest_point); + } + responses.add(OverlaysMessage::Draw); + } + if !drag_occurred && !extend_selection && clicked_selected { + if tool_data.saved_points_before_anchor_convert_smooth_sharp.is_empty() { + tool_data.saved_points_before_anchor_convert_smooth_sharp = shape_editor.selected_points().copied().collect::>(); + } + + shape_editor.deselect_all_points(); + shape_editor.deselect_all_segments(); + + shape_editor.selected_shape_state.entry(layer).or_default().select_point(nearest_point); + + responses.add(OverlaysMessage::Draw); + } + } + // Segment editing mode + else if let Some(nearest_segment) = nearest_segment { + if segment_mode { + let clicked_selected = shape_editor.selected_segments().any(|&segment| segment == nearest_segment.segment()); + if !drag_occurred && extend_selection { + if clicked_selected && tool_data.last_clicked_segment_was_selected { + shape_editor + .selected_shape_state + .entry(nearest_segment.layer()) + .or_default() + .deselect_segment(nearest_segment.segment()); + } else { + shape_editor.selected_shape_state.entry(nearest_segment.layer()).or_default().select_segment(nearest_segment.segment()); + } + + responses.add(OverlaysMessage::Draw); + } + if !drag_occurred && !extend_selection && clicked_selected { + shape_editor.deselect_all_segments(); + shape_editor.deselect_all_points(); + shape_editor.selected_shape_state.entry(nearest_segment.layer()).or_default().select_segment(nearest_segment.segment()); + + responses.add(OverlaysMessage::Draw); + } + } + } + // Deselect all points if the user clicks the filled region of the shape + else if tool_data.drag_start_pos.distance(input.mouse.position) <= DRAG_THRESHOLD { + shape_editor.deselect_all_points(); + shape_editor.deselect_all_segments(); + } + + if tool_data.temporary_colinear_handles { + tool_data.temporary_colinear_handles = false; + } + + if tool_data.handle_drag_toggle && drag_occurred { + shape_editor.deselect_all_points(); + shape_editor.select_points_by_manipulator_id(&tool_data.saved_points_before_handle_drag); + + tool_data.saved_points_before_handle_drag.clear(); + tool_data.handle_drag_toggle = false; + } + + tool_data.alt_dragging_from_anchor = false; + tool_data.alt_clicked_on_anchor = false; + tool_data.angle_locked = false; + + if tool_data.select_anchor_toggled { + shape_editor.deselect_all_points(); + shape_editor.select_points_by_manipulator_id(&tool_data.saved_points_before_anchor_select_toggle); + tool_data.remove_saved_points(); + tool_data.select_anchor_toggled = false; + } + + tool_data.snapping_axis = None; + tool_data.sliding_point_info = None; + + responses.add(DocumentMessage::EndTransaction); + responses.add(PathToolMessage::SelectedPointUpdated); + tool_data.snap_manager.cleanup(responses); + tool_data.opposite_handle_position = None; + + PathToolFsmState::Ready + } + + // Delete key + (_, PathToolMessage::Delete) => { + // Delete the selected points and clean up overlays + responses.add(DocumentMessage::AddTransaction); + shape_editor.delete_selected_segments(document, responses); + shape_editor.delete_selected_points(document, responses); + responses.add(PathToolMessage::SelectionChanged); + + PathToolFsmState::Ready + } + (_, PathToolMessage::BreakPath) => { + shape_editor.break_path_at_selected_point(document, responses); + PathToolFsmState::Ready + } + (_, PathToolMessage::DeleteAndBreakPath) => { + shape_editor.delete_point_and_break_path(document, responses); + PathToolFsmState::Ready + } + (_, PathToolMessage::FlipSmoothSharp) => { + // Double-clicked on a point + let nearest_point = shape_editor.find_nearest_point_indices(&document.network_interface, input.mouse.position, SELECTION_THRESHOLD); + if nearest_point.is_some() { + // Flip the selected point between smooth and sharp + if !tool_data.double_click_handled && tool_data.drag_start_pos.distance(input.mouse.position) <= DRAG_THRESHOLD { + responses.add(DocumentMessage::StartTransaction); + + shape_editor.select_points_by_manipulator_id(&tool_data.saved_points_before_anchor_convert_smooth_sharp.iter().copied().collect::>()); + shape_editor.flip_smooth_sharp(&document.network_interface, input.mouse.position, SELECTION_TOLERANCE, responses); + tool_data.saved_points_before_anchor_convert_smooth_sharp.clear(); + + responses.add(DocumentMessage::EndTransaction); + responses.add(PathToolMessage::SelectedPointUpdated); + } + + return PathToolFsmState::Ready; + } + + // Double-clicked on a filled region + if let Some(layer) = document.click(input) { + // Select all points in the layer + shape_editor.select_connected_anchors(document, layer, input.mouse.position); + responses.add(OverlaysMessage::Draw); + } + + PathToolFsmState::Ready + } + (_, PathToolMessage::Abort) => { + responses.add(OverlaysMessage::Draw); + PathToolFsmState::Ready + } + (_, PathToolMessage::NudgeSelectedPoints { delta_x, delta_y }) => { + shape_editor.move_selected_points_and_segments( + tool_data.opposing_handle_lengths.take(), + document, + (delta_x, delta_y).into(), + true, + false, + false, + tool_data.opposite_handle_position, + false, + responses, + ); + + PathToolFsmState::Ready + } + (_, PathToolMessage::SelectAllAnchors) => { + shape_editor.select_all_anchors_in_selected_layers(document); + responses.add(OverlaysMessage::Draw); + PathToolFsmState::Ready + } + (_, PathToolMessage::DeselectAllPoints) => { + shape_editor.deselect_all_points(); + responses.add(OverlaysMessage::Draw); + PathToolFsmState::Ready + } + (_, PathToolMessage::SelectedPointXChanged { new_x }) => { + if let Some(&SingleSelectedPoint { coordinates, id, layer, .. }) = tool_data.selection_status.as_one() { + shape_editor.reposition_control_point(&id, &document.network_interface, DVec2::new(new_x, coordinates.y), layer, responses); + } + PathToolFsmState::Ready + } + (_, PathToolMessage::SelectedPointYChanged { new_y }) => { + if let Some(&SingleSelectedPoint { coordinates, id, layer, .. }) = tool_data.selection_status.as_one() { + shape_editor.reposition_control_point(&id, &document.network_interface, DVec2::new(coordinates.x, new_y), layer, responses); + } + PathToolFsmState::Ready + } + (_, PathToolMessage::SelectedPointUpdated) => { + let colinear = shape_editor.selected_manipulator_angles(&document.network_interface); + tool_data.dragging_state = DraggingState { + point_select_state: shape_editor.get_dragging_state(&document.network_interface), + colinear, + }; + tool_data.update_selection_status(shape_editor, document); + self + } + (_, PathToolMessage::ManipulatorMakeHandlesColinear) => { + responses.add(DocumentMessage::StartTransaction); + shape_editor.convert_selected_manipulators_to_colinear_handles(responses, document); + responses.add(DocumentMessage::EndTransaction); + responses.add(PathToolMessage::SelectionChanged); + PathToolFsmState::Ready + } + (_, PathToolMessage::ManipulatorMakeHandlesFree) => { + responses.add(DocumentMessage::StartTransaction); + shape_editor.disable_colinear_handles_state_on_selected(&document.network_interface, responses); + responses.add(DocumentMessage::EndTransaction); + PathToolFsmState::Ready + } + (_, _) => PathToolFsmState::Ready, + } + } + + fn update_hints(&self, _responses: &mut VecDeque) { + // Moved logic to update_dynamic_hints + } + + fn update_cursor(&self, responses: &mut VecDeque) { + responses.add(FrontendMessage::UpdateMouseCursor { cursor: MouseCursorIcon::Default }); + } +} + +#[derive(Debug, PartialEq, Default)] +enum SelectionStatus { + #[default] + None, + One(SingleSelectedPoint), + Multiple(MultipleSelectedPoints), +} + +impl SelectionStatus { + fn as_one(&self) -> Option<&SingleSelectedPoint> { + match self { + SelectionStatus::One(one) => Some(one), + _ => None, + } + } + + fn angle(&self) -> Option { + match self { + Self::None => None, + Self::One(one) => Some(one.manipulator_angle), + Self::Multiple(one) => Some(one.manipulator_angle), + } + } +} + +#[derive(Debug, PartialEq)] +struct MultipleSelectedPoints { + manipulator_angle: ManipulatorAngle, +} + +#[derive(Debug, PartialEq)] +struct SingleSelectedPoint { + coordinates: DVec2, + id: ManipulatorPointId, + layer: LayerNodeIdentifier, + manipulator_angle: ManipulatorAngle, +} + +/// Sets the cumulative description of the selected points: if `None` are selected, if `One` is selected, or if `Multiple` are selected. +/// Applies to any selected points, whether they are anchors or handles; and whether they are from a single shape or across multiple shapes. +fn get_selection_status(network_interface: &NodeNetworkInterface, shape_state: &mut ShapeState) -> SelectionStatus { + let mut selection_layers = shape_state.selected_shape_state.iter().map(|(k, v)| (*k, v.selected_points_count())); + let total_selected_points = selection_layers.clone().map(|(_, v)| v).sum::(); + + // Check to see if only one manipulator group in a single shape is selected + if total_selected_points == 1 { + let Some(layer) = selection_layers.find(|(_, v)| *v > 0).map(|(k, _)| k) else { + return SelectionStatus::None; + }; + let Some(vector_data) = network_interface.compute_modified_vector(layer) else { + return SelectionStatus::None; + }; + let Some(&point) = shape_state.selected_points().next() else { + return SelectionStatus::None; + }; + let Some(local_position) = point.get_position(&vector_data) else { + return SelectionStatus::None; + }; + + let coordinates = network_interface.document_metadata().transform_to_document(layer).transform_point2(local_position); + let manipulator_angle = if vector_data.colinear(point) { ManipulatorAngle::Colinear } else { ManipulatorAngle::Free }; + + return SelectionStatus::One(SingleSelectedPoint { + coordinates, + layer, + id: point, + manipulator_angle, + }); + }; + + // Check to see if multiple manipulator groups are selected + if total_selected_points > 1 { + return SelectionStatus::Multiple(MultipleSelectedPoints { + manipulator_angle: shape_state.selected_manipulator_angles(network_interface), + }); + } + + SelectionStatus::None +} + +fn calculate_lock_angle( + tool_data: &mut PathToolData, + shape_state: &mut ShapeState, + responses: &mut VecDeque, + document: &DocumentMessageHandler, + vector_data: &VectorData, + handle_id: ManipulatorPointId, + tangent_to_neighboring_tangents: bool, +) -> Option { + let anchor = handle_id.get_anchor(vector_data)?; + let anchor_position = vector_data.point_domain.position_from_id(anchor); + let current_segment = handle_id.get_segment(); + let points_connected = vector_data.connected_count(anchor); + + let (anchor_position, segment) = anchor_position.zip(current_segment)?; + if points_connected == 1 { + calculate_segment_angle(anchor, segment, vector_data, false) + } else { + let opposite_handle = handle_id + .get_handle_pair(vector_data) + .iter() + .flatten() + .find(|&h| h.to_manipulator_point() != handle_id) + .copied() + .map(|h| h.to_manipulator_point()); + let opposite_handle_position = opposite_handle.and_then(|h| h.get_position(vector_data)).filter(|pos| (pos - anchor_position).length() > 1e-6); + + if let Some(opposite_pos) = opposite_handle_position { + if !vector_data.colinear_manipulators.iter().flatten().map(|h| h.to_manipulator_point()).any(|h| h == handle_id) { + shape_state.convert_selected_manipulators_to_colinear_handles(responses, document); + tool_data.temporary_colinear_handles = true; + } + Some(-(opposite_pos - anchor_position).angle_to(DVec2::X)) + } else { + let angle_1 = vector_data + .adjacent_segment(&handle_id) + .and_then(|(_, adjacent_segment)| calculate_segment_angle(anchor, adjacent_segment, vector_data, false)); + + let angle_2 = calculate_segment_angle(anchor, segment, vector_data, false); + + match (angle_1, angle_2) { + (Some(angle_1), Some(angle_2)) => { + let angle = Some((angle_1 + angle_2) / 2.); + if tangent_to_neighboring_tangents { + angle.map(|angle| angle + std::f64::consts::FRAC_PI_2) + } else { + angle + } + } + (Some(angle_1), None) => Some(angle_1), + (None, Some(angle_2)) => Some(angle_2), + (None, None) => None, + } + } + } +} + +fn check_handle_over_adjacent_anchor(handle_id: ManipulatorPointId, vector_data: &VectorData) -> Option { + let (anchor, handle_position) = handle_id.get_anchor(vector_data).zip(handle_id.get_position(vector_data))?; + + let check_if_close = |point_id: &PointId| { + let Some(anchor_position) = vector_data.point_domain.position_from_id(*point_id) else { + return false; + }; + (anchor_position - handle_position).length() < 10. + }; + + vector_data.connected_points(anchor).find(check_if_close) +} +fn calculate_adjacent_anchor_tangent( + currently_dragged_handle: ManipulatorPointId, + anchor: Option, + adjacent_anchor: Option, + vector_data: &VectorData, +) -> (Option, Option) { + // Early return if no anchor or no adjacent anchors + + let Some((dragged_handle_anchor, adjacent_anchor)) = anchor.zip(adjacent_anchor) else { + return (None, None); + }; + let adjacent_anchor_position = vector_data.point_domain.position_from_id(adjacent_anchor); + + let handles: Vec<_> = vector_data.all_connected(adjacent_anchor).filter(|handle| handle.length(vector_data) > 1e-6).collect(); + + match handles.len() { + 0 => { + // Find non-shared segments + let non_shared_segment: Vec<_> = vector_data + .segment_bezier_iter() + .filter_map(|(segment_id, _, start, end)| { + let touches_adjacent = start == adjacent_anchor || end == adjacent_anchor; + let shares_with_dragged = start == dragged_handle_anchor || end == dragged_handle_anchor; + + if touches_adjacent && !shares_with_dragged { Some(segment_id) } else { None } + }) + .collect(); + + match non_shared_segment.first() { + Some(&segment) => { + let angle = calculate_segment_angle(adjacent_anchor, segment, vector_data, true); + (angle, adjacent_anchor_position) + } + None => (None, None), + } + } + + 1 => { + let segment = handles[0].segment; + let angle = calculate_segment_angle(adjacent_anchor, segment, vector_data, true); + (angle, adjacent_anchor_position) + } + + 2 => { + // Use the angle formed by the handle of the shared segment relative to its associated anchor point. + let Some(shared_segment_handle) = handles + .iter() + .find(|handle| handle.opposite().to_manipulator_point() == currently_dragged_handle) + .map(|handle| handle.to_manipulator_point()) + else { + return (None, None); + }; + + let angle = shared_segment_handle + .get_position(vector_data) + .zip(adjacent_anchor_position) + .map(|(handle, anchor)| -(handle - anchor).angle_to(DVec2::X)); + + (angle, adjacent_anchor_position) + } + + _ => (None, None), + } +} + +fn update_dynamic_hints( + state: PathToolFsmState, + responses: &mut VecDeque, + shape_editor: &mut ShapeState, + document: &DocumentMessageHandler, + tool_data: &PathToolData, + tool_options: &PathToolOptions, +) { + // Condinting based on currently selected segment if it has any one g1 continuous handle + + let hint_data = match state { + PathToolFsmState::Ready => { + // Show point sliding hints only when there is an anchor with colinear handles selected + let single_anchor_selected = shape_editor.selected_points().count() == 1 && shape_editor.selected_points().any(|point| matches!(point, ManipulatorPointId::Anchor(_))); + let at_least_one_anchor_selected = shape_editor.selected_points().any(|point| matches!(point, ManipulatorPointId::Anchor(_))); + let at_least_one_point_selected = shape_editor.selected_points().count() >= 1; + + let mut single_colinear_anchor_selected = false; + if single_anchor_selected { + if let (Some(anchor), Some(layer)) = ( + shape_editor.selected_points().next(), + document.network_interface.selected_nodes().selected_layers(document.metadata()).next(), + ) { + if let Some(vector_data) = document.network_interface.compute_modified_vector(layer) { + single_colinear_anchor_selected = vector_data.colinear(*anchor) + } + } + } + + let mut drag_selected_hints = vec![HintInfo::mouse(MouseMotion::LmbDrag, "Drag Selected")]; + let mut delete_selected_hints = vec![HintInfo::keys([Key::Delete], "Delete Selected")]; + + if at_least_one_anchor_selected { + delete_selected_hints.push(HintInfo::keys([Key::Accel], "No Dissolve").prepend_plus()); + delete_selected_hints.push(HintInfo::keys([Key::Shift], "Cut Anchor").prepend_plus()); + } + + if single_colinear_anchor_selected { + drag_selected_hints.push(HintInfo::multi_keys([[Key::Control], [Key::Shift]], "Slide").prepend_plus()); + } + + let mut hint_data = match (tool_data.segment.is_some(), tool_options.path_editing_mode.segment_editing_mode) { + (true, true) => { + vec![ + HintGroup(vec![HintInfo::mouse(MouseMotion::Lmb, "Select Segment"), HintInfo::keys([Key::Shift], "Extend").prepend_plus()]), + HintGroup(vec![HintInfo::keys_and_mouse([Key::KeyA], MouseMotion::Lmb, "Mold Segment")]), + ] + } + (true, false) => { + vec![ + HintGroup(vec![HintInfo::mouse(MouseMotion::Lmb, "Insert Point on Segment")]), + HintGroup(vec![HintInfo::mouse(MouseMotion::LmbDrag, "Mold Segment")]), + HintGroup(vec![HintInfo::keys_and_mouse([Key::Alt], MouseMotion::Lmb, "Delete Segment")]), + ] + } + (false, _) => { + vec![ + HintGroup(vec![HintInfo::mouse(MouseMotion::Lmb, "Select Point"), HintInfo::keys([Key::Shift], "Extend").prepend_plus()]), + HintGroup(vec![HintInfo::mouse(MouseMotion::LmbDrag, "Select Area"), HintInfo::keys([Key::Control], "Lasso").prepend_plus()]), + ] + } + }; + + if at_least_one_anchor_selected { + // TODO: Dynamically show either "Smooth" or "Sharp" based on the current state + hint_data.push(HintGroup(vec![ + HintInfo::mouse(MouseMotion::LmbDouble, "Convert Anchor Point"), + HintInfo::keys_and_mouse([Key::Alt], MouseMotion::Lmb, "To Sharp"), + HintInfo::keys_and_mouse([Key::Alt], MouseMotion::LmbDrag, "To Smooth"), + ])); + } + + if at_least_one_point_selected { + let mut groups = vec![ + HintGroup(drag_selected_hints), + HintGroup(vec![HintInfo::multi_keys([[Key::KeyG], [Key::KeyR], [Key::KeyS]], "Grab/Rotate/Scale Selected")]), + HintGroup(vec![HintInfo::arrow_keys("Nudge Selected"), HintInfo::keys([Key::Shift], "10x").prepend_plus()]), + HintGroup(delete_selected_hints), + ]; + hint_data.append(&mut groups); + } + + HintData(hint_data) + } + PathToolFsmState::Dragging(dragging_state) => { + let colinear = dragging_state.colinear; + let mut dragging_hint_data = HintData(Vec::new()); + dragging_hint_data + .0 + .push(HintGroup(vec![HintInfo::mouse(MouseMotion::Rmb, ""), HintInfo::keys([Key::Escape], "Cancel").prepend_slash()])); + + let drag_anchor = HintInfo::keys([Key::Space], "Drag Anchor"); + let toggle_group = match dragging_state.point_select_state { + PointSelectState::HandleNoPair | PointSelectState::HandleWithPair => { + let mut hints = vec![HintInfo::keys([Key::Tab], "Swap Dragged Handle")]; + hints.push(HintInfo::keys( + [Key::KeyC], + if colinear == ManipulatorAngle::Colinear { + "Break Colinear Handles" + } else { + "Make Handles Colinear" + }, + )); + hints + } + PointSelectState::Anchor => Vec::new(), + }; + let hold_group = match dragging_state.point_select_state { + PointSelectState::HandleNoPair => { + let mut hints = vec![]; + if colinear != ManipulatorAngle::Free { + hints.push(HintInfo::keys([Key::Alt], "Equidistant Handles")); + } + hints.push(HintInfo::keys([Key::Shift], "15° Increments")); + hints.push(HintInfo::keys([Key::Control], "Lock Angle")); + hints.push(drag_anchor); + hints + } + PointSelectState::HandleWithPair => { + let mut hints = vec![]; + if colinear != ManipulatorAngle::Free { + hints.push(HintInfo::keys([Key::Alt], "Equidistant Handles")); + } + hints.push(HintInfo::keys([Key::Shift], "15° Increments")); + hints.push(HintInfo::keys([Key::Control], "Lock Angle")); + hints.push(drag_anchor); + hints + } + PointSelectState::Anchor => Vec::new(), + }; + + if !toggle_group.is_empty() { + dragging_hint_data.0.push(HintGroup(toggle_group)); + } + + if !hold_group.is_empty() { + dragging_hint_data.0.push(HintGroup(hold_group)); + } + + dragging_hint_data + } + PathToolFsmState::Drawing { .. } => HintData(vec![ + HintGroup(vec![HintInfo::mouse(MouseMotion::Rmb, ""), HintInfo::keys([Key::Escape], "Cancel").prepend_slash()]), + HintGroup(vec![ + HintInfo::mouse(MouseMotion::LmbDrag, "Select Area"), + HintInfo::keys([Key::Shift], "Extend").prepend_plus(), + HintInfo::keys([Key::Alt], "Subtract").prepend_plus(), + ]), + ]), + PathToolFsmState::MoldingSegment => { + let mut has_colinear_anchors = false; + + if let Some(segment) = &tool_data.segment { + let handle1 = HandleId::primary(segment.segment()); + let handle2 = HandleId::end(segment.segment()); + + if let Some(vector_data) = document.network_interface.compute_modified_vector(segment.layer()) { + let other_handle1 = vector_data.other_colinear_handle(handle1); + let other_handle2 = vector_data.other_colinear_handle(handle2); + if other_handle1.is_some() || other_handle2.is_some() { + has_colinear_anchors = true; + } + }; + } + + let handles_stored = if let Some(other_handles) = tool_data.temporary_adjacent_handles_while_molding { + other_handles[0].is_some() || other_handles[1].is_some() + } else { + false + }; + + let molding_disable_possible = has_colinear_anchors || handles_stored; + + let mut molding_hints = vec![HintGroup(vec![HintInfo::mouse(MouseMotion::Rmb, ""), HintInfo::keys([Key::Escape], "Cancel").prepend_slash()])]; + + if molding_disable_possible { + molding_hints.push(HintGroup(vec![HintInfo::keys([Key::Alt], "Break Colinear Handles")])); + } + + HintData(molding_hints) + } + PathToolFsmState::SlidingPoint => HintData(vec![HintGroup(vec![HintInfo::mouse(MouseMotion::Rmb, ""), HintInfo::keys([Key::Escape], "Cancel").prepend_slash()])]), + }; + responses.add(FrontendMessage::UpdateInputHints { hint_data }); +} diff --git a/editor/src/messages/tool/tool_messages/pen_tool.rs b/editor/src/messages/tool/tool_messages/pen_tool.rs new file mode 100644 index 0000000000000000000000000000000000000000..14f95a48f7f8a52de0d65f959d751ba8da0d8f41 --- /dev/null +++ b/editor/src/messages/tool/tool_messages/pen_tool.rs @@ -0,0 +1,2234 @@ +use super::tool_prelude::*; +use crate::consts::{COLOR_OVERLAY_BLUE, DEFAULT_STROKE_WIDTH, HIDE_HANDLE_DISTANCE, LINE_ROTATE_SNAP_ANGLE, SEGMENT_OVERLAY_SIZE}; +use crate::messages::input_mapper::utility_types::input_mouse::MouseKeys; +use crate::messages::portfolio::document::node_graph::document_node_definitions::resolve_document_node_type; +use crate::messages::portfolio::document::overlays::utility_functions::path_overlays; +use crate::messages::portfolio::document::overlays::utility_types::{DrawHandles, OverlayContext}; +use crate::messages::portfolio::document::utility_types::document_metadata::LayerNodeIdentifier; +use crate::messages::tool::common_functionality::auto_panning::AutoPanning; +use crate::messages::tool::common_functionality::color_selector::{ToolColorOptions, ToolColorType}; +use crate::messages::tool::common_functionality::graph_modification_utils::{self, merge_layers}; +use crate::messages::tool::common_functionality::shape_editor::ShapeState; +use crate::messages::tool::common_functionality::snapping::{SnapCache, SnapCandidatePoint, SnapConstraint, SnapData, SnapManager, SnapTypeConfiguration}; +use crate::messages::tool::common_functionality::utility_functions::{calculate_segment_angle, closest_point, should_extend}; +use bezier_rs::{Bezier, BezierHandles}; +use graph_craft::document::NodeId; +use graphene_std::Color; +use graphene_std::vector::{HandleId, ManipulatorPointId, NoHashBuilder, SegmentId, StrokeId, VectorData}; +use graphene_std::vector::{PointId, VectorModificationType}; + +#[derive(Default)] +pub struct PenTool { + fsm_state: PenToolFsmState, + tool_data: PenToolData, + options: PenOptions, +} + +pub struct PenOptions { + line_weight: f64, + fill: ToolColorOptions, + stroke: ToolColorOptions, + pen_overlay_mode: PenOverlayMode, +} + +impl Default for PenOptions { + fn default() -> Self { + Self { + line_weight: DEFAULT_STROKE_WIDTH, + fill: ToolColorOptions::new_secondary(), + stroke: ToolColorOptions::new_primary(), + pen_overlay_mode: PenOverlayMode::FrontierHandles, + } + } +} + +#[impl_message(Message, ToolMessage, Pen)] +#[derive(PartialEq, Clone, Debug, serde::Serialize, serde::Deserialize, specta::Type)] +pub enum PenToolMessage { + // Standard messages + Abort, + SelectionChanged, + WorkingColorChanged, + Overlays(OverlayContext), + + // Tool-specific messages + + // It is necessary to defer this until the transform of the layer can be accurately computed (quite hacky) + AddPointLayerPosition { + layer: LayerNodeIdentifier, + viewport: DVec2, + }, + Confirm, + DragStart { + append_to_selected: Key, + }, + DragStop, + PointerMove { + snap_angle: Key, + break_handle: Key, + lock_angle: Key, + colinear: Key, + move_anchor_with_handles: Key, + }, + PointerOutsideViewport { + snap_angle: Key, + break_handle: Key, + lock_angle: Key, + colinear: Key, + move_anchor_with_handles: Key, + }, + Redo, + Undo, + UpdateOptions(PenOptionsUpdate), + RecalculateLatestPointsPosition, + RemovePreviousHandle, + GRS { + grab: Key, + rotate: Key, + scale: Key, + }, + FinalPosition { + final_position: DVec2, + }, + SwapHandles, +} + +#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)] +enum PenToolFsmState { + #[default] + Ready, + DraggingHandle(HandleMode), + PlacingAnchor, + GRSHandle, +} + +#[derive(PartialEq, Eq, Hash, Copy, Clone, Debug, serde::Serialize, serde::Deserialize, specta::Type)] +pub enum PenOverlayMode { + AllHandles = 0, + FrontierHandles = 1, +} + +#[derive(PartialEq, Clone, Debug, serde::Serialize, serde::Deserialize, specta::Type)] +pub enum PenOptionsUpdate { + FillColor(Option), + FillColorType(ToolColorType), + LineWeight(f64), + StrokeColor(Option), + StrokeColorType(ToolColorType), + WorkingColors(Option, Option), + OverlayModeType(PenOverlayMode), +} + +impl ToolMetadata for PenTool { + fn icon_name(&self) -> String { + "VectorPenTool".into() + } + fn tooltip(&self) -> String { + "Pen Tool".into() + } + fn tool_type(&self) -> crate::messages::tool::utility_types::ToolType { + ToolType::Pen + } +} + +fn create_weight_widget(line_weight: f64) -> WidgetHolder { + NumberInput::new(Some(line_weight)) + .unit(" px") + .label("Weight") + .min(0.) + .max((1_u64 << f64::MANTISSA_DIGITS) as f64) + .on_update(|number_input: &NumberInput| PenToolMessage::UpdateOptions(PenOptionsUpdate::LineWeight(number_input.value.unwrap())).into()) + .widget_holder() +} + +impl LayoutHolder for PenTool { + fn layout(&self) -> Layout { + let mut widgets = self.options.fill.create_widgets( + "Fill", + true, + |_| PenToolMessage::UpdateOptions(PenOptionsUpdate::FillColor(None)).into(), + |color_type: ToolColorType| WidgetCallback::new(move |_| PenToolMessage::UpdateOptions(PenOptionsUpdate::FillColorType(color_type.clone())).into()), + |color: &ColorInput| PenToolMessage::UpdateOptions(PenOptionsUpdate::FillColor(color.value.as_solid().map(|color| color.to_linear_srgb()))).into(), + ); + + widgets.push(Separator::new(SeparatorType::Unrelated).widget_holder()); + + widgets.append(&mut self.options.stroke.create_widgets( + "Stroke", + true, + |_| PenToolMessage::UpdateOptions(PenOptionsUpdate::StrokeColor(None)).into(), + |color_type: ToolColorType| WidgetCallback::new(move |_| PenToolMessage::UpdateOptions(PenOptionsUpdate::StrokeColorType(color_type.clone())).into()), + |color: &ColorInput| PenToolMessage::UpdateOptions(PenOptionsUpdate::StrokeColor(color.value.as_solid().map(|color| color.to_linear_srgb()))).into(), + )); + + widgets.push(Separator::new(SeparatorType::Unrelated).widget_holder()); + + widgets.push(create_weight_widget(self.options.line_weight)); + + widgets.push(Separator::new(SeparatorType::Unrelated).widget_holder()); + + widgets.push( + RadioInput::new(vec![ + RadioEntryData::new("all") + .icon("HandleVisibilityAll") + .tooltip("Show all handles regardless of selection") + .on_update(move |_| PenToolMessage::UpdateOptions(PenOptionsUpdate::OverlayModeType(PenOverlayMode::AllHandles)).into()), + RadioEntryData::new("frontier") + .icon("HandleVisibilityFrontier") + .tooltip("Show only handles at the frontiers of the segments connected to selected points") + .on_update(move |_| PenToolMessage::UpdateOptions(PenOptionsUpdate::OverlayModeType(PenOverlayMode::FrontierHandles)).into()), + ]) + .selected_index(Some(self.options.pen_overlay_mode as u32)) + .widget_holder(), + ); + + Layout::WidgetLayout(WidgetLayout::new(vec![LayoutGroup::Row { widgets }])) + } +} + +impl<'a> MessageHandler> for PenTool { + fn process_message(&mut self, message: ToolMessage, responses: &mut VecDeque, tool_data: &mut ToolActionHandlerData<'a>) { + let ToolMessage::Pen(PenToolMessage::UpdateOptions(action)) = message else { + self.fsm_state.process_event(message, &mut self.tool_data, tool_data, &self.options, responses, true); + return; + }; + + match action { + PenOptionsUpdate::OverlayModeType(overlay_mode_type) => { + self.options.pen_overlay_mode = overlay_mode_type; + responses.add(OverlaysMessage::Draw); + } + PenOptionsUpdate::LineWeight(line_weight) => self.options.line_weight = line_weight, + PenOptionsUpdate::FillColor(color) => { + self.options.fill.custom_color = color; + self.options.fill.color_type = ToolColorType::Custom; + } + PenOptionsUpdate::FillColorType(color_type) => self.options.fill.color_type = color_type, + PenOptionsUpdate::StrokeColor(color) => { + self.options.stroke.custom_color = color; + self.options.stroke.color_type = ToolColorType::Custom; + } + PenOptionsUpdate::StrokeColorType(color_type) => self.options.stroke.color_type = color_type, + PenOptionsUpdate::WorkingColors(primary, secondary) => { + self.options.stroke.primary_working_color = primary; + self.options.stroke.secondary_working_color = secondary; + self.options.fill.primary_working_color = primary; + self.options.fill.secondary_working_color = secondary; + } + } + + self.send_layout(responses, LayoutTarget::ToolOptions); + } + + fn actions(&self) -> ActionList { + match self.fsm_state { + PenToolFsmState::Ready | PenToolFsmState::GRSHandle => actions!(PenToolMessageDiscriminant; + Undo, + DragStart, + DragStop, + Confirm, + Abort, + PointerMove, + FinalPosition + ), + PenToolFsmState::DraggingHandle(_) | PenToolFsmState::PlacingAnchor => actions!(PenToolMessageDiscriminant; + DragStart, + DragStop, + PointerMove, + Confirm, + Abort, + RemovePreviousHandle, + GRS, + SwapHandles + ), + } + } +} + +impl ToolTransition for PenTool { + fn event_to_message_map(&self) -> EventToMessageMap { + EventToMessageMap { + tool_abort: Some(PenToolMessage::Abort.into()), + selection_changed: Some(PenToolMessage::SelectionChanged.into()), + working_color_changed: Some(PenToolMessage::WorkingColorChanged.into()), + overlay_provider: Some(|overlay_context| PenToolMessage::Overlays(overlay_context).into()), + ..Default::default() + } + } +} +#[derive(Clone, Debug, Default)] +struct ModifierState { + snap_angle: bool, + lock_angle: bool, + break_handle: bool, + colinear: bool, + move_anchor_with_handles: bool, +} +#[derive(Clone, Debug)] +struct LastPoint { + id: PointId, + pos: DVec2, + in_segment: Option, + handle_start: DVec2, +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)] +enum HandleMode { + /// Pressing 'C' breaks colinearity + Free, + /// Pressing 'Alt': Handle length is locked + #[default] + ColinearLocked, + /// Pressing 'Alt': Handles are equidistant + ColinearEquidistant, +} + +/// The type of handle which is dragged by the cursor (under the cursor). +/// +/// ![Terminology](https://files.keavon.com/-/EachNotedLovebird/capture.png) +#[derive(Clone, Debug, Default, PartialEq, Copy)] +enum TargetHandle { + #[default] + None, + /// This is the handle being dragged and represents the out handle of the next preview segment that will be placed + /// after the current preview segment is finalized. Its position is stored in `tool_data.next_handle_start`. + /// + /// Pressing Tab swaps to the opposite handle type. The swapped handle can be either [`ManipulatorPointId::PreviewInHandle`] + /// or, in the case of a bent segment, [`ManipulatorPointId::EndHandle`] or [`ManipulatorPointId::PrimaryHandle`]. + /// + /// When closing a path, the handle being dragged becomes the end handle of the currently placed anchor. + /// + /// ![Terminology](https://files.keavon.com/-/EachNotedLovebird/capture.png) + FuturePreviewOutHandle, + /// The opposite handle that is drawn after placing an anchor and starting to drag the "next handle start", + /// continuing until Tab is pressed to swap the handles. + /// + /// ![Terminology](https://files.keavon.com/-/EachNotedLovebird/capture.png) + PreviewInHandle, + /// This is the primary handle of the segment from whose endpoint a new handle is being drawn. + /// When closing the path, the handle being dragged will be the [`TargetHandle::PreviewInHandle`] (see its documentation); + /// otherwise, it will be [`TargetHandle::FuturePreviewOutHandle`]. + /// + /// If a handle is dragged from a different endpoint within the same layer, the opposite handle will be + /// `ManipulatorPoint::Primary` if that point is the starting point of its path. + /// + /// ![Terminology](https://files.keavon.com/-/EachNotedLovebird/capture.png) + PriorOutHandle(SegmentId), + /// This is the end handle of the segment from whose endpoint a new handle is being drawn (same cases apply + /// as mentioned in [`TargetHandle::PriorOutHandle`]). If a handle is dragged from a different endpoint within the same + /// layer, the opposite handle will be `ManipulatorPoint::EndHandle` if that point is the end point of its path. + /// + /// ![Terminology](https://files.keavon.com/-/EachNotedLovebird/capture.png) + PriorInHandle(SegmentId), +} + +#[derive(Clone, Debug, Default)] +struct PenToolData { + snap_manager: SnapManager, + latest_points: Vec, + point_index: usize, + handle_end: Option, + next_point: DVec2, + next_handle_start: DVec2, + + g1_continuous: bool, + + angle: f64, + auto_panning: AutoPanning, + modifiers: ModifierState, + + buffering_merged_vector: bool, + + previous_handle_start_pos: DVec2, + previous_handle_end_pos: Option, + toggle_colinear_debounce: bool, + colinear: bool, + alt_pressed: bool, + space_pressed: bool, + /// Tracks whether to switch from `HandleMode::ColinearEquidistant` to `HandleMode::Free` + /// after releasing Ctrl, specifically when Ctrl was held before the handle was dragged from the anchor. + switch_to_free_on_ctrl_release: bool, + /// To prevent showing cursor when `KeyC` is pressed when handles are swapped. + handle_swapped: bool, + /// Prevents conflicts when the handle's angle is already locked and it passes near the anchor, + /// avoiding unintended direction changes. Specifically handles the case where a handle is being dragged, + /// and Ctrl is pressed near the anchor to make it colinear with its opposite handle. + angle_locked: bool, + path_closed: bool, + + handle_mode: HandleMode, + prior_segment_layer: Option, + current_layer: Option, + prior_segment_endpoint: Option, + prior_segment: Option, + + /// For vector meshes, storing all the previous segments the last anchor point was connected to + prior_segments: Option>, + handle_type: TargetHandle, + handle_start_offset: Option, + handle_end_offset: Option, + + snap_cache: SnapCache, +} + +impl PenToolData { + fn latest_point(&self) -> Option<&LastPoint> { + self.latest_points.get(self.point_index) + } + + fn latest_point_mut(&mut self) -> Option<&mut LastPoint> { + self.latest_points.get_mut(self.point_index) + } + + fn add_point(&mut self, point: LastPoint) { + self.point_index = (self.point_index + 1).min(self.latest_points.len()); + self.latest_points.truncate(self.point_index); + self.latest_points.push(point); + } + + fn cleanup(&mut self, responses: &mut VecDeque) { + self.handle_end = None; + self.latest_points.clear(); + self.point_index = 0; + self.snap_manager.cleanup(responses); + } + + /// Check whether target handle is primary, end, or `self.handle_end` + fn check_end_handle_type(&self, vector_data: &VectorData) -> TargetHandle { + match (self.handle_end, self.prior_segment_endpoint, self.prior_segment, self.path_closed) { + (Some(_), _, _, false) => TargetHandle::PreviewInHandle, + (None, Some(point), Some(segment), false) | (Some(_), Some(point), Some(segment), true) => { + if vector_data.segment_start_from_id(segment) == Some(point) { + TargetHandle::PriorOutHandle(segment) + } else { + TargetHandle::PriorInHandle(segment) + } + } + _ => TargetHandle::None, + } + } + + fn check_grs_end_handle(&self, vector_data: &VectorData) -> TargetHandle { + let Some(point) = self.latest_point().map(|point| point.id) else { return TargetHandle::None }; + let Some(segment) = self.prior_segment else { return TargetHandle::None }; + + if vector_data.segment_start_from_id(segment) == Some(point) { + TargetHandle::PriorOutHandle(segment) + } else { + TargetHandle::PriorInHandle(segment) + } + } + + fn get_opposite_handle_type(&self, handle_type: TargetHandle, vector_data: &VectorData) -> TargetHandle { + match handle_type { + TargetHandle::FuturePreviewOutHandle => self.check_end_handle_type(vector_data), + TargetHandle::PreviewInHandle => match (self.path_closed, self.prior_segment_endpoint, self.prior_segment) { + (true, Some(point), Some(segment)) => { + if vector_data.segment_start_from_id(segment) == Some(point) { + TargetHandle::PriorOutHandle(segment) + } else { + TargetHandle::PriorInHandle(segment) + } + } + (false, _, _) => TargetHandle::FuturePreviewOutHandle, + _ => TargetHandle::None, + }, + _ => { + if self.path_closed { + TargetHandle::PreviewInHandle + } else { + TargetHandle::FuturePreviewOutHandle + } + } + } + } + + fn update_handle_type(&mut self, handle_type: TargetHandle) { + self.handle_type = handle_type; + } + + fn update_target_handle_pos(&mut self, handle_type: TargetHandle, anchor_pos: DVec2, responses: &mut VecDeque, delta: DVec2, layer: LayerNodeIdentifier) { + match handle_type { + TargetHandle::FuturePreviewOutHandle => { + self.next_handle_start = delta; + } + TargetHandle::PreviewInHandle => { + if let Some(handle) = self.handle_end.as_mut() { + *handle = delta; + } + } + TargetHandle::PriorInHandle(segment) => { + let relative_position = delta - anchor_pos; + let modification_type = VectorModificationType::SetEndHandle { segment, relative_position }; + responses.add(GraphOperationMessage::Vector { layer, modification_type }); + } + TargetHandle::PriorOutHandle(segment) => { + let relative_position = delta - anchor_pos; + let modification_type = VectorModificationType::SetPrimaryHandle { segment, relative_position }; + responses.add(GraphOperationMessage::Vector { layer, modification_type }); + } + TargetHandle::None => {} + } + } + + fn target_handle_position(&self, handle_type: TargetHandle, vector_data: &VectorData) -> Option { + match handle_type { + TargetHandle::PriorOutHandle(segment) => ManipulatorPointId::PrimaryHandle(segment).get_position(vector_data), + TargetHandle::PriorInHandle(segment) => ManipulatorPointId::EndHandle(segment).get_position(vector_data), + TargetHandle::PreviewInHandle => self.handle_end, + TargetHandle::FuturePreviewOutHandle => Some(self.next_handle_start), + TargetHandle::None => None, + } + } + + /// Remove the handles selected when swapping handles + fn cleanup_target_selections(&self, shape_editor: &mut ShapeState, layer: Option, document: &DocumentMessageHandler, responses: &mut VecDeque) { + let Some(shape_state) = layer.and_then(|layer| shape_editor.selected_shape_state.get_mut(&layer)) else { + return; + }; + + let Some(vector_data) = layer.and_then(|layer| document.network_interface.compute_modified_vector(layer)) else { + return; + }; + + match self.check_end_handle_type(&vector_data) { + TargetHandle::PriorInHandle(segment) => shape_state.deselect_point(ManipulatorPointId::EndHandle(segment)), + TargetHandle::PriorOutHandle(segment) => shape_state.deselect_point(ManipulatorPointId::PrimaryHandle(segment)), + _ => {} + } + responses.add(OverlaysMessage::Draw); + } + + /// Selects the handle which is currently dragged by the user. + fn add_target_selections(&self, shape_editor: &mut ShapeState, layer: Option) { + let Some(shape_state) = layer.and_then(|layer| shape_editor.selected_shape_state.get_mut(&layer)) else { + return; + }; + + match self.handle_type { + TargetHandle::PriorInHandle(segment) => shape_state.select_point(ManipulatorPointId::EndHandle(segment)), + TargetHandle::PriorOutHandle(segment) => shape_state.select_point(ManipulatorPointId::PrimaryHandle(segment)), + _ => {} + } + } + + /// Check whether moving the initially created point. + fn moving_start_point(&self) -> bool { + self.latest_points.len() == 1 && self.latest_point().is_some_and(|point| point.pos == self.next_point) + } + + // When the vector data transform changes, the positions of the points must be recalculated. + fn recalculate_latest_points_position(&mut self, document: &DocumentMessageHandler) { + let selected_nodes = document.network_interface.selected_nodes(); + let mut selected_layers = selected_nodes.selected_layers(document.metadata()); + if let (Some(layer), None) = (selected_layers.next(), selected_layers.next()) { + let Some(vector_data) = document.network_interface.compute_modified_vector(layer) else { + return; + }; + for point in &mut self.latest_points { + let Some(pos) = vector_data.point_domain.position_from_id(point.id) else { + continue; + }; + point.pos = pos; + point.handle_start = point.pos; + } + } + } + + /// If the user places the anchor on top of the previous anchor, it becomes sharp and the outgoing handle may be dragged. + fn bend_from_previous_point( + &mut self, + snap_data: SnapData, + transform: DAffine2, + layer: LayerNodeIdentifier, + preferences: &PreferencesMessageHandler, + shape_editor: &mut ShapeState, + responses: &mut VecDeque, + ) { + self.g1_continuous = true; + let document = snap_data.document; + self.next_handle_start = self.next_point; + let vector_data = document.network_interface.compute_modified_vector(layer).unwrap(); + self.update_handle_type(TargetHandle::FuturePreviewOutHandle); + self.handle_mode = HandleMode::ColinearLocked; + + // Break the control + let Some((last_pos, id)) = self.latest_point().map(|point| (point.pos, point.id)) else { return }; + + let transform = document.metadata().document_to_viewport * transform; + let on_top = transform.transform_point2(self.next_point).distance_squared(transform.transform_point2(last_pos)) < crate::consts::SNAP_POINT_TOLERANCE.powi(2); + if on_top { + self.handle_end = None; + self.handle_mode = HandleMode::Free; + + self.store_clicked_endpoint(document, &transform, snap_data.input, preferences); + + if self.modifiers.lock_angle { + self.set_lock_angle(&vector_data, id, self.prior_segment); + let last_segment = self.prior_segment; + let Some(point) = self.latest_point_mut() else { return }; + point.in_segment = last_segment; + self.switch_to_free_on_ctrl_release = true; + return; + } + + if let Some(point) = self.latest_point_mut() { + point.in_segment = None; + } + } + + // Closing path + let closing_path_on_point = self.close_path_on_point(snap_data, &vector_data, document, preferences, id, &transform); + if !closing_path_on_point && preferences.vector_meshes { + // Attempt to find nearest segment and close path on segment by creating an anchor point on it + let tolerance = crate::consts::SNAP_POINT_TOLERANCE; + if let Some(closest_segment) = shape_editor.upper_closest_segment(&document.network_interface, transform.transform_point2(self.next_point), tolerance) { + let (point, _) = closest_segment.adjusted_insert(responses); + + self.update_handle_type(TargetHandle::PreviewInHandle); + self.handle_end_offset = None; + self.path_closed = true; + self.next_handle_start = self.next_point; + + self.prior_segment_endpoint = Some(point); + self.prior_segment_layer = Some(closest_segment.layer()); + self.prior_segments = None; + self.prior_segment = None; + + // Should also update the SnapCache here? + + self.handle_mode = HandleMode::Free; + if let (true, Some(prior_endpoint)) = (self.modifiers.lock_angle, self.prior_segment_endpoint) { + self.set_lock_angle(&vector_data, prior_endpoint, self.prior_segment); + self.switch_to_free_on_ctrl_release = true; + } + } + } + } + + fn close_path_on_point( + &mut self, + snap_data: SnapData, + vector_data: &VectorData, + document: &DocumentMessageHandler, + preferences: &PreferencesMessageHandler, + id: PointId, + transform: &DAffine2, + ) -> bool { + for id in vector_data.extendable_points(preferences.vector_meshes).filter(|&point| point != id) { + let Some(pos) = vector_data.point_domain.position_from_id(id) else { continue }; + let transformed_distance_between_squared = transform.transform_point2(pos).distance_squared(transform.transform_point2(self.next_point)); + let snap_point_tolerance_squared = crate::consts::SNAP_POINT_TOLERANCE.powi(2); + + if transformed_distance_between_squared < snap_point_tolerance_squared { + self.update_handle_type(TargetHandle::PreviewInHandle); + self.handle_end_offset = None; + self.path_closed = true; + self.next_handle_start = self.next_point; + self.store_clicked_endpoint(document, transform, snap_data.input, preferences); + self.handle_mode = HandleMode::Free; + if let (true, Some(prior_endpoint)) = (self.modifiers.lock_angle, self.prior_segment_endpoint) { + self.set_lock_angle(vector_data, prior_endpoint, self.prior_segment); + self.switch_to_free_on_ctrl_release = true; + } + return true; + } + } + false + } + + fn finish_placing_handle(&mut self, snap_data: SnapData, transform: DAffine2, preferences: &PreferencesMessageHandler, responses: &mut VecDeque) -> Option { + let document = snap_data.document; + let next_handle_start = self.next_handle_start; + let handle_start = self.latest_point()?.handle_start; + let mouse = snap_data.input.mouse.position; + self.handle_swapped = false; + self.handle_end_offset = None; + self.handle_start_offset = None; + let Some(handle_end) = self.handle_end else { + responses.add(DocumentMessage::EndTransaction); + self.handle_end = Some(next_handle_start); + self.place_anchor(snap_data, transform, mouse, preferences, responses); + self.latest_point_mut()?.handle_start = next_handle_start; + return None; + }; + let next_point = self.next_point; + self.place_anchor(snap_data, transform, mouse, preferences, responses); + let handles = [handle_start - self.latest_point()?.pos, handle_end - next_point].map(Some); + + // Get close path + let mut end = None; + let selected_nodes = document.network_interface.selected_nodes(); + let mut selected_layers = selected_nodes.selected_layers(document.metadata()); + let layer = selected_layers.next().filter(|_| selected_layers.next().is_none()).or(self.current_layer)?; + let vector_data = document.network_interface.compute_modified_vector(layer)?; + let start = self.latest_point()?.id; + let transform = document.metadata().document_to_viewport * transform; + for id in vector_data.extendable_points(preferences.vector_meshes).filter(|&point| point != start) { + let Some(pos) = vector_data.point_domain.position_from_id(id) else { continue }; + let transformed_distance_between_squared = transform.transform_point2(pos).distance_squared(transform.transform_point2(next_point)); + let snap_point_tolerance_squared = crate::consts::SNAP_POINT_TOLERANCE.powi(2); + if transformed_distance_between_squared < snap_point_tolerance_squared { + end = Some(id); + } + } + let close_subpath = end.is_some(); + + // Generate new point if not closing + let end = end.unwrap_or_else(|| { + let end = PointId::generate(); + let modification_type = VectorModificationType::InsertPoint { id: end, position: next_point }; + responses.add(GraphOperationMessage::Vector { layer, modification_type }); + + end + }); + + // Store the segment + let id = SegmentId::generate(); + if self.path_closed { + if let Some((handles, handle1_pos)) = match self.get_opposite_handle_type(TargetHandle::PreviewInHandle, &vector_data) { + TargetHandle::PriorOutHandle(segment) => { + let handles = [HandleId::end(id), HandleId::primary(segment)]; + let handle1_pos = handles[1].to_manipulator_point().get_position(&vector_data); + handle1_pos.map(|pos| (handles, pos)) + } + TargetHandle::PriorInHandle(segment) => { + let handles = [HandleId::end(id), HandleId::end(segment)]; + let handle1_pos = handles[1].to_manipulator_point().get_position(&vector_data); + handle1_pos.map(|pos| (handles, pos)) + } + _ => None, + } { + let angle = (handle_end - next_point).angle_to(handle1_pos - next_point); + let pi = std::f64::consts::PI; + let colinear = (angle - pi).abs() < 1e-6 || (angle + pi).abs() < 1e-6; + responses.add(GraphOperationMessage::Vector { + layer, + modification_type: VectorModificationType::SetG1Continuous { handles, enabled: colinear }, + }); + self.cleanup(responses); + } + } + + self.prior_segment = Some(id); + + let points = [start, end]; + let modification_type = VectorModificationType::InsertSegment { id, points, handles }; + responses.add(GraphOperationMessage::Vector { layer, modification_type }); + + // Mirror + if let Some((last_segment, last_point)) = self.latest_point().and_then(|point| point.in_segment).zip(self.latest_point()) { + let end = vector_data.segment_end_from_id(last_segment) == Some(last_point.id); + let handles = if end { + [HandleId::end(last_segment), HandleId::primary(id)] + } else { + [HandleId::primary(last_segment), HandleId::primary(id)] + }; + + if let Some(h1) = handles[0].to_manipulator_point().get_position(&vector_data) { + let angle = (h1 - last_point.pos).angle_to(last_point.handle_start - last_point.pos); + let pi = std::f64::consts::PI; + let colinear = (angle - pi).abs() < 1e-6 || (angle + pi).abs() < 1e-6; + responses.add(GraphOperationMessage::Vector { + layer, + modification_type: VectorModificationType::SetG1Continuous { handles, enabled: colinear }, + }); + } + } + if !close_subpath { + self.add_point(LastPoint { + id: end, + pos: next_point, + in_segment: self.g1_continuous.then_some(id), + handle_start: next_handle_start, + }); + } + self.path_closed = false; + self.prior_segment_endpoint = None; + responses.add(DocumentMessage::EndTransaction); + Some(if close_subpath { PenToolFsmState::Ready } else { PenToolFsmState::PlacingAnchor }) + } + + #[allow(clippy::too_many_arguments)] + /// Calculates snap position delta while moving anchor and its handles. + fn space_anchor_handle_snap( + &mut self, + viewport_to_document: &DAffine2, + transform: &DAffine2, + snap_data: &SnapData<'_>, + mouse: &DVec2, + vector_data: &VectorData, + input: &InputPreprocessorMessageHandler, + ) -> Option { + let reference_handle = if self.path_closed { TargetHandle::PreviewInHandle } else { TargetHandle::FuturePreviewOutHandle }; + let end_handle = self.get_opposite_handle_type(reference_handle, vector_data); + let end_handle_pos = self.target_handle_position(end_handle, vector_data); + let ref_pos = self.target_handle_position(reference_handle, vector_data)?; + let snap = &mut self.snap_manager; + let snap_data = SnapData::new_snap_cache(snap_data.document, input, &self.snap_cache); + + let handle_start_offset = self.handle_start_offset.unwrap_or(DVec2::ZERO); + let document_pos = viewport_to_document.transform_point2(*mouse + handle_start_offset); + + let anchor_offset = transform.transform_point2(self.next_point - ref_pos); + + let handle_start = SnapCandidatePoint::handle(document_pos); + let anchor = SnapCandidatePoint::handle(document_pos + anchor_offset); + + let snapped_near_handle_start = snap.free_snap(&snap_data, &handle_start, SnapTypeConfiguration::default()); + let snapped_anchor = snap.free_snap(&snap_data, &anchor, SnapTypeConfiguration::default()); + + let handle_snap_option = end_handle_pos.and_then(|handle| match end_handle { + TargetHandle::None => None, + TargetHandle::FuturePreviewOutHandle => None, + _ => { + let handle_offset = transform.transform_point2(handle - ref_pos); + let handle_snap = SnapCandidatePoint::handle(document_pos + handle_offset); + Some((handle, handle_snap)) + } + }); + + let mut delta: DVec2; + let best_snapped = if snapped_near_handle_start.other_snap_better(&snapped_anchor) { + delta = snapped_anchor.snapped_point_document - transform.transform_point2(self.next_point); + snapped_anchor + } else { + delta = snapped_near_handle_start.snapped_point_document - transform.transform_point2(ref_pos); + snapped_near_handle_start + }; + + let Some((handle, handle_snap)) = handle_snap_option else { + snap.update_indicator(best_snapped); + return Some(transform.inverse().transform_vector2(delta)); + }; + + let snapped_handle = snap.free_snap(&snap_data, &handle_snap, SnapTypeConfiguration::default()); + + if best_snapped.other_snap_better(&snapped_handle) { + delta = snapped_handle.snapped_point_document - transform.transform_point2(handle); + snap.update_indicator(snapped_handle); + } else { + snap.update_indicator(best_snapped); + } + + // Transform delta back to original coordinate space + Some(transform.inverse().transform_vector2(delta)) + } + + /// Calculates the offset from the mouse when swapping handles, and swaps the handles. + fn swap_handles( + &mut self, + layer: Option, + document: &DocumentMessageHandler, + shape_editor: &mut ShapeState, + input: &InputPreprocessorMessageHandler, + responses: &mut VecDeque, + ) { + // Validate necessary data exists + let Some(vector_data) = layer.and_then(|layer| document.network_interface.compute_modified_vector(layer)) else { + return; + }; + + let Some(viewport) = layer.map(|layer| document.metadata().transform_to_viewport(layer)) else { + return; + }; + + // Determine if we need to swap to opposite handle + let should_swap_to_opposite = self.path_closed && matches!(self.handle_type, TargetHandle::PreviewInHandle | TargetHandle::PriorOutHandle(..) | TargetHandle::PriorInHandle(..)) + || !self.path_closed && matches!(self.handle_type, TargetHandle::FuturePreviewOutHandle); + + // Determine if we need to swap to start handle + let should_swap_to_start = !self.path_closed && !matches!(self.handle_type, TargetHandle::None | TargetHandle::FuturePreviewOutHandle); + + if should_swap_to_opposite { + let opposite_type = self.get_opposite_handle_type(self.handle_type, &vector_data); + // Update offset + let Some(handle_pos) = self.target_handle_position(opposite_type, &vector_data) else { + self.handle_swapped = false; + return; + }; + if (handle_pos - self.next_point).length() < 1e-6 { + self.handle_swapped = false; + return; + } + self.handle_end_offset = Some(viewport.transform_point2(handle_pos) - input.mouse.position); + + // Update selections if in closed path mode + if self.path_closed { + self.cleanup_target_selections(shape_editor, layer, document, responses); + } + self.update_handle_type(opposite_type); + self.add_target_selections(shape_editor, layer); + } else if should_swap_to_start { + self.cleanup_target_selections(shape_editor, layer, document, responses); + + // Calculate offset from mouse position to next handle start + if let Some(layer_id) = layer { + let transform = document.metadata().transform_to_viewport(layer_id); + self.handle_start_offset = Some(transform.transform_point2(self.next_handle_start) - input.mouse.position); + } + + self.update_handle_type(TargetHandle::FuturePreviewOutHandle); + } + + responses.add(FrontendMessage::UpdateMouseCursor { cursor: MouseCursorIcon::None }); + } + + /// Handles moving the initially created point + fn handle_single_point_path_drag(&mut self, delta: DVec2, layer: LayerNodeIdentifier, responses: &mut VecDeque) -> Option { + self.next_handle_start += delta; + self.next_point += delta; + + let Some(latest) = self.latest_point_mut() else { + return Some(PenToolFsmState::DraggingHandle(self.handle_mode)); + }; + + latest.pos += delta; + + let modification_type = VectorModificationType::ApplyPointDelta { point: latest.id, delta }; + + responses.add(GraphOperationMessage::Vector { layer, modification_type }); + + responses.add(OverlaysMessage::Draw); + Some(PenToolFsmState::DraggingHandle(self.handle_mode)) + } + + fn move_anchor_and_handles(&mut self, delta: DVec2, layer: LayerNodeIdentifier, responses: &mut VecDeque, vector_data: &VectorData) { + if self.handle_end.is_none() { + if let Some(latest_pt) = self.latest_point_mut() { + latest_pt.pos += delta; + } + } + + let Some(end_point) = self.prior_segment_endpoint else { return }; + + let modification_type_anchor = VectorModificationType::ApplyPointDelta { point: end_point, delta }; + responses.add(GraphOperationMessage::Vector { + layer, + modification_type: modification_type_anchor, + }); + + let reference_handle = if self.path_closed { TargetHandle::PreviewInHandle } else { TargetHandle::FuturePreviewOutHandle }; + + // Move the end handle + let end_handle_type = self.get_opposite_handle_type(reference_handle, vector_data); + match end_handle_type { + TargetHandle::PriorInHandle(..) | TargetHandle::PriorOutHandle(..) => { + let Some(handle_pos) = self.target_handle_position(end_handle_type, vector_data) else { return }; + self.update_target_handle_pos(end_handle_type, self.next_point, responses, handle_pos + delta, layer); + } + _ => {} + } + } + + fn drag_handle( + &mut self, + snap_data: SnapData, + transform: DAffine2, + mouse: DVec2, + responses: &mut VecDeque, + layer: Option, + input: &InputPreprocessorMessageHandler, + ) -> Option { + let colinear = (self.handle_mode == HandleMode::ColinearEquidistant && self.modifiers.break_handle) || (self.handle_mode == HandleMode::ColinearLocked && !self.modifiers.break_handle); + let document = snap_data.document; + let Some(layer) = layer else { return Some(PenToolFsmState::DraggingHandle(self.handle_mode)) }; + let vector_data = document.network_interface.compute_modified_vector(layer)?; + let viewport_to_document = document.metadata().document_to_viewport.inverse(); + let mut mouse_pos = mouse; + + // Handles pressing Space to drag anchor and its handles + if self.modifiers.move_anchor_with_handles { + let Some(delta) = self.space_anchor_handle_snap(&viewport_to_document, &transform, &snap_data, &mouse, &vector_data, input) else { + return Some(PenToolFsmState::DraggingHandle(self.handle_mode)); + }; + + if self.moving_start_point() { + return self.handle_single_point_path_drag(delta, layer, responses); + } + + self.next_handle_start += delta; + self.next_point += delta; + + if let Some(handle) = self.handle_end.as_mut() { + *handle += delta; + if !self.path_closed { + responses.add(OverlaysMessage::Draw); + return Some(PenToolFsmState::DraggingHandle(self.handle_mode)); + }; + } + + self.move_anchor_and_handles(delta, layer, responses, &vector_data); + + responses.add(OverlaysMessage::Draw); + return Some(PenToolFsmState::DraggingHandle(self.handle_mode)); + } + + match self.handle_type { + TargetHandle::FuturePreviewOutHandle => { + let offset = self.handle_start_offset.unwrap_or(DVec2::ZERO); + mouse_pos += offset; + self.next_handle_start = self.compute_snapped_angle(snap_data.clone(), transform, colinear, mouse_pos, Some(self.next_point), false); + } + _ => { + mouse_pos += self.handle_end_offset.unwrap_or(DVec2::ZERO); + let mouse_pos = self.compute_snapped_angle(snap_data.clone(), transform, colinear, mouse_pos, Some(self.next_point), false); + self.update_target_handle_pos(self.handle_type, self.next_point, responses, mouse_pos, layer); + } + } + + let mouse_pos = viewport_to_document.transform_point2(mouse_pos); + let anchor = transform.transform_point2(self.next_point); + let distance = (mouse_pos - anchor).length(); + + if self.switch_to_free_on_ctrl_release && !self.modifiers.lock_angle { + self.switch_to_free_on_ctrl_release = false; + self.handle_mode = HandleMode::Free; + } + + if distance > 20. && self.handle_mode == HandleMode::Free && self.modifiers.lock_angle && !self.angle_locked { + self.angle_locked = true + } + + match self.handle_mode { + HandleMode::ColinearLocked | HandleMode::ColinearEquidistant => { + self.g1_continuous = true; + self.apply_colinear_constraint(responses, layer, self.next_point, &vector_data); + self.adjust_handle_length(responses, layer, &vector_data); + } + HandleMode::Free => { + self.g1_continuous = false; + } + } + + if distance < 20. && self.handle_mode == HandleMode::Free && self.modifiers.lock_angle && !self.angle_locked { + let Some(endpoint) = self.prior_segment_endpoint else { + return Some(PenToolFsmState::DraggingHandle(self.handle_mode)); + }; + self.set_lock_angle(&vector_data, endpoint, self.prior_segment); + self.switch_to_free_on_ctrl_release = true; + let last_segment = self.prior_segment; + if let Some(latest) = self.latest_point_mut() { + latest.in_segment = last_segment; + } + } + + responses.add(OverlaysMessage::Draw); + + Some(PenToolFsmState::DraggingHandle(self.handle_mode)) + } + + /// Makes the opposite handle equidistant or locks its length. + fn adjust_handle_length(&mut self, responses: &mut VecDeque, layer: LayerNodeIdentifier, vector_data: &VectorData) { + let opposite_handle_type = self.get_opposite_handle_type(self.handle_type, vector_data); + match self.handle_mode { + HandleMode::ColinearEquidistant => { + if self.modifiers.break_handle { + // Store handle for later restoration only when Alt is first pressed + if !self.alt_pressed { + self.previous_handle_end_pos = self.target_handle_position(opposite_handle_type, vector_data); + self.alt_pressed = true; + } + + // Set handle to opposite position of the other handle + let Some(new_position) = self.target_handle_position(self.handle_type, vector_data).map(|handle| self.next_point * 2. - handle) else { + return; + }; + self.update_target_handle_pos(opposite_handle_type, self.next_point, responses, new_position, layer); + } else if self.alt_pressed { + // Restore the previous handle position when Alt is released + if let Some(previous_handle) = self.previous_handle_end_pos { + self.update_target_handle_pos(opposite_handle_type, self.next_point, responses, previous_handle, layer); + } + self.alt_pressed = false; + self.previous_handle_end_pos = None; + } + } + HandleMode::ColinearLocked => { + if !self.modifiers.break_handle { + let Some(new_position) = self.target_handle_position(self.handle_type, vector_data).map(|handle| self.next_point * 2. - handle) else { + return; + }; + self.update_target_handle_pos(opposite_handle_type, self.next_point, responses, new_position, layer); + } + } + HandleMode::Free => {} + } + } + + fn apply_colinear_constraint(&mut self, responses: &mut VecDeque, layer: LayerNodeIdentifier, anchor_pos: DVec2, vector_data: &VectorData) { + let Some(handle) = self.target_handle_position(self.handle_type, vector_data) else { + return; + }; + + if (anchor_pos - handle).length() < 1e-6 && self.modifiers.lock_angle { + return; + } + + let Some(direction) = (anchor_pos - handle).try_normalize() else { + return; + }; + let opposite_handle = self.get_opposite_handle_type(self.handle_type, vector_data); + let Some(handle_offset) = self.target_handle_position(opposite_handle, vector_data).map(|handle| (handle - anchor_pos).length()) else { + return; + }; + let new_handle_position = anchor_pos + handle_offset * direction; + self.update_target_handle_pos(opposite_handle, self.next_point, responses, new_handle_position, layer); + } + + fn place_anchor(&mut self, snap_data: SnapData, transform: DAffine2, mouse: DVec2, preferences: &PreferencesMessageHandler, responses: &mut VecDeque) -> Option { + let document = snap_data.document; + + let relative = if self.path_closed { None } else { self.latest_point().map(|point| point.pos) }; + self.next_point = self.compute_snapped_angle(snap_data, transform, false, mouse, relative, true); + + let selected_nodes = document.network_interface.selected_nodes(); + let mut selected_layers = selected_nodes.selected_layers(document.metadata()); + let layer = selected_layers.next().filter(|_| selected_layers.next().is_none()).or(self.current_layer)?; + let vector_data = document.network_interface.compute_modified_vector(layer)?; + let transform = document.metadata().document_to_viewport * transform; + for point in vector_data.extendable_points(preferences.vector_meshes) { + let Some(pos) = vector_data.point_domain.position_from_id(point) else { continue }; + let transformed_distance_between_squared = transform.transform_point2(pos).distance_squared(transform.transform_point2(self.next_point)); + let snap_point_tolerance_squared = crate::consts::SNAP_POINT_TOLERANCE.powi(2); + if transformed_distance_between_squared < snap_point_tolerance_squared { + self.next_point = pos; + } + } + if let Some(handle_end) = self.handle_end.as_mut() { + *handle_end = self.next_point; + self.next_handle_start = self.next_point; + } + responses.add(OverlaysMessage::Draw); + + Some(PenToolFsmState::PlacingAnchor) + } + + /// Snap the angle of the line from relative to position if the key is pressed. + fn compute_snapped_angle(&mut self, snap_data: SnapData, transform: DAffine2, colinear: bool, mouse: DVec2, relative: Option, neighbor: bool) -> DVec2 { + let ModifierState { snap_angle, lock_angle, .. } = self.modifiers; + let document = snap_data.document; + let mut document_pos = document.metadata().document_to_viewport.inverse().transform_point2(mouse); + let snap = &mut self.snap_manager; + + let neighbors = relative.filter(|_| neighbor).map_or(Vec::new(), |neighbor| vec![neighbor]); + + let config = SnapTypeConfiguration::default(); + if let Some(relative) = relative + .map(|layer| transform.transform_point2(layer)) + .filter(|&relative| (snap_angle || lock_angle) && (relative - document_pos).length_squared() > f64::EPSILON * 100.) + { + let resolution = LINE_ROTATE_SNAP_ANGLE.to_radians(); + + let angle = if lock_angle { + self.angle + } else if (relative - document_pos) != DVec2::ZERO && !lock_angle { + (-(relative - document_pos).angle_to(DVec2::X) / resolution).round() * resolution + } else { + self.angle + }; + document_pos = relative - (relative - document_pos).project_onto(DVec2::new(angle.cos(), angle.sin())); + + let constraint = SnapConstraint::Line { + origin: relative, + direction: document_pos - relative, + }; + let near_point = SnapCandidatePoint::handle_neighbors(document_pos, neighbors.clone()); + let far_point = SnapCandidatePoint::handle_neighbors(2. * relative - document_pos, neighbors); + if colinear { + let snapped = snap.constrained_snap(&snap_data, &near_point, constraint, config); + let snapped_far = snap.constrained_snap(&snap_data, &far_point, constraint, config); + document_pos = if snapped_far.other_snap_better(&snapped) { + snapped.snapped_point_document + } else { + 2. * relative - snapped_far.snapped_point_document + }; + snap.update_indicator(if snapped_far.other_snap_better(&snapped) { snapped } else { snapped_far }); + } else { + let snapped = snap.constrained_snap(&snap_data, &near_point, constraint, config); + document_pos = snapped.snapped_point_document; + snap.update_indicator(snapped); + } + } else if let Some(relative) = relative.map(|layer| transform.transform_point2(layer)).filter(|_| colinear) { + let snapped = snap.free_snap(&snap_data, &SnapCandidatePoint::handle_neighbors(document_pos, neighbors.clone()), config); + let snapped_far = snap.free_snap(&snap_data, &SnapCandidatePoint::handle_neighbors(2. * relative - document_pos, neighbors), config); + document_pos = if snapped_far.other_snap_better(&snapped) { + snapped.snapped_point_document + } else { + 2. * relative - snapped_far.snapped_point_document + }; + snap.update_indicator(if snapped_far.other_snap_better(&snapped) { snapped } else { snapped_far }); + } else { + let snapped = snap.free_snap(&snap_data, &SnapCandidatePoint::handle_neighbors(document_pos, neighbors), config); + document_pos = snapped.snapped_point_document; + snap.update_indicator(snapped); + } + + if let Some(relative) = relative.map(|layer| transform.transform_point2(layer)) { + if (relative - document_pos) != DVec2::ZERO && (relative - document_pos).length_squared() > f64::EPSILON * 100. { + self.angle = -(relative - document_pos).angle_to(DVec2::X) + } + } + + transform.inverse().transform_point2(document_pos) + } + + #[allow(clippy::too_many_arguments)] + fn create_initial_point( + &mut self, + document: &DocumentMessageHandler, + input: &InputPreprocessorMessageHandler, + responses: &mut VecDeque, + tool_options: &PenOptions, + append: bool, + preferences: &PreferencesMessageHandler, + shape_editor: &mut ShapeState, + ) { + let point = SnapCandidatePoint::handle(document.metadata().document_to_viewport.inverse().transform_point2(input.mouse.position)); + let snapped = self.snap_manager.free_snap(&SnapData::new(document, input), &point, SnapTypeConfiguration::default()); + let viewport = document.metadata().document_to_viewport.transform_point2(snapped.snapped_point_document); + self.handle_type = TargetHandle::FuturePreviewOutHandle; + + let selected_nodes = document.network_interface.selected_nodes(); + self.handle_end = None; + + let tolerance = crate::consts::SNAP_POINT_TOLERANCE; + let extension_choice = should_extend(document, viewport, tolerance, selected_nodes.selected_layers(document.metadata()), preferences); + if let Some((layer, point, position)) = extension_choice { + self.current_layer = Some(layer); + self.extend_existing_path(document, layer, point, position); + return; + } else if preferences.vector_meshes { + if let Some(closest_segment) = shape_editor.upper_closest_segment(&document.network_interface, viewport, tolerance) { + let (point, segments) = closest_segment.adjusted_insert(responses); + let layer = closest_segment.layer(); + let position = closest_segment.closest_point_document(); + + // Setting any one of the new segments created as the previous segment + self.prior_segment_endpoint = Some(point); + self.prior_segment_layer = Some(layer); + self.prior_segments = Some(segments.to_vec()); + + self.extend_existing_path(document, layer, point, position); + return; + } + } + + if append { + if let Some((layer, point, _)) = closest_point(document, viewport, tolerance, document.metadata().all_layers(), |_| false, preferences) { + let vector_data = document.network_interface.compute_modified_vector(layer).unwrap(); + let segment = vector_data.all_connected(point).collect::>().first().map(|s| s.segment); + + if self.modifiers.lock_angle { + self.set_lock_angle(&vector_data, point, segment); + self.switch_to_free_on_ctrl_release = true; + } + } + let mut selected_layers_except_artboards = selected_nodes.selected_layers_except_artboards(&document.network_interface); + let existing_layer = selected_layers_except_artboards.next().filter(|_| selected_layers_except_artboards.next().is_none()); + if let Some(layer) = existing_layer { + // Add point to existing layer + responses.add(PenToolMessage::AddPointLayerPosition { layer, viewport }); + return; + } + } + + if let Some((layer, point, _position)) = closest_point(document, viewport, tolerance, document.metadata().all_layers(), |_| false, preferences) { + let vector_data = document.network_interface.compute_modified_vector(layer).unwrap(); + let segment = vector_data.all_connected(point).collect::>().first().map(|s| s.segment); + self.handle_mode = HandleMode::Free; + if self.modifiers.lock_angle { + self.set_lock_angle(&vector_data, point, segment); + self.switch_to_free_on_ctrl_release = true; + } + } + + // New path layer + let node_type = resolve_document_node_type("Path").expect("Path node does not exist"); + let nodes = vec![(NodeId(0), node_type.default_node_template())]; + + let parent = document.new_layer_bounding_artboard(input); + let layer = graph_modification_utils::new_custom(NodeId::new(), nodes, parent, responses); + self.current_layer = Some(layer); + tool_options.fill.apply_fill(layer, responses); + tool_options.stroke.apply_stroke(tool_options.line_weight, layer, responses); + self.prior_segment = None; + self.prior_segments = None; + responses.add(NodeGraphMessage::SelectedNodesSet { nodes: vec![layer.to_node()] }); + + // This causes the following message to be run only after the next graph evaluation runs and the transforms are updated + responses.add(Message::StartBuffer); + // It is necessary to defer this until the transform of the layer can be accurately computed (quite hacky) + responses.add(PenToolMessage::AddPointLayerPosition { layer, viewport }); + } + + /// Perform extension of an existing path + fn extend_existing_path(&mut self, document: &DocumentMessageHandler, layer: LayerNodeIdentifier, point: PointId, position: DVec2) { + let vector_data = document.network_interface.compute_modified_vector(layer); + let (handle_start, in_segment) = if let Some(vector_data) = &vector_data { + vector_data + .segment_bezier_iter() + .find_map(|(segment_id, bezier, start, end)| { + let is_end = point == end; + let is_start = point == start; + if !is_end && !is_start { + return None; + } + + let handle = match bezier.handles { + BezierHandles::Cubic { handle_start, handle_end, .. } => { + if is_start { + handle_start + } else { + handle_end + } + } + BezierHandles::Quadratic { handle } => handle, + _ => return None, + }; + Some((segment_id, is_end, handle)) + }) + .map(|(segment_id, is_end, handle)| { + let mirrored_handle = position * 2. - handle; + let in_segment = if is_end { Some(segment_id) } else { None }; + (mirrored_handle, in_segment) + }) + .unwrap_or_else(|| (position, None)) + } else { + (position, None) + }; + + let in_segment = if self.modifiers.lock_angle { self.prior_segment } else { in_segment }; + + self.add_point(LastPoint { + id: point, + pos: position, + in_segment, + handle_start, + }); + + self.next_point = position; + self.next_handle_start = handle_start; + let vector_data = document.network_interface.compute_modified_vector(layer).unwrap(); + let segment = vector_data.all_connected(point).collect::>().first().map(|s| s.segment); + self.handle_mode = HandleMode::Free; + + if self.modifiers.lock_angle { + self.set_lock_angle(&vector_data, point, segment); + self.switch_to_free_on_ctrl_release = true; + } + } + + // Stores the segment and point ID of the clicked endpoint + fn store_clicked_endpoint(&mut self, document: &DocumentMessageHandler, transform: &DAffine2, input: &InputPreprocessorMessageHandler, preferences: &PreferencesMessageHandler) { + let mut manipulators = HashMap::with_hasher(NoHashBuilder); + let mut unselected = Vec::new(); + let mut layer_manipulators = HashSet::with_hasher(NoHashBuilder); + + let point = SnapCandidatePoint::handle(document.metadata().document_to_viewport.inverse().transform_point2(input.mouse.position)); + + let snapped = self.snap_manager.free_snap(&SnapData::new(document, input), &point, SnapTypeConfiguration::default()); + let viewport = document.metadata().document_to_viewport.transform_point2(snapped.snapped_point_document); + + let tolerance = crate::consts::SNAP_POINT_TOLERANCE; + self.prior_segment = None; + self.prior_segment_endpoint = None; + self.prior_segment_layer = None; + self.prior_segments = None; + + if let Some((layer, point, _position)) = closest_point(document, viewport, tolerance, document.metadata().all_layers(), |_| false, preferences) { + self.prior_segment_endpoint = Some(point); + self.prior_segment_layer = Some(layer); + let vector_data = document.network_interface.compute_modified_vector(layer).unwrap(); + let segment = vector_data.all_connected(point).collect::>().first().map(|s| s.segment); + self.prior_segment = segment; + layer_manipulators.insert(point); + for (&id, &position) in vector_data.point_domain.ids().iter().zip(vector_data.point_domain.positions()) { + if id == point { + continue; + } + unselected.push(SnapCandidatePoint::handle(transform.transform_point2(position))) + } + manipulators.insert(layer, layer_manipulators); + self.snap_cache = SnapCache { manipulators, unselected } + } + } + + fn set_lock_angle(&mut self, vector_data: &VectorData, anchor: PointId, segment: Option) { + let anchor_position = vector_data.point_domain.position_from_id(anchor); + + let Some((anchor_position, segment)) = anchor_position.zip(segment) else { + self.handle_mode = HandleMode::Free; + return; + }; + + match (self.handle_type, self.path_closed) { + (TargetHandle::FuturePreviewOutHandle, _) | (TargetHandle::PreviewInHandle, true) => { + if let Some(required_handle) = calculate_segment_angle(anchor, segment, vector_data, true) { + self.angle = required_handle; + self.handle_mode = HandleMode::ColinearEquidistant; + } + } + (TargetHandle::PriorInHandle(..) | TargetHandle::PriorOutHandle(..), true) => { + self.angle = -(self.handle_end.unwrap() - anchor_position).angle_to(DVec2::X); + self.handle_mode = HandleMode::ColinearEquidistant; + } + _ => { + self.angle = -(self.next_handle_start - anchor_position).angle_to(DVec2::X); + self.handle_mode = HandleMode::ColinearEquidistant; + } + } + } + + fn add_point_layer_position(&mut self, document: &DocumentMessageHandler, responses: &mut VecDeque, layer: LayerNodeIdentifier, viewport: DVec2) { + // Add the first point + let id = PointId::generate(); + let pos = document.metadata().transform_to_viewport(layer).inverse().transform_point2(viewport); + let modification_type = VectorModificationType::InsertPoint { id, position: pos }; + responses.add(GraphOperationMessage::Vector { layer, modification_type }); + self.add_point(LastPoint { + id, + pos, + in_segment: None, + handle_start: pos, + }); + self.next_point = pos; + self.next_handle_start = pos; + self.handle_end = None; + } +} + +impl Fsm for PenToolFsmState { + type ToolData = PenToolData; + type ToolOptions = PenOptions; + + fn transition(self, event: ToolMessage, tool_data: &mut Self::ToolData, tool_action_data: &mut ToolActionHandlerData, tool_options: &Self::ToolOptions, responses: &mut VecDeque) -> Self { + let ToolActionHandlerData { + document, + global_tool_data, + input, + shape_editor, + preferences, + .. + } = tool_action_data; + let selected_nodes = document.network_interface.selected_nodes(); + let mut selected_layers = selected_nodes.selected_layers(document.metadata()); + let layer = selected_layers.next().filter(|_| selected_layers.next().is_none()).or(tool_data.current_layer); + + let mut transform = layer.map(|layer| document.metadata().transform_to_document(layer)).unwrap_or_default(); + + if !transform.inverse().is_finite() { + let parent_transform = layer.and_then(|layer| layer.parent(document.metadata())).map(|layer| document.metadata().transform_to_document(layer)); + + transform = parent_transform.unwrap_or(DAffine2::IDENTITY); + } + + if !transform.inverse().is_finite() { + transform = DAffine2::IDENTITY; + } + + let ToolMessage::Pen(event) = event else { return self }; + match (self, event) { + (PenToolFsmState::PlacingAnchor | PenToolFsmState::GRSHandle, PenToolMessage::GRS { grab, rotate, scale }) => { + let Some(layer) = layer else { return PenToolFsmState::PlacingAnchor }; + + let Some(latest) = tool_data.latest_point() else { return PenToolFsmState::PlacingAnchor }; + if latest.handle_start == latest.pos { + return PenToolFsmState::PlacingAnchor; + } + + let latest_pos = latest.pos; + let latest_handle_start = latest.handle_start; + + let viewport = document.metadata().transform_to_viewport(layer); + let last_point = viewport.transform_point2(latest.pos); + let handle = viewport.transform_point2(latest.handle_start); + + if input.keyboard.key(grab) { + responses.add(TransformLayerMessage::BeginGrabPen { last_point, handle }); + } else if input.keyboard.key(rotate) { + responses.add(TransformLayerMessage::BeginRotatePen { last_point, handle }); + } else if input.keyboard.key(scale) { + responses.add(TransformLayerMessage::BeginScalePen { last_point, handle }); + } + + let vector_data = document.network_interface.compute_modified_vector(layer).unwrap(); + tool_data.previous_handle_start_pos = latest.handle_start; + let opposite_handle = tool_data.check_grs_end_handle(&vector_data); + tool_data.previous_handle_end_pos = tool_data.target_handle_position(opposite_handle, &vector_data); + let handle1 = latest_handle_start - latest_pos; + let Some(opposite_handle_pos) = tool_data.target_handle_position(opposite_handle, &vector_data) else { + return PenToolFsmState::GRSHandle; + }; + let handle2 = opposite_handle_pos - latest_pos; + let pi = std::f64::consts::PI; + let angle = handle1.angle_to(handle2); + tool_data.colinear = (angle - pi).abs() < 1e-6 || (angle + pi).abs() < 1e-6; + PenToolFsmState::GRSHandle + } + (PenToolFsmState::GRSHandle, PenToolMessage::FinalPosition { final_position }) => { + let Some(layer) = layer else { return PenToolFsmState::GRSHandle }; + let vector_data = document.network_interface.compute_modified_vector(layer); + let Some(vector_data) = vector_data else { return PenToolFsmState::GRSHandle }; + + if let Some(latest_pt) = tool_data.latest_point_mut() { + let layer_space_to_viewport = document.metadata().transform_to_viewport(layer); + let final_pos = layer_space_to_viewport.inverse().transform_point2(final_position); + latest_pt.handle_start = final_pos; + } + + responses.add(OverlaysMessage::Draw); + let Some(latest) = tool_data.latest_point() else { + return PenToolFsmState::GRSHandle; + }; + let opposite_handle = tool_data.check_grs_end_handle(&vector_data); + let Some(opposite_handle_pos) = tool_data.target_handle_position(opposite_handle, &vector_data) else { + return PenToolFsmState::GRSHandle; + }; + + if tool_data.colinear { + let Some(direction) = (latest.pos - latest.handle_start).try_normalize() else { + return PenToolFsmState::GRSHandle; + }; + + if (latest.pos - latest.handle_start).length_squared() < f64::EPSILON { + return PenToolFsmState::GRSHandle; + } + let relative_distance = (opposite_handle_pos - latest.pos).length(); + let relative_position = relative_distance * direction + latest.pos; + tool_data.update_target_handle_pos(opposite_handle, latest.pos, responses, relative_position, layer); + } + + responses.add(OverlaysMessage::Draw); + + PenToolFsmState::GRSHandle + } + (PenToolFsmState::GRSHandle, PenToolMessage::Confirm) => { + tool_data.next_point = input.mouse.position; + tool_data.next_handle_start = input.mouse.position; + + responses.add(OverlaysMessage::Draw); + responses.add(PenToolMessage::PointerMove { + snap_angle: Key::Control, + break_handle: Key::Alt, + lock_angle: Key::Shift, + colinear: Key::KeyC, + move_anchor_with_handles: Key::Space, + }); + + PenToolFsmState::PlacingAnchor + } + (PenToolFsmState::GRSHandle, PenToolMessage::Abort) => { + tool_data.next_point = input.mouse.position; + tool_data.next_handle_start = input.mouse.position; + + let Some(layer) = layer else { return PenToolFsmState::GRSHandle }; + let vector_data = document.network_interface.compute_modified_vector(layer).unwrap(); + let opposite_handle = tool_data.check_grs_end_handle(&vector_data); + + let previous = tool_data.previous_handle_start_pos; + if let Some(latest) = tool_data.latest_point_mut() { + latest.handle_start = previous; + } else { + return PenToolFsmState::PlacingAnchor; + } + + responses.add(OverlaysMessage::Draw); + responses.add(PenToolMessage::PointerMove { + snap_angle: Key::Control, + break_handle: Key::Alt, + lock_angle: Key::Shift, + colinear: Key::KeyC, + move_anchor_with_handles: Key::Space, + }); + + let Some((previous_pos, latest)) = tool_data.previous_handle_end_pos.zip(tool_data.latest_point()) else { + return PenToolFsmState::PlacingAnchor; + }; + tool_data.update_target_handle_pos(opposite_handle, latest.pos, responses, previous_pos, layer); + + PenToolFsmState::PlacingAnchor + } + (_, PenToolMessage::SelectionChanged) => { + responses.add(OverlaysMessage::Draw); + self + } + (PenToolFsmState::Ready, PenToolMessage::Overlays(mut overlay_context)) => { + match tool_options.pen_overlay_mode { + PenOverlayMode::AllHandles => { + path_overlays(document, DrawHandles::All, shape_editor, &mut overlay_context); + } + PenOverlayMode::FrontierHandles => { + path_overlays(document, DrawHandles::None, shape_editor, &mut overlay_context); + } + } + // Check if there is an anchor within threshold + // If not check if there is a closest segment within threshold, if yes then draw overlay + let tolerance = crate::consts::SNAP_POINT_TOLERANCE; + let point = SnapCandidatePoint::handle(document.metadata().document_to_viewport.inverse().transform_point2(input.mouse.position)); + let snapped = tool_data.snap_manager.free_snap(&SnapData::new(document, input), &point, SnapTypeConfiguration::default()); + let viewport = document.metadata().document_to_viewport.transform_point2(snapped.snapped_point_document); + + let close_to_point = closest_point(document, viewport, tolerance, document.metadata().all_layers(), |_| false, preferences).is_some(); + if preferences.vector_meshes && !close_to_point { + if let Some(closest_segment) = shape_editor.upper_closest_segment(&document.network_interface, viewport, tolerance) { + let pos = closest_segment.closest_point_to_viewport(); + let perp = closest_segment.calculate_perp(document); + overlay_context.manipulator_anchor(pos, true, None); + overlay_context.line(pos - perp * SEGMENT_OVERLAY_SIZE, pos + perp * SEGMENT_OVERLAY_SIZE, Some(COLOR_OVERLAY_BLUE), None); + } + } + tool_data.snap_manager.draw_overlays(SnapData::new(document, input), &mut overlay_context); + self + } + (_, PenToolMessage::Overlays(mut overlay_context)) => { + let display_anchors = overlay_context.visibility_settings.anchors(); + let display_handles = overlay_context.visibility_settings.handles(); + + let valid = |point: DVec2, handle: DVec2| point.distance_squared(handle) >= HIDE_HANDLE_DISTANCE * HIDE_HANDLE_DISTANCE; + + let transform = document.metadata().document_to_viewport * transform; + + // The currently-being-placed anchor + let next_anchor = transform.transform_point2(tool_data.next_point); + // The currently-being-placed anchor's outgoing handle (the one currently being dragged out) + let next_handle_start = transform.transform_point2(tool_data.next_handle_start); + + // The most recently placed anchor + let anchor_start = tool_data.latest_point().map(|point| transform.transform_point2(point.pos)); + // The most recently placed anchor's incoming handle (opposite the one currently being dragged out) + let handle_end = tool_data.handle_end.map(|point| transform.transform_point2(point)); + // The most recently placed anchor's outgoing handle (which is currently influencing the currently-being-placed segment) + let handle_start = tool_data.latest_point().map(|point| transform.transform_point2(point.handle_start)); + + if let (Some((start, handle_start)), Some(handle_end)) = (tool_data.latest_point().map(|point| (point.pos, point.handle_start)), tool_data.handle_end) { + let handles = BezierHandles::Cubic { handle_start, handle_end }; + let end = tool_data.next_point; + let bezier = Bezier { start, handles, end }; + if (end - start).length_squared() > f64::EPSILON { + // Draw the curve for the currently-being-placed segment + overlay_context.outline_bezier(bezier, transform); + } + } + + if display_handles { + // Draw the line between the currently-being-placed anchor and its currently-being-dragged-out outgoing handle (opposite the one currently being dragged out) + overlay_context.line(next_anchor, next_handle_start, None, None); + } + + match tool_options.pen_overlay_mode { + PenOverlayMode::AllHandles => { + path_overlays(document, DrawHandles::All, shape_editor, &mut overlay_context); + } + PenOverlayMode::FrontierHandles => { + if let Some(latest_segment) = tool_data.prior_segment { + path_overlays(document, DrawHandles::SelectedAnchors(vec![latest_segment]), shape_editor, &mut overlay_context); + } + // If a vector mesh then there can be more than one prior segments + else if let Some(segments) = tool_data.prior_segments.clone() { + if preferences.vector_meshes { + path_overlays(document, DrawHandles::SelectedAnchors(segments), shape_editor, &mut overlay_context); + } + } else { + path_overlays(document, DrawHandles::None, shape_editor, &mut overlay_context); + }; + } + } + + if let (Some(anchor_start), Some(handle_start), Some(handle_end)) = (anchor_start, handle_start, handle_end) { + if display_handles { + // Draw the line between the most recently placed anchor and its outgoing handle (which is currently influencing the currently-being-placed segment) + overlay_context.line(anchor_start, handle_start, None, None); + + // Draw the line between the currently-being-placed anchor and its incoming handle (opposite the one currently being dragged out) + overlay_context.line(next_anchor, handle_end, None, None); + } + + if self == PenToolFsmState::PlacingAnchor && anchor_start != handle_start && tool_data.modifiers.lock_angle { + // Draw the line between the currently-being-placed anchor and last-placed point (lock angle bent overlays) + overlay_context.dashed_line(anchor_start, next_anchor, None, None, Some(4.), Some(4.), Some(0.5)); + } + + // Draw the line between the currently-being-placed anchor and last-placed point (snap angle bent overlays) + if self == PenToolFsmState::PlacingAnchor && anchor_start != handle_start && tool_data.modifiers.snap_angle { + overlay_context.dashed_line(anchor_start, next_anchor, None, None, Some(4.), Some(4.), Some(0.5)); + } + + if self == PenToolFsmState::DraggingHandle(tool_data.handle_mode) && valid(next_anchor, handle_end) && display_handles { + // Draw the handle circle for the currently-being-dragged-out incoming handle (opposite the one currently being dragged out) + let selected = tool_data.handle_type == TargetHandle::PreviewInHandle; + if display_handles { + overlay_context.manipulator_handle(handle_end, selected, None); + overlay_context.manipulator_handle(handle_end, selected, None); + } + } + + if valid(anchor_start, handle_start) && display_handles { + // Draw the handle circle for the most recently placed anchor's outgoing handle (which is currently influencing the currently-being-placed segment) + overlay_context.manipulator_handle(handle_start, false, None); + } + } else { + // Draw the whole path and its manipulators when the user is clicking-and-dragging out from the most recently placed anchor to set its outgoing handle, during which it would otherwise not have its overlays drawn + match tool_options.pen_overlay_mode { + PenOverlayMode::AllHandles => { + path_overlays(document, DrawHandles::All, shape_editor, &mut overlay_context); + } + PenOverlayMode::FrontierHandles => { + path_overlays(document, DrawHandles::None, shape_editor, &mut overlay_context); + } + } + } + + if self == PenToolFsmState::DraggingHandle(tool_data.handle_mode) && valid(next_anchor, next_handle_start) && display_handles { + // Draw the handle circle for the currently-being-dragged-out outgoing handle (the one currently being dragged out, under the user's cursor) + let selected = tool_data.handle_type == TargetHandle::FuturePreviewOutHandle; + overlay_context.manipulator_handle(next_handle_start, selected, None); + } + + if self == PenToolFsmState::DraggingHandle(tool_data.handle_mode) && display_anchors { + // Draw the anchor square for the most recently placed anchor + overlay_context.manipulator_anchor(next_anchor, false, None); + } + + if self == PenToolFsmState::PlacingAnchor && preferences.vector_meshes { + let tolerance = crate::consts::SNAP_POINT_TOLERANCE; + let point = SnapCandidatePoint::handle(document.metadata().document_to_viewport.inverse().transform_point2(input.mouse.position)); + let snapped = tool_data.snap_manager.free_snap(&SnapData::new(document, input), &point, SnapTypeConfiguration::default()); + let viewport = document.metadata().document_to_viewport.transform_point2(snapped.snapped_point_document); + let close_to_point = closest_point(document, viewport, tolerance, document.metadata().all_layers(), |_| false, preferences).is_some(); + if !close_to_point { + if let Some(closest_segment) = shape_editor.upper_closest_segment(&document.network_interface, viewport, tolerance) { + let pos = closest_segment.closest_point_to_viewport(); + let perp = closest_segment.calculate_perp(document); + overlay_context.manipulator_anchor(pos, true, None); + overlay_context.line(pos - perp * SEGMENT_OVERLAY_SIZE, pos + perp * SEGMENT_OVERLAY_SIZE, Some(COLOR_OVERLAY_BLUE), None); + } + } + } + + // Display a filled overlay of the shape if the new point closes the path + if let Some(latest_point) = tool_data.latest_point() { + let handle_start = latest_point.handle_start; + let handle_end = tool_data.handle_end.unwrap_or(tool_data.next_handle_start); + let next_point = tool_data.next_point; + let start = latest_point.id; + + if let Some(layer) = layer { + let mut vector_data = document.network_interface.compute_modified_vector(layer).unwrap(); + + let closest_point = vector_data.extendable_points(preferences.vector_meshes).filter(|&id| id != start).find(|&id| { + vector_data.point_domain.position_from_id(id).map_or(false, |pos| { + let dist_sq = transform.transform_point2(pos).distance_squared(transform.transform_point2(next_point)); + dist_sq < crate::consts::SNAP_POINT_TOLERANCE.powi(2) + }) + }); + + // We have the point. Join the 2 vertices and check if any path is closed. + if let Some(end) = closest_point { + let segment_id = SegmentId::generate(); + vector_data.push(segment_id, start, end, BezierHandles::Cubic { handle_start, handle_end }, StrokeId::ZERO); + + let grouped_segments = vector_data.auto_join_paths(); + let closed_paths = grouped_segments.iter().filter(|path| path.is_closed() && path.contains(segment_id)); + + let subpaths: Vec<_> = closed_paths + .filter_map(|path| { + let segments = path.edges.iter().filter_map(|edge| { + vector_data + .segment_domain + .iter() + .find(|(id, _, _, _)| id == &edge.id) + .map(|(_, start, end, bezier)| if start == edge.start { (bezier, start, end) } else { (bezier.reversed(), end, start) }) + }); + vector_data.subpath_from_segments_ignore_discontinuities(segments) + }) + .collect(); + + let mut fill_color = graphene_std::Color::from_rgb_str(COLOR_OVERLAY_BLUE.strip_prefix('#').unwrap()) + .unwrap() + .with_alpha(0.05) + .to_rgba_hex_srgb(); + fill_color.insert(0, '#'); + overlay_context.fill_path(subpaths.iter(), transform, fill_color.as_str()); + } + } + } + + // Draw the overlays that visualize current snapping + tool_data.snap_manager.draw_overlays(SnapData::new(document, input), &mut overlay_context); + + self + } + (_, PenToolMessage::WorkingColorChanged) => { + responses.add(PenToolMessage::UpdateOptions(PenOptionsUpdate::WorkingColors( + Some(global_tool_data.primary_color), + Some(global_tool_data.secondary_color), + ))); + self + } + (PenToolFsmState::Ready, PenToolMessage::DragStart { append_to_selected }) => { + responses.add(DocumentMessage::StartTransaction); + tool_data.handle_mode = HandleMode::Free; + + // Get the closest point and the segment it is on + let append = input.keyboard.key(append_to_selected); + + tool_data.store_clicked_endpoint(document, &transform, input, preferences); + tool_data.create_initial_point(document, input, responses, tool_options, append, preferences, shape_editor); + + // Enter the dragging handle state while the mouse is held down, allowing the user to move the mouse and position the handle + PenToolFsmState::DraggingHandle(tool_data.handle_mode) + } + (_, PenToolMessage::AddPointLayerPosition { layer, viewport }) => { + tool_data.add_point_layer_position(document, responses, layer, viewport); + + self + } + (state, PenToolMessage::RecalculateLatestPointsPosition) => { + tool_data.recalculate_latest_points_position(document); + state + } + (PenToolFsmState::PlacingAnchor, PenToolMessage::DragStart { append_to_selected }) => { + let point = SnapCandidatePoint::handle(document.metadata().document_to_viewport.inverse().transform_point2(input.mouse.position)); + let snapped = tool_data.snap_manager.free_snap(&SnapData::new(document, input), &point, SnapTypeConfiguration::default()); + let viewport = document.metadata().document_to_viewport.transform_point2(snapped.snapped_point_document); + + // Early return if the buffer was started and this message is being run again after the buffer (so that place_anchor updates the state with the newly merged vector) + if tool_data.buffering_merged_vector { + if let Some(layer) = layer { + tool_data.buffering_merged_vector = false; + tool_data.handle_mode = HandleMode::ColinearLocked; + tool_data.bend_from_previous_point(SnapData::new(document, input), transform, layer, preferences, shape_editor, responses); + tool_data.place_anchor(SnapData::new(document, input), transform, input.mouse.position, preferences, responses); + } + tool_data.buffering_merged_vector = false; + PenToolFsmState::DraggingHandle(tool_data.handle_mode) + } else { + if tool_data.handle_end.is_some() { + responses.add(DocumentMessage::StartTransaction); + } + // Merge two layers if the point is connected to the end point of another path + + // This might not be the correct solution to artboards being included as the other layer, which occurs due to the compute_modified_vector call in should_extend using the click targets for a layer instead of vector data. + let layers = LayerNodeIdentifier::ROOT_PARENT + .descendants(document.metadata()) + .filter(|layer| !document.network_interface.is_artboard(&layer.to_node(), &[])); + if let Some((other_layer, _, _)) = should_extend(document, viewport, crate::consts::SNAP_POINT_TOLERANCE, layers, preferences) { + let selected_nodes = document.network_interface.selected_nodes(); + let mut selected_layers = selected_nodes.selected_layers(document.metadata()); + if let Some(current_layer) = selected_layers + .next() + .filter(|current_layer| selected_layers.next().is_none() && *current_layer != other_layer) + .or(tool_data.current_layer.filter(|layer| *layer != other_layer)) + { + merge_layers(document, current_layer, other_layer, responses); + } + } + + // Even if no buffer was started, the message still has to be run again in order to call bend_from_previous_point + tool_data.buffering_merged_vector = true; + responses.add(PenToolMessage::DragStart { append_to_selected }); + PenToolFsmState::PlacingAnchor + } + } + (PenToolFsmState::PlacingAnchor, PenToolMessage::RemovePreviousHandle) => { + if let Some(last_point) = tool_data.latest_points.last_mut() { + last_point.handle_start = last_point.pos; + responses.add(OverlaysMessage::Draw); + } else { + log::trace!("No latest point available to modify handle_start."); + } + self + } + (PenToolFsmState::DraggingHandle(_), PenToolMessage::DragStop) => { + tool_data.cleanup_target_selections(shape_editor, layer, document, responses); + tool_data + .finish_placing_handle(SnapData::new(document, input), transform, preferences, responses) + .unwrap_or(PenToolFsmState::PlacingAnchor) + } + ( + PenToolFsmState::DraggingHandle(_), + PenToolMessage::PointerMove { + snap_angle, + break_handle, + lock_angle, + colinear, + move_anchor_with_handles, + }, + ) => { + tool_data.modifiers = ModifierState { + snap_angle: input.keyboard.key(snap_angle), + lock_angle: input.keyboard.key(lock_angle), + break_handle: input.keyboard.key(break_handle), + colinear: input.keyboard.key(colinear), + move_anchor_with_handles: input.keyboard.key(move_anchor_with_handles), + }; + + let snap_data = SnapData::new(document, input); + if tool_data.modifiers.colinear && !tool_data.toggle_colinear_debounce { + tool_data.handle_mode = match tool_data.handle_mode { + HandleMode::Free => { + let last_segment = tool_data.prior_segment; + if let Some(latest) = tool_data.latest_point_mut() { + latest.in_segment = last_segment; + } + HandleMode::ColinearEquidistant + } + HandleMode::ColinearEquidistant | HandleMode::ColinearLocked => HandleMode::Free, + }; + tool_data.toggle_colinear_debounce = true; + } + + let Some(vector_data) = layer.and_then(|layer| document.network_interface.compute_modified_vector(layer)) else { + return self; + }; + + if tool_data.modifiers.move_anchor_with_handles && !tool_data.space_pressed { + let reference_handle = if tool_data.path_closed { + TargetHandle::PreviewInHandle + } else { + TargetHandle::FuturePreviewOutHandle + }; + let handle_start = layer.map(|layer| { + document + .metadata() + .transform_to_viewport(layer) + .transform_point2(tool_data.target_handle_position(reference_handle, &vector_data).unwrap()) + }); + tool_data.handle_start_offset = handle_start.map(|start| start - input.mouse.position); + tool_data.space_pressed = true; + } + + if !tool_data.modifiers.move_anchor_with_handles { + tool_data.space_pressed = false; + } + + if !tool_data.modifiers.colinear { + tool_data.toggle_colinear_debounce = false; + } + + if !tool_data.modifiers.lock_angle { + tool_data.angle_locked = false; + } + + let state = tool_data + .drag_handle(snap_data, transform, input.mouse.position, responses, layer, input) + .unwrap_or(PenToolFsmState::Ready); + + if tool_data.handle_swapped { + responses.add(FrontendMessage::UpdateMouseCursor { cursor: MouseCursorIcon::None }); + } + + // Auto-panning + let messages = [ + PenToolMessage::PointerOutsideViewport { + snap_angle, + break_handle, + lock_angle, + colinear, + move_anchor_with_handles, + } + .into(), + PenToolMessage::PointerMove { + snap_angle, + break_handle, + lock_angle, + colinear, + move_anchor_with_handles, + } + .into(), + ]; + tool_data.auto_panning.setup_by_mouse_position(input, &messages, responses); + + state + } + ( + PenToolFsmState::PlacingAnchor, + PenToolMessage::PointerMove { + snap_angle, + break_handle, + lock_angle, + colinear, + move_anchor_with_handles, + }, + ) => { + tool_data.switch_to_free_on_ctrl_release = false; + tool_data.alt_pressed = false; + tool_data.modifiers = ModifierState { + snap_angle: input.keyboard.key(snap_angle), + lock_angle: input.keyboard.key(lock_angle), + break_handle: input.keyboard.key(break_handle), + colinear: input.keyboard.key(colinear), + move_anchor_with_handles: input.keyboard.key(move_anchor_with_handles), + }; + let state = tool_data + .place_anchor(SnapData::new(document, input), transform, input.mouse.position, preferences, responses) + .unwrap_or(PenToolFsmState::Ready); + + // Auto-panning + let messages = [ + PenToolMessage::PointerOutsideViewport { + snap_angle, + break_handle, + lock_angle, + colinear, + move_anchor_with_handles, + } + .into(), + PenToolMessage::PointerMove { + snap_angle, + break_handle, + lock_angle, + colinear, + move_anchor_with_handles, + } + .into(), + ]; + tool_data.auto_panning.setup_by_mouse_position(input, &messages, responses); + + state + } + (PenToolFsmState::DraggingHandle(_), PenToolMessage::SwapHandles) => { + if !tool_data.handle_swapped { + tool_data.handle_swapped = true + } + tool_data.swap_handles(layer, document, shape_editor, input, responses); + responses.add(OverlaysMessage::Draw); + self + } + ( + PenToolFsmState::Ready, + PenToolMessage::PointerMove { + snap_angle, + break_handle, + lock_angle, + colinear, + move_anchor_with_handles, + }, + ) => { + tool_data.modifiers = ModifierState { + snap_angle: input.keyboard.key(snap_angle), + lock_angle: input.keyboard.key(lock_angle), + break_handle: input.keyboard.key(break_handle), + colinear: input.keyboard.key(colinear), + move_anchor_with_handles: input.keyboard.key(move_anchor_with_handles), + }; + tool_data.snap_manager.preview_draw(&SnapData::new(document, input), input.mouse.position); + responses.add(OverlaysMessage::Draw); + self + } + (PenToolFsmState::DraggingHandle(mode), PenToolMessage::PointerOutsideViewport { .. }) => { + // Auto-panning + let _ = tool_data.auto_panning.shift_viewport(input, responses); + + PenToolFsmState::DraggingHandle(mode) + } + (PenToolFsmState::PlacingAnchor, PenToolMessage::PointerOutsideViewport { .. }) => { + if !input.mouse.mouse_keys.contains(MouseKeys::LEFT) { + return self; + } + // Auto-panning + let _ = tool_data.auto_panning.shift_viewport(input, responses); + + PenToolFsmState::PlacingAnchor + } + ( + state, + PenToolMessage::PointerOutsideViewport { + snap_angle, + break_handle, + lock_angle, + colinear, + move_anchor_with_handles, + }, + ) => { + // Auto-panning + let messages = [ + PenToolMessage::PointerOutsideViewport { + snap_angle, + break_handle, + lock_angle, + colinear, + move_anchor_with_handles, + } + .into(), + PenToolMessage::PointerMove { + snap_angle, + break_handle, + lock_angle, + colinear, + move_anchor_with_handles, + } + .into(), + ]; + tool_data.auto_panning.stop(&messages, responses); + + state + } + (PenToolFsmState::DraggingHandle(..), PenToolMessage::Confirm) => { + // Confirm to end path + if let Some((vector_data, layer)) = layer.and_then(|layer| document.network_interface.compute_modified_vector(layer)).zip(layer) { + let single_point_in_layer = vector_data.point_domain.ids().len() == 1; + tool_data.finish_placing_handle(SnapData::new(document, input), transform, preferences, responses); + let latest_points = tool_data.latest_points.len() == 1; + + if latest_points && single_point_in_layer { + responses.add(NodeGraphMessage::DeleteNodes { + node_ids: vec![layer.to_node()], + delete_children: true, + }); + responses.add(NodeGraphMessage::RunDocumentGraph); + } else if (latest_points && tool_data.prior_segment_endpoint.is_none()) + || (tool_data.prior_segment_endpoint.is_some() && tool_data.prior_segment_layer != Some(layer) && latest_points) + { + let vector_modification = VectorModificationType::RemovePoint { + id: tool_data.latest_point().unwrap().id, + }; + responses.add(GraphOperationMessage::Vector { + layer, + modification_type: vector_modification, + }); + responses.add(PenToolMessage::Abort); + } else { + responses.add(DocumentMessage::EndTransaction); + } + } + tool_data.cleanup(responses); + tool_data.cleanup_target_selections(shape_editor, layer, document, responses); + + responses.add(OverlaysMessage::Draw); + + PenToolFsmState::Ready + } + (PenToolFsmState::PlacingAnchor, PenToolMessage::Confirm) => { + responses.add(DocumentMessage::EndTransaction); + tool_data.cleanup(responses); + tool_data.cleanup_target_selections(shape_editor, layer, document, responses); + + PenToolFsmState::Ready + } + (PenToolFsmState::DraggingHandle(..), PenToolMessage::Abort) => { + responses.add(DocumentMessage::AbortTransaction); + if tool_data.handle_end.is_none() { + tool_data.cleanup(responses); + tool_data.cleanup_target_selections(shape_editor, layer, document, responses); + + PenToolFsmState::Ready + } else { + tool_data + .place_anchor(SnapData::new(document, input), transform, input.mouse.position, preferences, responses) + .unwrap_or(PenToolFsmState::Ready) + } + } + (PenToolFsmState::PlacingAnchor, PenToolMessage::Abort) => { + let should_delete_layer = if let Some(vector_data) = layer.and_then(|layer| document.network_interface.compute_modified_vector(layer)) { + vector_data.point_domain.ids().len() == 1 + } else { + false + }; + + responses.add(DocumentMessage::AbortTransaction); + tool_data.cleanup(responses); + tool_data.cleanup_target_selections(shape_editor, layer, document, responses); + + if should_delete_layer { + responses.add(NodeGraphMessage::DeleteNodes { + node_ids: vec![layer.unwrap().to_node()], + delete_children: true, + }); + responses.add(NodeGraphMessage::RunDocumentGraph); + } + responses.add(OverlaysMessage::Draw); + + PenToolFsmState::Ready + } + (_, PenToolMessage::Abort) => PenToolFsmState::Ready, + (PenToolFsmState::DraggingHandle(..) | PenToolFsmState::PlacingAnchor, PenToolMessage::Undo) => { + if tool_data.point_index > 0 { + tool_data.point_index -= 1; + tool_data + .place_anchor(SnapData::new(document, input), transform, input.mouse.position, preferences, responses) + .unwrap_or(PenToolFsmState::PlacingAnchor) + } else { + responses.add(PenToolMessage::Abort); + self + } + } + (_, PenToolMessage::Redo) => { + tool_data.point_index = (tool_data.point_index + 1).min(tool_data.latest_points.len().saturating_sub(1)); + tool_data.place_anchor(SnapData::new(document, input), transform, input.mouse.position, preferences, responses); + match tool_data.point_index { + 0 => PenToolFsmState::Ready, + _ => PenToolFsmState::PlacingAnchor, + } + } + _ => self, + } + } + + fn update_hints(&self, responses: &mut VecDeque) { + let hint_data = match self { + PenToolFsmState::Ready | PenToolFsmState::GRSHandle => HintData(vec![HintGroup(vec![ + HintInfo::mouse(MouseMotion::Lmb, "Draw Path"), + // TODO: Only show this if a single layer is selected and it's of a valid type (e.g. a vector path but not raster or artboard) + HintInfo::keys([Key::Shift], "Append to Selected Layer").prepend_plus(), + ])]), + PenToolFsmState::PlacingAnchor => HintData(vec![ + HintGroup(vec![ + HintInfo::mouse(MouseMotion::Rmb, ""), + HintInfo::keys([Key::Escape], "").prepend_slash(), + HintInfo::keys([Key::Enter], "End Path").prepend_slash(), + ]), + HintGroup(vec![HintInfo::keys([Key::Shift], "15° Increments"), HintInfo::keys([Key::Control], "Lock Angle")]), + HintGroup(vec![HintInfo::mouse(MouseMotion::Lmb, "Add Sharp Point"), HintInfo::mouse(MouseMotion::LmbDrag, "Add Smooth Point")]), + HintGroup(vec![ + HintInfo::mouse(MouseMotion::Lmb, ""), + HintInfo::mouse(MouseMotion::LmbDrag, "Bend Prev. Point").prepend_slash(), + HintInfo::keys([Key::Control], "Lock Angle").prepend_plus(), + ]), + ]), + PenToolFsmState::DraggingHandle(mode) => { + let mut dragging_hint_data = HintData(Vec::new()); + dragging_hint_data.0.push(HintGroup(vec![ + HintInfo::mouse(MouseMotion::Rmb, ""), + HintInfo::keys([Key::Escape], "Cancel Segment").prepend_slash(), + HintInfo::keys([Key::Enter], "End Path"), + ])); + + let mut toggle_group = match mode { + HandleMode::Free => { + vec![HintInfo::keys([Key::KeyC], "Make Handles Colinear")] + } + HandleMode::ColinearLocked | HandleMode::ColinearEquidistant => { + vec![HintInfo::keys([Key::KeyC], "Break Colinear Handles")] + } + }; + toggle_group.push(HintInfo::keys([Key::Tab], "Swap Dragged Handle")); + + let mut common_hints = vec![HintInfo::keys([Key::Shift], "15° Increments"), HintInfo::keys([Key::Control], "Lock Angle")]; + let mut hold_group = match mode { + HandleMode::Free => common_hints, + HandleMode::ColinearLocked => { + common_hints.push(HintInfo::keys([Key::Alt], "Non-Equidistant Handles")); + common_hints + } + HandleMode::ColinearEquidistant => { + common_hints.push(HintInfo::keys([Key::Alt], "Equidistant Handles")); + common_hints + } + }; + hold_group.push(HintInfo::keys([Key::Space], "Drag Anchor")); + + dragging_hint_data.0.push(HintGroup(toggle_group)); + dragging_hint_data.0.push(HintGroup(hold_group)); + dragging_hint_data + } + }; + + responses.add(FrontendMessage::UpdateInputHints { hint_data }); + } + + fn update_cursor(&self, responses: &mut VecDeque) { + responses.add(FrontendMessage::UpdateMouseCursor { cursor: MouseCursorIcon::Default }); + } +} diff --git a/editor/src/messages/tool/tool_messages/select_tool.rs b/editor/src/messages/tool/tool_messages/select_tool.rs new file mode 100644 index 0000000000000000000000000000000000000000..76158d08e5771455fe46bbe005923ceda84777cb --- /dev/null +++ b/editor/src/messages/tool/tool_messages/select_tool.rs @@ -0,0 +1,1755 @@ +#![allow(clippy::too_many_arguments)] + +use super::tool_prelude::*; +use crate::consts::*; +use crate::messages::input_mapper::utility_types::input_mouse::ViewportPosition; +use crate::messages::portfolio::document::graph_operation::utility_types::TransformIn; +use crate::messages::portfolio::document::overlays::utility_types::OverlayContext; +use crate::messages::portfolio::document::utility_types::document_metadata::{DocumentMetadata, LayerNodeIdentifier}; +use crate::messages::portfolio::document::utility_types::misc::{AlignAggregate, AlignAxis, FlipAxis, GroupFolderType}; +use crate::messages::portfolio::document::utility_types::network_interface::{FlowType, NodeNetworkInterface, NodeTemplate}; +use crate::messages::portfolio::document::utility_types::nodes::SelectedNodes; +use crate::messages::preferences::SelectionMode; +use crate::messages::tool::common_functionality::auto_panning::AutoPanning; +use crate::messages::tool::common_functionality::compass_rose::{Axis, CompassRose}; +use crate::messages::tool::common_functionality::graph_modification_utils::is_layer_fed_by_node_of_name; +use crate::messages::tool::common_functionality::measure; +use crate::messages::tool::common_functionality::pivot::Pivot; +use crate::messages::tool::common_functionality::shape_editor::SelectionShapeType; +use crate::messages::tool::common_functionality::snapping::{self, SnapCandidatePoint, SnapData, SnapManager}; +use crate::messages::tool::common_functionality::transformation_cage::*; +use crate::messages::tool::common_functionality::utility_functions::{resize_bounds, rotate_bounds, skew_bounds, text_bounding_box, transforming_transform_cage}; +use bezier_rs::Subpath; +use glam::DMat2; +use graph_craft::document::NodeId; +use graphene_std::path_bool::BooleanOperation; +use graphene_std::renderer::Quad; +use graphene_std::renderer::Rect; +use graphene_std::transform::ReferencePoint; +use std::fmt; + +#[derive(Default)] +pub struct SelectTool { + fsm_state: SelectToolFsmState, + tool_data: SelectToolData, +} + +#[allow(dead_code)] +#[derive(Default)] +pub struct SelectOptions { + nested_selection_behavior: NestedSelectionBehavior, +} + +#[derive(PartialEq, Eq, Clone, Debug, Hash, serde::Serialize, serde::Deserialize, specta::Type)] +pub enum SelectOptionsUpdate { + NestedSelectionBehavior(NestedSelectionBehavior), +} + +#[derive(Default, PartialEq, Eq, Clone, Copy, Debug, Hash, serde::Serialize, serde::Deserialize, specta::Type)] +pub enum NestedSelectionBehavior { + #[default] + Shallowest, + Deepest, +} + +impl fmt::Display for NestedSelectionBehavior { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + NestedSelectionBehavior::Deepest => write!(f, "Deep Select"), + NestedSelectionBehavior::Shallowest => write!(f, "Shallow Select"), + } + } +} + +#[derive(PartialEq, Clone, Debug, serde::Serialize, serde::Deserialize, specta::Type)] +pub struct SelectToolPointerKeys { + pub axis_align: Key, + pub snap_angle: Key, + pub center: Key, + pub duplicate: Key, +} + +#[impl_message(Message, ToolMessage, Select)] +#[derive(PartialEq, Clone, Debug, serde::Serialize, serde::Deserialize, specta::Type)] +pub enum SelectToolMessage { + // Standard messages + Abort, + Overlays(OverlayContext), + + // Tool-specific messages + DragStart { + extend_selection: Key, + remove_from_selection: Key, + select_deepest: Key, + lasso_select: Key, + skew: Key, + }, + DragStop { + remove_from_selection: Key, + }, + EditLayer, + Enter, + PointerMove(SelectToolPointerKeys), + PointerOutsideViewport(SelectToolPointerKeys), + SelectOptions(SelectOptionsUpdate), + SetPivot { + position: ReferencePoint, + }, +} + +impl ToolMetadata for SelectTool { + fn icon_name(&self) -> String { + "GeneralSelectTool".into() + } + fn tooltip(&self) -> String { + "Select Tool".into() + } + fn tool_type(&self) -> crate::messages::tool::utility_types::ToolType { + ToolType::Select + } +} + +impl SelectTool { + fn deep_selection_widget(&self) -> WidgetHolder { + let layer_selection_behavior_entries = [NestedSelectionBehavior::Shallowest, NestedSelectionBehavior::Deepest] + .iter() + .map(|mode| { + MenuListEntry::new(format!("{mode:?}")) + .label(mode.to_string()) + .on_commit(move |_| SelectToolMessage::SelectOptions(SelectOptionsUpdate::NestedSelectionBehavior(*mode)).into()) + }) + .collect(); + + DropdownInput::new(vec![layer_selection_behavior_entries]) + .selected_index(Some((self.tool_data.nested_selection_behavior == NestedSelectionBehavior::Deepest) as u32)) + .tooltip("Choose if clicking nested layers directly selects the deepest, or selects the shallowest and deepens by double clicking") + .widget_holder() + } + + fn pivot_reference_point_widget(&self, disabled: bool) -> WidgetHolder { + ReferencePointInput::new(self.tool_data.pivot.to_pivot_position()) + .on_update(|pivot_input: &ReferencePointInput| SelectToolMessage::SetPivot { position: pivot_input.value }.into()) + .disabled(disabled) + .widget_holder() + } + + fn alignment_widgets(&self, disabled: bool) -> impl Iterator + use<> { + [AlignAxis::X, AlignAxis::Y] + .into_iter() + .flat_map(|axis| [(axis, AlignAggregate::Min), (axis, AlignAggregate::Center), (axis, AlignAggregate::Max)]) + .map(move |(axis, aggregate)| { + let (icon, tooltip) = match (axis, aggregate) { + (AlignAxis::X, AlignAggregate::Min) => ("AlignLeft", "Align Left"), + (AlignAxis::X, AlignAggregate::Center) => ("AlignHorizontalCenter", "Align Horizontal Center"), + (AlignAxis::X, AlignAggregate::Max) => ("AlignRight", "Align Right"), + (AlignAxis::Y, AlignAggregate::Min) => ("AlignTop", "Align Top"), + (AlignAxis::Y, AlignAggregate::Center) => ("AlignVerticalCenter", "Align Vertical Center"), + (AlignAxis::Y, AlignAggregate::Max) => ("AlignBottom", "Align Bottom"), + }; + IconButton::new(icon, 24) + .tooltip(tooltip) + .on_update(move |_| DocumentMessage::AlignSelectedLayers { axis, aggregate }.into()) + .disabled(disabled) + .widget_holder() + }) + } + + fn flip_widgets(&self, disabled: bool) -> impl Iterator + use<> { + [(FlipAxis::X, "Horizontal"), (FlipAxis::Y, "Vertical")].into_iter().map(move |(flip_axis, name)| { + IconButton::new("Flip".to_string() + name, 24) + .tooltip("Flip ".to_string() + name) + .on_update(move |_| DocumentMessage::FlipSelectedLayers { flip_axis }.into()) + .disabled(disabled) + .widget_holder() + }) + } + + fn turn_widgets(&self, disabled: bool) -> impl Iterator + use<> { + [(-90., "TurnNegative90", "Turn -90°"), (90., "TurnPositive90", "Turn 90°")] + .into_iter() + .map(move |(degrees, icon, name)| { + IconButton::new(icon, 24) + .tooltip(name) + .on_update(move |_| DocumentMessage::RotateSelectedLayers { degrees }.into()) + .disabled(disabled) + .widget_holder() + }) + } + + fn boolean_widgets(&self, selected_count: usize) -> impl Iterator + use<> { + let list = ::list(); + list.into_iter().map(|i| i.into_iter()).flatten().map(move |(operation, info)| { + let mut tooltip = info.label.to_string(); + if let Some(doc) = info.docstring.as_deref() { + tooltip.push_str("\n\n"); + tooltip.push_str(doc); + } + IconButton::new(info.icon.as_deref().unwrap(), 24) + .tooltip(tooltip) + .disabled(selected_count == 0) + .on_update(move |_| { + let group_folder_type = GroupFolderType::BooleanOperation(*operation); + DocumentMessage::GroupSelectedLayers { group_folder_type }.into() + }) + .widget_holder() + }) + } +} + +impl LayoutHolder for SelectTool { + fn layout(&self) -> Layout { + let mut widgets = Vec::new(); + + // Select mode (Deep/Shallow) + widgets.push(self.deep_selection_widget()); + + // Pivot + widgets.push(Separator::new(SeparatorType::Unrelated).widget_holder()); + widgets.push(self.pivot_reference_point_widget(self.tool_data.selected_layers_count == 0)); + + // Align + let disabled = self.tool_data.selected_layers_count < 2; + widgets.push(Separator::new(SeparatorType::Unrelated).widget_holder()); + widgets.extend(self.alignment_widgets(disabled)); + // widgets.push( + // PopoverButton::new() + // .popover_layout(vec![ + // LayoutGroup::Row { + // widgets: vec![TextLabel::new("Align").bold(true).widget_holder()], + // }, + // LayoutGroup::Row { + // widgets: vec![TextLabel::new("Coming soon").widget_holder()], + // }, + // ]) + // .disabled(disabled) + // .widget_holder(), + // ); + + // Flip + let disabled = self.tool_data.selected_layers_count == 0; + widgets.push(Separator::new(SeparatorType::Unrelated).widget_holder()); + widgets.extend(self.flip_widgets(disabled)); + + // Turn + widgets.push(Separator::new(SeparatorType::Unrelated).widget_holder()); + widgets.extend(self.turn_widgets(disabled)); + + // Boolean + widgets.push(Separator::new(SeparatorType::Unrelated).widget_holder()); + widgets.extend(self.boolean_widgets(self.tool_data.selected_layers_count)); + + Layout::WidgetLayout(WidgetLayout::new(vec![LayoutGroup::Row { widgets }])) + } +} + +impl<'a> MessageHandler> for SelectTool { + fn process_message(&mut self, message: ToolMessage, responses: &mut VecDeque, tool_data: &mut ToolActionHandlerData<'a>) { + if let ToolMessage::Select(SelectToolMessage::SelectOptions(SelectOptionsUpdate::NestedSelectionBehavior(nested_selection_behavior))) = message { + self.tool_data.nested_selection_behavior = nested_selection_behavior; + responses.add(ToolMessage::UpdateHints); + } + + self.fsm_state.process_event(message, &mut self.tool_data, tool_data, &(), responses, false); + + if self.tool_data.pivot.should_refresh_pivot_position() || self.tool_data.selected_layers_changed { + // Send the layout containing the updated pivot position (a bit ugly to do it here not in the fsm but that doesn't have SelectTool) + self.send_layout(responses, LayoutTarget::ToolOptions); + self.tool_data.selected_layers_changed = false; + } + } + + fn actions(&self) -> ActionList { + let mut common = actions!(SelectToolMessageDiscriminant; + PointerMove, + Abort, + EditLayer, + Enter, + ); + + let additional = match self.fsm_state { + SelectToolFsmState::Ready { .. } => actions!(SelectToolMessageDiscriminant; DragStart), + _ => actions!(SelectToolMessageDiscriminant; DragStop), + }; + common.extend(additional); + + common + } +} + +impl ToolTransition for SelectTool { + fn event_to_message_map(&self) -> EventToMessageMap { + EventToMessageMap { + tool_abort: Some(SelectToolMessage::Abort.into()), + overlay_provider: Some(|overlay_context| SelectToolMessage::Overlays(overlay_context).into()), + ..Default::default() + } + } +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] +enum SelectToolFsmState { + Ready { + selection: NestedSelectionBehavior, + }, + Drawing { + selection_shape: SelectionShapeType, + has_drawn: bool, + }, + Dragging { + axis: Axis, + using_compass: bool, + has_dragged: bool, + deepest: bool, + remove: bool, + }, + ResizingBounds, + SkewingBounds { + skew: Key, + }, + RotatingBounds, + DraggingPivot, +} + +impl Default for SelectToolFsmState { + fn default() -> Self { + let selection = NestedSelectionBehavior::Deepest; + SelectToolFsmState::Ready { selection } + } +} + +#[derive(Clone, Debug, Default)] +struct SelectToolData { + drag_start: ViewportPosition, + drag_current: ViewportPosition, + lasso_polygon: Vec, + selection_mode: Option, + layers_dragging: Vec, + layer_selected_on_start: Option, + select_single_layer: Option, + axis_align: bool, + non_duplicated_layers: Option>, + bounding_box_manager: Option, + snap_manager: SnapManager, + cursor: MouseCursorIcon, + pivot: Pivot, + compass_rose: CompassRose, + line_center: DVec2, + skew_edge: EdgeBool, + nested_selection_behavior: NestedSelectionBehavior, + selected_layers_count: usize, + selected_layers_changed: bool, + snap_candidates: Vec, + auto_panning: AutoPanning, +} + +impl SelectToolData { + fn get_snap_candidates(&mut self, document: &DocumentMessageHandler, input: &InputPreprocessorMessageHandler) { + self.snap_candidates.clear(); + for &layer in &self.layers_dragging { + if (self.snap_candidates.len() as f64) < document.snapping_state.tolerance { + snapping::get_layer_snap_points(layer, &SnapData::new(document, input), &mut self.snap_candidates); + } + if let Some(bounds) = document.metadata().bounding_box_with_transform(layer, DAffine2::IDENTITY) { + let quad = document.metadata().transform_to_document(layer) * Quad::from_box(bounds); + snapping::get_bbox_points(quad, &mut self.snap_candidates, snapping::BBoxSnapValues::BOUNDING_BOX, document); + } + } + } + + pub fn selection_quad(&self) -> Quad { + let bbox = self.selection_box(); + Quad::from_box(bbox) + } + + pub fn calculate_selection_mode_from_direction(&mut self) -> SelectionMode { + let bbox: [DVec2; 2] = self.selection_box(); + let above_threshold = bbox[1].distance_squared(bbox[0]) > DRAG_DIRECTION_MODE_DETERMINATION_THRESHOLD.powi(2); + + if self.selection_mode.is_none() && above_threshold { + let mode = if bbox[1].x < bbox[0].x { + SelectionMode::Touched + } else { + // This also covers the case where they're equal: the area is zero, so we use `Enclosed` to ensure the selection ends up empty, as nothing will be enclosed by an empty area + SelectionMode::Enclosed + }; + self.selection_mode = Some(mode); + } + + self.selection_mode.unwrap_or(SelectionMode::Touched) + } + + pub fn selection_box(&self) -> [DVec2; 2] { + if self.drag_current == self.drag_start { + let tolerance = DVec2::splat(SELECTION_TOLERANCE); + [self.drag_start - tolerance, self.drag_start + tolerance] + } else { + [self.drag_start, self.drag_current] + } + } + + pub fn intersect_lasso_no_artboards(&self, document: &DocumentMessageHandler, input: &InputPreprocessorMessageHandler) -> Vec { + if self.lasso_polygon.len() < 2 { + return Vec::new(); + } + let polygon = Subpath::from_anchors_linear(self.lasso_polygon.clone(), true); + document.intersect_polygon_no_artboards(polygon, input).collect() + } + + pub fn is_layer_inside_lasso_polygon(&self, layer: &LayerNodeIdentifier, document: &DocumentMessageHandler, input: &InputPreprocessorMessageHandler) -> bool { + if self.lasso_polygon.len() < 2 { + return false; + } + let polygon = Subpath::from_anchors_linear(self.lasso_polygon.clone(), true); + document.is_layer_fully_inside_polygon(layer, input, polygon) + } + + /// Duplicates the currently dragging layers. Called when Alt is pressed and the layers have not yet been duplicated. + fn start_duplicates(&mut self, document: &mut DocumentMessageHandler, responses: &mut VecDeque) { + self.non_duplicated_layers = Some(self.layers_dragging.clone()); + let mut new_dragging = Vec::new(); + + // Get the shallowest unique layers and sort by their index relative to parent for ordered processing + let mut layers = document.network_interface.shallowest_unique_layers(&[]).collect::>(); + + layers.sort_by_key(|layer| { + let Some(parent) = layer.parent(document.metadata()) else { return usize::MAX }; + DocumentMessageHandler::get_calculated_insert_index(document.metadata(), &SelectedNodes(vec![layer.to_node()]), parent) + }); + + for layer in layers.into_iter().rev() { + let Some(parent) = layer.parent(document.metadata()) else { continue }; + + // Moves the layer back to its starting position. + responses.add(GraphOperationMessage::TransformChange { + layer, + transform: DAffine2::from_translation(self.drag_start - self.drag_current), + transform_in: TransformIn::Viewport, + skip_rerender: true, + }); + + // Copy the layer + let mut copy_ids = HashMap::new(); + let node_id = layer.to_node(); + copy_ids.insert(node_id, NodeId(0)); + + document + .network_interface + .upstream_flow_back_from_nodes(vec![layer.to_node()], &[], FlowType::LayerChildrenUpstreamFlow) + .enumerate() + .for_each(|(index, node_id)| { + copy_ids.insert(node_id, NodeId((index + 1) as u64)); + }); + + let nodes = document.network_interface.copy_nodes(©_ids, &[]).collect::>(); + + let insert_index = DocumentMessageHandler::get_calculated_insert_index(document.metadata(), &SelectedNodes(vec![layer.to_node()]), parent); + + let new_ids: HashMap<_, _> = nodes.iter().map(|(id, _)| (*id, NodeId::new())).collect(); + + let layer_id = *new_ids.get(&NodeId(0)).expect("Node Id 0 should be a layer"); + let layer = LayerNodeIdentifier::new_unchecked(layer_id); + new_dragging.push(layer); + responses.add(NodeGraphMessage::AddNodes { nodes, new_ids }); + responses.add(NodeGraphMessage::MoveLayerToStack { layer, parent, insert_index }); + } + let nodes = new_dragging.iter().map(|layer| layer.to_node()).collect(); + responses.add(NodeGraphMessage::SelectedNodesSet { nodes }); + responses.add(NodeGraphMessage::RunDocumentGraph); + self.layers_dragging = new_dragging; + } + + /// Removes the duplicated layers. Called when Alt is released and the layers have previously been duplicated. + fn stop_duplicates(&mut self, document: &DocumentMessageHandler, responses: &mut VecDeque) { + let Some(original) = self.non_duplicated_layers.take() else { + return; + }; + + // Delete the duplicated layers + for layer in document.network_interface.shallowest_unique_layers(&[]) { + responses.add(NodeGraphMessage::DeleteNodes { + node_ids: vec![layer.to_node()], + delete_children: true, + }); + } + + for &layer in &original { + responses.add(GraphOperationMessage::TransformChange { + layer, + transform: DAffine2::from_translation(self.drag_current - self.drag_start), + transform_in: TransformIn::Viewport, + skip_rerender: true, + }); + } + let nodes = original + .iter() + .filter_map(|layer| { + if *layer != LayerNodeIdentifier::ROOT_PARENT { + Some(layer.to_node()) + } else { + log::error!("ROOT_PARENT cannot be part of non_duplicated_layers"); + None + } + }) + .collect(); + responses.add(NodeGraphMessage::SelectedNodesSet { nodes }); + responses.add(NodeGraphMessage::RunDocumentGraph); + responses.add(NodeGraphMessage::SelectedNodesUpdated); + responses.add(NodeGraphMessage::SendGraph); + self.layers_dragging = original; + } +} + +impl Fsm for SelectToolFsmState { + type ToolData = SelectToolData; + type ToolOptions = (); + + fn transition(self, event: ToolMessage, tool_data: &mut Self::ToolData, tool_action_data: &mut ToolActionHandlerData, _tool_options: &(), responses: &mut VecDeque) -> Self { + let ToolActionHandlerData { document, input, font_cache, .. } = tool_action_data; + + let ToolMessage::Select(event) = event else { return self }; + match (self, event) { + (_, SelectToolMessage::Overlays(mut overlay_context)) => { + tool_data.snap_manager.draw_overlays(SnapData::new(document, input), &mut overlay_context); + + let selected_layers_count = document.network_interface.selected_nodes().selected_unlocked_layers(&document.network_interface).count(); + tool_data.selected_layers_changed = selected_layers_count != tool_data.selected_layers_count; + tool_data.selected_layers_count = selected_layers_count; + + // Outline selected layers, but not artboards + if overlay_context.visibility_settings.selection_outline() { + for layer in document + .network_interface + .selected_nodes() + .selected_visible_and_unlocked_layers(&document.network_interface) + .filter(|layer| !document.network_interface.is_artboard(&layer.to_node(), &[])) + { + let layer_to_viewport = document.metadata().transform_to_viewport(layer); + overlay_context.outline(document.metadata().layer_with_free_points_outline(layer), layer_to_viewport, None); + + if is_layer_fed_by_node_of_name(layer, &document.network_interface, "Text") { + let transformed_quad = layer_to_viewport * text_bounding_box(layer, document, font_cache); + overlay_context.dashed_quad(transformed_quad, None, None, Some(7.), Some(5.), None); + } + } + } + + // Update bounds + let mut transform = document + .network_interface + .selected_nodes() + .selected_visible_and_unlocked_layers(&document.network_interface) + .find(|layer| !document.network_interface.is_artboard(&layer.to_node(), &[])) + .map(|layer| document.metadata().transform_to_viewport_with_first_transform_node_if_group(layer, &document.network_interface)) + .unwrap_or_default(); + + // Check if the matrix is not invertible + let mut transform_tampered = false; + if transform.matrix2.determinant() == 0. { + transform.matrix2 += DMat2::IDENTITY * 1e-4; // TODO: Is this the cleanest way to handle this? + transform_tampered = true; + } + + let bounds = document + .network_interface + .selected_nodes() + .selected_visible_and_unlocked_layers(&document.network_interface) + .filter(|layer| !document.network_interface.is_artboard(&layer.to_node(), &[])) + .filter_map(|layer| { + document + .metadata() + .bounding_box_with_transform(layer, transform.inverse() * document.metadata().transform_to_viewport(layer)) + }) + .reduce(graphene_std::renderer::Quad::combine_bounds); + + // When not in Drawing State + // Only highlight layers if the viewport is not being panned (middle mouse button is pressed) + // TODO: Don't use `Key::MouseMiddle` directly, instead take it as a variable from the input mappings list like in all other places; or find a better way than checking the key state + if !matches!(self, Self::Drawing { .. }) && !input.keyboard.get(Key::MouseMiddle as usize) { + // Get the layer the user is hovering over + let click = document.click(input); + let not_selected_click = click.filter(|&hovered_layer| !document.network_interface.selected_nodes().selected_layers_contains(hovered_layer, document.metadata())); + if let Some(layer) = not_selected_click { + if overlay_context.visibility_settings.hover_outline() { + let layer_to_viewport = document.metadata().transform_to_viewport(layer); + let mut hover_overlay_draw = |layer: LayerNodeIdentifier, color: Option<&str>| { + if layer.has_children(document.metadata()) { + if let Some(bounds) = document.metadata().bounding_box_viewport(layer) { + overlay_context.quad(Quad::from_box(bounds), color, None); + } + } else { + overlay_context.outline(document.metadata().layer_with_free_points_outline(layer), layer_to_viewport, color); + } + }; + let layer = match tool_data.nested_selection_behavior { + NestedSelectionBehavior::Deepest => document.find_deepest(&[layer]), + NestedSelectionBehavior::Shallowest => layer_selected_shallowest(layer, document), + } + .unwrap_or(layer); + hover_overlay_draw(layer, None); + if matches!(tool_data.nested_selection_behavior, NestedSelectionBehavior::Shallowest) { + let mut selected = document.network_interface.selected_nodes(); + selected.add_selected_nodes(vec![layer.to_node()]); + if let Some(new_selected) = click.unwrap().ancestors(document.metadata()).filter(not_artboard(document)).find(|ancestor| { + ancestor + .parent(document.metadata()) + .is_some_and(|parent| selected.selected_layers_contains(parent, document.metadata())) + }) { + let mut fill_color = graphene_std::Color::from_rgb_str(COLOR_OVERLAY_BLUE.strip_prefix('#').unwrap()) + .unwrap() + .with_alpha(0.5) + .to_rgba_hex_srgb(); + fill_color.insert(0, '#'); + let fill_color = Some(fill_color.as_str()); + hover_overlay_draw(new_selected, fill_color); + } + } + } + + // Measure with Alt held down + // TODO: Don't use `Key::Alt` directly, instead take it as a variable from the input mappings list like in all other places + if overlay_context.visibility_settings.quick_measurement() && !matches!(self, Self::ResizingBounds { .. }) && input.keyboard.get(Key::Alt as usize) { + // Get all selected layers and compute their viewport-aligned AABB + let selected_bounds_viewport = document + .network_interface + .selected_nodes() + .selected_visible_and_unlocked_layers(&document.network_interface) + .filter(|layer| !document.network_interface.is_artboard(&layer.to_node(), &[])) + .filter_map(|layer| { + // Get the layer's bounding box in its local space + let local_bounds = document.metadata().bounding_box_with_transform(layer, DAffine2::IDENTITY)?; + // Transform the bounds directly to viewport space + let viewport_quad = document.metadata().transform_to_viewport(layer) * Quad::from_box(local_bounds); + // Convert the quad to an AABB in viewport space + Some(Rect::from_box(viewport_quad.bounding_box())) + }) + .reduce(Rect::combine_bounds); + + // Get the hovered layer's viewport-aligned AABB + let hovered_bounds_viewport = document.metadata().bounding_box_with_transform(layer, DAffine2::IDENTITY).map(|bounds| { + let viewport_quad = document.metadata().transform_to_viewport(layer) * Quad::from_box(bounds); + Rect::from_box(viewport_quad.bounding_box()) + }); + + // Use the viewport-aligned AABBs for measurement + if let (Some(selected_bounds), Some(hovered_bounds)) = (selected_bounds_viewport, hovered_bounds_viewport) { + // Since we're already in viewport space, use identity transform + measure::overlay(selected_bounds, hovered_bounds, DAffine2::IDENTITY, DAffine2::IDENTITY, &mut overlay_context); + } + } + } + } + + if let Some(bounds) = bounds { + let bounding_box_manager = tool_data.bounding_box_manager.get_or_insert(BoundingBoxManager::default()); + + bounding_box_manager.bounds = bounds; + bounding_box_manager.transform = transform; + bounding_box_manager.transform_tampered = transform_tampered; + if overlay_context.visibility_settings.transform_cage() { + bounding_box_manager.render_overlays(&mut overlay_context, true); + } + } else { + tool_data.bounding_box_manager.take(); + } + + let angle = bounds + .map(|bounds| transform * Quad::from_box(bounds)) + .map_or(0., |quad| (quad.top_left() - quad.top_right()).to_angle()); + + let mouse_position = input.mouse.position; + let compass_rose_state = tool_data.compass_rose.compass_rose_state(mouse_position, angle); + + let show_hover_ring = if let SelectToolFsmState::Dragging { axis, using_compass, .. } = self { + using_compass && !axis.is_constraint() + } else { + compass_rose_state.is_ring() + }; + + let dragging_bounds = tool_data + .bounding_box_manager + .as_mut() + .and_then(|bounding_box| bounding_box.check_selected_edges(input.mouse.position)) + .is_some(); + + let rotating_bounds = tool_data + .bounding_box_manager + .as_ref() + .map(|bounding_box| bounding_box.check_rotate(input.mouse.position)) + .unwrap_or_default(); + + let is_resizing_or_rotating = matches!(self, SelectToolFsmState::ResizingBounds | SelectToolFsmState::SkewingBounds { .. } | SelectToolFsmState::RotatingBounds); + + if overlay_context.visibility_settings.transform_cage() { + if let Some(bounds) = tool_data.bounding_box_manager.as_mut() { + let edges = bounds.check_selected_edges(input.mouse.position); + let is_skewing = matches!(self, SelectToolFsmState::SkewingBounds { .. }); + let is_near_square = edges.is_some_and(|hover_edge| bounds.over_extended_edge_midpoint(input.mouse.position, hover_edge)); + if is_skewing || (dragging_bounds && is_near_square && !is_resizing_or_rotating) { + bounds.render_skew_gizmos(&mut overlay_context, tool_data.skew_edge); + } + if !is_skewing && dragging_bounds { + if let Some(edges) = edges { + tool_data.skew_edge = bounds.get_closest_edge(edges, input.mouse.position); + } + } + } + } + + let might_resize_or_rotate = dragging_bounds || rotating_bounds; + let can_get_into_other_states = might_resize_or_rotate && !matches!(self, SelectToolFsmState::Dragging { .. }); + + let show_compass = !(can_get_into_other_states || is_resizing_or_rotating); + let show_compass_with_ring = bounds.map(|bounds| transform * Quad::from_box(bounds)).and_then(|quad| { + const MIN_ARROWS_TO_RESIZE_HANDLE_DISTANCE: f64 = 4.; + (show_compass && quad.all_sides_at_least_width(COMPASS_ROSE_HOVER_RING_DIAMETER + RESIZE_HANDLE_SIZE + MIN_ARROWS_TO_RESIZE_HANDLE_DISTANCE)) + .then_some( + matches!(self, SelectToolFsmState::Dragging { .. }) + .then_some(show_hover_ring) + .or((quad.contains(mouse_position)).then_some(show_hover_ring)), + ) + .flatten() + }); + + // Update pivot + tool_data.pivot.update_pivot(document, &mut overlay_context, Some((angle,))); + + // Update compass rose + if overlay_context.visibility_settings.compass_rose() { + tool_data.compass_rose.refresh_position(document); + let compass_center = tool_data.compass_rose.compass_rose_position(); + if !matches!(self, Self::Dragging { .. }) { + tool_data.line_center = compass_center; + } + + overlay_context.compass_rose(compass_center, angle, show_compass_with_ring); + + let axis_state = if let SelectToolFsmState::Dragging { axis, .. } = self { + Some((axis, false)) + } else { + compass_rose_state.axis_type().and_then(|axis| axis.is_constraint().then_some((axis, true))) + }; + + if show_compass_with_ring.is_some() { + if let Some((axis, hover)) = axis_state { + if axis.is_constraint() { + let e0 = tool_data + .bounding_box_manager + .as_ref() + .map(|bounding_box_manager| bounding_box_manager.transform * Quad::from_box(bounding_box_manager.bounds)) + .map_or(DVec2::X, |quad| (quad.top_left() - quad.top_right()).normalize_or(DVec2::X)); + + let (direction, color) = match axis { + Axis::X => (e0, COLOR_OVERLAY_RED), + Axis::Y => (e0.perp(), COLOR_OVERLAY_GREEN), + _ => unreachable!(), + }; + + let viewport_diagonal = input.viewport_bounds.size().length(); + + let color = if !hover { + color + } else { + let color_string = &graphene_std::Color::from_rgb_str(color.strip_prefix('#').unwrap()).unwrap().with_alpha(0.25).to_rgba_hex_srgb(); + &format!("#{}", color_string) + }; + let line_center = tool_data.line_center; + overlay_context.line(line_center - direction * viewport_diagonal, line_center + direction * viewport_diagonal, Some(color), None); + } + } + } + + if axis_state.is_none_or(|(axis, _)| !axis.is_constraint()) && tool_data.axis_align { + let mouse_position = mouse_position - tool_data.drag_start; + let snap_resolution = SELECTION_DRAG_ANGLE.to_radians(); + let angle = -mouse_position.angle_to(DVec2::X); + let snapped_angle = (angle / snap_resolution).round() * snap_resolution; + + let extension = tool_data.drag_current - tool_data.drag_start; + let origin = compass_center - extension; + let viewport_diagonal = input.viewport_bounds.size().length(); + + let edge = DVec2::from_angle(snapped_angle).normalize_or(DVec2::X) * viewport_diagonal; + let perp = edge.perp(); + + let (edge_color, perp_color) = if edge.x.abs() > edge.y.abs() { + (COLOR_OVERLAY_RED, COLOR_OVERLAY_GREEN) + } else { + (COLOR_OVERLAY_GREEN, COLOR_OVERLAY_RED) + }; + let mut perp_color = graphene_std::Color::from_rgb_str(perp_color.strip_prefix('#').unwrap()).unwrap().with_alpha(0.25).to_rgba_hex_srgb(); + perp_color.insert(0, '#'); + let perp_color = perp_color.as_str(); + overlay_context.line(origin - edge * viewport_diagonal, origin + edge * viewport_diagonal, Some(edge_color), None); + overlay_context.line(origin - perp * viewport_diagonal, origin + perp * viewport_diagonal, Some(perp_color), None); + } + } + + // Check if the tool is in selection mode + if let Self::Drawing { selection_shape, .. } = self { + // Get the updated selection box bounds + let quad = Quad::from_box([tool_data.drag_start, tool_data.drag_current]); + + let current_selection_mode = match tool_action_data.preferences.get_selection_mode() { + SelectionMode::Directional => tool_data.calculate_selection_mode_from_direction(), + SelectionMode::Touched => SelectionMode::Touched, + SelectionMode::Enclosed => SelectionMode::Enclosed, + }; + + // Draw outline visualizations on the layers to be selected + let intersected_layers = match selection_shape { + SelectionShapeType::Box => document.intersect_quad_no_artboards(quad, input).collect(), + SelectionShapeType::Lasso => tool_data.intersect_lasso_no_artboards(document, input), + }; + let layers_to_outline = intersected_layers.into_iter().filter(|layer| match current_selection_mode { + SelectionMode::Enclosed => match selection_shape { + SelectionShapeType::Box => document.is_layer_fully_inside(layer, quad), + SelectionShapeType::Lasso => tool_data.is_layer_inside_lasso_polygon(layer, document, input), + }, + SelectionMode::Touched => match tool_data.nested_selection_behavior { + NestedSelectionBehavior::Deepest => !layer.has_children(document.metadata()), + NestedSelectionBehavior::Shallowest => true, + }, + SelectionMode::Directional => unreachable!(), + }); + + if overlay_context.visibility_settings.selection_outline() { + // Draws a temporary outline on the layers that will be selected by the current box/lasso area + for layer in layers_to_outline { + let layer_to_viewport = document.metadata().transform_to_viewport(layer); + overlay_context.outline(document.metadata().layer_with_free_points_outline(layer), layer_to_viewport, None); + } + } + + // Update the selection box + let mut fill_color = graphene_std::Color::from_rgb_str(COLOR_OVERLAY_BLUE.strip_prefix('#').unwrap()) + .unwrap() + .with_alpha(0.05) + .to_rgba_hex_srgb(); + fill_color.insert(0, '#'); + let fill_color = Some(fill_color.as_str()); + + let polygon = &tool_data.lasso_polygon; + + match (selection_shape, current_selection_mode) { + (SelectionShapeType::Box, SelectionMode::Enclosed) => overlay_context.dashed_quad(quad, None, fill_color, Some(4.), Some(4.), Some(0.5)), + (SelectionShapeType::Lasso, SelectionMode::Enclosed) => overlay_context.dashed_polygon(polygon, None, fill_color, Some(4.), Some(4.), Some(0.5)), + (SelectionShapeType::Box, _) => overlay_context.quad(quad, None, fill_color), + (SelectionShapeType::Lasso, _) => overlay_context.polygon(polygon, None, fill_color), + } + } + self + } + (_, SelectToolMessage::EditLayer) => { + // Edit the clicked layer + if let Some(intersect) = document.click(input) { + match tool_data.nested_selection_behavior { + NestedSelectionBehavior::Shallowest => edit_layer_shallowest_manipulation(document, intersect, responses), + NestedSelectionBehavior::Deepest => edit_layer_deepest_manipulation(intersect, &document.network_interface, responses), + } + } + + self + } + ( + SelectToolFsmState::Ready { .. }, + SelectToolMessage::DragStart { + extend_selection, + remove_from_selection, + select_deepest, + lasso_select, + .. + }, + ) => { + tool_data.drag_start = input.mouse.position; + tool_data.drag_current = input.mouse.position; + tool_data.selection_mode = None; + + let mut selected: Vec<_> = document.network_interface.selected_nodes().selected_visible_and_unlocked_layers(&document.network_interface).collect(); + let intersection_list = document.click_list(input).collect::>(); + let intersection = document.find_deepest(&intersection_list); + + let (resize, rotate, skew) = transforming_transform_cage(document, &mut tool_data.bounding_box_manager, input, responses, &mut tool_data.layers_dragging); + + // If the user is dragging the bounding box bounds, go into ResizingBounds mode. + // If the user is dragging the rotate trigger, go into RotatingBounds mode. + // If the user clicks on a layer that is in their current selection, go into the dragging mode. + // If the user clicks on new shape, make that layer their new selection. + // Otherwise enter the box select mode + let bounds = tool_data + .bounding_box_manager + .as_ref() + .map(|bounding_box_manager| bounding_box_manager.transform * Quad::from_box(bounding_box_manager.bounds)); + + let angle = bounds.map_or(0., |quad| (quad.top_left() - quad.top_right()).to_angle()); + let mouse_position = input.mouse.position; + let compass_rose_state = tool_data.compass_rose.compass_rose_state(mouse_position, angle); + let is_over_pivot = tool_data.pivot.is_over(mouse_position); + + let show_compass = bounds.is_some_and(|quad| quad.all_sides_at_least_width(COMPASS_ROSE_HOVER_RING_DIAMETER) && quad.contains(mouse_position)); + let can_grab_compass_rose = compass_rose_state.can_grab() && (show_compass || bounds.is_none()); + + let state = if is_over_pivot + // Dragging the pivot + { + responses.add(DocumentMessage::StartTransaction); + + // tool_data.snap_manager.start_snap(document, input, document.bounding_boxes(), true, true); + // tool_data.snap_manager.add_all_document_handles(document, input, &[], &[], &[]); + + SelectToolFsmState::DraggingPivot + } + // Dragging one (or two, forming a corner) of the transform cage bounding box edges + else if resize { + tool_data.get_snap_candidates(document, input); + SelectToolFsmState::ResizingBounds + } else if skew { + tool_data.get_snap_candidates(document, input); + SelectToolFsmState::SkewingBounds { skew: Key::Control } + } + // Dragging the selected layers around to transform them + else if can_grab_compass_rose || intersection.is_some_and(|intersection| selected.iter().any(|selected_layer| intersection.starts_with(*selected_layer, document.metadata()))) { + responses.add(DocumentMessage::StartTransaction); + + if input.keyboard.key(select_deepest) || tool_data.nested_selection_behavior == NestedSelectionBehavior::Deepest { + tool_data.select_single_layer = intersection; + } else { + tool_data.select_single_layer = intersection.and_then(|intersection| intersection.ancestors(document.metadata()).find(|ancestor| selected.contains(ancestor))); + } + + tool_data.layers_dragging = selected; + + tool_data.get_snap_candidates(document, input); + let (axis, using_compass) = { + let axis_state = compass_rose_state.axis_type().filter(|_| can_grab_compass_rose); + (axis_state.unwrap_or_default(), axis_state.is_some()) + }; + SelectToolFsmState::Dragging { + axis, + using_compass, + has_dragged: false, + deepest: input.keyboard.key(select_deepest), + remove: input.keyboard.key(extend_selection), + } + } + // Dragging near the transform cage bounding box to rotate it + else if rotate { + SelectToolFsmState::RotatingBounds + } + // Dragging a selection box + else { + tool_data.layers_dragging = selected; + let extend = input.keyboard.key(extend_selection); + if !extend && !input.keyboard.key(remove_from_selection) { + responses.add(DocumentMessage::DeselectAllLayers); + tool_data.layers_dragging.clear(); + } + + if let Some(intersection) = intersection { + tool_data.layer_selected_on_start = Some(intersection); + selected = intersection_list; + + match tool_data.nested_selection_behavior { + NestedSelectionBehavior::Shallowest if !input.keyboard.key(select_deepest) => drag_shallowest_manipulation(responses, selected, tool_data, document, false, extend), + _ => drag_deepest_manipulation(responses, selected, tool_data, document, false), + } + tool_data.get_snap_candidates(document, input); + + responses.add(DocumentMessage::StartTransaction); + SelectToolFsmState::Dragging { + axis: Axis::None, + using_compass: false, + has_dragged: false, + deepest: input.keyboard.key(select_deepest), + remove: input.keyboard.key(extend_selection), + } + } else { + let selection_shape = if input.keyboard.key(lasso_select) { SelectionShapeType::Lasso } else { SelectionShapeType::Box }; + SelectToolFsmState::Drawing { selection_shape, has_drawn: false } + } + }; + tool_data.non_duplicated_layers = None; + + state + } + (SelectToolFsmState::DraggingPivot, SelectToolMessage::Abort) => { + responses.add(DocumentMessage::AbortTransaction); + + let selection = tool_data.nested_selection_behavior; + SelectToolFsmState::Ready { selection } + } + ( + SelectToolFsmState::Dragging { + axis, + using_compass, + has_dragged, + deepest, + remove, + }, + SelectToolMessage::PointerMove(modifier_keys), + ) => { + if !has_dragged { + responses.add(ToolMessage::UpdateHints); + } + if input.keyboard.key(modifier_keys.duplicate) && tool_data.non_duplicated_layers.is_none() { + tool_data.start_duplicates(document, responses); + } else if !input.keyboard.key(modifier_keys.duplicate) && tool_data.non_duplicated_layers.is_some() { + tool_data.stop_duplicates(document, responses); + } + + tool_data.axis_align = input.keyboard.key(modifier_keys.axis_align); + + // Ignore the non duplicated layers if the current layers have not spawned yet. + let layers_exist = tool_data.layers_dragging.iter().all(|&layer| document.metadata().click_targets(layer).is_some()); + let ignore = tool_data.non_duplicated_layers.as_ref().filter(|_| !layers_exist).unwrap_or(&tool_data.layers_dragging); + + let snap_data = SnapData::ignore(document, input, ignore); + let (start, current) = (tool_data.drag_start, tool_data.drag_current); + let e0 = tool_data + .bounding_box_manager + .as_ref() + .map(|bounding_box_manager| bounding_box_manager.transform * Quad::from_box(bounding_box_manager.bounds)) + .map_or(DVec2::X, |quad| (quad.top_left() - quad.top_right()).normalize_or(DVec2::X)); + + let mouse_delta = snap_drag(start, current, tool_data.axis_align, axis, snap_data, &mut tool_data.snap_manager, &tool_data.snap_candidates); + let mouse_delta = match axis { + Axis::X => mouse_delta.project_onto(e0), + Axis::Y => mouse_delta.project_onto(e0.perp()), + Axis::None => mouse_delta, + }; + + // TODO: Cache the result of `shallowest_unique_layers` to avoid this heavy computation every frame of movement, see https://github.com/GraphiteEditor/Graphite/pull/481 + for layer in document.network_interface.shallowest_unique_layers(&[]) { + responses.add_front(GraphOperationMessage::TransformChange { + layer, + transform: DAffine2::from_translation(mouse_delta), + transform_in: TransformIn::Viewport, + skip_rerender: false, + }); + } + tool_data.drag_current += mouse_delta; + + // Auto-panning + let messages = [ + SelectToolMessage::PointerOutsideViewport(modifier_keys.clone()).into(), + SelectToolMessage::PointerMove(modifier_keys).into(), + ]; + tool_data.auto_panning.setup_by_mouse_position(input, &messages, responses); + + SelectToolFsmState::Dragging { + axis, + using_compass, + has_dragged: true, + deepest, + remove, + } + } + (SelectToolFsmState::ResizingBounds, SelectToolMessage::PointerMove(modifier_keys)) => { + if let Some(bounds) = &mut tool_data.bounding_box_manager { + resize_bounds( + document, + responses, + bounds, + &mut tool_data.layers_dragging, + &mut tool_data.snap_manager, + &mut tool_data.snap_candidates, + input, + input.keyboard.key(modifier_keys.center), + input.keyboard.key(modifier_keys.axis_align), + ToolType::Select, + ); + let messages = [ + SelectToolMessage::PointerOutsideViewport(modifier_keys.clone()).into(), + SelectToolMessage::PointerMove(modifier_keys).into(), + ]; + tool_data.auto_panning.setup_by_mouse_position(input, &messages, responses); + } + SelectToolFsmState::ResizingBounds + } + (SelectToolFsmState::SkewingBounds { skew }, SelectToolMessage::PointerMove(_)) => { + if let Some(bounds) = &mut tool_data.bounding_box_manager { + skew_bounds( + document, + responses, + bounds, + input.keyboard.key(skew), + &mut tool_data.layers_dragging, + input.mouse.position, + ToolType::Select, + ); + } + SelectToolFsmState::SkewingBounds { skew } + } + (SelectToolFsmState::RotatingBounds, SelectToolMessage::PointerMove(_)) => { + if let Some(bounds) = &mut tool_data.bounding_box_manager { + rotate_bounds( + document, + responses, + bounds, + &mut tool_data.layers_dragging, + tool_data.drag_start, + input.mouse.position, + input.keyboard.key(Key::Shift), + ToolType::Select, + ); + } + + SelectToolFsmState::RotatingBounds + } + (SelectToolFsmState::DraggingPivot, SelectToolMessage::PointerMove(modifier_keys)) => { + let mouse_position = input.mouse.position; + let snapped_mouse_position = mouse_position; + tool_data.pivot.set_viewport_position(snapped_mouse_position, document, responses); + + // Auto-panning + let messages = [ + SelectToolMessage::PointerOutsideViewport(modifier_keys.clone()).into(), + SelectToolMessage::PointerMove(modifier_keys).into(), + ]; + tool_data.auto_panning.setup_by_mouse_position(input, &messages, responses); + + SelectToolFsmState::DraggingPivot + } + (SelectToolFsmState::Drawing { selection_shape, has_drawn }, SelectToolMessage::PointerMove(modifier_keys)) => { + if !has_drawn { + responses.add(ToolMessage::UpdateHints); + } + + tool_data.drag_current = input.mouse.position; + responses.add(OverlaysMessage::Draw); + + if selection_shape == SelectionShapeType::Lasso { + extend_lasso(&mut tool_data.lasso_polygon, tool_data.drag_current); + } + + // Auto-panning + let messages = [ + SelectToolMessage::PointerOutsideViewport(modifier_keys.clone()).into(), + SelectToolMessage::PointerMove(modifier_keys).into(), + ]; + tool_data.auto_panning.setup_by_mouse_position(input, &messages, responses); + + SelectToolFsmState::Drawing { selection_shape, has_drawn: true } + } + (SelectToolFsmState::Ready { .. }, SelectToolMessage::PointerMove(_)) => { + let dragging_bounds = tool_data + .bounding_box_manager + .as_mut() + .and_then(|bounding_box| bounding_box.check_selected_edges(input.mouse.position)) + .is_some(); + + let mut cursor = tool_data + .bounding_box_manager + .as_ref() + .map_or(MouseCursorIcon::Default, |bounds| bounds.get_cursor(input, true, dragging_bounds, Some(tool_data.skew_edge))); + + // Dragging the pivot overrules the other operations + if tool_data.pivot.is_over(input.mouse.position) { + cursor = MouseCursorIcon::Move; + } + + // Generate the hover outline + responses.add(OverlaysMessage::Draw); + + if tool_data.cursor != cursor { + tool_data.cursor = cursor; + responses.add(FrontendMessage::UpdateMouseCursor { cursor }); + } + + let selection = tool_data.nested_selection_behavior; + SelectToolFsmState::Ready { selection } + } + ( + SelectToolFsmState::Dragging { + axis, + using_compass, + has_dragged, + deepest, + remove, + }, + SelectToolMessage::PointerOutsideViewport(_), + ) => { + // Auto-panning + if let Some(shift) = tool_data.auto_panning.shift_viewport(input, responses) { + tool_data.drag_current += shift; + tool_data.drag_start += shift; + } + + SelectToolFsmState::Dragging { + axis, + using_compass, + has_dragged, + deepest, + remove, + } + } + (SelectToolFsmState::ResizingBounds | SelectToolFsmState::SkewingBounds { .. }, SelectToolMessage::PointerOutsideViewport(_)) => { + // Auto-panning + if let Some(shift) = tool_data.auto_panning.shift_viewport(input, responses) { + if let Some(bounds) = &mut tool_data.bounding_box_manager { + bounds.center_of_transformation += shift; + bounds.original_bound_transform.translation += shift; + } + } + + self + } + (SelectToolFsmState::DraggingPivot, SelectToolMessage::PointerOutsideViewport(_)) => { + // Auto-panning + let _ = tool_data.auto_panning.shift_viewport(input, responses); + + self + } + (SelectToolFsmState::Drawing { .. }, SelectToolMessage::PointerOutsideViewport(_)) => { + // Auto-panning + if let Some(shift) = tool_data.auto_panning.shift_viewport(input, responses) { + tool_data.drag_start += shift; + } + + self + } + (state, SelectToolMessage::PointerOutsideViewport(modifier_keys)) => { + // Auto-panning + let messages = [ + SelectToolMessage::PointerOutsideViewport(modifier_keys.clone()).into(), + SelectToolMessage::PointerMove(modifier_keys).into(), + ]; + tool_data.auto_panning.stop(&messages, responses); + + state + } + (SelectToolFsmState::Dragging { has_dragged, remove, deepest, .. }, SelectToolMessage::DragStop { remove_from_selection }) => { + // Deselect layer if not snap dragging + responses.add(DocumentMessage::EndTransaction); + tool_data.axis_align = false; + + if !has_dragged && input.keyboard.key(remove_from_selection) && tool_data.layer_selected_on_start.is_none() { + // When you click on the layer with remove from selection key (shift) pressed, we deselect all nodes that are children. + let quad = tool_data.selection_quad(); + let intersection = document.intersect_quad_no_artboards(quad, input); + + if let Some(path) = intersection.last() { + let replacement_selected_layers: Vec<_> = document + .network_interface + .selected_nodes() + .selected_layers(document.metadata()) + .filter(|&layer| !path.starts_with(layer, document.metadata())) + .collect(); + + tool_data.layers_dragging.clear(); + tool_data.layers_dragging.extend(replacement_selected_layers.iter()); + + responses.add(NodeGraphMessage::SelectedNodesSet { + nodes: replacement_selected_layers + .iter() + .filter_map(|layer| { + if *layer != LayerNodeIdentifier::ROOT_PARENT { + Some(layer.to_node()) + } else { + log::error!("ROOT_PARENT cannot be part of replacement_selected_layers"); + None + } + }) + .collect(), + }); + } + } else if tool_data.select_single_layer.take().is_some() { + // Previously, we may have had many layers selected. If the user clicks without dragging, we should just select the one layer that has been clicked. + if !has_dragged { + let selected = document.click_list(input).collect::>(); + let intersection = document.find_deepest(&selected); + if let Some(intersection) = intersection { + tool_data.layer_selected_on_start = Some(intersection); + + match tool_data.nested_selection_behavior { + NestedSelectionBehavior::Shallowest if remove && !deepest => drag_shallowest_manipulation(responses, selected, tool_data, document, true, true), + NestedSelectionBehavior::Deepest if remove => drag_deepest_manipulation(responses, selected, tool_data, document, true), + NestedSelectionBehavior::Shallowest if !deepest => drag_shallowest_manipulation(responses, selected, tool_data, document, false, true), + _ => { + responses.add(DocumentMessage::DeselectAllLayers); + tool_data.layers_dragging.clear(); + drag_deepest_manipulation(responses, selected, tool_data, document, false) + } + } + + tool_data.get_snap_candidates(document, input); + + responses.add(DocumentMessage::StartTransaction); + } + } + } + + tool_data.layer_selected_on_start = None; + + tool_data.snap_manager.cleanup(responses); + tool_data.select_single_layer = None; + + let selection = tool_data.nested_selection_behavior; + SelectToolFsmState::Ready { selection } + } + ( + SelectToolFsmState::ResizingBounds + | SelectToolFsmState::SkewingBounds { .. } + | SelectToolFsmState::RotatingBounds + | SelectToolFsmState::Dragging { .. } + | SelectToolFsmState::DraggingPivot, + SelectToolMessage::DragStop { .. } | SelectToolMessage::Enter, + ) => { + let drag_too_small = input.mouse.position.distance(tool_data.drag_start) < 10. * f64::EPSILON; + let response = if drag_too_small { DocumentMessage::AbortTransaction } else { DocumentMessage::EndTransaction }; + responses.add(response); + tool_data.axis_align = false; + tool_data.snap_manager.cleanup(responses); + + if !matches!(self, SelectToolFsmState::DraggingPivot) { + if let Some(bounds) = &mut tool_data.bounding_box_manager { + bounds.original_transforms.clear(); + } + } + + let selection = tool_data.nested_selection_behavior; + SelectToolFsmState::Ready { selection } + } + (SelectToolFsmState::Drawing { selection_shape, .. }, SelectToolMessage::DragStop { remove_from_selection }) => { + let quad = tool_data.selection_quad(); + + let selection_mode = match tool_action_data.preferences.get_selection_mode() { + SelectionMode::Directional => tool_data.calculate_selection_mode_from_direction(), + selection_mode => selection_mode, + }; + + let intersection: Vec = match selection_shape { + SelectionShapeType::Box => document.intersect_quad_no_artboards(quad, input).collect(), + SelectionShapeType::Lasso => tool_data.intersect_lasso_no_artboards(document, input), + }; + let new_selected: HashSet<_> = if selection_mode == SelectionMode::Enclosed { + let is_inside = |layer: &LayerNodeIdentifier| match selection_shape { + SelectionShapeType::Box => document.is_layer_fully_inside(layer, quad), + SelectionShapeType::Lasso => tool_data.is_layer_inside_lasso_polygon(layer, document, input), + }; + intersection.into_iter().filter(is_inside).collect() + } else { + intersection.into_iter().collect() + }; + + let current_selected: HashSet<_> = document.network_interface.selected_nodes().selected_layers(document.metadata()).collect(); + let negative_selection = input.keyboard.key(remove_from_selection); + let selection_modified = new_selected != current_selected; + + // Negative selection when both Shift and Ctrl are pressed + if negative_selection { + let updated_selection = current_selected + .into_iter() + .filter(|layer| !new_selected.iter().any(|selected| layer.starts_with(*selected, document.metadata()))) + .collect(); + tool_data.layers_dragging = updated_selection; + } else if selection_modified { + match tool_data.nested_selection_behavior { + NestedSelectionBehavior::Deepest => { + let filtered_selections = filter_nested_selection(document.metadata(), &new_selected); + tool_data.layers_dragging.extend(filtered_selections); + } + NestedSelectionBehavior::Shallowest => { + // Find each new_selected's parent node + let parent_selected: HashSet<_> = new_selected + .into_iter() + .map(|layer| layer.ancestors(document.metadata()).filter(not_artboard(document)).last().unwrap_or(layer)) + .collect(); + tool_data.layers_dragging.extend(parent_selected.iter().copied()); + } + } + } + + if negative_selection || selection_modified { + responses.add(NodeGraphMessage::SelectedNodesSet { + nodes: tool_data + .layers_dragging + .iter() + .filter_map(|layer| { + if *layer != LayerNodeIdentifier::ROOT_PARENT { + Some(layer.to_node()) + } else { + log::error!("ROOT_PARENT cannot be part of tool_data.layers_dragging"); + None + } + }) + .collect(), + }); + } + + tool_data.lasso_polygon.clear(); + + responses.add(OverlaysMessage::Draw); + + let selection = tool_data.nested_selection_behavior; + SelectToolFsmState::Ready { selection } + } + (SelectToolFsmState::Ready { .. }, SelectToolMessage::Enter) => { + let selected_nodes = document.network_interface.selected_nodes(); + let mut selected_layers = selected_nodes.selected_layers(document.metadata()); + + if let Some(layer) = selected_layers.next() { + // Check that only one layer is selected + if selected_layers.next().is_none() && is_layer_fed_by_node_of_name(layer, &document.network_interface, "Text") { + responses.add_front(ToolMessage::ActivateTool { tool_type: ToolType::Text }); + responses.add(TextToolMessage::EditSelected); + } + } + + let selection = tool_data.nested_selection_behavior; + SelectToolFsmState::Ready { selection } + } + (SelectToolFsmState::Dragging { .. }, SelectToolMessage::Abort) => { + responses.add(DocumentMessage::AbortTransaction); + tool_data.snap_manager.cleanup(responses); + tool_data.axis_align = false; + tool_data.lasso_polygon.clear(); + responses.add(OverlaysMessage::Draw); + + let selection = tool_data.nested_selection_behavior; + SelectToolFsmState::Ready { selection } + } + (_, SelectToolMessage::Abort) => { + tool_data.layers_dragging.retain(|layer| { + if *layer != LayerNodeIdentifier::ROOT_PARENT { + document.network_interface.document_network().nodes.contains_key(&layer.to_node()) + } else { + false + } + }); + + if let Some(bounds) = &mut tool_data.bounding_box_manager { + bounds.original_transforms.clear(); + } + + responses.add(DocumentMessage::AbortTransaction); + tool_data.snap_manager.cleanup(responses); + tool_data.lasso_polygon.clear(); + responses.add(OverlaysMessage::Draw); + + let selection = tool_data.nested_selection_behavior; + SelectToolFsmState::Ready { selection } + } + (_, SelectToolMessage::SetPivot { position }) => { + responses.add(DocumentMessage::StartTransaction); + + let pos: Option = position.into(); + tool_data.pivot.set_normalized_position(pos.unwrap(), document, responses); + + self + } + _ => self, + } + } + + fn standard_tool_messages(&self, message: &ToolMessage, responses: &mut VecDeque) -> bool { + // Check for standard hits or cursor events + match message { + ToolMessage::UpdateHints => { + self.update_hints(responses); + true + } + ToolMessage::UpdateCursor => { + self.update_cursor(responses); + true + } + _ => false, + } + } + + fn update_hints(&self, responses: &mut VecDeque) { + match self { + SelectToolFsmState::Ready { selection } => { + let hint_data = HintData(vec![ + HintGroup({ + let mut hints = vec![HintInfo::mouse(MouseMotion::Lmb, "Select Object"), HintInfo::keys([Key::Shift], "Extend").prepend_plus()]; + if *selection == NestedSelectionBehavior::Shallowest { + hints.extend([HintInfo::keys([Key::Accel], "Deepest").prepend_plus(), HintInfo::mouse(MouseMotion::LmbDouble, "Deepen")]); + } + hints + }), + HintGroup(vec![ + HintInfo::mouse(MouseMotion::LmbDrag, "Select Area"), + HintInfo::keys([Key::Shift], "Extend").prepend_plus(), + HintInfo::keys([Key::Alt], "Subtract").prepend_plus(), + HintInfo::keys([Key::Control], "Lasso").prepend_plus(), + ]), + // TODO: Make all the following hints only appear if there is at least one selected layer + HintGroup(vec![HintInfo::mouse(MouseMotion::LmbDrag, "Drag Selected")]), + HintGroup(vec![HintInfo::multi_keys([[Key::KeyG], [Key::KeyR], [Key::KeyS]], "Grab/Rotate/Scale Selected")]), + HintGroup(vec![ + HintInfo::arrow_keys("Nudge Selected"), + HintInfo::keys([Key::Shift], "10x").prepend_plus(), + HintInfo::keys([Key::Alt], "Resize Corner").prepend_plus(), + HintInfo::keys([Key::Control], "Other Corner").prepend_plus(), + ]), + HintGroup(vec![ + HintInfo::keys_and_mouse([Key::Alt], MouseMotion::LmbDrag, "Move Duplicate"), + HintInfo::keys([Key::Control, Key::KeyD], "Duplicate").add_mac_keys([Key::Command, Key::KeyD]), + ]), + ]); + responses.add(FrontendMessage::UpdateInputHints { hint_data }); + } + SelectToolFsmState::Dragging { axis, using_compass, has_dragged, .. } if *has_dragged => { + let mut hint_data = vec![ + HintGroup(vec![HintInfo::mouse(MouseMotion::Rmb, ""), HintInfo::keys([Key::Escape], "Cancel").prepend_slash()]), + HintGroup(vec![ + HintInfo::keys([Key::Alt], "Move Duplicate"), + HintInfo::keys([Key::Control, Key::KeyD], "Place Duplicate").add_mac_keys([Key::Command, Key::KeyD]), + ]), + ]; + + if !(*using_compass && axis.is_constraint()) { + hint_data.push(HintGroup(vec![HintInfo::keys([Key::Shift], "Constrain to Axis")])); + }; + let hint_data = HintData(hint_data); + responses.add(FrontendMessage::UpdateInputHints { hint_data }); + } + SelectToolFsmState::Drawing { has_drawn, .. } if *has_drawn => { + let hint_data = HintData(vec![ + HintGroup(vec![HintInfo::mouse(MouseMotion::Rmb, ""), HintInfo::keys([Key::Escape], "Cancel").prepend_slash()]), + HintGroup(vec![HintInfo::keys([Key::Shift], "Extend"), HintInfo::keys([Key::Alt], "Subtract")]), + // TODO: Re-select deselected layers during drag when Shift is pressed, and re-deselect if Shift is released before drag ends. + // TODO: (See https://discord.com/channels/731730685944922173/1216976541947531264/1321360311298818048) + // HintGroup(vec![HintInfo::keys([Key::Shift], "Extend")]) + ]); + responses.add(FrontendMessage::UpdateInputHints { hint_data }); + } + SelectToolFsmState::Drawing { .. } | SelectToolFsmState::Dragging { .. } => {} + SelectToolFsmState::ResizingBounds => { + let hint_data = HintData(vec![ + HintGroup(vec![HintInfo::mouse(MouseMotion::Rmb, ""), HintInfo::keys([Key::Escape], "Cancel").prepend_slash()]), + HintGroup(vec![HintInfo::keys([Key::Alt], "From Pivot"), HintInfo::keys([Key::Shift], "Preserve Aspect Ratio")]), + ]); + responses.add(FrontendMessage::UpdateInputHints { hint_data }); + } + SelectToolFsmState::RotatingBounds => { + let hint_data = HintData(vec![ + HintGroup(vec![HintInfo::mouse(MouseMotion::Rmb, ""), HintInfo::keys([Key::Escape], "Cancel").prepend_slash()]), + HintGroup(vec![HintInfo::keys([Key::Shift], "15° Increments")]), + ]); + responses.add(FrontendMessage::UpdateInputHints { hint_data }); + } + SelectToolFsmState::SkewingBounds { .. } => { + let hint_data = HintData(vec![ + HintGroup(vec![HintInfo::mouse(MouseMotion::Rmb, ""), HintInfo::keys([Key::Escape], "Cancel").prepend_slash()]), + HintGroup(vec![HintInfo::keys([Key::Control], "Unlock Slide")]), + ]); + responses.add(FrontendMessage::UpdateInputHints { hint_data }); + } + SelectToolFsmState::DraggingPivot => { + let hint_data = HintData(vec![HintGroup(vec![HintInfo::mouse(MouseMotion::Rmb, ""), HintInfo::keys([Key::Escape], "Cancel").prepend_slash()])]); + responses.add(FrontendMessage::UpdateInputHints { hint_data }); + } + } + } + + fn update_cursor(&self, responses: &mut VecDeque) { + responses.add(FrontendMessage::UpdateMouseCursor { cursor: MouseCursorIcon::Default }); + } +} + +fn not_artboard(document: &DocumentMessageHandler) -> impl Fn(&LayerNodeIdentifier) -> bool + '_ { + |&layer| layer != LayerNodeIdentifier::ROOT_PARENT && !document.network_interface.is_artboard(&layer.to_node(), &[]) +} + +fn drag_shallowest_manipulation(responses: &mut VecDeque, selected: Vec, tool_data: &mut SelectToolData, document: &DocumentMessageHandler, remove: bool, exists: bool) { + if selected.is_empty() { + return; + } + + let clicked_layer = document.find_deepest(&selected).unwrap_or_else(|| { + LayerNodeIdentifier::ROOT_PARENT + .children(document.metadata()) + .next() + .expect("ROOT_PARENT should have at least one layer when clicking") + }); + + let metadata = document.metadata(); + + let selected_layers = document.network_interface.selected_nodes().selected_layers(document.metadata()).collect::>(); + let final_selection: Option = (!selected_layers.is_empty() && selected_layers != vec![LayerNodeIdentifier::ROOT_PARENT]).then_some(()).and_then(|_| { + let mut relevant_layers = document.network_interface.selected_nodes().selected_layers(document.metadata()).collect::>(); + if !relevant_layers.contains(&clicked_layer) { + relevant_layers.push(clicked_layer); + } + clicked_layer + .ancestors(metadata) + .filter(not_artboard(document)) + .find(|&ancestor| relevant_layers.iter().all(|layer| *layer == ancestor || ancestor.is_ancestor_of(metadata, layer))) + .and_then(|least_common_ancestor| { + let common_siblings: Vec<_> = least_common_ancestor.children(metadata).collect(); + (clicked_layer == least_common_ancestor) + .then_some(least_common_ancestor) + .or_else(|| common_siblings.iter().find(|&&child| clicked_layer == child || child.is_ancestor_of(metadata, &clicked_layer)).copied()) + }) + }); + + if final_selection.is_some_and(|layer| selected_layers.iter().any(|selected| layer.is_child_of(metadata, selected))) { + if exists && remove && selected_layers.len() == 1 { + responses.add(DocumentMessage::DeselectAllLayers); + tool_data.layers_dragging.clear(); + } + return; + } + + if !exists && !remove { + responses.add(DocumentMessage::DeselectAllLayers); + tool_data.layers_dragging.clear(); + } + + let new_selected = final_selection.unwrap_or_else(|| clicked_layer.ancestors(document.metadata()).filter(not_artboard(document)).last().unwrap_or(clicked_layer)); + tool_data.layers_dragging.extend(vec![new_selected]); + tool_data.layers_dragging.retain(|&selected_layer| !selected_layer.is_child_of(metadata, &new_selected)); + if remove { + tool_data.layers_dragging.retain(|&selected_layer| clicked_layer != selected_layer); + if selected_layers.contains(&new_selected) { + tool_data.layers_dragging.retain(|&selected_layer| new_selected != selected_layer); + } + } + + responses.add(NodeGraphMessage::SelectedNodesSet { + nodes: tool_data + .layers_dragging + .iter() + .filter_map(|layer| { + if *layer != LayerNodeIdentifier::ROOT_PARENT { + Some(layer.to_node()) + } else { + log::error!("ROOT_PARENT cannot be part of tool_data.layers_dragging"); + None + } + }) + .collect(), + }); +} + +fn layer_selected_shallowest(clicked_layer: LayerNodeIdentifier, document: &DocumentMessageHandler) -> Option { + let metadata = document.metadata(); + let selected_layers = document.network_interface.selected_nodes().selected_layers(document.metadata()).collect::>(); + let final_selection: Option = (!selected_layers.is_empty() && selected_layers != vec![LayerNodeIdentifier::ROOT_PARENT]).then_some(()).and_then(|_| { + let mut relevant_layers = document.network_interface.selected_nodes().selected_layers(document.metadata()).collect::>(); + if !relevant_layers.contains(&clicked_layer) { + relevant_layers.push(clicked_layer); + } + clicked_layer + .ancestors(metadata) + .filter(not_artboard(document)) + .find(|&ancestor| relevant_layers.iter().all(|layer| *layer == ancestor || ancestor.is_ancestor_of(metadata, layer))) + .and_then(|least_common_ancestor| { + let common_siblings: Vec<_> = least_common_ancestor.children(metadata).collect(); + (clicked_layer == least_common_ancestor) + .then_some(least_common_ancestor) + .or_else(|| common_siblings.iter().find(|&&child| clicked_layer == child || child.is_ancestor_of(metadata, &clicked_layer)).copied()) + }) + }); + + if final_selection.is_some_and(|layer| selected_layers.iter().any(|selected| layer.is_child_of(metadata, selected))) { + return None; + } + + let new_selected = final_selection.unwrap_or_else(|| clicked_layer.ancestors(document.metadata()).filter(not_artboard(document)).last().unwrap_or(clicked_layer)); + Some(new_selected) +} + +fn drag_deepest_manipulation(responses: &mut VecDeque, selected: Vec, tool_data: &mut SelectToolData, document: &DocumentMessageHandler, remove: bool) { + let layer = document.find_deepest(&selected).unwrap_or( + LayerNodeIdentifier::ROOT_PARENT + .children(document.metadata()) + .next() + .expect("ROOT_PARENT should have a layer child when clicking"), + ); + if !remove { + tool_data.layers_dragging.extend(vec![layer]); + } else { + tool_data.layers_dragging.retain(|&selected_layer| layer != selected_layer); + } + responses.add(NodeGraphMessage::SelectedNodesSet { + nodes: tool_data + .layers_dragging + .iter() + .filter_map(|layer| { + if *layer != LayerNodeIdentifier::ROOT_PARENT { + Some(layer.to_node()) + } else { + log::error!("ROOT_PARENT cannot be part of tool_data.layers_dragging"); + None + } + }) + .collect(), + }); +} + +/// Called when you double click on the layer of the shallowest layer. +/// If possible, the direct sibling of an old selected layer is the new selected layer. +/// Otherwise, the first non-parent ancestor is selected. +fn edit_layer_shallowest_manipulation(document: &DocumentMessageHandler, layer: LayerNodeIdentifier, responses: &mut VecDeque) { + let Some(new_selected) = layer.ancestors(document.metadata()).filter(not_artboard(document)).find(|ancestor| { + ancestor + .parent(document.metadata()) + .is_some_and(|parent| document.network_interface.selected_nodes().selected_layers_contains(parent, document.metadata())) + }) else { + return; + }; + + if new_selected == LayerNodeIdentifier::ROOT_PARENT { + log::error!("new_selected cannot be ROOT_PARENT"); + return; + } + + responses.add(NodeGraphMessage::SelectedNodesSet { nodes: vec![new_selected.to_node()] }); +} + +/// Called when a double click on a layer in deep select mode. +/// If the layer is text, the text tool is selected. +fn edit_layer_deepest_manipulation(layer: LayerNodeIdentifier, network_interface: &NodeNetworkInterface, responses: &mut VecDeque) { + if is_layer_fed_by_node_of_name(layer, network_interface, "Text") { + responses.add_front(ToolMessage::ActivateTool { tool_type: ToolType::Text }); + responses.add(TextToolMessage::EditSelected); + } +} + +pub fn extend_lasso(lasso_polygon: &mut Vec, point: DVec2) { + if lasso_polygon.len() < 2 { + lasso_polygon.push(point); + } else { + let last_points = lasso_polygon.last_chunk::<2>().unwrap(); + let distance = last_points[0].distance_squared(last_points[1]); + + if distance < SELECTION_TOLERANCE.powi(2) { + lasso_polygon.pop(); + } + lasso_polygon.push(point); + } +} + +pub fn filter_nested_selection(metadata: &DocumentMetadata, new_selected: &HashSet) -> HashSet { + // First collect childless layers + let mut filtered_selection: HashSet<_> = new_selected.iter().copied().filter(|layer| !layer.has_children(metadata)).collect(); + + // Then process parents with all children selected + for &layer in new_selected { + // Skip if the layer is not a parent + if !layer.has_children(metadata) { + continue; + } + + // If any ancestor is already present in the filtered selection, don't include its child + if layer.ancestors(metadata).any(|ancestor| filtered_selection.contains(&ancestor)) { + continue; + } + + // Skip if any of the children are not selected + if !layer.descendants(metadata).all(|descendant| new_selected.contains(&descendant)) { + continue; + } + + // Remove all descendants of the parent + for child in layer.descendants(metadata) { + filtered_selection.remove(&child); + } + // Add the parent + filtered_selection.insert(layer); + } + + filtered_selection +} diff --git a/editor/src/messages/tool/tool_messages/shape_tool.rs b/editor/src/messages/tool/tool_messages/shape_tool.rs new file mode 100644 index 0000000000000000000000000000000000000000..532000040417323d99db4c76bc42d98905db6a56 --- /dev/null +++ b/editor/src/messages/tool/tool_messages/shape_tool.rs @@ -0,0 +1,909 @@ +use super::tool_prelude::*; +use crate::consts::{DEFAULT_STROKE_WIDTH, SNAP_POINT_TOLERANCE}; +use crate::messages::portfolio::document::graph_operation::utility_types::TransformIn; +use crate::messages::portfolio::document::overlays::utility_types::OverlayContext; +use crate::messages::portfolio::document::utility_types::document_metadata::LayerNodeIdentifier; +use crate::messages::portfolio::document::utility_types::network_interface::InputConnector; +use crate::messages::tool::common_functionality::auto_panning::AutoPanning; +use crate::messages::tool::common_functionality::color_selector::{ToolColorOptions, ToolColorType}; +use crate::messages::tool::common_functionality::gizmos::gizmo_manager::GizmoManager; +use crate::messages::tool::common_functionality::graph_modification_utils; +use crate::messages::tool::common_functionality::graph_modification_utils::NodeGraphLayer; +use crate::messages::tool::common_functionality::resize::Resize; +use crate::messages::tool::common_functionality::shapes::line_shape::{LineToolData, clicked_on_line_endpoints}; +use crate::messages::tool::common_functionality::shapes::polygon_shape::Polygon; +use crate::messages::tool::common_functionality::shapes::shape_utility::{ShapeToolModifierKey, ShapeType, anchor_overlays, transform_cage_overlays}; +use crate::messages::tool::common_functionality::shapes::star_shape::Star; +use crate::messages::tool::common_functionality::shapes::{Ellipse, Line, Rectangle}; +use crate::messages::tool::common_functionality::snapping::{self, SnapCandidatePoint, SnapData, SnapTypeConfiguration}; +use crate::messages::tool::common_functionality::transformation_cage::{BoundingBoxManager, EdgeBool}; +use crate::messages::tool::common_functionality::utility_functions::{closest_point, resize_bounds, rotate_bounds, skew_bounds, transforming_transform_cage}; +use graph_craft::document::value::TaggedValue; +use graph_craft::document::{NodeId, NodeInput}; +use graphene_std::Color; +use graphene_std::renderer::Quad; +use graphene_std::vector::misc::ArcType; +use std::vec; + +#[derive(Default)] +pub struct ShapeTool { + fsm_state: ShapeToolFsmState, + tool_data: ShapeToolData, + options: ShapeToolOptions, +} + +pub struct ShapeToolOptions { + line_weight: f64, + fill: ToolColorOptions, + stroke: ToolColorOptions, + vertices: u32, + shape_type: ShapeType, + arc_type: ArcType, +} + +impl Default for ShapeToolOptions { + fn default() -> Self { + Self { + line_weight: DEFAULT_STROKE_WIDTH, + fill: ToolColorOptions::new_secondary(), + stroke: ToolColorOptions::new_primary(), + vertices: 5, + shape_type: ShapeType::Polygon, + arc_type: ArcType::Open, + } + } +} + +#[derive(PartialEq, Clone, Debug, serde::Serialize, serde::Deserialize, specta::Type)] +pub enum ShapeOptionsUpdate { + FillColor(Option), + FillColorType(ToolColorType), + LineWeight(f64), + StrokeColor(Option), + StrokeColorType(ToolColorType), + WorkingColors(Option, Option), + Vertices(u32), + ShapeType(ShapeType), + ArcType(ArcType), +} + +#[impl_message(Message, ToolMessage, Shape)] +#[derive(PartialEq, Clone, Debug, serde::Serialize, serde::Deserialize, specta::Type)] +pub enum ShapeToolMessage { + // Standard messages + Overlays(OverlayContext), + Abort, + WorkingColorChanged, + + // Tool-specific messages + DragStart, + DragStop, + HideShapeTypeWidget(bool), + PointerMove(ShapeToolModifierKey), + PointerOutsideViewport(ShapeToolModifierKey), + UpdateOptions(ShapeOptionsUpdate), + SetShape(ShapeType), + + IncreaseSides, + DecreaseSides, + + NudgeSelectedLayers { delta_x: f64, delta_y: f64, resize: Key, resize_opposite_corner: Key }, +} + +fn create_sides_widget(vertices: u32) -> WidgetHolder { + NumberInput::new(Some(vertices as f64)) + .label("Sides") + .int() + .min(3.) + .max(1000.) + .mode(NumberInputMode::Increment) + .on_update(|number_input: &NumberInput| ShapeToolMessage::UpdateOptions(ShapeOptionsUpdate::Vertices(number_input.value.unwrap() as u32)).into()) + .widget_holder() +} + +fn create_shape_option_widget(shape_type: ShapeType) -> WidgetHolder { + let entries = vec![vec![ + MenuListEntry::new("Polygon") + .label("Polygon") + .on_commit(move |_| ShapeToolMessage::UpdateOptions(ShapeOptionsUpdate::ShapeType(ShapeType::Polygon)).into()), + MenuListEntry::new("Star") + .label("Star") + .on_commit(move |_| ShapeToolMessage::UpdateOptions(ShapeOptionsUpdate::ShapeType(ShapeType::Star)).into()), + ]]; + DropdownInput::new(entries).selected_index(Some(shape_type as u32)).widget_holder() +} + +fn create_weight_widget(line_weight: f64) -> WidgetHolder { + NumberInput::new(Some(line_weight)) + .unit(" px") + .label("Weight") + .min(0.) + .max((1_u64 << f64::MANTISSA_DIGITS) as f64) + .on_update(|number_input: &NumberInput| ShapeToolMessage::UpdateOptions(ShapeOptionsUpdate::LineWeight(number_input.value.unwrap())).into()) + .widget_holder() +} + +impl LayoutHolder for ShapeTool { + fn layout(&self) -> Layout { + let mut widgets = vec![]; + + if !self.tool_data.hide_shape_option_widget { + widgets.push(create_shape_option_widget(self.options.shape_type)); + widgets.push(Separator::new(SeparatorType::Unrelated).widget_holder()); + + if self.options.shape_type == ShapeType::Polygon || self.options.shape_type == ShapeType::Star { + widgets.push(create_sides_widget(self.options.vertices)); + widgets.push(Separator::new(SeparatorType::Unrelated).widget_holder()); + } + } + + if self.options.shape_type != ShapeType::Line { + widgets.append(&mut self.options.fill.create_widgets( + "Fill", + true, + |_| ShapeToolMessage::UpdateOptions(ShapeOptionsUpdate::FillColor(None)).into(), + |color_type: ToolColorType| WidgetCallback::new(move |_| ShapeToolMessage::UpdateOptions(ShapeOptionsUpdate::FillColorType(color_type.clone())).into()), + |color: &ColorInput| ShapeToolMessage::UpdateOptions(ShapeOptionsUpdate::FillColor(color.value.as_solid().map(|color| color.to_linear_srgb()))).into(), + )); + + widgets.push(Separator::new(SeparatorType::Unrelated).widget_holder()); + } + + widgets.append(&mut self.options.stroke.create_widgets( + "Stroke", + true, + |_| ShapeToolMessage::UpdateOptions(ShapeOptionsUpdate::StrokeColor(None)).into(), + |color_type: ToolColorType| WidgetCallback::new(move |_| ShapeToolMessage::UpdateOptions(ShapeOptionsUpdate::StrokeColorType(color_type.clone())).into()), + |color: &ColorInput| ShapeToolMessage::UpdateOptions(ShapeOptionsUpdate::StrokeColor(color.value.as_solid().map(|color| color.to_linear_srgb()))).into(), + )); + widgets.push(Separator::new(SeparatorType::Unrelated).widget_holder()); + widgets.push(create_weight_widget(self.options.line_weight)); + + Layout::WidgetLayout(WidgetLayout::new(vec![LayoutGroup::Row { widgets }])) + } +} + +impl<'a> MessageHandler> for ShapeTool { + fn process_message(&mut self, message: ToolMessage, responses: &mut VecDeque, tool_data: &mut ToolActionHandlerData<'a>) { + let ToolMessage::Shape(ShapeToolMessage::UpdateOptions(action)) = message else { + self.fsm_state.process_event(message, &mut self.tool_data, tool_data, &self.options, responses, true); + return; + }; + match action { + ShapeOptionsUpdate::FillColor(color) => { + self.options.fill.custom_color = color; + self.options.fill.color_type = ToolColorType::Custom; + } + ShapeOptionsUpdate::FillColorType(color_type) => { + self.options.fill.color_type = color_type; + } + ShapeOptionsUpdate::LineWeight(line_weight) => { + self.options.line_weight = line_weight; + } + ShapeOptionsUpdate::StrokeColor(color) => { + self.options.stroke.custom_color = color; + self.options.stroke.color_type = ToolColorType::Custom; + } + ShapeOptionsUpdate::StrokeColorType(color_type) => { + self.options.stroke.color_type = color_type; + } + ShapeOptionsUpdate::WorkingColors(primary, secondary) => { + self.options.stroke.primary_working_color = primary; + self.options.stroke.secondary_working_color = secondary; + self.options.fill.primary_working_color = primary; + self.options.fill.secondary_working_color = secondary; + } + ShapeOptionsUpdate::ShapeType(shape) => { + self.options.shape_type = shape; + self.tool_data.current_shape = shape; + } + ShapeOptionsUpdate::Vertices(vertices) => { + self.options.vertices = vertices; + } + ShapeOptionsUpdate::ArcType(arc_type) => { + self.options.arc_type = arc_type; + } + } + + self.fsm_state.update_hints(responses); + self.send_layout(responses, LayoutTarget::ToolOptions); + } + + fn actions(&self) -> ActionList { + match self.fsm_state { + ShapeToolFsmState::Ready(_) => actions!(ShapeToolMessageDiscriminant; + DragStart, + PointerMove, + SetShape, + Abort, + HideShapeTypeWidget, + IncreaseSides, + DecreaseSides, + NudgeSelectedLayers, + ), + ShapeToolFsmState::Drawing(_) + | ShapeToolFsmState::ResizingBounds + | ShapeToolFsmState::DraggingLineEndpoints + | ShapeToolFsmState::RotatingBounds + | ShapeToolFsmState::ModifyingGizmo + | ShapeToolFsmState::SkewingBounds { .. } => { + actions!(ShapeToolMessageDiscriminant; + DragStop, + Abort, + PointerMove, + SetShape, + HideShapeTypeWidget, + IncreaseSides, + DecreaseSides, + NudgeSelectedLayers, + ) + } + } + } +} + +impl ToolMetadata for ShapeTool { + fn icon_name(&self) -> String { + "VectorPolygonTool".into() + } + fn tooltip(&self) -> String { + "Shape Tool".into() + } + fn tool_type(&self) -> ToolType { + ToolType::Shape + } +} + +impl ToolTransition for ShapeTool { + fn event_to_message_map(&self) -> EventToMessageMap { + EventToMessageMap { + overlay_provider: Some(|overlay_context| ShapeToolMessage::Overlays(overlay_context).into()), + tool_abort: Some(ShapeToolMessage::Abort.into()), + working_color_changed: Some(ShapeToolMessage::WorkingColorChanged.into()), + ..Default::default() + } + } +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub enum ShapeToolFsmState { + Ready(ShapeType), + Drawing(ShapeType), + + // Gizmos + DraggingLineEndpoints, + ModifyingGizmo, + + // Transform cage + ResizingBounds, + RotatingBounds, + SkewingBounds { skew: Key }, +} + +impl Default for ShapeToolFsmState { + fn default() -> Self { + ShapeToolFsmState::Ready(ShapeType::default()) + } +} + +#[derive(Clone, Debug, Default)] +pub struct ShapeToolData { + pub data: Resize, + auto_panning: AutoPanning, + + // In viewport space + pub last_mouse_position: DVec2, + + // Hide the dropdown menu when using Line, Rectangle, or Ellipse aliases + pub hide_shape_option_widget: bool, + + // Shape-specific data + pub line_data: LineToolData, + + // Used for by transform cage + pub bounding_box_manager: Option, + layers_dragging: Vec, + snap_candidates: Vec, + skew_edge: EdgeBool, + cursor: MouseCursorIcon, + + // Current shape which is being drawn + current_shape: ShapeType, + + // Gizmos + gizmo_manger: GizmoManager, +} + +impl ShapeToolData { + fn get_snap_candidates(&mut self, document: &DocumentMessageHandler, input: &InputPreprocessorMessageHandler) { + self.snap_candidates.clear(); + for &layer in &self.layers_dragging { + if (self.snap_candidates.len() as f64) < document.snapping_state.tolerance { + snapping::get_layer_snap_points(layer, &SnapData::new(document, input), &mut self.snap_candidates); + } + if let Some(bounds) = document.metadata().bounding_box_with_transform(layer, DAffine2::IDENTITY) { + let quad = document.metadata().transform_to_document(layer) * Quad::from_box(bounds); + snapping::get_bbox_points(quad, &mut self.snap_candidates, snapping::BBoxSnapValues::BOUNDING_BOX, document); + } + } + } +} + +impl Fsm for ShapeToolFsmState { + type ToolData = ShapeToolData; + type ToolOptions = ShapeToolOptions; + + fn transition( + self, + event: ToolMessage, + tool_data: &mut Self::ToolData, + ToolActionHandlerData { + document, + global_tool_data, + input, + preferences, + shape_editor, + .. + }: &mut ToolActionHandlerData, + tool_options: &Self::ToolOptions, + responses: &mut VecDeque, + ) -> Self { + let all_selected_layers_line = document + .network_interface + .selected_nodes() + .selected_visible_and_unlocked_layers(&document.network_interface) + .all(|layer| graph_modification_utils::get_line_id(layer, &document.network_interface).is_some()); + + let ToolMessage::Shape(event) = event else { return self }; + + match (self, event) { + (_, ShapeToolMessage::Overlays(mut overlay_context)) => { + let mouse_position = tool_data + .data + .snap_manager + .indicator_pos() + .map(|pos| document.metadata().document_to_viewport.transform_point2(pos)) + .unwrap_or(input.mouse.position); + let is_resizing_or_rotating = matches!(self, ShapeToolFsmState::ResizingBounds | ShapeToolFsmState::SkewingBounds { .. } | ShapeToolFsmState::RotatingBounds); + + if matches!(self, Self::Ready(_)) && !input.keyboard.key(Key::Control) { + tool_data.gizmo_manger.handle_actions(mouse_position, document, responses); + tool_data.gizmo_manger.overlays(document, input, shape_editor, mouse_position, &mut overlay_context); + } + + if matches!(self, ShapeToolFsmState::ModifyingGizmo) && !input.keyboard.key(Key::Control) { + tool_data.gizmo_manger.dragging_overlays(document, input, shape_editor, mouse_position, &mut overlay_context); + } + + let modifying_transform_cage = matches!(self, ShapeToolFsmState::ResizingBounds | ShapeToolFsmState::RotatingBounds | ShapeToolFsmState::SkewingBounds { .. }); + let hovering_over_gizmo = tool_data.gizmo_manger.hovering_over_gizmo(); + + if !is_resizing_or_rotating && !matches!(self, ShapeToolFsmState::ModifyingGizmo) && !modifying_transform_cage && !hovering_over_gizmo { + tool_data.data.snap_manager.draw_overlays(SnapData::new(document, input), &mut overlay_context); + } + + if modifying_transform_cage && !matches!(self, ShapeToolFsmState::ModifyingGizmo) { + transform_cage_overlays(document, tool_data, &mut overlay_context); + } + + if input.keyboard.key(Key::Control) && matches!(self, ShapeToolFsmState::Ready(_)) { + anchor_overlays(document, &mut overlay_context); + } else if matches!(self, ShapeToolFsmState::Ready(_)) { + Line::overlays(document, tool_data, &mut overlay_context); + + if all_selected_layers_line { + return self; + } + + if !hovering_over_gizmo { + transform_cage_overlays(document, tool_data, &mut overlay_context); + } + + let dragging_bounds = tool_data + .bounding_box_manager + .as_mut() + .and_then(|bounding_box| bounding_box.check_selected_edges(input.mouse.position)) + .is_some(); + + if let Some(bounds) = tool_data.bounding_box_manager.as_mut() { + let edges = bounds.check_selected_edges(input.mouse.position); + let is_skewing = matches!(self, ShapeToolFsmState::SkewingBounds { .. }); + let is_near_square = edges.is_some_and(|hover_edge| bounds.over_extended_edge_midpoint(input.mouse.position, hover_edge)); + if is_skewing || (dragging_bounds && is_near_square && !is_resizing_or_rotating && !hovering_over_gizmo) { + bounds.render_skew_gizmos(&mut overlay_context, tool_data.skew_edge); + } + if !is_skewing && dragging_bounds && !hovering_over_gizmo { + if let Some(edges) = edges { + tool_data.skew_edge = bounds.get_closest_edge(edges, input.mouse.position); + } + } + } + } + + if matches!(self, ShapeToolFsmState::Drawing(_) | ShapeToolFsmState::DraggingLineEndpoints) { + Line::overlays(document, tool_data, &mut overlay_context); + } + + self + } + (ShapeToolFsmState::Ready(_), ShapeToolMessage::IncreaseSides) => { + responses.add(ShapeToolMessage::UpdateOptions(ShapeOptionsUpdate::Vertices(tool_options.vertices + 1))); + self + } + (ShapeToolFsmState::Ready(_), ShapeToolMessage::DecreaseSides) => { + responses.add(ShapeToolMessage::UpdateOptions(ShapeOptionsUpdate::Vertices((tool_options.vertices - 1).max(3)))); + self + } + ( + ShapeToolFsmState::Ready(_), + ShapeToolMessage::NudgeSelectedLayers { + delta_x, + delta_y, + resize, + resize_opposite_corner, + }, + ) => { + responses.add(DocumentMessage::NudgeSelectedLayers { + delta_x, + delta_y, + resize, + resize_opposite_corner, + }); + + self + } + (ShapeToolFsmState::Drawing(_), ShapeToolMessage::NudgeSelectedLayers { .. }) => { + let increase = input.keyboard.key(Key::ArrowUp); + let decrease = input.keyboard.key(Key::ArrowDown); + + if increase { + responses.add(ShapeToolMessage::IncreaseSides); + return self; + } + + if decrease { + responses.add(ShapeToolMessage::DecreaseSides); + return self; + } + self + } + (ShapeToolFsmState::Drawing(_), ShapeToolMessage::IncreaseSides) => { + if let Some(layer) = tool_data.data.layer { + let Some(node_id) = graph_modification_utils::get_polygon_id(layer, &document.network_interface).or(graph_modification_utils::get_star_id(layer, &document.network_interface)) + else { + return self; + }; + + let Some(node_inputs) = NodeGraphLayer::new(layer, &document.network_interface) + .find_node_inputs("Regular Polygon") + .or(NodeGraphLayer::new(layer, &document.network_interface).find_node_inputs("Star")) + else { + return self; + }; + + let Some(&TaggedValue::U32(n)) = node_inputs.get(1).unwrap().as_value() else { + return self; + }; + + responses.add(ShapeToolMessage::UpdateOptions(ShapeOptionsUpdate::Vertices(n + 1))); + + responses.add(NodeGraphMessage::SetInput { + input_connector: InputConnector::node(node_id, 1), + input: NodeInput::value(TaggedValue::U32(n + 1), false), + }); + responses.add(NodeGraphMessage::RunDocumentGraph); + } + + self + } + (ShapeToolFsmState::Drawing(_), ShapeToolMessage::DecreaseSides) => { + if let Some(layer) = tool_data.data.layer { + let Some(node_id) = graph_modification_utils::get_polygon_id(layer, &document.network_interface).or(graph_modification_utils::get_star_id(layer, &document.network_interface)) + else { + return self; + }; + + let Some(node_inputs) = NodeGraphLayer::new(layer, &document.network_interface) + .find_node_inputs("Regular Polygon") + .or(NodeGraphLayer::new(layer, &document.network_interface).find_node_inputs("Star")) + else { + return self; + }; + + let Some(&TaggedValue::U32(n)) = node_inputs.get(1).unwrap().as_value() else { + return self; + }; + + responses.add(ShapeToolMessage::UpdateOptions(ShapeOptionsUpdate::Vertices((n - 1).max(3)))); + + responses.add(NodeGraphMessage::SetInput { + input_connector: InputConnector::node(node_id, 1), + input: NodeInput::value(TaggedValue::U32((n - 1).max(3)), false), + }); + responses.add(NodeGraphMessage::RunDocumentGraph); + } + + self + } + (ShapeToolFsmState::Ready(_), ShapeToolMessage::DragStart) => { + tool_data.line_data.drag_start = input.mouse.position; + + // Snapped position in viewport space + let mouse_pos = tool_data + .data + .snap_manager + .indicator_pos() + .map(|pos| document.metadata().document_to_viewport.transform_point2(pos)) + .unwrap_or(input.mouse.position); + + tool_data.line_data.drag_current = mouse_pos; + + if tool_data.gizmo_manger.handle_click() { + tool_data.data.drag_start = document.metadata().document_to_viewport.inverse().transform_point2(mouse_pos); + return ShapeToolFsmState::ModifyingGizmo; + } + + // If clicked on endpoints of a selected line, drag its endpoints + if let Some((layer, _, _)) = closest_point( + document, + mouse_pos, + SNAP_POINT_TOLERANCE, + document.network_interface.selected_nodes().selected_visible_and_unlocked_layers(&document.network_interface), + |_| false, + preferences, + ) { + if clicked_on_line_endpoints(layer, document, input, tool_data) && !input.keyboard.key(Key::Control) { + return ShapeToolFsmState::DraggingLineEndpoints; + } + } + + let (resize, rotate, skew) = transforming_transform_cage(document, &mut tool_data.bounding_box_manager, input, responses, &mut tool_data.layers_dragging); + + if !input.keyboard.key(Key::Control) { + match (resize, rotate, skew) { + (true, false, false) => { + tool_data.get_snap_candidates(document, input); + return ShapeToolFsmState::ResizingBounds; + } + (false, true, false) => { + tool_data.data.drag_start = mouse_pos; + return ShapeToolFsmState::RotatingBounds; + } + (false, false, true) => { + tool_data.get_snap_candidates(document, input); + return ShapeToolFsmState::SkewingBounds { skew: Key::Control }; + } + _ => {} + } + }; + + match tool_data.current_shape { + ShapeType::Polygon | ShapeType::Star | ShapeType::Ellipse | ShapeType::Rectangle => tool_data.data.start(document, input), + ShapeType::Line => { + let point = SnapCandidatePoint::handle(document.metadata().document_to_viewport.inverse().transform_point2(input.mouse.position)); + let snapped = tool_data.data.snap_manager.free_snap(&SnapData::new(document, input), &point, SnapTypeConfiguration::default()); + tool_data.data.drag_start = snapped.snapped_point_document; + } + } + + responses.add(DocumentMessage::StartTransaction); + + let node = match tool_data.current_shape { + ShapeType::Polygon => Polygon::create_node(tool_options.vertices), + ShapeType::Star => Star::create_node(tool_options.vertices), + ShapeType::Rectangle => Rectangle::create_node(), + ShapeType::Ellipse => Ellipse::create_node(), + ShapeType::Line => Line::create_node(document, tool_data.data.drag_start), + }; + + let nodes = vec![(NodeId(0), node)]; + let layer = graph_modification_utils::new_custom(NodeId::new(), nodes, document.new_layer_bounding_artboard(input), responses); + + responses.add(Message::StartBuffer); + + match tool_data.current_shape { + ShapeType::Ellipse | ShapeType::Rectangle | ShapeType::Polygon | ShapeType::Star => { + responses.add(GraphOperationMessage::TransformSet { + layer, + transform: DAffine2::from_scale_angle_translation(DVec2::ONE, 0., input.mouse.position), + transform_in: TransformIn::Viewport, + skip_rerender: false, + }); + + tool_options.fill.apply_fill(layer, responses); + } + ShapeType::Line => { + tool_data.line_data.weight = tool_options.line_weight; + tool_data.line_data.editing_layer = Some(layer); + } + } + tool_options.stroke.apply_stroke(tool_options.line_weight, layer, responses); + + tool_options.stroke.apply_stroke(tool_options.line_weight, layer, responses); + tool_data.data.layer = Some(layer); + + ShapeToolFsmState::Drawing(tool_data.current_shape) + } + (ShapeToolFsmState::Drawing(shape), ShapeToolMessage::PointerMove(modifier)) => { + let Some(layer) = tool_data.data.layer else { + return ShapeToolFsmState::Ready(shape); + }; + + match tool_data.current_shape { + ShapeType::Rectangle => Rectangle::update_shape(document, input, layer, tool_data, modifier, responses), + ShapeType::Ellipse => Ellipse::update_shape(document, input, layer, tool_data, modifier, responses), + ShapeType::Line => Line::update_shape(document, input, layer, tool_data, modifier, responses), + ShapeType::Polygon => Polygon::update_shape(document, input, layer, tool_data, modifier, responses), + ShapeType::Star => Star::update_shape(document, input, layer, tool_data, modifier, responses), + } + + // Auto-panning + let messages = [ShapeToolMessage::PointerOutsideViewport(modifier).into(), ShapeToolMessage::PointerMove(modifier).into()]; + tool_data.auto_panning.setup_by_mouse_position(input, &messages, responses); + + self + } + (ShapeToolFsmState::DraggingLineEndpoints, ShapeToolMessage::PointerMove(modifier)) => { + let Some(layer) = tool_data.line_data.editing_layer else { + return ShapeToolFsmState::Ready(tool_data.current_shape); + }; + + Line::update_shape(document, input, layer, tool_data, modifier, responses); + // Auto-panning + let messages = [ShapeToolMessage::PointerOutsideViewport(modifier).into(), ShapeToolMessage::PointerMove(modifier).into()]; + tool_data.auto_panning.setup_by_mouse_position(input, &messages, responses); + + self + } + (ShapeToolFsmState::ModifyingGizmo, ShapeToolMessage::PointerMove(..)) => { + responses.add(DocumentMessage::StartTransaction); + tool_data.gizmo_manger.handle_update(tool_data.data.drag_start, document, input, responses); + + responses.add(OverlaysMessage::Draw); + + ShapeToolFsmState::ModifyingGizmo + } + (ShapeToolFsmState::ResizingBounds, ShapeToolMessage::PointerMove(modifier)) => { + if let Some(bounds) = &mut tool_data.bounding_box_manager { + let messages = [ShapeToolMessage::PointerOutsideViewport(modifier).into(), ShapeToolMessage::PointerMove(modifier).into()]; + resize_bounds( + document, + responses, + bounds, + &mut tool_data.layers_dragging, + &mut tool_data.data.snap_manager, + &mut tool_data.snap_candidates, + input, + input.keyboard.key(modifier[0]), + input.keyboard.key(modifier[1]), + ToolType::Shape, + ); + tool_data.auto_panning.setup_by_mouse_position(input, &messages, responses); + } + + responses.add(OverlaysMessage::Draw); + ShapeToolFsmState::ResizingBounds + } + (ShapeToolFsmState::RotatingBounds, ShapeToolMessage::PointerMove(modifier)) => { + if let Some(bounds) = &mut tool_data.bounding_box_manager { + rotate_bounds( + document, + responses, + bounds, + &mut tool_data.layers_dragging, + tool_data.data.drag_start, + input.mouse.position, + input.keyboard.key(modifier[1]), + ToolType::Shape, + ); + } + + ShapeToolFsmState::RotatingBounds + } + (ShapeToolFsmState::SkewingBounds { skew }, ShapeToolMessage::PointerMove(_)) => { + if let Some(bounds) = &mut tool_data.bounding_box_manager { + skew_bounds( + document, + responses, + bounds, + input.keyboard.key(skew), + &mut tool_data.layers_dragging, + input.mouse.position, + ToolType::Shape, + ); + } + + ShapeToolFsmState::SkewingBounds { skew } + } + + (_, ShapeToolMessage::PointerMove(_)) => { + let dragging_bounds = tool_data + .bounding_box_manager + .as_mut() + .and_then(|bounding_box| bounding_box.check_selected_edges(input.mouse.position)) + .is_some(); + + let cursor = tool_data.bounding_box_manager.as_ref().map_or(MouseCursorIcon::Crosshair, |bounds| { + let cursor = bounds.get_cursor(input, true, dragging_bounds, Some(tool_data.skew_edge)); + if cursor == MouseCursorIcon::Default { MouseCursorIcon::Crosshair } else { cursor } + }); + + if tool_data.cursor != cursor && !input.keyboard.key(Key::Control) && !all_selected_layers_line { + tool_data.cursor = cursor; + responses.add(FrontendMessage::UpdateMouseCursor { cursor }); + } + + tool_data.data.snap_manager.preview_draw(&SnapData::new(document, input), input.mouse.position); + + responses.add(OverlaysMessage::Draw); + self + } + (ShapeToolFsmState::ResizingBounds | ShapeToolFsmState::SkewingBounds { .. }, ShapeToolMessage::PointerOutsideViewport(_)) => { + // Auto-panning + if let Some(shift) = tool_data.auto_panning.shift_viewport(input, responses) { + if let Some(bounds) = &mut tool_data.bounding_box_manager { + bounds.center_of_transformation += shift; + bounds.original_bound_transform.translation += shift; + } + } + + self + } + (ShapeToolFsmState::Ready(_), ShapeToolMessage::PointerOutsideViewport(..)) => self, + (_, ShapeToolMessage::PointerOutsideViewport { .. }) => { + // Auto-panning + let _ = tool_data.auto_panning.shift_viewport(input, responses); + self + } + ( + ShapeToolFsmState::Drawing(_) + | ShapeToolFsmState::DraggingLineEndpoints + | ShapeToolFsmState::ResizingBounds + | ShapeToolFsmState::RotatingBounds + | ShapeToolFsmState::SkewingBounds { .. } + | ShapeToolFsmState::ModifyingGizmo, + ShapeToolMessage::DragStop, + ) => { + input.mouse.finish_transaction(tool_data.data.drag_start, responses); + tool_data.data.cleanup(responses); + + tool_data.gizmo_manger.handle_cleanup(); + + if let Some(bounds) = &mut tool_data.bounding_box_manager { + bounds.original_transforms.clear(); + } + + tool_data.line_data.dragging_endpoint = None; + + responses.add(FrontendMessage::UpdateMouseCursor { cursor: MouseCursorIcon::Crosshair }); + + ShapeToolFsmState::Ready(tool_data.current_shape) + } + ( + ShapeToolFsmState::Drawing(_) + | ShapeToolFsmState::DraggingLineEndpoints + | ShapeToolFsmState::ResizingBounds + | ShapeToolFsmState::RotatingBounds + | ShapeToolFsmState::SkewingBounds { .. } + | ShapeToolFsmState::ModifyingGizmo, + ShapeToolMessage::Abort, + ) => { + responses.add(DocumentMessage::AbortTransaction); + tool_data.data.cleanup(responses); + tool_data.line_data.dragging_endpoint = None; + + tool_data.gizmo_manger.handle_cleanup(); + + if let Some(bounds) = &mut tool_data.bounding_box_manager { + bounds.original_transforms.clear(); + } + + responses.add(FrontendMessage::UpdateMouseCursor { cursor: MouseCursorIcon::Crosshair }); + + ShapeToolFsmState::Ready(tool_data.current_shape) + } + (_, ShapeToolMessage::WorkingColorChanged) => { + responses.add(ShapeToolMessage::UpdateOptions(ShapeOptionsUpdate::WorkingColors( + Some(global_tool_data.primary_color), + Some(global_tool_data.secondary_color), + ))); + self + } + (_, ShapeToolMessage::SetShape(shape)) => { + responses.add(DocumentMessage::AbortTransaction); + tool_data.data.cleanup(responses); + tool_data.current_shape = shape; + + ShapeToolFsmState::Ready(shape) + } + (_, ShapeToolMessage::HideShapeTypeWidget(hide)) => { + tool_data.hide_shape_option_widget = hide; + responses.add(ToolMessage::RefreshToolOptions); + self + } + _ => self, + } + } + + fn update_hints(&self, responses: &mut VecDeque) { + let hint_data = match self { + ShapeToolFsmState::Ready(shape) => { + let hint_groups = match shape { + ShapeType::Polygon | ShapeType::Star => vec![ + HintGroup(vec![ + HintInfo::mouse(MouseMotion::LmbDrag, "Draw Polygon"), + HintInfo::keys([Key::Shift], "Constrain Regular").prepend_plus(), + HintInfo::keys([Key::Alt], "From Center").prepend_plus(), + ]), + HintGroup(vec![HintInfo::multi_keys([[Key::BracketLeft], [Key::BracketRight]], "Decrease/Increase Sides")]), + ], + ShapeType::Ellipse => vec![HintGroup(vec![ + HintInfo::mouse(MouseMotion::LmbDrag, "Draw Ellipse"), + HintInfo::keys([Key::Shift], "Constrain Circular").prepend_plus(), + HintInfo::keys([Key::Alt], "From Center").prepend_plus(), + ])], + ShapeType::Line => vec![HintGroup(vec![ + HintInfo::mouse(MouseMotion::LmbDrag, "Draw Line"), + HintInfo::keys([Key::Shift], "15° Increments").prepend_plus(), + HintInfo::keys([Key::Alt], "From Center").prepend_plus(), + HintInfo::keys([Key::Control], "Lock Angle").prepend_plus(), + ])], + ShapeType::Rectangle => vec![HintGroup(vec![ + HintInfo::mouse(MouseMotion::LmbDrag, "Draw Rectangle"), + HintInfo::keys([Key::Shift], "Constrain Square").prepend_plus(), + HintInfo::keys([Key::Alt], "From Center").prepend_plus(), + ])], + }; + HintData(hint_groups) + } + ShapeToolFsmState::Drawing(shape) => { + let mut common_hint_group = vec![HintGroup(vec![HintInfo::mouse(MouseMotion::Rmb, ""), HintInfo::keys([Key::Escape], "Cancel").prepend_slash()])]; + let tool_hint_group = match shape { + ShapeType::Polygon | ShapeType::Star => HintGroup(vec![HintInfo::keys([Key::Shift], "Constrain Regular"), HintInfo::keys([Key::Alt], "From Center")]), + ShapeType::Rectangle => HintGroup(vec![HintInfo::keys([Key::Shift], "Constrain Square"), HintInfo::keys([Key::Alt], "From Center")]), + ShapeType::Ellipse => HintGroup(vec![HintInfo::keys([Key::Shift], "Constrain Circular"), HintInfo::keys([Key::Alt], "From Center")]), + ShapeType::Line => HintGroup(vec![ + HintInfo::keys([Key::Shift], "15° Increments"), + HintInfo::keys([Key::Alt], "From Center"), + HintInfo::keys([Key::Control], "Lock Angle"), + ]), + }; + + common_hint_group.push(tool_hint_group); + + if matches!(shape, ShapeType::Polygon | ShapeType::Star) { + common_hint_group.push(HintGroup(vec![HintInfo::multi_keys([[Key::BracketLeft], [Key::BracketRight]], "Decrease/Increase Sides")])); + } + + HintData(common_hint_group) + } + ShapeToolFsmState::DraggingLineEndpoints => HintData(vec![ + HintGroup(vec![HintInfo::mouse(MouseMotion::Rmb, ""), HintInfo::keys([Key::Escape], "Cancel").prepend_slash()]), + HintGroup(vec![ + HintInfo::keys([Key::Shift], "15° Increments"), + HintInfo::keys([Key::Alt], "From Center"), + HintInfo::keys([Key::Control], "Lock Angle"), + ]), + ]), + ShapeToolFsmState::ResizingBounds => HintData(vec![ + HintGroup(vec![HintInfo::mouse(MouseMotion::Rmb, ""), HintInfo::keys([Key::Escape], "Cancel").prepend_slash()]), + HintGroup(vec![HintInfo::keys([Key::Alt], "From Pivot"), HintInfo::keys([Key::Shift], "Preserve Aspect Ratio")]), + ]), + ShapeToolFsmState::RotatingBounds => HintData(vec![ + HintGroup(vec![HintInfo::mouse(MouseMotion::Rmb, ""), HintInfo::keys([Key::Escape], "Cancel").prepend_slash()]), + HintGroup(vec![HintInfo::keys([Key::Shift], "15° Increments")]), + ]), + ShapeToolFsmState::SkewingBounds { .. } => HintData(vec![ + HintGroup(vec![HintInfo::mouse(MouseMotion::Rmb, ""), HintInfo::keys([Key::Escape], "Cancel").prepend_slash()]), + HintGroup(vec![HintInfo::keys([Key::Control], "Unlock Slide")]), + ]), + ShapeToolFsmState::ModifyingGizmo => HintData(vec![HintGroup(vec![HintInfo::mouse(MouseMotion::Rmb, ""), HintInfo::keys([Key::Escape], "Cancel").prepend_slash()])]), + }; + + responses.add(FrontendMessage::UpdateInputHints { hint_data }); + } + + fn update_cursor(&self, responses: &mut VecDeque) { + responses.add(FrontendMessage::UpdateMouseCursor { cursor: MouseCursorIcon::Crosshair }); + } +} diff --git a/editor/src/messages/tool/tool_messages/spline_tool.rs b/editor/src/messages/tool/tool_messages/spline_tool.rs new file mode 100644 index 0000000000000000000000000000000000000000..2ac541d7028bff7a6928ec28c6b44100b3f354c8 --- /dev/null +++ b/editor/src/messages/tool/tool_messages/spline_tool.rs @@ -0,0 +1,855 @@ +use super::tool_prelude::*; +use crate::consts::{DEFAULT_STROKE_WIDTH, DRAG_THRESHOLD, PATH_JOIN_THRESHOLD, SNAP_POINT_TOLERANCE}; +use crate::messages::input_mapper::utility_types::input_mouse::MouseKeys; +use crate::messages::portfolio::document::node_graph::document_node_definitions::resolve_document_node_type; +use crate::messages::portfolio::document::overlays::utility_functions::path_endpoint_overlays; +use crate::messages::portfolio::document::overlays::utility_types::OverlayContext; +use crate::messages::portfolio::document::utility_types::document_metadata::LayerNodeIdentifier; +use crate::messages::tool::common_functionality::auto_panning::AutoPanning; +use crate::messages::tool::common_functionality::color_selector::{ToolColorOptions, ToolColorType}; +use crate::messages::tool::common_functionality::graph_modification_utils::{self, find_spline, merge_layers, merge_points}; +use crate::messages::tool::common_functionality::snapping::{SnapCandidatePoint, SnapData, SnapManager, SnapTypeConfiguration, SnappedPoint}; +use crate::messages::tool::common_functionality::utility_functions::{closest_point, should_extend}; +use graph_craft::document::{NodeId, NodeInput}; +use graphene_std::Color; +use graphene_std::vector::{PointId, SegmentId, VectorModificationType}; + +#[derive(Default)] +pub struct SplineTool { + fsm_state: SplineToolFsmState, + tool_data: SplineToolData, + options: SplineOptions, +} + +pub struct SplineOptions { + line_weight: f64, + fill: ToolColorOptions, + stroke: ToolColorOptions, +} + +impl Default for SplineOptions { + fn default() -> Self { + Self { + line_weight: DEFAULT_STROKE_WIDTH, + fill: ToolColorOptions::new_none(), + stroke: ToolColorOptions::new_primary(), + } + } +} + +#[impl_message(Message, ToolMessage, Spline)] +#[derive(PartialEq, Clone, Debug, serde::Serialize, serde::Deserialize, specta::Type)] +pub enum SplineToolMessage { + // Standard messages + Overlays(OverlayContext), + CanvasTransformed, + Abort, + WorkingColorChanged, + + // Tool-specific messages + Confirm, + DragStart { append_to_selected: Key }, + DragStop, + MergeEndpoints, + PointerMove, + PointerOutsideViewport, + Undo, + UpdateOptions(SplineOptionsUpdate), +} + +#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)] +enum SplineToolFsmState { + #[default] + Ready, + Drawing, + MergingEndpoints, +} + +#[derive(PartialEq, Clone, Debug, serde::Serialize, serde::Deserialize, specta::Type)] +pub enum SplineOptionsUpdate { + FillColor(Option), + FillColorType(ToolColorType), + LineWeight(f64), + StrokeColor(Option), + StrokeColorType(ToolColorType), + WorkingColors(Option, Option), +} + +impl ToolMetadata for SplineTool { + fn icon_name(&self) -> String { + "VectorSplineTool".into() + } + fn tooltip(&self) -> String { + "Spline Tool".into() + } + fn tool_type(&self) -> crate::messages::tool::utility_types::ToolType { + ToolType::Spline + } +} + +fn create_weight_widget(line_weight: f64) -> WidgetHolder { + NumberInput::new(Some(line_weight)) + .unit(" px") + .label("Weight") + .min(0.) + .max((1_u64 << f64::MANTISSA_DIGITS) as f64) + .on_update(|number_input: &NumberInput| SplineToolMessage::UpdateOptions(SplineOptionsUpdate::LineWeight(number_input.value.unwrap())).into()) + .widget_holder() +} + +impl LayoutHolder for SplineTool { + fn layout(&self) -> Layout { + let mut widgets = self.options.fill.create_widgets( + "Fill", + true, + |_| SplineToolMessage::UpdateOptions(SplineOptionsUpdate::FillColor(None)).into(), + |color_type: ToolColorType| WidgetCallback::new(move |_| SplineToolMessage::UpdateOptions(SplineOptionsUpdate::FillColorType(color_type.clone())).into()), + |color: &ColorInput| SplineToolMessage::UpdateOptions(SplineOptionsUpdate::FillColor(color.value.as_solid().map(|color| color.to_linear_srgb()))).into(), + ); + + widgets.push(Separator::new(SeparatorType::Unrelated).widget_holder()); + + widgets.append(&mut self.options.stroke.create_widgets( + "Stroke", + true, + |_| SplineToolMessage::UpdateOptions(SplineOptionsUpdate::StrokeColor(None)).into(), + |color_type: ToolColorType| WidgetCallback::new(move |_| SplineToolMessage::UpdateOptions(SplineOptionsUpdate::StrokeColorType(color_type.clone())).into()), + |color: &ColorInput| SplineToolMessage::UpdateOptions(SplineOptionsUpdate::StrokeColor(color.value.as_solid().map(|color| color.to_linear_srgb()))).into(), + )); + widgets.push(Separator::new(SeparatorType::Unrelated).widget_holder()); + widgets.push(create_weight_widget(self.options.line_weight)); + + Layout::WidgetLayout(WidgetLayout::new(vec![LayoutGroup::Row { widgets }])) + } +} + +impl<'a> MessageHandler> for SplineTool { + fn process_message(&mut self, message: ToolMessage, responses: &mut VecDeque, tool_data: &mut ToolActionHandlerData<'a>) { + let ToolMessage::Spline(SplineToolMessage::UpdateOptions(action)) = message else { + self.fsm_state.process_event(message, &mut self.tool_data, tool_data, &self.options, responses, true); + return; + }; + match action { + SplineOptionsUpdate::LineWeight(line_weight) => self.options.line_weight = line_weight, + SplineOptionsUpdate::FillColor(color) => { + self.options.fill.custom_color = color; + self.options.fill.color_type = ToolColorType::Custom; + } + SplineOptionsUpdate::FillColorType(color_type) => self.options.fill.color_type = color_type, + SplineOptionsUpdate::StrokeColor(color) => { + self.options.stroke.custom_color = color; + self.options.stroke.color_type = ToolColorType::Custom; + } + SplineOptionsUpdate::StrokeColorType(color_type) => self.options.stroke.color_type = color_type, + SplineOptionsUpdate::WorkingColors(primary, secondary) => { + self.options.stroke.primary_working_color = primary; + self.options.stroke.secondary_working_color = secondary; + self.options.fill.primary_working_color = primary; + self.options.fill.secondary_working_color = secondary; + } + } + + self.send_layout(responses, LayoutTarget::ToolOptions); + } + + fn actions(&self) -> ActionList { + match self.fsm_state { + SplineToolFsmState::Ready => actions!(SplineToolMessageDiscriminant; + Undo, + DragStart, + DragStop, + PointerMove, + Confirm, + Abort, + ), + SplineToolFsmState::Drawing => actions!(SplineToolMessageDiscriminant; + DragStop, + PointerMove, + Confirm, + Abort, + ), + SplineToolFsmState::MergingEndpoints => actions!(SplineToolMessageDiscriminant; + MergeEndpoints, + ), + } + } +} + +impl ToolTransition for SplineTool { + fn event_to_message_map(&self) -> EventToMessageMap { + EventToMessageMap { + overlay_provider: Some(|overlay_context: OverlayContext| SplineToolMessage::Overlays(overlay_context).into()), + canvas_transformed: Some(SplineToolMessage::CanvasTransformed.into()), + tool_abort: Some(SplineToolMessage::Abort.into()), + working_color_changed: Some(SplineToolMessage::WorkingColorChanged.into()), + ..Default::default() + } + } +} + +#[derive(Clone, Debug)] +enum EndpointPosition { + Start, + End, +} + +#[derive(Clone, Debug, Default)] +struct SplineToolData { + /// List of points inserted. + points: Vec<(PointId, DVec2)>, + /// Point to be inserted. + next_point: DVec2, + /// Point that was inserted temporarily to show preview. + preview_point: Option, + /// Segment that was inserted temporarily to show preview. + preview_segment: Option, + extend: bool, + weight: f64, + /// The layer we are editing. + current_layer: Option, + /// The layers to merge to the current layer before we merge endpoints in merge_endpoint field. + merge_layers: HashSet, + /// The endpoint IDs to merge with the spline's start/end endpoint after spline drawing is finished. + merge_endpoints: Vec<(EndpointPosition, PointId)>, + snap_manager: SnapManager, + auto_panning: AutoPanning, +} + +impl SplineToolData { + fn cleanup(&mut self) { + self.current_layer = None; + self.merge_layers = HashSet::new(); + self.merge_endpoints = Vec::new(); + self.preview_point = None; + self.preview_segment = None; + self.extend = false; + self.points = Vec::new(); + } + + /// Get the snapped point while ignoring current layer + fn snapped_point(&mut self, document: &DocumentMessageHandler, input: &InputPreprocessorMessageHandler) -> SnappedPoint { + let metadata = document.metadata(); + let transform = self.current_layer.map_or(metadata.document_to_viewport, |layer| metadata.transform_to_viewport(layer)); + let point = SnapCandidatePoint::handle(transform.inverse().transform_point2(input.mouse.position)); + let ignore = if let Some(layer) = self.current_layer { vec![layer] } else { vec![] }; + let snap_data = SnapData::ignore(document, input, &ignore); + self.snap_manager.free_snap(&snap_data, &point, SnapTypeConfiguration::default()) + } +} + +impl Fsm for SplineToolFsmState { + type ToolData = SplineToolData; + type ToolOptions = SplineOptions; + + fn transition(self, event: ToolMessage, tool_data: &mut Self::ToolData, tool_action_data: &mut ToolActionHandlerData, tool_options: &Self::ToolOptions, responses: &mut VecDeque) -> Self { + let ToolActionHandlerData { + document, + global_tool_data, + input, + shape_editor, + preferences, + .. + } = tool_action_data; + + let ToolMessage::Spline(event) = event else { return self }; + match (self, event) { + (_, SplineToolMessage::CanvasTransformed) => self, + (_, SplineToolMessage::Overlays(mut overlay_context)) => { + path_endpoint_overlays(document, shape_editor, &mut overlay_context, preferences); + tool_data.snap_manager.draw_overlays(SnapData::new(document, input), &mut overlay_context); + self + } + (SplineToolFsmState::MergingEndpoints, SplineToolMessage::MergeEndpoints) => { + let Some(current_layer) = tool_data.current_layer else { return SplineToolFsmState::Ready }; + + if let Some(&layer) = tool_data.merge_layers.iter().last() { + merge_layers(document, current_layer, layer, responses); + tool_data.merge_layers.remove(&layer); + + responses.add(SplineToolMessage::MergeEndpoints); + return SplineToolFsmState::MergingEndpoints; + } + + let Some((start_endpoint, _)) = tool_data.points.first() else { return SplineToolFsmState::Ready }; + let Some((last_endpoint, _)) = tool_data.points.last() else { return SplineToolFsmState::Ready }; + + if let Some((position, second_endpoint)) = tool_data.merge_endpoints.pop() { + let first_endpoint = match position { + EndpointPosition::Start => *start_endpoint, + EndpointPosition::End => *last_endpoint, + }; + merge_points(document, current_layer, first_endpoint, second_endpoint, responses); + + responses.add(SplineToolMessage::MergeEndpoints); + return SplineToolFsmState::MergingEndpoints; + } + + responses.add(DocumentMessage::EndTransaction); + SplineToolFsmState::Ready + } + (SplineToolFsmState::Ready, SplineToolMessage::DragStart { append_to_selected }) => { + responses.add(DocumentMessage::StartTransaction); + + tool_data.snap_manager.cleanup(responses); + tool_data.cleanup(); + tool_data.weight = tool_options.line_weight; + + let point = SnapCandidatePoint::handle(document.metadata().document_to_viewport.inverse().transform_point2(input.mouse.position)); + let snapped = tool_data.snap_manager.free_snap(&SnapData::new(document, input), &point, SnapTypeConfiguration::default()); + let viewport = document.metadata().document_to_viewport.transform_point2(snapped.snapped_point_document); + + let layers = LayerNodeIdentifier::ROOT_PARENT + .descendants(document.metadata()) + .filter(|layer| !document.network_interface.is_artboard(&layer.to_node(), &[])); + + // Extend an endpoint of the selected path + if let Some((layer, point, position)) = should_extend(document, viewport, SNAP_POINT_TOLERANCE, layers, preferences) { + if find_spline(document, layer).is_some() { + // If the point is the part of Spline then we extend it. + tool_data.current_layer = Some(layer); + tool_data.points.push((point, position)); + tool_data.next_point = position; + tool_data.extend = true; + + extend_spline(tool_data, true, responses); + + return SplineToolFsmState::Drawing; + } else { + tool_data.merge_layers.insert(layer); + tool_data.merge_endpoints.push((EndpointPosition::Start, point)); + } + } + + let selected_nodes = document.network_interface.selected_nodes(); + let mut selected_layers_except_artboards = selected_nodes.selected_layers_except_artboards(&document.network_interface); + let selected_layer = selected_layers_except_artboards.next().filter(|_| selected_layers_except_artboards.next().is_none()); + + let append_to_selected_layer = input.keyboard.key(append_to_selected); + + // Create new path in the selected layer when shift is down + if let (Some(layer), true) = (selected_layer, append_to_selected_layer) { + tool_data.current_layer = Some(layer); + + let transform = document.metadata().transform_to_viewport(layer); + let position = transform.inverse().transform_point2(input.mouse.position); + tool_data.next_point = position; + + return SplineToolFsmState::Drawing; + } + + responses.add(DocumentMessage::DeselectAllLayers); + + let parent = document.new_layer_bounding_artboard(input); + + let path_node_type = resolve_document_node_type("Path").expect("Path node does not exist"); + let path_node = path_node_type.default_node_template(); + let spline_node_type = resolve_document_node_type("Spline").expect("Spline node does not exist"); + let spline_node = spline_node_type.node_template_input_override([Some(NodeInput::node(NodeId(1), 0))]); + let nodes = vec![(NodeId(1), path_node), (NodeId(0), spline_node)]; + + let layer = graph_modification_utils::new_custom(NodeId::new(), nodes, parent, responses); + tool_options.fill.apply_fill(layer, responses); + tool_options.stroke.apply_stroke(tool_data.weight, layer, responses); + tool_data.current_layer = Some(layer); + + responses.add(Message::StartBuffer); + + SplineToolFsmState::Drawing + } + (SplineToolFsmState::Drawing, SplineToolMessage::DragStop) => { + // The first DragStop event will be ignored to prevent insertion of new point. + if tool_data.extend { + tool_data.extend = false; + return SplineToolFsmState::Drawing; + } + if tool_data.current_layer.is_none() { + return SplineToolFsmState::Ready; + }; + tool_data.next_point = tool_data.snapped_point(document, input).snapped_point_document; + if tool_data.points.last().is_none_or(|last_pos| last_pos.1.distance(tool_data.next_point) > DRAG_THRESHOLD) { + let preview_point = tool_data.preview_point; + extend_spline(tool_data, false, responses); + tool_data.preview_point = preview_point; + + if try_merging_lastest_endpoint(document, tool_data, preferences).is_some() { + responses.add(SplineToolMessage::Confirm); + } + } + + SplineToolFsmState::Drawing + } + (SplineToolFsmState::Drawing, SplineToolMessage::PointerMove) => { + let Some(layer) = tool_data.current_layer else { return SplineToolFsmState::Ready }; + let ignore = |cp: PointId| tool_data.preview_point.is_some_and(|pp| pp == cp) || tool_data.points.last().is_some_and(|(ep, _)| *ep == cp); + let join_point = closest_point(document, input.mouse.position, PATH_JOIN_THRESHOLD, vec![layer].into_iter(), ignore, preferences); + + // Endpoints snapping + if let Some((_, _, point)) = join_point { + tool_data.next_point = point; + tool_data.snap_manager.clear_indicator(); + } else { + let snapped_point = tool_data.snapped_point(document, input); + tool_data.next_point = snapped_point.snapped_point_document; + tool_data.snap_manager.update_indicator(snapped_point); + } + + extend_spline(tool_data, true, responses); + + // Auto-panning + let messages = [SplineToolMessage::PointerOutsideViewport.into(), SplineToolMessage::PointerMove.into()]; + tool_data.auto_panning.setup_by_mouse_position(input, &messages, responses); + + SplineToolFsmState::Drawing + } + (_, SplineToolMessage::PointerMove) => { + tool_data.snap_manager.preview_draw(&SnapData::new(document, input), input.mouse.position); + responses.add(OverlaysMessage::Draw); + self + } + (SplineToolFsmState::Drawing, SplineToolMessage::PointerOutsideViewport) => { + if !input.mouse.mouse_keys.contains(MouseKeys::LEFT) { + return self; + } + // Auto-panning + let _ = tool_data.auto_panning.shift_viewport(input, responses); + + SplineToolFsmState::Drawing + } + (state, SplineToolMessage::PointerOutsideViewport) => { + // Auto-panning + let messages = [SplineToolMessage::PointerOutsideViewport.into(), SplineToolMessage::PointerMove.into()]; + tool_data.auto_panning.stop(&messages, responses); + + state + } + (SplineToolFsmState::Drawing, SplineToolMessage::Confirm) => { + if tool_data.points.len() >= 2 { + delete_preview(tool_data, responses); + } + responses.add(SplineToolMessage::MergeEndpoints); + SplineToolFsmState::MergingEndpoints + } + (SplineToolFsmState::Drawing, SplineToolMessage::Abort) => { + responses.add(DocumentMessage::AbortTransaction); + SplineToolFsmState::Ready + } + (_, SplineToolMessage::WorkingColorChanged) => { + responses.add(SplineToolMessage::UpdateOptions(SplineOptionsUpdate::WorkingColors( + Some(global_tool_data.primary_color), + Some(global_tool_data.secondary_color), + ))); + self + } + _ => self, + } + } + + fn update_hints(&self, responses: &mut VecDeque) { + let hint_data = match self { + SplineToolFsmState::Ready => HintData(vec![HintGroup(vec![ + HintInfo::mouse(MouseMotion::Lmb, "Draw Spline"), + HintInfo::keys([Key::Shift], "Append to Selected Layer").prepend_plus(), + ])]), + SplineToolFsmState::Drawing => HintData(vec![ + HintGroup(vec![HintInfo::mouse(MouseMotion::Rmb, ""), HintInfo::keys([Key::Escape], "Cancel").prepend_slash()]), + HintGroup(vec![HintInfo::mouse(MouseMotion::Lmb, "Extend Spline")]), + HintGroup(vec![HintInfo::keys([Key::Enter], "End Spline")]), + ]), + SplineToolFsmState::MergingEndpoints => HintData(vec![]), + }; + + responses.add(FrontendMessage::UpdateInputHints { hint_data }); + } + + fn update_cursor(&self, responses: &mut VecDeque) { + responses.add(FrontendMessage::UpdateMouseCursor { cursor: MouseCursorIcon::Default }); + } +} + +fn try_merging_lastest_endpoint(document: &DocumentMessageHandler, tool_data: &mut SplineToolData, preferences: &PreferencesMessageHandler) -> Option<()> { + if tool_data.points.len() < 2 { + return None; + }; + let (last_endpoint, last_endpoint_position) = tool_data.points.last()?; + let preview_point = tool_data.preview_point; + let current_layer = tool_data.current_layer?; + + let layers = LayerNodeIdentifier::ROOT_PARENT + .descendants(document.metadata()) + .filter(|layer| !document.network_interface.is_artboard(&layer.to_node(), &[])); + + let exclude = |p: PointId| preview_point.is_some_and(|pp| pp == p) || *last_endpoint == p; + let position = document.metadata().transform_to_viewport(current_layer).transform_point2(*last_endpoint_position); + + let (layer, endpoint, _) = closest_point(document, position, PATH_JOIN_THRESHOLD, layers, exclude, preferences)?; + tool_data.merge_layers.insert(layer); + tool_data.merge_endpoints.push((EndpointPosition::End, endpoint)); + + Some(()) +} + +fn extend_spline(tool_data: &mut SplineToolData, show_preview: bool, responses: &mut VecDeque) { + delete_preview(tool_data, responses); + + let Some(layer) = tool_data.current_layer else { return }; + + let next_point_pos = tool_data.next_point; + let next_point_id = PointId::generate(); + let modification_type = VectorModificationType::InsertPoint { + id: next_point_id, + position: next_point_pos, + }; + responses.add(GraphOperationMessage::Vector { layer, modification_type }); + + if let Some((last_point_id, _)) = tool_data.points.last() { + let points = [*last_point_id, next_point_id]; + let id = SegmentId::generate(); + let modification_type = VectorModificationType::InsertSegment { id, points, handles: [None, None] }; + responses.add(GraphOperationMessage::Vector { layer, modification_type }); + + if show_preview { + tool_data.preview_segment = Some(id); + } + } + + if show_preview { + tool_data.preview_point = Some(next_point_id); + } else { + tool_data.points.push((next_point_id, next_point_pos)); + } +} + +fn delete_preview(tool_data: &mut SplineToolData, responses: &mut VecDeque) { + let Some(layer) = tool_data.current_layer else { return }; + + if let Some(id) = tool_data.preview_point { + let modification_type = VectorModificationType::RemovePoint { id }; + responses.add(GraphOperationMessage::Vector { layer, modification_type }); + } + if let Some(id) = tool_data.preview_segment { + let modification_type = VectorModificationType::RemoveSegment { id }; + responses.add(GraphOperationMessage::Vector { layer, modification_type }); + } + + tool_data.preview_point = None; + tool_data.preview_segment = None; +} + +#[cfg(test)] +mod test_spline_tool { + use crate::messages::portfolio::document::graph_operation::utility_types::TransformIn; + use crate::messages::tool::tool_messages::spline_tool::find_spline; + use crate::test_utils::test_prelude::*; + use glam::DAffine2; + use graphene_std::vector::PointId; + use graphene_std::vector::VectorData; + + fn assert_point_positions(vector_data: &VectorData, layer_to_viewport: DAffine2, expected_points: &[DVec2], epsilon: f64) { + let points_in_viewport: Vec = vector_data + .point_domain + .ids() + .iter() + .filter_map(|&point_id| { + let position = vector_data.point_domain.position_from_id(point_id)?; + Some(layer_to_viewport.transform_point2(position)) + }) + .collect(); + + // Verify each point position is close to the expected position + for (i, expected_point) in expected_points.iter().enumerate() { + let actual_point = points_in_viewport[i]; + let distance = (actual_point - *expected_point).length(); + + assert!( + distance < epsilon, + "Point {} position mismatch: expected {:?}, got {:?} (distance: {})", + i, + expected_point, + actual_point, + distance + ); + } + } + + #[tokio::test] + async fn test_continue_drawing_from_existing_spline() { + let mut editor = EditorTestUtils::create(); + editor.new_document().await; + + let initial_points = [DVec2::new(100., 100.), DVec2::new(200., 150.), DVec2::new(300., 100.)]; + + editor.select_tool(ToolType::Spline).await; + + for &point in &initial_points { + editor.click_tool(ToolType::Spline, MouseKeys::LEFT, point, ModifierKeys::empty()).await; + } + + editor.press(Key::Enter, ModifierKeys::empty()).await; + + let document = editor.active_document(); + let spline_layer = document + .metadata() + .all_layers() + .find(|layer| find_spline(document, *layer).is_some()) + .expect("Failed to find a layer with a spline node"); + + let first_spline_node = find_spline(document, spline_layer).expect("Spline node not found in the layer"); + + let first_vector_data = document.network_interface.compute_modified_vector(spline_layer).expect("Vector data not found for the spline layer"); + + // Verify initial spline has correct number of points and segments + let initial_point_count = first_vector_data.point_domain.ids().len(); + let initial_segment_count = first_vector_data.segment_domain.ids().len(); + assert_eq!(initial_point_count, 3, "Expected 3 points in initial spline, found {}", initial_point_count); + assert_eq!(initial_segment_count, 2, "Expected 2 segments in initial spline, found {}", initial_segment_count); + + let layer_to_viewport = document.metadata().transform_to_viewport(spline_layer); + + let endpoints: Vec<(PointId, DVec2)> = first_vector_data + .extendable_points(false) + .filter_map(|point_id| first_vector_data.point_domain.position_from_id(point_id).map(|pos| (point_id, layer_to_viewport.transform_point2(pos)))) + .collect(); + + assert_eq!(endpoints.len(), 2, "Expected 2 endpoints in the initial spline"); + + let (_, endpoint_position) = endpoints.first().expect("No endpoints found in spline"); + + editor.select_tool(ToolType::Spline).await; + editor.click_tool(ToolType::Spline, MouseKeys::LEFT, *endpoint_position, ModifierKeys::empty()).await; + + let continuation_points = [DVec2::new(400., 150.), DVec2::new(500., 100.)]; + + for &point in &continuation_points { + editor.click_tool(ToolType::Spline, MouseKeys::LEFT, point, ModifierKeys::empty()).await; + } + + editor.press(Key::Enter, ModifierKeys::empty()).await; + + let document = editor.active_document(); + let extended_vector_data = document + .network_interface + .compute_modified_vector(spline_layer) + .expect("Vector data not found for the extended spline layer"); + + // Verify extended spline has correct number of points and segments + let extended_point_count = extended_vector_data.point_domain.ids().len(); + let extended_segment_count = extended_vector_data.segment_domain.ids().len(); + + assert_eq!(extended_point_count, 5, "Expected 5 points in extended spline, found {}", extended_point_count); + assert_eq!(extended_segment_count, 4, "Expected 4 segments in extended spline, found {}", extended_segment_count); + + // Verify the spline node is still the same + let extended_spline_node = find_spline(document, spline_layer).expect("Spline node not found after extension"); + assert_eq!(first_spline_node, extended_spline_node, "Spline node changed after extension"); + + // Verify the positions of all points in the extended spline + let layer_to_viewport = document.metadata().transform_to_viewport(spline_layer); + + let all_expected_points = [initial_points[0], initial_points[1], initial_points[2], continuation_points[0], continuation_points[1]]; + + assert_point_positions(&extended_vector_data, layer_to_viewport, &all_expected_points, 1e-10); + } + + #[tokio::test] + async fn test_spline_with_zoomed_view() { + let mut editor = EditorTestUtils::create(); + editor.new_document().await; + + // Zooming the viewport + editor.handle_message(NavigationMessage::CanvasZoomSet { zoom_factor: 2. }).await; + + // Selecting the spline tool + editor.select_tool(ToolType::Spline).await; + + // Adding points by clicking at different positions + editor.click_tool(ToolType::Spline, MouseKeys::LEFT, DVec2::new(50., 50.), ModifierKeys::empty()).await; + editor.click_tool(ToolType::Spline, MouseKeys::LEFT, DVec2::new(100., 50.), ModifierKeys::empty()).await; + editor.click_tool(ToolType::Spline, MouseKeys::LEFT, DVec2::new(150., 100.), ModifierKeys::empty()).await; + + // Finish the spline + editor.handle_message(SplineToolMessage::Confirm).await; + + // Evaluate the graph to ensure everything is processed + if let Err(e) = editor.eval_graph().await { + panic!("Graph evaluation failed: {}", e); + } + + // Get the layer and vector data + let document = editor.active_document(); + let network_interface = &document.network_interface; + let layer = network_interface + .selected_nodes() + .selected_visible_and_unlocked_layers(network_interface) + .next() + .expect("Should have a selected layer"); + let vector_data = network_interface.compute_modified_vector(layer).expect("Should have vector data"); + let layer_to_viewport = document.metadata().transform_to_viewport(layer); + + // Expected points in viewport coordinates + let expected_points = vec![DVec2::new(50., 50.), DVec2::new(100., 50.), DVec2::new(150., 100.)]; + + // Assert all points are correctly positioned + assert_point_positions(&vector_data, layer_to_viewport, &expected_points, 1e-10); + } + + #[tokio::test] + async fn test_spline_with_panned_view() { + let mut editor = EditorTestUtils::create(); + editor.new_document().await; + + let pan_amount = DVec2::new(200., 150.); + editor.handle_message(NavigationMessage::CanvasPan { delta: pan_amount }).await; + + editor.select_tool(ToolType::Spline).await; + + // Add points by clicking at different positions + editor.click_tool(ToolType::Spline, MouseKeys::LEFT, DVec2::new(50., 50.), ModifierKeys::empty()).await; + editor.click_tool(ToolType::Spline, MouseKeys::LEFT, DVec2::new(100., 50.), ModifierKeys::empty()).await; + editor.click_tool(ToolType::Spline, MouseKeys::LEFT, DVec2::new(150., 100.), ModifierKeys::empty()).await; + + editor.handle_message(SplineToolMessage::Confirm).await; + + // Evaluating the graph to ensure everything is processed + if let Err(e) = editor.eval_graph().await { + panic!("Graph evaluation failed: {}", e); + } + + // Get the layer and vector data + let document = editor.active_document(); + let network_interface = &document.network_interface; + let layer = network_interface + .selected_nodes() + .selected_visible_and_unlocked_layers(network_interface) + .next() + .expect("Should have a selected layer"); + let vector_data = network_interface.compute_modified_vector(layer).expect("Should have vector data"); + let layer_to_viewport = document.metadata().transform_to_viewport(layer); + + // Expected points in viewport coordinates + let expected_points = vec![DVec2::new(50., 50.), DVec2::new(100., 50.), DVec2::new(150., 100.)]; + + // Assert all points are correctly positioned + assert_point_positions(&vector_data, layer_to_viewport, &expected_points, 1e-10); + } + + #[tokio::test] + async fn test_spline_with_tilted_view() { + let mut editor = EditorTestUtils::create(); + editor.new_document().await; + + // Tilt/rotate the viewport (45 degrees) + editor.handle_message(NavigationMessage::CanvasTiltSet { angle_radians: 45_f64.to_radians() }).await; + editor.select_tool(ToolType::Spline).await; + + editor.click_tool(ToolType::Spline, MouseKeys::LEFT, DVec2::new(50., 50.), ModifierKeys::empty()).await; + editor.click_tool(ToolType::Spline, MouseKeys::LEFT, DVec2::new(100., 50.), ModifierKeys::empty()).await; + editor.click_tool(ToolType::Spline, MouseKeys::LEFT, DVec2::new(150., 100.), ModifierKeys::empty()).await; + + editor.handle_message(SplineToolMessage::Confirm).await; + + // Evaluating the graph to ensure everything is processed + if let Err(e) = editor.eval_graph().await { + panic!("Graph evaluation failed: {}", e); + } + + // Get the layer and vector data + let document = editor.active_document(); + let network_interface = &document.network_interface; + let layer = network_interface + .selected_nodes() + .selected_visible_and_unlocked_layers(network_interface) + .next() + .expect("Should have a selected layer"); + let vector_data = network_interface.compute_modified_vector(layer).expect("Should have vector data"); + let layer_to_viewport = document.metadata().transform_to_viewport(layer); + + // Expected points in viewport coordinates + let expected_points = vec![DVec2::new(50., 50.), DVec2::new(100., 50.), DVec2::new(150., 100.)]; + + // Assert all points are correctly positioned + assert_point_positions(&vector_data, layer_to_viewport, &expected_points, 1e-10); + } + + #[tokio::test] + async fn test_spline_with_combined_transformations() { + let mut editor = EditorTestUtils::create(); + editor.new_document().await; + + // Applying multiple transformations + editor.handle_message(NavigationMessage::CanvasZoomSet { zoom_factor: 1.5 }).await; + editor.handle_message(NavigationMessage::CanvasPan { delta: DVec2::new(100., 75.) }).await; + editor.handle_message(NavigationMessage::CanvasTiltSet { angle_radians: 30_f64.to_radians() }).await; + + editor.select_tool(ToolType::Spline).await; + + editor.click_tool(ToolType::Spline, MouseKeys::LEFT, DVec2::new(50., 50.), ModifierKeys::empty()).await; + editor.click_tool(ToolType::Spline, MouseKeys::LEFT, DVec2::new(100., 50.), ModifierKeys::empty()).await; + editor.click_tool(ToolType::Spline, MouseKeys::LEFT, DVec2::new(150., 100.), ModifierKeys::empty()).await; + + editor.handle_message(SplineToolMessage::Confirm).await; + if let Err(e) = editor.eval_graph().await { + panic!("Graph evaluation failed: {}", e); + } + + // Get the layer and vector data + let document = editor.active_document(); + let network_interface = &document.network_interface; + let layer = network_interface + .selected_nodes() + .selected_visible_and_unlocked_layers(network_interface) + .next() + .expect("Should have a selected layer"); + let vector_data = network_interface.compute_modified_vector(layer).expect("Should have vector data"); + let layer_to_viewport = document.metadata().transform_to_viewport(layer); + + // Expected points in viewport coordinates + let expected_points = vec![DVec2::new(50., 50.), DVec2::new(100., 50.), DVec2::new(150., 100.)]; + + // Assert all points are correctly positioned + assert_point_positions(&vector_data, layer_to_viewport, &expected_points, 1e-10); + } + + #[tokio::test] + async fn test_spline_tool_with_transformed_artboard() { + let mut editor = EditorTestUtils::create(); + editor.new_document().await; + + editor.drag_tool(ToolType::Artboard, 0., 0., 500., 500., ModifierKeys::empty()).await; + let document = editor.active_document(); + let artboard_layer = document.network_interface.selected_nodes().selected_layers(document.metadata()).next().unwrap(); + + editor + .handle_message(GraphOperationMessage::TransformSet { + layer: artboard_layer, + transform: DAffine2::from_scale_angle_translation(DVec2::new(1.5, 1.2), 30_f64.to_radians(), DVec2::new(50., 25.)), + transform_in: TransformIn::Local, + skip_rerender: false, + }) + .await; + + let spline_points = [DVec2::new(100., 100.), DVec2::new(200., 150.), DVec2::new(300., 100.)]; + + editor.draw_spline(&spline_points).await; + + let document = editor.active_document(); + + let mut layers = document.metadata().all_layers(); + layers.next(); + + let spline_layer = layers.next().expect("Failed to find the spline layer"); + assert!(find_spline(document, spline_layer).is_some(), "Spline node not found in the layer"); + + let vector_data = document.network_interface.compute_modified_vector(spline_layer).expect("Vector data not found for the spline layer"); + + // Verify we have the correct number of points and segments + let point_count = vector_data.point_domain.ids().len(); + let segment_count = vector_data.segment_domain.ids().len(); + + assert_eq!(point_count, 3, "Expected 3 points in the spline, found {}", point_count); + assert_eq!(segment_count, 2, "Expected 2 segments in the spline, found {}", segment_count); + + let layer_to_viewport = document.metadata().transform_to_viewport(spline_layer); + + assert_point_positions(&vector_data, layer_to_viewport, &spline_points, 1e-10); + } +} diff --git a/editor/src/messages/tool/tool_messages/text_tool.rs b/editor/src/messages/tool/tool_messages/text_tool.rs new file mode 100644 index 0000000000000000000000000000000000000000..e56e53d477f5348bcda86b48607e0df3b3db9762 --- /dev/null +++ b/editor/src/messages/tool/tool_messages/text_tool.rs @@ -0,0 +1,916 @@ +#![allow(clippy::too_many_arguments)] + +use super::tool_prelude::*; +use crate::consts::{COLOR_OVERLAY_BLUE, COLOR_OVERLAY_RED, DRAG_THRESHOLD}; +use crate::messages::portfolio::document::graph_operation::utility_types::TransformIn; +use crate::messages::portfolio::document::overlays::utility_types::OverlayContext; +use crate::messages::portfolio::document::utility_types::document_metadata::LayerNodeIdentifier; +use crate::messages::portfolio::document::utility_types::network_interface::InputConnector; +use crate::messages::tool::common_functionality::auto_panning::AutoPanning; +use crate::messages::tool::common_functionality::color_selector::{ToolColorOptions, ToolColorType}; +use crate::messages::tool::common_functionality::graph_modification_utils::{self, is_layer_fed_by_node_of_name}; +use crate::messages::tool::common_functionality::pivot::Pivot; +use crate::messages::tool::common_functionality::resize::Resize; +use crate::messages::tool::common_functionality::snapping::{self, SnapCandidatePoint, SnapData}; +use crate::messages::tool::common_functionality::transformation_cage::*; +use crate::messages::tool::common_functionality::utility_functions::text_bounding_box; +use graph_craft::document::value::TaggedValue; +use graph_craft::document::{NodeId, NodeInput}; +use graphene_std::Color; +use graphene_std::renderer::Quad; +use graphene_std::text::{Font, FontCache, TypesettingConfig, lines_clipping, load_font}; +use graphene_std::vector::style::Fill; + +#[derive(Default)] +pub struct TextTool { + fsm_state: TextToolFsmState, + tool_data: TextToolData, + options: TextOptions, +} + +pub struct TextOptions { + font_size: f64, + line_height_ratio: f64, + character_spacing: f64, + font_name: String, + font_style: String, + fill: ToolColorOptions, + tilt: f64, +} + +impl Default for TextOptions { + fn default() -> Self { + Self { + font_size: 24., + line_height_ratio: 1.2, + character_spacing: 0., + font_name: graphene_std::consts::DEFAULT_FONT_FAMILY.into(), + font_style: graphene_std::consts::DEFAULT_FONT_STYLE.into(), + fill: ToolColorOptions::new_primary(), + tilt: 0., + } + } +} + +#[impl_message(Message, ToolMessage, Text)] +#[derive(PartialEq, Clone, Debug, serde::Serialize, serde::Deserialize, specta::Type)] +pub enum TextToolMessage { + // Standard messages + Abort, + WorkingColorChanged, + Overlays(OverlayContext), + + // Tool-specific messages + DragStart, + DragStop, + EditSelected, + Interact, + PointerMove { center: Key, lock_ratio: Key }, + PointerOutsideViewport { center: Key, lock_ratio: Key }, + TextChange { new_text: String, is_left_or_right_click: bool }, + UpdateBounds { new_text: String }, + UpdateOptions(TextOptionsUpdate), +} + +#[derive(PartialEq, Clone, Debug, serde::Serialize, serde::Deserialize, specta::Type)] +pub enum TextOptionsUpdate { + FillColor(Option), + FillColorType(ToolColorType), + Font { family: String, style: String }, + FontSize(f64), + LineHeightRatio(f64), + CharacterSpacing(f64), + WorkingColors(Option, Option), +} + +impl ToolMetadata for TextTool { + fn icon_name(&self) -> String { + "VectorTextTool".into() + } + fn tooltip(&self) -> String { + "Text Tool".into() + } + fn tool_type(&self) -> crate::messages::tool::utility_types::ToolType { + ToolType::Text + } +} + +fn create_text_widgets(tool: &TextTool) -> Vec { + let font = FontInput::new(&tool.options.font_name, &tool.options.font_style) + .is_style_picker(false) + .on_update(|font_input: &FontInput| { + TextToolMessage::UpdateOptions(TextOptionsUpdate::Font { + family: font_input.font_family.clone(), + style: font_input.font_style.clone(), + }) + .into() + }) + .widget_holder(); + let style = FontInput::new(&tool.options.font_name, &tool.options.font_style) + .is_style_picker(true) + .on_update(|font_input: &FontInput| { + TextToolMessage::UpdateOptions(TextOptionsUpdate::Font { + family: font_input.font_family.clone(), + style: font_input.font_style.clone(), + }) + .into() + }) + .widget_holder(); + let size = NumberInput::new(Some(tool.options.font_size)) + .unit(" px") + .label("Size") + .int() + .min(1.) + .max((1_u64 << f64::MANTISSA_DIGITS) as f64) + .on_update(|number_input: &NumberInput| TextToolMessage::UpdateOptions(TextOptionsUpdate::FontSize(number_input.value.unwrap())).into()) + .widget_holder(); + let line_height_ratio = NumberInput::new(Some(tool.options.line_height_ratio)) + .label("Line Height") + .int() + .min(0.) + .max((1_u64 << f64::MANTISSA_DIGITS) as f64) + .step(0.1) + .on_update(|number_input: &NumberInput| TextToolMessage::UpdateOptions(TextOptionsUpdate::LineHeightRatio(number_input.value.unwrap())).into()) + .widget_holder(); + let character_spacing = NumberInput::new(Some(tool.options.character_spacing)) + .label("Char. Spacing") + .int() + .min(0.) + .max((1_u64 << f64::MANTISSA_DIGITS) as f64) + .step(0.1) + .on_update(|number_input: &NumberInput| TextToolMessage::UpdateOptions(TextOptionsUpdate::CharacterSpacing(number_input.value.unwrap())).into()) + .widget_holder(); + vec![ + font, + Separator::new(SeparatorType::Related).widget_holder(), + style, + Separator::new(SeparatorType::Related).widget_holder(), + size, + Separator::new(SeparatorType::Related).widget_holder(), + line_height_ratio, + Separator::new(SeparatorType::Related).widget_holder(), + character_spacing, + ] +} + +impl LayoutHolder for TextTool { + fn layout(&self) -> Layout { + let mut widgets = create_text_widgets(self); + + widgets.push(Separator::new(SeparatorType::Unrelated).widget_holder()); + + widgets.append(&mut self.options.fill.create_widgets( + "Fill", + true, + |_| TextToolMessage::UpdateOptions(TextOptionsUpdate::FillColor(None)).into(), + |color_type: ToolColorType| WidgetCallback::new(move |_| TextToolMessage::UpdateOptions(TextOptionsUpdate::FillColorType(color_type.clone())).into()), + |color: &ColorInput| TextToolMessage::UpdateOptions(TextOptionsUpdate::FillColor(color.value.as_solid().map(|color| color.to_linear_srgb()))).into(), + )); + + Layout::WidgetLayout(WidgetLayout::new(vec![LayoutGroup::Row { widgets }])) + } +} + +impl<'a> MessageHandler> for TextTool { + fn process_message(&mut self, message: ToolMessage, responses: &mut VecDeque, tool_data: &mut ToolActionHandlerData<'a>) { + let ToolMessage::Text(TextToolMessage::UpdateOptions(action)) = message else { + self.fsm_state.process_event(message, &mut self.tool_data, tool_data, &self.options, responses, true); + return; + }; + match action { + TextOptionsUpdate::Font { family, style } => { + self.options.font_name = family; + self.options.font_style = style; + + self.send_layout(responses, LayoutTarget::ToolOptions); + } + TextOptionsUpdate::FontSize(font_size) => self.options.font_size = font_size, + TextOptionsUpdate::LineHeightRatio(line_height_ratio) => self.options.line_height_ratio = line_height_ratio, + TextOptionsUpdate::CharacterSpacing(character_spacing) => self.options.character_spacing = character_spacing, + TextOptionsUpdate::FillColor(color) => { + self.options.fill.custom_color = color; + self.options.fill.color_type = ToolColorType::Custom; + } + TextOptionsUpdate::FillColorType(color_type) => self.options.fill.color_type = color_type, + TextOptionsUpdate::WorkingColors(primary, secondary) => { + self.options.fill.primary_working_color = primary; + self.options.fill.secondary_working_color = secondary; + } + } + + self.send_layout(responses, LayoutTarget::ToolOptions); + } + + fn actions(&self) -> ActionList { + match self.fsm_state { + TextToolFsmState::Ready => actions!(TextToolMessageDiscriminant; + DragStart, + PointerOutsideViewport, + PointerMove, + ), + TextToolFsmState::Editing => actions!(TextToolMessageDiscriminant; + DragStart, + Abort, + ), + TextToolFsmState::Placing | TextToolFsmState::Dragging => actions!(TextToolMessageDiscriminant; + DragStop, + Abort, + PointerMove, + PointerOutsideViewport, + ), + TextToolFsmState::ResizingBounds => actions!(TextToolMessageDiscriminant; + DragStop, + Abort, + PointerMove, + PointerOutsideViewport, + ), + } + } +} + +impl ToolTransition for TextTool { + fn event_to_message_map(&self) -> EventToMessageMap { + EventToMessageMap { + canvas_transformed: None, + tool_abort: Some(TextToolMessage::Abort.into()), + working_color_changed: Some(TextToolMessage::WorkingColorChanged.into()), + overlay_provider: Some(|overlay_context| TextToolMessage::Overlays(overlay_context).into()), + ..Default::default() + } + } +} + +#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)] +enum TextToolFsmState { + /// The tool is ready to place or edit text. + #[default] + Ready, + /// The user is typing in the interactive viewport text area. + Editing, + /// The user is dragging to create a new text area. + Placing, + /// The user is dragging an existing text layer to move it. + Dragging, + /// The user is dragging to resize the text area. + ResizingBounds, +} + +#[derive(Clone, Debug)] +pub struct EditingText { + text: String, + font: Font, + typesetting: TypesettingConfig, + color: Option, + transform: DAffine2, +} + +#[derive(Clone, Debug, Copy)] +struct ResizingLayer { + id: LayerNodeIdentifier, + /// The transform of the text layer in document space at the start of the transformation. + original_transform: DAffine2, +} + +#[derive(Clone, Debug, Default)] +struct TextToolData { + layer: LayerNodeIdentifier, + editing_text: Option, + new_text: String, + drag_start: DVec2, + drag_current: DVec2, + resize: Resize, + auto_panning: AutoPanning, + // Since the overlays must be drawn without knowledge of the inputs + cached_resize_bounds: [DVec2; 2], + bounding_box_manager: Option, + pivot: Pivot, + snap_candidates: Vec, + // TODO: Handle multiple layers in the future + layer_dragging: Option, +} + +impl TextToolData { + fn delete_empty_layer(&mut self, font_cache: &FontCache, responses: &mut VecDeque) -> TextToolFsmState { + // Remove the editable textbox UI first + self.set_editing(false, font_cache, responses); + + // Delete the empty text layer and update the graph + responses.add(NodeGraphMessage::DeleteNodes { + node_ids: vec![self.layer.to_node()], + delete_children: true, + }); + responses.add(NodeGraphMessage::RunDocumentGraph); + + TextToolFsmState::Ready + } + /// Set the editing state of the currently modifying layer + fn set_editing(&self, editable: bool, font_cache: &FontCache, responses: &mut VecDeque) { + if let Some(editing_text) = self.editing_text.as_ref().filter(|_| editable) { + responses.add(FrontendMessage::DisplayEditableTextbox { + text: editing_text.text.clone(), + line_height_ratio: editing_text.typesetting.line_height_ratio, + font_size: editing_text.typesetting.font_size, + color: editing_text.color.unwrap_or(Color::BLACK), + url: font_cache.get_preview_url(&editing_text.font).cloned().unwrap_or_default(), + transform: editing_text.transform.to_cols_array(), + max_width: editing_text.typesetting.max_width, + max_height: editing_text.typesetting.max_height, + }); + } else { + // Check if DisplayRemoveEditableTextbox is already in the responses queue + let has_remove_textbox = responses.iter().any(|msg| matches!(msg, Message::Frontend(FrontendMessage::DisplayRemoveEditableTextbox))); + responses.add(FrontendMessage::DisplayRemoveEditableTextbox); + + if has_remove_textbox { + responses.add(NodeGraphMessage::SelectedNodesSet { nodes: Vec::new() }); + } + } + } + + fn load_layer_text_node(&mut self, document: &DocumentMessageHandler) -> Option<()> { + let transform = document.metadata().transform_to_viewport(self.layer); + let color = graph_modification_utils::get_fill_color(self.layer, &document.network_interface).unwrap_or(Color::BLACK); + let (text, font, typesetting) = graph_modification_utils::get_text(self.layer, &document.network_interface)?; + self.editing_text = Some(EditingText { + text: text.clone(), + font: font.clone(), + typesetting, + color: Some(color), + transform, + }); + self.new_text.clone_from(text); + Some(()) + } + + fn start_editing_layer(&mut self, layer: LayerNodeIdentifier, tool_state: TextToolFsmState, document: &DocumentMessageHandler, font_cache: &FontCache, responses: &mut VecDeque) { + if layer == LayerNodeIdentifier::ROOT_PARENT { + log::error!("Cannot edit ROOT_PARENT in TextTooLData") + } + + if tool_state == TextToolFsmState::Editing { + self.set_editing(false, font_cache, responses); + } + + self.layer = layer; + if self.load_layer_text_node(document).is_some() { + responses.add(DocumentMessage::AddTransaction); + + self.set_editing(true, font_cache, responses); + + responses.add(NodeGraphMessage::SelectedNodesSet { nodes: vec![self.layer.to_node()] }); + // Make the rendered text invisible while editing + responses.add(NodeGraphMessage::SetInput { + input_connector: InputConnector::node(graph_modification_utils::get_text_id(self.layer, &document.network_interface).unwrap(), 1), + input: NodeInput::value(TaggedValue::String("".to_string()), false), + }); + responses.add(NodeGraphMessage::RunDocumentGraph); + }; + } + + fn new_text(&mut self, document: &DocumentMessageHandler, editing_text: EditingText, font_cache: &FontCache, responses: &mut VecDeque) { + // Create new text + self.new_text = String::new(); + responses.add(DocumentMessage::AddTransaction); + + self.layer = LayerNodeIdentifier::new_unchecked(NodeId::new()); + + responses.add(GraphOperationMessage::NewTextLayer { + id: self.layer.to_node(), + text: String::new(), + font: editing_text.font.clone(), + typesetting: editing_text.typesetting, + parent: document.new_layer_parent(true), + insert_index: 0, + }); + responses.add(Message::StartBuffer); + responses.add(GraphOperationMessage::FillSet { + layer: self.layer, + fill: if editing_text.color.is_some() { + Fill::Solid(editing_text.color.unwrap().to_gamma_srgb()) + } else { + Fill::None + }, + }); + responses.add(GraphOperationMessage::TransformSet { + layer: self.layer, + transform: editing_text.transform, + transform_in: TransformIn::Viewport, + skip_rerender: true, + }); + self.editing_text = Some(editing_text); + + self.set_editing(true, font_cache, responses); + + responses.add(NodeGraphMessage::SelectedNodesSet { nodes: vec![self.layer.to_node()] }); + + responses.add(NodeGraphMessage::RunDocumentGraph); + } + + fn check_click(document: &DocumentMessageHandler, input: &InputPreprocessorMessageHandler, font_cache: &FontCache) -> Option { + document + .metadata() + .all_layers() + .filter(|&layer| is_layer_fed_by_node_of_name(layer, &document.network_interface, "Text")) + .find(|&layer| { + let transformed_quad = document.metadata().transform_to_viewport(layer) * text_bounding_box(layer, document, font_cache); + let mouse = DVec2::new(input.mouse.position.x, input.mouse.position.y); + + transformed_quad.contains(mouse) + }) + } + + fn get_snap_candidates(&mut self, document: &DocumentMessageHandler, font_cache: &FontCache) { + self.snap_candidates.clear(); + + if let Some(ResizingLayer { id, .. }) = self.layer_dragging { + let quad = document.metadata().transform_to_document(id) * text_bounding_box(id, document, font_cache); + snapping::get_bbox_points(quad, &mut self.snap_candidates, snapping::BBoxSnapValues::BOUNDING_BOX, document); + } + } +} + +fn can_edit_selected(document: &DocumentMessageHandler) -> Option { + let selected_nodes = document.network_interface.selected_nodes(); + let mut selected_layers = selected_nodes.selected_layers(document.metadata()); + let layer = selected_layers.next()?; + + // Check that only one layer is selected + if selected_layers.next().is_some() { + return None; + } + + if !is_layer_fed_by_node_of_name(layer, &document.network_interface, "Text") { + return None; + } + + Some(layer) +} + +impl Fsm for TextToolFsmState { + type ToolData = TextToolData; + type ToolOptions = TextOptions; + + fn transition(self, event: ToolMessage, tool_data: &mut Self::ToolData, transition_data: &mut ToolActionHandlerData, tool_options: &Self::ToolOptions, responses: &mut VecDeque) -> Self { + let ToolActionHandlerData { + document, + global_tool_data, + input, + font_cache, + .. + } = transition_data; + let fill_color = graphene_std::Color::from_rgb_str(COLOR_OVERLAY_BLUE.strip_prefix('#').unwrap()) + .unwrap() + .with_alpha(0.05) + .to_rgba_hex_srgb(); + + let ToolMessage::Text(event) = event else { return self }; + match (self, event) { + (TextToolFsmState::Editing, TextToolMessage::Overlays(mut overlay_context)) => { + responses.add(FrontendMessage::DisplayEditableTextboxTransform { + transform: document.metadata().transform_to_viewport(tool_data.layer).to_cols_array(), + }); + if let Some(editing_text) = tool_data.editing_text.as_mut() { + let font_data = font_cache.get(&editing_text.font).map(|data| load_font(data)); + let far = graphene_std::text::bounding_box(&tool_data.new_text, font_data, editing_text.typesetting, false); + if far.x != 0. && far.y != 0. { + let quad = Quad::from_box([DVec2::ZERO, far]); + let transformed_quad = document.metadata().transform_to_viewport(tool_data.layer) * quad; + overlay_context.quad(transformed_quad, None, Some(&("#".to_string() + &fill_color))); + } + } + + TextToolFsmState::Editing + } + (_, TextToolMessage::Overlays(mut overlay_context)) => { + if matches!(self, Self::Placing) { + // Get the updated selection box bounds + let quad = Quad::from_box(tool_data.cached_resize_bounds); + + // Draw a bounding box on the layers to be selected + for layer in document.intersect_quad_no_artboards(quad, input) { + overlay_context.quad( + Quad::from_box(document.metadata().bounding_box_viewport(layer).unwrap_or([DVec2::ZERO; 2])), + None, + Some(&("#".to_string() + &fill_color)), + ); + } + + overlay_context.quad(quad, None, Some(&("#".to_string() + &fill_color))); + } + + // TODO: implement bounding box for multiple layers + let selected = document.network_interface.selected_nodes(); + let mut all_layers = selected.selected_visible_and_unlocked_layers(&document.network_interface); + let layer = all_layers.find(|layer| is_layer_fed_by_node_of_name(*layer, &document.network_interface, "Text")); + let bounds = layer.map(|layer| text_bounding_box(layer, document, font_cache)); + let layer_transform = layer.map(|layer| document.metadata().transform_to_viewport(layer)).unwrap_or(DAffine2::IDENTITY); + + if layer.is_none() || bounds.is_none() || layer_transform.matrix2.determinant() == 0. { + return self; + } + + if overlay_context.visibility_settings.transform_cage() { + if let Some(bounds) = bounds { + let bounding_box_manager = tool_data.bounding_box_manager.get_or_insert(BoundingBoxManager::default()); + bounding_box_manager.bounds = [bounds.0[0], bounds.0[2]]; + bounding_box_manager.transform = layer_transform; + + bounding_box_manager.render_quad(&mut overlay_context); + // Draw red overlay if text is clipped + let transformed_quad = layer_transform * bounds; + if let Some((text, font, typesetting)) = graph_modification_utils::get_text(layer.unwrap(), &document.network_interface) { + let font_data = font_cache.get(font).map(|data| load_font(data)); + if lines_clipping(text.as_str(), font_data, typesetting) { + overlay_context.line(transformed_quad.0[2], transformed_quad.0[3], Some(COLOR_OVERLAY_RED), Some(3.)); + } + } + + bounding_box_manager.render_overlays(&mut overlay_context, false); + tool_data.pivot.update_pivot(document, &mut overlay_context, None); + } + } else { + tool_data.bounding_box_manager.take(); + } + + tool_data.resize.snap_manager.draw_overlays(SnapData::new(document, input), &mut overlay_context); + + self + } + (state, TextToolMessage::EditSelected) => { + if let Some(layer) = can_edit_selected(document) { + tool_data.start_editing_layer(layer, state, document, font_cache, responses); + return TextToolFsmState::Editing; + } + + state + } + (TextToolFsmState::Ready, TextToolMessage::DragStart) => { + tool_data.resize.start(document, input); + tool_data.cached_resize_bounds = [tool_data.resize.viewport_drag_start(document); 2]; + tool_data.drag_start = input.mouse.position; + tool_data.drag_current = input.mouse.position; + + let dragging_bounds = tool_data.bounding_box_manager.as_mut().and_then(|bounding_box| { + let edges = bounding_box.check_selected_edges(input.mouse.position); + + bounding_box.selected_edges = edges.map(|(top, bottom, left, right)| { + let selected_edges = SelectedEdges::new(top, bottom, left, right, bounding_box.bounds); + bounding_box.opposite_pivot = selected_edges.calculate_pivot(); + selected_edges + }); + + edges + }); + + let selected = document.network_interface.selected_nodes(); + let mut all_selected = selected.selected_visible_and_unlocked_layers(&document.network_interface); + let selected = all_selected.find(|layer| is_layer_fed_by_node_of_name(*layer, &document.network_interface, "Text")); + + if dragging_bounds.is_some() { + responses.add(DocumentMessage::StartTransaction); + + // Set the original transform + if let Some(id) = selected { + let original_transform = document.metadata().transform_to_document(id); + tool_data.layer_dragging = Some(ResizingLayer { id, original_transform }); + } + + if let Some(bounds) = &mut tool_data.bounding_box_manager { + bounds.original_bound_transform = bounds.transform; + bounds.center_of_transformation = bounds.transform.transform_point2((bounds.bounds[0] + bounds.bounds[1]) / 2.); + } + tool_data.get_snap_candidates(document, font_cache); + + return TextToolFsmState::ResizingBounds; + } else if let Some(clicked_layer) = TextToolData::check_click(document, input, font_cache) { + responses.add(DocumentMessage::StartTransaction); + + if selected != Some(clicked_layer) { + responses.add(NodeGraphMessage::SelectedNodesSet { nodes: vec![clicked_layer.to_node()] }); + } + + let original_transform = document.metadata().transform_to_document(clicked_layer); + tool_data.layer_dragging = Some(ResizingLayer { + id: clicked_layer, + original_transform, + }); + tool_data.get_snap_candidates(document, font_cache); + return TextToolFsmState::Dragging; + } + TextToolFsmState::Placing + } + (TextToolFsmState::Ready, TextToolMessage::PointerMove { .. }) => { + // This ensures the cursor only changes if a layer is selected + let selected = document.network_interface.selected_nodes(); + let mut all_selected = selected.selected_visible_and_unlocked_layers(&document.network_interface); + let layer = all_selected.find(|&layer| is_layer_fed_by_node_of_name(layer, &document.network_interface, "Text")); + + let mut cursor = tool_data + .bounding_box_manager + .as_ref() + .map_or(MouseCursorIcon::Text, |bounds| bounds.get_cursor(input, false, false, None)); + if layer.is_none() || cursor == MouseCursorIcon::Default { + cursor = MouseCursorIcon::Text; + } + + responses.add(OverlaysMessage::Draw); + responses.add(FrontendMessage::UpdateMouseCursor { cursor }); + + TextToolFsmState::Ready + } + (TextToolFsmState::Placing, TextToolMessage::PointerMove { center, lock_ratio }) => { + tool_data.cached_resize_bounds = tool_data.resize.calculate_points_ignore_layer(document, input, center, lock_ratio, false); + + responses.add(OverlaysMessage::Draw); + + // Auto-panning + let messages = [ + TextToolMessage::PointerOutsideViewport { center, lock_ratio }.into(), + TextToolMessage::PointerMove { center, lock_ratio }.into(), + ]; + tool_data.auto_panning.setup_by_mouse_position(input, &messages, responses); + + TextToolFsmState::Placing + } + (TextToolFsmState::Dragging, TextToolMessage::PointerMove { center, lock_ratio }) => { + if let Some(dragging_layer) = &tool_data.layer_dragging { + let delta = input.mouse.position - tool_data.drag_current; + tool_data.drag_current = input.mouse.position; + + responses.add(GraphOperationMessage::TransformChange { + layer: dragging_layer.id, + transform: DAffine2::from_translation(delta), + transform_in: TransformIn::Viewport, + skip_rerender: false, + }); + + responses.add(NodeGraphMessage::RunDocumentGraph); + + // Auto-panning + let messages = [ + TextToolMessage::PointerOutsideViewport { center, lock_ratio }.into(), + TextToolMessage::PointerMove { center, lock_ratio }.into(), + ]; + tool_data.auto_panning.setup_by_mouse_position(input, &messages, responses); + } + + TextToolFsmState::Dragging + } + (TextToolFsmState::ResizingBounds, TextToolMessage::PointerMove { center, lock_ratio }) => { + if let Some(bounds) = &mut tool_data.bounding_box_manager { + if let Some(movement) = &mut bounds.selected_edges { + let (centered, constrain) = (input.keyboard.key(center), input.keyboard.key(lock_ratio)); + let center_position = centered.then_some(bounds.center_of_transformation); + + let Some(dragging_layer) = tool_data.layer_dragging else { return TextToolFsmState::Ready }; + let Some(node_id) = graph_modification_utils::get_text_id(dragging_layer.id, &document.network_interface) else { + warn!("Cannot get text node id"); + tool_data.layer_dragging.take(); + return TextToolFsmState::Ready; + }; + + let selected = vec![dragging_layer.id]; + let snap = Some(SizeSnapData { + manager: &mut tool_data.resize.snap_manager, + points: &mut tool_data.snap_candidates, + snap_data: SnapData::ignore(document, input, &selected), + }); + + let (position, size) = movement.new_size(input.mouse.position, bounds.original_bound_transform, center_position, constrain, snap); + // Normalize so the size is always positive + let (position, size) = (position.min(position + size), size.abs()); + + // Compute the offset needed for the top left in bounds space + let original_position = movement.bounds[0].min(movement.bounds[1]); + let translation_bounds_space = position - original_position; + + // Compute a transformation from bounds->viewport->layer + let transform_to_layer = document.metadata().transform_to_viewport(dragging_layer.id).inverse() * bounds.original_bound_transform; + let size_layer = transform_to_layer.transform_vector2(size); + + // Find the translation necessary from the original position in viewport space + let translation_viewport = bounds.original_bound_transform.transform_vector2(translation_bounds_space); + + responses.add(NodeGraphMessage::SetInput { + input_connector: InputConnector::node(node_id, 6), + input: NodeInput::value(TaggedValue::OptionalF64(Some(size_layer.x)), false), + }); + responses.add(NodeGraphMessage::SetInput { + input_connector: InputConnector::node(node_id, 7), + input: NodeInput::value(TaggedValue::OptionalF64(Some(size_layer.y)), false), + }); + responses.add(GraphOperationMessage::TransformSet { + layer: dragging_layer.id, + transform: DAffine2::from_translation(translation_viewport) * document.metadata().document_to_viewport * dragging_layer.original_transform, + transform_in: TransformIn::Viewport, + skip_rerender: false, + }); + responses.add(NodeGraphMessage::RunDocumentGraph); + + // Auto-panning + let messages = [ + TextToolMessage::PointerOutsideViewport { center, lock_ratio }.into(), + TextToolMessage::PointerMove { center, lock_ratio }.into(), + ]; + tool_data.auto_panning.setup_by_mouse_position(input, &messages, responses); + } + } + TextToolFsmState::ResizingBounds + } + (_, TextToolMessage::PointerMove { .. }) => { + tool_data.resize.snap_manager.preview_draw(&SnapData::new(document, input), input.mouse.position); + responses.add(OverlaysMessage::Draw); + + self + } + (TextToolFsmState::Placing, TextToolMessage::PointerOutsideViewport { .. }) => { + // Auto-panning setup + let _ = tool_data.auto_panning.shift_viewport(input, responses); + + TextToolFsmState::Placing + } + (TextToolFsmState::ResizingBounds | TextToolFsmState::Dragging, TextToolMessage::PointerOutsideViewport { .. }) => { + // Auto-panning + if let Some(shift) = tool_data.auto_panning.shift_viewport(input, responses) { + if let Some(bounds) = &mut tool_data.bounding_box_manager { + bounds.center_of_transformation += shift; + bounds.original_bound_transform.translation += shift; + } + } + + self + } + (state, TextToolMessage::PointerOutsideViewport { center, lock_ratio }) => { + // Auto-panning stop + let messages = [ + TextToolMessage::PointerOutsideViewport { center, lock_ratio }.into(), + TextToolMessage::PointerMove { center, lock_ratio }.into(), + ]; + tool_data.auto_panning.stop(&messages, responses); + + state + } + (TextToolFsmState::ResizingBounds, TextToolMessage::DragStop) => { + let drag_too_small = input.mouse.position.distance(tool_data.resize.viewport_drag_start(document)) < 10. * f64::EPSILON; + let response = if drag_too_small { DocumentMessage::AbortTransaction } else { DocumentMessage::EndTransaction }; + responses.add(response); + + tool_data.resize.snap_manager.cleanup(responses); + + if let Some(bounds) = &mut tool_data.bounding_box_manager { + bounds.original_transforms.clear(); + } + + TextToolFsmState::Ready + } + (TextToolFsmState::Placing, TextToolMessage::DragStop) => { + let [start, end] = tool_data.cached_resize_bounds; + let has_dragged = (start - end).length_squared() > DRAG_THRESHOLD * DRAG_THRESHOLD; + + // Check if the user has clicked (no dragging) on some existing text + if !has_dragged { + if let Some(clicked_text_layer_path) = TextToolData::check_click(document, input, font_cache) { + tool_data.start_editing_layer(clicked_text_layer_path, self, document, font_cache, responses); + return TextToolFsmState::Editing; + } + } + + // Otherwise create some new text + let constraint_size = has_dragged.then_some((start - end).abs()); + let editing_text = EditingText { + text: String::new(), + transform: DAffine2::from_translation(start), + typesetting: TypesettingConfig { + font_size: tool_options.font_size, + line_height_ratio: tool_options.line_height_ratio, + max_width: constraint_size.map(|size| size.x), + character_spacing: tool_options.character_spacing, + max_height: constraint_size.map(|size| size.y), + tilt: tool_options.tilt, + }, + font: Font::new(tool_options.font_name.clone(), tool_options.font_style.clone()), + color: tool_options.fill.active_color(), + }; + tool_data.new_text(document, editing_text, font_cache, responses); + TextToolFsmState::Editing + } + (TextToolFsmState::Dragging, TextToolMessage::DragStop) => { + let drag_too_small = input.mouse.position.distance(tool_data.drag_start) < 10. * f64::EPSILON; + let response = if drag_too_small { DocumentMessage::AbortTransaction } else { DocumentMessage::EndTransaction }; + responses.add(response); + + tool_data.resize.snap_manager.cleanup(responses); + + if let Some(bounds) = &mut tool_data.bounding_box_manager { + bounds.original_transforms.clear(); + } + + if drag_too_small { + if let Some(layer_info) = &tool_data.layer_dragging { + tool_data.start_editing_layer(layer_info.id, self, document, font_cache, responses); + return TextToolFsmState::Editing; + } + } + tool_data.layer_dragging.take(); + + TextToolFsmState::Ready + } + (TextToolFsmState::Editing, TextToolMessage::TextChange { new_text, is_left_or_right_click }) => { + tool_data.new_text = new_text; + + if !is_left_or_right_click { + tool_data.set_editing(false, font_cache, responses); + + responses.add(NodeGraphMessage::SetInput { + input_connector: InputConnector::node(graph_modification_utils::get_text_id(tool_data.layer, &document.network_interface).unwrap(), 1), + input: NodeInput::value(TaggedValue::String(tool_data.new_text.clone()), false), + }); + responses.add(NodeGraphMessage::RunDocumentGraph); + + TextToolFsmState::Ready + } else { + if tool_data.new_text.is_empty() { + return tool_data.delete_empty_layer(font_cache, responses); + } + + responses.add(FrontendMessage::TriggerTextCommit); + TextToolFsmState::Editing + } + } + (TextToolFsmState::Editing, TextToolMessage::UpdateBounds { new_text }) => { + tool_data.new_text = new_text; + responses.add(OverlaysMessage::Draw); + TextToolFsmState::Editing + } + (_, TextToolMessage::WorkingColorChanged) => { + responses.add(TextToolMessage::UpdateOptions(TextOptionsUpdate::WorkingColors( + Some(global_tool_data.primary_color), + Some(global_tool_data.secondary_color), + ))); + self + } + (TextToolFsmState::Editing, TextToolMessage::Abort) => { + if tool_data.new_text.is_empty() { + return tool_data.delete_empty_layer(font_cache, responses); + } + + responses.add(FrontendMessage::TriggerTextCommit); + TextToolFsmState::Editing + } + (state, TextToolMessage::Abort) => { + if matches!(state, TextToolFsmState::ResizingBounds | TextToolFsmState::Dragging) { + responses.add(DocumentMessage::AbortTransaction); + if let Some(bounds) = &mut tool_data.bounding_box_manager { + bounds.original_transforms.clear(); + } + if matches!(state, TextToolFsmState::Dragging) { + tool_data.layer_dragging.take(); + } + } else { + input.mouse.finish_transaction(tool_data.resize.viewport_drag_start(document), responses); + } + tool_data.resize.cleanup(responses); + + TextToolFsmState::Ready + } + _ => self, + } + } + + fn update_hints(&self, responses: &mut VecDeque) { + let hint_data = match self { + TextToolFsmState::Ready => HintData(vec![ + HintGroup(vec![HintInfo::mouse(MouseMotion::Lmb, "Place Text")]), + HintGroup(vec![ + HintInfo::mouse(MouseMotion::LmbDrag, "Place Text Box"), + HintInfo::keys([Key::Shift], "Constrain Square").prepend_plus(), + HintInfo::keys([Key::Alt], "From Center").prepend_plus(), + ]), + HintGroup(vec![HintInfo::mouse(MouseMotion::Lmb, "Edit Text")]), + ]), + TextToolFsmState::Editing => HintData(vec![HintGroup(vec![ + HintInfo::keys([Key::Control, Key::Enter], "").add_mac_keys([Key::Command, Key::Enter]), + HintInfo::keys([Key::Escape], "Commit Changes").prepend_slash(), + ])]), + TextToolFsmState::Placing => HintData(vec![ + HintGroup(vec![HintInfo::mouse(MouseMotion::Rmb, ""), HintInfo::keys([Key::Escape], "Cancel").prepend_slash()]), + HintGroup(vec![HintInfo::keys([Key::Shift], "Constrain Square"), HintInfo::keys([Key::Alt], "From Center")]), + ]), + TextToolFsmState::Dragging => HintData(vec![HintGroup(vec![HintInfo::mouse(MouseMotion::Rmb, ""), HintInfo::keys([Key::Escape], "Cancel").prepend_slash()])]), + TextToolFsmState::ResizingBounds => HintData(vec![ + HintGroup(vec![HintInfo::mouse(MouseMotion::Rmb, ""), HintInfo::keys([Key::Escape], "Cancel").prepend_slash()]), + HintGroup(vec![HintInfo::keys([Key::Shift], "Lock Aspect Ratio"), HintInfo::keys([Key::Alt], "From Center")]), + ]), + }; + + responses.add(FrontendMessage::UpdateInputHints { hint_data }); + } + + fn update_cursor(&self, responses: &mut VecDeque) { + let cursor = match self { + TextToolFsmState::Placing => MouseCursorIcon::Crosshair, + _ => MouseCursorIcon::Text, + }; + responses.add(FrontendMessage::UpdateMouseCursor { cursor }); + } +} diff --git a/editor/src/messages/tool/transform_layer/mod.rs b/editor/src/messages/tool/transform_layer/mod.rs new file mode 100644 index 0000000000000000000000000000000000000000..823edf1a4508f9fb1173f123119cd5fd03b220b0 --- /dev/null +++ b/editor/src/messages/tool/transform_layer/mod.rs @@ -0,0 +1,15 @@ +//! Handles Blender inspired layer transformation with the G R and S keys for grabbing, rotating and scaling. +//! +//! Other features include +//! - Typing a number for a precise transformation +//! - Shift to slow transformation +//! - Ctrl to snap angles to 15° +//! - Escape or right click to cancel + +mod transform_layer_message; +mod transform_layer_message_handler; + +#[doc(inline)] +pub use transform_layer_message::{TransformLayerMessage, TransformLayerMessageDiscriminant}; +#[doc(inline)] +pub use transform_layer_message_handler::TransformLayerMessageHandler; diff --git a/editor/src/messages/tool/transform_layer/transform_layer_message.rs b/editor/src/messages/tool/transform_layer/transform_layer_message.rs new file mode 100644 index 0000000000000000000000000000000000000000..e68d2702c4bd9b948a9328196f7f85a8b72f1451 --- /dev/null +++ b/editor/src/messages/tool/transform_layer/transform_layer_message.rs @@ -0,0 +1,32 @@ +use crate::messages::input_mapper::utility_types::input_keyboard::Key; +use crate::messages::portfolio::document::overlays::utility_types::OverlayContext; +use crate::messages::portfolio::document::utility_types::transformation::TransformType; +use crate::messages::prelude::*; +use glam::DVec2; + +#[impl_message(Message, ToolMessage, TransformLayer)] +#[derive(PartialEq, Clone, Debug, serde::Serialize, serde::Deserialize)] +pub enum TransformLayerMessage { + // Overlays + Overlays(OverlayContext), + + // Messages + ApplyTransformOperation { final_transform: bool }, + BeginTransformOperation { operation: TransformType }, + BeginGrab, + BeginRotate, + BeginScale, + BeginGRS { operation: TransformType }, + BeginGrabPen { last_point: DVec2, handle: DVec2 }, + BeginRotatePen { last_point: DVec2, handle: DVec2 }, + BeginScalePen { last_point: DVec2, handle: DVec2 }, + CancelTransformOperation, + ConstrainX, + ConstrainY, + PointerMove { slow_key: Key, increments_key: Key }, + SelectionChanged, + TypeBackspace, + TypeDecimalPoint, + TypeDigit { digit: u8 }, + TypeNegate, +} diff --git a/editor/src/messages/tool/transform_layer/transform_layer_message_handler.rs b/editor/src/messages/tool/transform_layer/transform_layer_message_handler.rs new file mode 100644 index 0000000000000000000000000000000000000000..e449bbd3b86becf091f75b75674840a9fd6b56cb --- /dev/null +++ b/editor/src/messages/tool/transform_layer/transform_layer_message_handler.rs @@ -0,0 +1,1275 @@ +use crate::consts::{ANGLE_MEASURE_RADIUS_FACTOR, ARC_MEASURE_RADIUS_FACTOR_RANGE, COLOR_OVERLAY_BLUE, SLOWING_DIVISOR}; +use crate::messages::input_mapper::utility_types::input_mouse::{DocumentPosition, ViewportPosition}; +use crate::messages::portfolio::document::overlays::utility_types::{OverlayProvider, Pivot}; +use crate::messages::portfolio::document::utility_types::document_metadata::LayerNodeIdentifier; +use crate::messages::portfolio::document::utility_types::misc::PTZ; +use crate::messages::portfolio::document::utility_types::transformation::{Axis, OriginalTransforms, Selected, TransformOperation, TransformType, Typing}; +use crate::messages::prelude::*; +use crate::messages::tool::common_functionality::shape_editor::ShapeState; +use crate::messages::tool::tool_messages::tool_prelude::Key; +use crate::messages::tool::utility_types::{ToolData, ToolType}; +use glam::{DAffine2, DVec2}; +use graphene_std::renderer::Quad; +use graphene_std::vector::ManipulatorPointId; +use graphene_std::vector::{VectorData, VectorModificationType}; +use std::f64::consts::{PI, TAU}; + +const TRANSFORM_GRS_OVERLAY_PROVIDER: OverlayProvider = |context| TransformLayerMessage::Overlays(context).into(); + +// TODO: Get these from the input mapper +const SLOW_KEY: Key = Key::Shift; +const INCREMENTS_KEY: Key = Key::Control; + +#[derive(Debug, Clone, Default)] +pub struct TransformLayerMessageHandler { + pub transform_operation: TransformOperation, + + slow: bool, + increments: bool, + local: bool, + layer_bounding_box: Quad, + typing: Typing, + + mouse_position: ViewportPosition, + start_mouse: ViewportPosition, + + original_transforms: OriginalTransforms, + pivot: ViewportPosition, + + local_pivot: DocumentPosition, + local_mouse_start: DocumentPosition, + grab_target: DocumentPosition, + + ptz: PTZ, + initial_transform: DAffine2, + + operation_count: usize, + + // Pen tool (outgoing handle GRS manipulation) + handle: DVec2, + last_point: DVec2, + grs_pen_handle: bool, +} + +impl TransformLayerMessageHandler { + pub fn is_transforming(&self) -> bool { + self.transform_operation != TransformOperation::None + } + + pub fn hints(&self, responses: &mut VecDeque) { + self.transform_operation.hints(responses, self.local); + } +} + +fn calculate_pivot(selected_points: &Vec<&ManipulatorPointId>, vector_data: &VectorData, viewspace: DAffine2, get_location: impl Fn(&ManipulatorPointId) -> Option) -> Option<(DVec2, DVec2)> { + let [point] = selected_points.as_slice() else { + // Handle the case where there are multiple points + let mut point_count = 0; + let average_position = selected_points.iter().filter_map(|p| get_location(p)).inspect(|_| point_count += 1).sum::() / point_count as f64; + + return Some((average_position, average_position)); + }; + + match point { + ManipulatorPointId::PrimaryHandle(_) | ManipulatorPointId::EndHandle(_) => { + // Get the anchor position and transform it to the pivot + let pivot_pos = point.get_anchor_position(vector_data).map(|anchor_position| viewspace.transform_point2(anchor_position))?; + let target = viewspace.transform_point2(point.get_position(vector_data)?); + Some((pivot_pos, target)) + } + _ => { + // Calculate the average position of all selected points + let mut point_count = 0; + let average_position = selected_points.iter().filter_map(|p| get_location(p)).inspect(|_| point_count += 1).sum::() / point_count as f64; + Some((average_position, average_position)) + } + } +} + +fn project_edge_to_quad(edge: DVec2, quad: &Quad, local: bool, axis_constraint: Axis) -> DVec2 { + match axis_constraint { + Axis::X => { + if local { + edge.project_onto(quad.top_right() - quad.top_left()) + } else { + edge.with_y(0.) + } + } + Axis::Y => { + if local { + edge.project_onto(quad.bottom_left() - quad.top_left()) + } else { + edge.with_x(0.) + } + } + _ => edge, + } +} + +fn update_colinear_handles(selected_layers: &[LayerNodeIdentifier], document: &DocumentMessageHandler, responses: &mut VecDeque) { + for &layer in selected_layers { + let Some(vector_data) = document.network_interface.compute_modified_vector(layer) else { continue }; + + for [handle1, handle2] in &vector_data.colinear_manipulators { + let manipulator1 = handle1.to_manipulator_point(); + let manipulator2 = handle2.to_manipulator_point(); + + let Some(anchor) = manipulator1.get_anchor_position(&vector_data) else { continue }; + let Some(pos1) = manipulator1.get_position(&vector_data).map(|pos| pos - anchor) else { continue }; + let Some(pos2) = manipulator2.get_position(&vector_data).map(|pos| pos - anchor) else { continue }; + + let angle = pos1.angle_to(pos2); + + // Check if handles are not colinear (not approximately equal to +/- PI) + if (angle - PI).abs() > 1e-6 && (angle + PI).abs() > 1e-6 { + let modification_type = VectorModificationType::SetG1Continuous { + handles: [*handle1, *handle2], + enabled: false, + }; + + responses.add(GraphOperationMessage::Vector { layer, modification_type }); + } + } + } +} + +type TransformData<'a> = (&'a DocumentMessageHandler, &'a InputPreprocessorMessageHandler, &'a ToolData, &'a mut ShapeState); +impl MessageHandler> for TransformLayerMessageHandler { + fn process_message(&mut self, message: TransformLayerMessage, responses: &mut VecDeque, (document, input, tool_data, shape_editor): TransformData) { + let using_path_tool = tool_data.active_tool_type == ToolType::Path; + let using_select_tool = tool_data.active_tool_type == ToolType::Select; + let using_pen_tool = tool_data.active_tool_type == ToolType::Pen; + let using_shape_tool = tool_data.active_tool_type == ToolType::Shape; + + // TODO: Add support for transforming layer not in the document network + let selected_layers = document + .network_interface + .selected_nodes() + .selected_layers(document.metadata()) + .filter(|&layer| document.network_interface.is_visible(&layer.to_node(), &[]) && !document.network_interface.is_locked(&layer.to_node(), &[])) + .collect::>(); + + let mut selected = Selected::new( + &mut self.original_transforms, + &mut self.pivot, + &selected_layers, + responses, + &document.network_interface, + Some(shape_editor), + &tool_data.active_tool_type, + Some(&mut self.handle), + ); + + let document_to_viewport = document.metadata().document_to_viewport; + let mut begin_operation = |operation: TransformOperation, typing: &mut Typing, mouse_position: &mut DVec2, start_mouse: &mut DVec2, transform: &mut DAffine2| { + if operation != TransformOperation::None { + selected.revert_operation(); + typing.clear(); + } + + if using_pen_tool { + selected.responses.add(PenToolMessage::GRS { + grab: Key::KeyG, + rotate: Key::KeyR, + scale: Key::KeyS, + }); + return; + } + + if !using_path_tool { + *selected.pivot = selected.mean_average_of_pivots(); + self.local_pivot = document.metadata().document_to_viewport.inverse().transform_point2(*selected.pivot); + self.grab_target = document.metadata().document_to_viewport.inverse().transform_point2(selected.mean_average_of_pivots()); + } + // Here vector data from all layers is not considered which can be a problem in pivot calculation + else if let Some(vector_data) = selected_layers.first().and_then(|&layer| document.network_interface.compute_modified_vector(layer)) { + *selected.original_transforms = OriginalTransforms::default(); + + let viewspace = document.metadata().transform_to_viewport(selected_layers[0]); + + let selected_segments = shape_editor.selected_segments().collect::>(); + + let mut affected_points = shape_editor.selected_points().copied().collect::>(); + + for (segment_id, _, start, end) in vector_data.segment_bezier_iter() { + if selected_segments.contains(&segment_id) { + affected_points.push(ManipulatorPointId::Anchor(start)); + affected_points.push(ManipulatorPointId::Anchor(end)); + } + } + + let affected_point_refs = affected_points.iter().collect(); + + let get_location = |point: &&ManipulatorPointId| point.get_position(&vector_data).map(|position| viewspace.transform_point2(position)); + if let Some((new_pivot, grab_target)) = calculate_pivot(&affected_point_refs, &vector_data, viewspace, |point: &ManipulatorPointId| get_location(&point)) { + *selected.pivot = new_pivot; + + self.local_pivot = document_to_viewport.inverse().transform_point2(*selected.pivot); + self.grab_target = document_to_viewport.inverse().transform_point2(grab_target); + } else { + log::warn!("Failed to calculate pivot."); + } + } + + *mouse_position = input.mouse.position; + *start_mouse = input.mouse.position; + *transform = document_to_viewport; + self.local_mouse_start = document.metadata().document_to_viewport.inverse().transform_point2(input.mouse.position); + + selected.original_transforms.clear(); + + selected.responses.add(DocumentMessage::StartTransaction); + }; + + match message { + // Overlays + TransformLayerMessage::Overlays(mut overlay_context) => { + if !overlay_context.visibility_settings.transform_measurement() { + return; + } + + for layer in document.metadata().all_layers() { + if !document.network_interface.is_artboard(&layer.to_node(), &[]) { + continue; + }; + + let viewport_box = input.viewport_bounds.size(); + let axis_constraint = self.transform_operation.axis_constraint(); + + let format_rounded = |value: f64, precision: usize| { + if self.typing.digits.is_empty() || !self.transform_operation.can_begin_typing() { + format!("{:.*}", precision, value).trim_end_matches('0').trim_end_matches('.').to_string() + } else { + self.typing.string.clone() + } + }; + + // TODO: Ensure removing this and adding this doesn't change the position of layers under PTZ ops + // responses.add(TransformLayerMessage::PointerMove { + // slow_key: SLOW_KEY, + // increments_key: INCREMENTS_KEY, + // }); + + match self.transform_operation { + TransformOperation::None => (), + TransformOperation::Grabbing(translation) => { + let translation = translation.to_dvec(self.initial_transform, self.increments); + let viewport_translate = document_to_viewport.transform_vector2(translation); + let pivot = document_to_viewport.transform_point2(self.grab_target); + let quad = Quad::from_box([pivot, pivot + viewport_translate]).0; + let e1 = (self.layer_bounding_box.0[1] - self.layer_bounding_box.0[0]).normalize_or(DVec2::X); + + if matches!(axis_constraint, Axis::Both | Axis::X) && translation.x != 0. { + let end = if self.local { (quad[1] - quad[0]).rotate(e1) + quad[0] } else { quad[1] }; + overlay_context.dashed_line(quad[0], end, None, None, Some(2.), Some(2.), Some(0.5)); + + let x_transform = DAffine2::from_translation((quad[0] + end) / 2.); + overlay_context.text(&format_rounded(translation.x, 3), COLOR_OVERLAY_BLUE, None, x_transform, 4., [Pivot::Middle, Pivot::End]); + } + + if matches!(axis_constraint, Axis::Both | Axis::Y) && translation.y != 0. { + let end = if self.local { (quad[3] - quad[0]).rotate(e1) + quad[0] } else { quad[3] }; + overlay_context.dashed_line(quad[0], end, None, None, Some(2.), Some(2.), Some(0.5)); + let x_parameter = viewport_translate.x.clamp(-1., 1.); + let y_transform = DAffine2::from_translation((quad[0] + end) / 2. + x_parameter * DVec2::X * 0.); + let pivot_selection = if x_parameter >= -1e-3 { Pivot::Start } else { Pivot::End }; + if axis_constraint != Axis::Both || self.typing.digits.is_empty() || !self.transform_operation.can_begin_typing() { + overlay_context.text(&format_rounded(translation.y, 2), COLOR_OVERLAY_BLUE, None, y_transform, 3., [pivot_selection, Pivot::Middle]); + } + } + + if matches!(axis_constraint, Axis::Both) && translation.x != 0. && translation.y != 0. { + overlay_context.line(quad[1], quad[2], None, None); + overlay_context.line(quad[3], quad[2], None, None); + } + } + TransformOperation::Scaling(scale) => { + let scale = scale.to_f64(self.increments); + let text = format!("{}x", format_rounded(scale, 3)); + let pivot = document_to_viewport.transform_point2(self.local_pivot); + let start_mouse = document_to_viewport.transform_point2(self.local_mouse_start); + let local_edge = start_mouse - pivot; + let local_edge = project_edge_to_quad(local_edge, &self.layer_bounding_box, self.local, axis_constraint); + let boundary_point = pivot + local_edge * scale.min(1.); + let end_point = pivot + local_edge * scale.max(1.); + + if scale > 0. { + overlay_context.dashed_line(pivot, boundary_point, None, None, Some(2.), Some(2.), Some(0.5)); + } + overlay_context.line(boundary_point, end_point, None, None); + + let transform = DAffine2::from_translation(boundary_point.midpoint(pivot) + local_edge.perp().normalize_or(DVec2::X) * local_edge.element_product().signum() * 24.); + overlay_context.text(&text, COLOR_OVERLAY_BLUE, None, transform, 16., [Pivot::Middle, Pivot::Middle]); + } + TransformOperation::Rotating(rotation) => { + let angle = rotation.to_f64(self.increments); + let pivot = document_to_viewport.transform_point2(self.local_pivot); + let start_mouse = document_to_viewport.transform_point2(self.local_mouse_start); + let offset_angle = if self.grs_pen_handle { + self.handle - self.last_point + } else if using_path_tool { + start_mouse - pivot + } else { + self.layer_bounding_box.top_right() - self.layer_bounding_box.top_right() + }; + let tilt_offset = document.document_ptz.unmodified_tilt(); + let offset_angle = offset_angle.to_angle() + tilt_offset; + let width = viewport_box.max_element(); + let radius = start_mouse.distance(pivot); + let arc_radius = ANGLE_MEASURE_RADIUS_FACTOR * width; + let radius = radius.clamp(ARC_MEASURE_RADIUS_FACTOR_RANGE.0 * width, ARC_MEASURE_RADIUS_FACTOR_RANGE.1 * width); + let angle_in_degrees = angle.to_degrees(); + let display_angle = if angle_in_degrees.is_sign_positive() { + angle_in_degrees - (angle_in_degrees / 360.).floor() * 360. + } else if angle_in_degrees.is_sign_negative() { + angle_in_degrees - ((angle_in_degrees / 360.).floor() + 1.) * 360. + } else { + angle_in_degrees + }; + let text = format!("{}°", format_rounded(display_angle, 2)); + let text_texture_width = overlay_context.get_width(&text) / 2.; + let text_texture_height = 12.; + let text_angle_on_unit_circle = DVec2::from_angle((angle % TAU) / 2. + offset_angle); + let text_texture_position = DVec2::new( + (arc_radius + 4. + text_texture_width) * text_angle_on_unit_circle.x, + (arc_radius + text_texture_height) * text_angle_on_unit_circle.y, + ); + let transform = DAffine2::from_translation(text_texture_position + pivot); + overlay_context.draw_angle(pivot, radius, arc_radius, offset_angle, angle); + overlay_context.text(&text, COLOR_OVERLAY_BLUE, None, transform, 16., [Pivot::Middle, Pivot::Middle]); + } + } + } + } + + // Messages + TransformLayerMessage::ApplyTransformOperation { final_transform } => { + selected.original_transforms.clear(); + self.typing.clear(); + if final_transform { + self.transform_operation = TransformOperation::None; + self.operation_count = 0; + } + + if using_pen_tool { + self.last_point = DVec2::ZERO; + self.grs_pen_handle = false; + + selected.pen_handle = None; + selected.responses.add(PenToolMessage::Confirm); + } else { + update_colinear_handles(&selected_layers, document, responses); + responses.add(DocumentMessage::EndTransaction); + responses.add(ToolMessage::UpdateHints); + responses.add(NodeGraphMessage::RunDocumentGraph); + } + + if final_transform { + responses.add(OverlaysMessage::RemoveProvider(TRANSFORM_GRS_OVERLAY_PROVIDER)); + } + } + TransformLayerMessage::BeginTransformOperation { operation } => { + begin_operation(self.transform_operation, &mut self.typing, &mut self.mouse_position, &mut self.start_mouse, &mut self.initial_transform); + self.transform_operation = match operation { + TransformType::Grab => TransformOperation::Grabbing(Default::default()), + TransformType::Rotate => TransformOperation::Rotating(Default::default()), + TransformType::Scale => TransformOperation::Scaling(Default::default()), + }; + self.layer_bounding_box = selected.bounding_box(); + } + TransformLayerMessage::BeginGrabPen { last_point, handle } | TransformLayerMessage::BeginRotatePen { last_point, handle } | TransformLayerMessage::BeginScalePen { last_point, handle } => { + self.typing.clear(); + + self.last_point = last_point; + self.handle = handle; + self.grs_pen_handle = true; + self.mouse_position = input.mouse.position; + self.start_mouse = input.mouse.position; + + let top_left = DVec2::new(last_point.x, handle.y); + let bottom_right = DVec2::new(handle.x, last_point.y); + self.local = false; + self.layer_bounding_box = Quad::from_box([top_left, bottom_right]); + self.grab_target = document.metadata().document_to_viewport.inverse().transform_point2(handle); + self.pivot = last_point; + self.local_pivot = document.metadata().document_to_viewport.inverse().transform_point2(self.pivot); + self.local_mouse_start = document.metadata().document_to_viewport.inverse().transform_point2(self.start_mouse); + self.handle = handle; + + // Operation-specific logic + self.transform_operation = match message { + TransformLayerMessage::BeginGrabPen { .. } => TransformOperation::Grabbing(Default::default()), + TransformLayerMessage::BeginRotatePen { .. } => TransformOperation::Rotating(Default::default()), + TransformLayerMessage::BeginScalePen { .. } => TransformOperation::Scaling(Default::default()), + _ => unreachable!(), // Safe because the match arms are exhaustive + }; + + responses.add(OverlaysMessage::AddProvider(TRANSFORM_GRS_OVERLAY_PROVIDER)); + // Find a way better than this hack + responses.add(TransformLayerMessage::PointerMove { + slow_key: SLOW_KEY, + increments_key: INCREMENTS_KEY, + }); + } + TransformLayerMessage::BeginGRS { operation: transform_type } => { + let selected_points: Vec<&ManipulatorPointId> = shape_editor.selected_points().collect(); + let selected_segments = shape_editor.selected_segments().collect::>(); + + if (using_path_tool && selected_points.is_empty() && selected_segments.is_empty()) + || (!using_path_tool && !using_select_tool && !using_pen_tool && !using_shape_tool) + || selected_layers.is_empty() + || transform_type.equivalent_to(self.transform_operation) + { + return; + } + + if let Some(vector_data) = selected_layers.first().and_then(|&layer| document.network_interface.compute_modified_vector(layer)) { + if let [point] = selected_points.as_slice() { + if matches!(point, ManipulatorPointId::Anchor(_)) { + if let Some([handle1, handle2]) = point.get_handle_pair(&vector_data) { + let handle1_length = handle1.length(&vector_data); + let handle2_length = handle2.length(&vector_data); + + if (handle1_length == 0. && handle2_length == 0. && !using_select_tool) || (handle1_length == f64::MAX && handle2_length == f64::MAX && !using_select_tool) { + // G should work for this point but not R and S + if matches!(transform_type, TransformType::Rotate | TransformType::Scale) { + selected.original_transforms.clear(); + return; + } + } + } + } else { + let handle_length = point.as_handle().map(|handle| handle.length(&vector_data)); + + if handle_length == Some(0.) { + selected.original_transforms.clear(); + return; + } + } + } + } + + self.local = false; + self.operation_count += 1; + + let chain_operation = self.transform_operation != TransformOperation::None; + if chain_operation { + responses.add(TransformLayerMessage::ApplyTransformOperation { final_transform: false }); + } else { + responses.add(OverlaysMessage::AddProvider(TRANSFORM_GRS_OVERLAY_PROVIDER)); + } + responses.add(TransformLayerMessage::BeginTransformOperation { operation: transform_type }); + responses.add(TransformLayerMessage::PointerMove { + slow_key: SLOW_KEY, + increments_key: INCREMENTS_KEY, + }); + } + TransformLayerMessage::BeginGrab => responses.add_front(TransformLayerMessage::BeginGRS { operation: TransformType::Grab }), + TransformLayerMessage::BeginRotate => responses.add_front(TransformLayerMessage::BeginGRS { operation: TransformType::Rotate }), + TransformLayerMessage::BeginScale => responses.add_front(TransformLayerMessage::BeginGRS { operation: TransformType::Scale }), + TransformLayerMessage::CancelTransformOperation => { + if using_pen_tool { + self.typing.clear(); + + self.last_point = DVec2::ZERO; + self.transform_operation = TransformOperation::None; + self.handle = DVec2::ZERO; + + responses.add(PenToolMessage::Abort); + responses.add(ToolMessage::UpdateHints); + } else { + selected.original_transforms.clear(); + self.typing.clear(); + self.transform_operation = TransformOperation::None; + + responses.add(DocumentMessage::RepeatedAbortTransaction { undo_count: self.operation_count }); + self.operation_count = 0; + responses.add(ToolMessage::UpdateHints); + } + + responses.add(OverlaysMessage::RemoveProvider(TRANSFORM_GRS_OVERLAY_PROVIDER)); + } + TransformLayerMessage::ConstrainX => { + let pivot = document_to_viewport.transform_point2(self.local_pivot); + self.local = self.transform_operation.constrain_axis( + Axis::X, + &mut selected, + self.increments, + self.local, + self.layer_bounding_box, + document_to_viewport, + pivot, + self.initial_transform, + ); + self.transform_operation.grs_typed( + self.typing.evaluate(), + &mut selected, + self.increments, + self.local, + self.layer_bounding_box, + document_to_viewport, + pivot, + self.initial_transform, + ); + } + TransformLayerMessage::ConstrainY => { + let pivot = document_to_viewport.transform_point2(self.local_pivot); + self.local = self.transform_operation.constrain_axis( + Axis::Y, + &mut selected, + self.increments, + self.local, + self.layer_bounding_box, + document_to_viewport, + pivot, + self.initial_transform, + ); + self.transform_operation.grs_typed( + self.typing.evaluate(), + &mut selected, + self.increments, + self.local, + self.layer_bounding_box, + document_to_viewport, + pivot, + self.initial_transform, + ); + } + TransformLayerMessage::PointerMove { slow_key, increments_key } => { + self.slow = input.keyboard.get(slow_key as usize); + let old_ptz = self.ptz; + self.ptz = document.document_ptz; + if old_ptz != self.ptz { + self.mouse_position = input.mouse.position; + return; + } + + let pivot = document_to_viewport.transform_point2(self.local_pivot); + + let new_increments = input.keyboard.get(increments_key as usize); + if new_increments != self.increments { + self.increments = new_increments; + self.transform_operation + .apply_transform_operation(&mut selected, self.increments, self.local, self.layer_bounding_box, document_to_viewport, pivot, self.initial_transform); + } + + if self.typing.digits.is_empty() || !self.transform_operation.can_begin_typing() { + match self.transform_operation { + TransformOperation::None => unreachable!(), + TransformOperation::Grabbing(translation) => { + let delta_pos = input.mouse.position - self.mouse_position; + let delta_pos = (self.initial_transform * document_to_viewport.inverse()).transform_vector2(delta_pos); + let change = if self.slow { delta_pos / SLOWING_DIVISOR } else { delta_pos }; + self.transform_operation = TransformOperation::Grabbing(translation.increment_amount(change)); + self.transform_operation.apply_transform_operation( + &mut selected, + self.increments, + self.local, + self.layer_bounding_box, + document_to_viewport, + pivot, + self.initial_transform, + ); + } + TransformOperation::Rotating(rotation) => { + let start_offset = pivot - self.mouse_position; + let end_offset = pivot - input.mouse.position; + let angle = start_offset.angle_to(end_offset); + + let change = if self.slow { angle / SLOWING_DIVISOR } else { angle }; + + self.transform_operation = TransformOperation::Rotating(rotation.increment_amount(change)); + self.transform_operation.apply_transform_operation( + &mut selected, + self.increments, + self.local, + self.layer_bounding_box, + document_to_viewport, + pivot, + self.initial_transform, + ); + } + TransformOperation::Scaling(mut scale) => { + let axis_constraint = scale.constraint; + let to_mouse_final = self.mouse_position - pivot; + let to_mouse_final_old = input.mouse.position - pivot; + let to_mouse_start = self.start_mouse - pivot; + + let to_mouse_final = project_edge_to_quad(to_mouse_final, &self.layer_bounding_box, self.local, axis_constraint); + let to_mouse_final_old = project_edge_to_quad(to_mouse_final_old, &self.layer_bounding_box, self.local, axis_constraint); + let to_mouse_start = project_edge_to_quad(to_mouse_start, &self.layer_bounding_box, self.local, axis_constraint); + + let change = { + let previous_frame_dist = to_mouse_final.dot(to_mouse_start); + let current_frame_dist = to_mouse_final_old.dot(to_mouse_start); + let start_transform_dist = to_mouse_start.length_squared(); + + (current_frame_dist - previous_frame_dist) / start_transform_dist + }; + let change = if self.slow { change / SLOWING_DIVISOR } else { change }; + + scale = scale.increment_amount(change); + self.transform_operation = TransformOperation::Scaling(scale); + self.transform_operation.apply_transform_operation( + &mut selected, + self.increments, + self.local, + self.layer_bounding_box, + document_to_viewport, + pivot, + self.initial_transform, + ); + } + }; + } + + self.mouse_position = input.mouse.position; + } + TransformLayerMessage::SelectionChanged => { + let target_layers = document.network_interface.selected_nodes().selected_layers(document.metadata()).collect(); + shape_editor.set_selected_layers(target_layers); + } + TransformLayerMessage::TypeBackspace => { + let pivot = document_to_viewport.transform_point2(self.local_pivot); + if self.typing.digits.is_empty() && self.typing.negative { + self.transform_operation + .negate(&mut selected, self.increments, self.local, self.layer_bounding_box, document_to_viewport, pivot, self.initial_transform); + self.typing.type_negate(); + } + self.transform_operation.grs_typed( + self.typing.type_backspace(), + &mut selected, + self.increments, + self.local, + self.layer_bounding_box, + document_to_viewport, + pivot, + self.initial_transform, + ); + } + TransformLayerMessage::TypeDecimalPoint => { + let pivot = document_to_viewport.transform_point2(self.local_pivot); + if self.transform_operation.can_begin_typing() { + self.transform_operation.grs_typed( + self.typing.type_decimal_point(), + &mut selected, + self.increments, + self.local, + self.layer_bounding_box, + document_to_viewport, + pivot, + self.initial_transform, + ) + } + } + TransformLayerMessage::TypeDigit { digit } => { + if self.transform_operation.can_begin_typing() { + let pivot = document_to_viewport.transform_point2(self.local_pivot); + self.transform_operation.grs_typed( + self.typing.type_number(digit), + &mut selected, + self.increments, + self.local, + self.layer_bounding_box, + document_to_viewport, + pivot, + self.initial_transform, + ) + } + } + TransformLayerMessage::TypeNegate => { + let pivot = document_to_viewport.transform_point2(self.local_pivot); + if self.typing.digits.is_empty() { + self.transform_operation + .negate(&mut selected, self.increments, self.local, self.layer_bounding_box, document_to_viewport, pivot, self.initial_transform); + } + self.transform_operation.grs_typed( + self.typing.type_negate(), + &mut selected, + self.increments, + self.local, + self.layer_bounding_box, + document_to_viewport, + pivot, + self.initial_transform, + ) + } + } + } + + fn actions(&self) -> ActionList { + let mut common = actions!(TransformLayerMessageDiscriminant; + BeginGrab, + BeginRotate, + BeginScale, + ); + + if self.transform_operation != TransformOperation::None { + let active = actions!(TransformLayerMessageDiscriminant; + PointerMove, + CancelTransformOperation, + ApplyTransformOperation, + TypeDigit, + TypeBackspace, + TypeDecimalPoint, + TypeNegate, + ConstrainX, + ConstrainY, + ); + common.extend(active); + } + + common + } +} + +#[cfg(test)] +mod test_transform_layer { + use crate::messages::portfolio::document::graph_operation::transform_utils; + use crate::messages::portfolio::document::graph_operation::utility_types::ModifyInputsContext; + use crate::messages::portfolio::document::utility_types::misc::GroupFolderType; + use crate::messages::prelude::Message; + use crate::messages::tool::transform_layer::transform_layer_message_handler::VectorModificationType; + use crate::test_utils::test_prelude::*; + use glam::DAffine2; + use graphene_std::vector::PointId; + use std::collections::VecDeque; + + async fn get_layer_transform(editor: &mut EditorTestUtils, layer: LayerNodeIdentifier) -> Option { + let document = editor.active_document(); + let network_interface = &document.network_interface; + let _responses: VecDeque = VecDeque::new(); + let transform_node_id = ModifyInputsContext::locate_node_in_layer_chain("Transform", layer, network_interface)?; + let document_node = network_interface.document_network().nodes.get(&transform_node_id)?; + Some(transform_utils::get_current_transform(&document_node.inputs)) + } + + #[tokio::test] + async fn test_grab_apply() { + let mut editor = EditorTestUtils::create(); + editor.new_document().await; + + editor.drag_tool(ToolType::Rectangle, 0., 0., 100., 100., ModifierKeys::empty()).await; + + let document = editor.active_document(); + let layer = document.metadata().all_layers().next().unwrap(); + + let original_transform = get_layer_transform(&mut editor, layer).await.unwrap(); + + editor.handle_message(TransformLayerMessage::BeginGrab).await; + + let translation = DVec2::new(50., 50.); + editor.move_mouse(translation.x, translation.y, ModifierKeys::empty(), MouseKeys::NONE).await; + + editor + .handle_message(TransformLayerMessage::PointerMove { + slow_key: Key::Shift, + increments_key: Key::Control, + }) + .await; + + editor.handle_message(TransformLayerMessage::ApplyTransformOperation { final_transform: true }).await; + + let final_transform = get_layer_transform(&mut editor, layer).await.unwrap(); + + let translation_diff = (final_transform.translation - original_transform.translation).length(); + assert!(translation_diff > 10., "Transform should have changed after applying transformation. Diff: {}", translation_diff); + } + + #[tokio::test] + async fn test_grab_cancel() { + let mut editor = EditorTestUtils::create(); + editor.new_document().await; + editor.drag_tool(ToolType::Rectangle, 0., 0., 100., 100., ModifierKeys::empty()).await; + + let document = editor.active_document(); + let layer = document.metadata().all_layers().next().unwrap(); + let original_transform = get_layer_transform(&mut editor, layer).await.expect("Should be able to get the layer transform"); + + editor.handle_message(TransformLayerMessage::BeginGrab).await; + editor.move_mouse(50., 50., ModifierKeys::empty(), MouseKeys::NONE).await; + editor + .handle_message(TransformLayerMessage::PointerMove { + slow_key: Key::Shift, + increments_key: Key::Control, + }) + .await; + + let during_transform = get_layer_transform(&mut editor, layer).await.expect("Should be able to get the layer transform during operation"); + + assert!(original_transform != during_transform, "Transform should change during operation"); + + editor.handle_message(TransformLayerMessage::CancelTransformOperation).await; + + let final_transform = get_layer_transform(&mut editor, layer).await.expect("Should be able to get the final transform"); + let final_translation = final_transform.translation; + let original_translation = original_transform.translation; + + // Verify transform is either restored to original OR reset to identity + assert!( + (final_translation - original_translation).length() < 5. || final_translation.length() < 0.001, + "Transform neither restored to original nor reset to identity. Original: {:?}, Final: {:?}", + original_translation, + final_translation + ); + } + + #[tokio::test] + async fn test_rotate_apply() { + let mut editor = EditorTestUtils::create(); + editor.new_document().await; + editor.drag_tool(ToolType::Rectangle, 0., 0., 100., 100., ModifierKeys::empty()).await; + + let document = editor.active_document(); + let layer = document.metadata().all_layers().next().unwrap(); + + let original_transform = get_layer_transform(&mut editor, layer).await.unwrap(); + + editor.handle_message(TransformLayerMessage::BeginRotate).await; + + editor.move_mouse(150., 50., ModifierKeys::empty(), MouseKeys::NONE).await; + + editor + .handle_message(TransformLayerMessage::PointerMove { + slow_key: Key::Shift, + increments_key: Key::Control, + }) + .await; + + editor.handle_message(TransformLayerMessage::ApplyTransformOperation { final_transform: true }).await; + + let final_transform = get_layer_transform(&mut editor, layer).await.unwrap(); + println!("Final transform: {:?}", final_transform); + + // Check matrix components have changed (rotation affects matrix2) + let matrix_diff = (final_transform.matrix2.x_axis - original_transform.matrix2.x_axis).length(); + assert!(matrix_diff > 0.1, "Rotation should have changed the transform matrix. Diff: {}", matrix_diff); + } + + #[tokio::test] + async fn test_rotate_cancel() { + let mut editor = EditorTestUtils::create(); + editor.new_document().await; + editor.drag_tool(ToolType::Rectangle, 0., 0., 100., 100., ModifierKeys::empty()).await; + + let document = editor.active_document(); + let layer = document.metadata().all_layers().next().unwrap(); + let original_transform = get_layer_transform(&mut editor, layer).await.unwrap(); + + editor.handle_message(TransformLayerMessage::BeginRotate).await; + editor.handle_message(TransformLayerMessage::CancelTransformOperation).await; + + let after_cancel = get_layer_transform(&mut editor, layer).await.unwrap(); + + assert!(!after_cancel.translation.x.is_nan(), "Transform is NaN after cancel"); + assert!(!after_cancel.translation.y.is_nan(), "Transform is NaN after cancel"); + + let translation_diff = (after_cancel.translation - original_transform.translation).length(); + assert!(translation_diff < 1., "Translation component changed too much: {}", translation_diff); + } + + #[tokio::test] + async fn test_scale_apply() { + let mut editor = EditorTestUtils::create(); + editor.new_document().await; + editor.drag_tool(ToolType::Rectangle, 0., 0., 100., 100., ModifierKeys::empty()).await; + + let document = editor.active_document(); + let layer = document.metadata().all_layers().next().unwrap(); + + let original_transform = get_layer_transform(&mut editor, layer).await.unwrap(); + + editor.handle_message(TransformLayerMessage::BeginScale).await; + + editor.move_mouse(150., 150., ModifierKeys::empty(), MouseKeys::NONE).await; + + editor + .handle_message(TransformLayerMessage::PointerMove { + slow_key: Key::Shift, + increments_key: Key::Control, + }) + .await; + + editor.handle_message(TransformLayerMessage::ApplyTransformOperation { final_transform: true }).await; + + let final_transform = get_layer_transform(&mut editor, layer).await.unwrap(); + + // Check scaling components have changed + let scale_diff_x = (final_transform.matrix2.x_axis.x - original_transform.matrix2.x_axis.x).abs(); + let scale_diff_y = (final_transform.matrix2.y_axis.y - original_transform.matrix2.y_axis.y).abs(); + + assert!( + scale_diff_x > 0.1 || scale_diff_y > 0.1, + "Scaling should have changed the transform matrix. Diffs: x={}, y={}", + scale_diff_x, + scale_diff_y + ); + } + + #[tokio::test] + async fn test_scale_cancel() { + let mut editor = EditorTestUtils::create(); + editor.new_document().await; + editor.drag_tool(ToolType::Rectangle, 0., 0., 100., 100., ModifierKeys::empty()).await; + + let document = editor.active_document(); + let layer = document.metadata().all_layers().next().unwrap(); + let original_transform = get_layer_transform(&mut editor, layer).await.unwrap(); + + editor.handle_message(TransformLayerMessage::BeginScale).await; + + // Cancel immediately without moving to ensure proper reset + editor.handle_message(TransformLayerMessage::CancelTransformOperation).await; + + let after_cancel = get_layer_transform(&mut editor, layer).await.unwrap(); + + // The scale factor is represented in the matrix2 part, so check those components + assert!( + (after_cancel.matrix2.x_axis.x - original_transform.matrix2.x_axis.x).abs() < 0.1 && (after_cancel.matrix2.y_axis.y - original_transform.matrix2.y_axis.y).abs() < 0.1, + "Matrix scale components should be restored after cancellation" + ); + + // Also check translation component is similar + let translation_diff = (after_cancel.translation - original_transform.translation).length(); + assert!(translation_diff < 1., "Translation component changed too much: {}", translation_diff); + } + + #[tokio::test] + async fn test_grab_rotate_scale_chained() { + let mut editor = EditorTestUtils::create(); + editor.new_document().await; + editor.drag_tool(ToolType::Rectangle, 0., 0., 100., 100., ModifierKeys::empty()).await; + let document = editor.active_document(); + let layer = document.metadata().all_layers().next().unwrap(); + editor.handle_message(NodeGraphMessage::SelectedNodesSet { nodes: vec![layer.to_node()] }).await; + let original_transform = get_layer_transform(&mut editor, layer).await.unwrap(); + + editor.handle_message(TransformLayerMessage::BeginGrab).await; + editor.move_mouse(150., 130., ModifierKeys::empty(), MouseKeys::NONE).await; + editor + .handle_message(TransformLayerMessage::PointerMove { + slow_key: Key::Shift, + increments_key: Key::Control, + }) + .await; + + let after_grab_transform = get_layer_transform(&mut editor, layer).await.unwrap(); + let expected_translation = DVec2::new(50., 30.); + let actual_translation = after_grab_transform.translation - original_transform.translation; + assert!( + (actual_translation - expected_translation).length() < 1e-5, + "Expected translation of {:?}, got {:?}", + expected_translation, + actual_translation + ); + + // 2. Chain to rotation - from current position to create ~45 degree rotation + editor.handle_message(TransformLayerMessage::BeginRotate).await; + editor.move_mouse(190., 90., ModifierKeys::empty(), MouseKeys::NONE).await; + editor + .handle_message(TransformLayerMessage::PointerMove { + slow_key: Key::Shift, + increments_key: Key::Control, + }) + .await; + let after_rotate_transform = get_layer_transform(&mut editor, layer).await.unwrap(); + // Checking for off-diagonal elements close to 0.707, which corresponds to cos(45°) and sin(45°) + assert!( + !after_rotate_transform.matrix2.abs_diff_eq(after_grab_transform.matrix2, 1e-5) && + (after_rotate_transform.matrix2.x_axis.y.abs() - 0.707).abs() < 0.1 && // Check for off-diagonal elements close to 0.707 + (after_rotate_transform.matrix2.y_axis.x.abs() - 0.707).abs() < 0.1, // that would indicate ~45° rotation + "Rotation should change matrix components with approximately 45° rotation" + ); + + // 3. Chain to scaling - scale(area) up by 2x + editor.handle_message(TransformLayerMessage::BeginScale).await; + editor.move_mouse(250., 200., ModifierKeys::empty(), MouseKeys::NONE).await; + editor + .handle_message(TransformLayerMessage::PointerMove { + slow_key: Key::Shift, + increments_key: Key::Control, + }) + .await; + + let after_scale_transform = get_layer_transform(&mut editor, layer).await.unwrap(); + let before_scale_det = after_rotate_transform.matrix2.determinant(); + let after_scale_det = after_scale_transform.matrix2.determinant(); + assert!( + after_scale_det >= 2. * before_scale_det, + "Scale should increase the determinant of the matrix (before: {}, after: {})", + before_scale_det, + after_scale_det + ); + + editor.handle_message(TransformLayerMessage::ApplyTransformOperation { final_transform: true }).await; + let final_transform = get_layer_transform(&mut editor, layer).await.unwrap(); + + assert!(final_transform.abs_diff_eq(after_scale_transform, 1e-5), "Final transform should match the transform before committing"); + assert!(!final_transform.abs_diff_eq(original_transform, 1e-5), "Final transform should be different from original transform"); + } + + #[tokio::test] + async fn test_scale_with_panned_view() { + let mut editor = EditorTestUtils::create(); + editor.new_document().await; + editor.drag_tool(ToolType::Rectangle, 0., 0., 100., 100., ModifierKeys::empty()).await; + let document = editor.active_document(); + let layer = document.metadata().all_layers().next().unwrap(); + + let original_transform = get_layer_transform(&mut editor, layer).await.unwrap(); + + let pan_amount = DVec2::new(200., 150.); + editor.handle_message(NavigationMessage::CanvasPan { delta: pan_amount }).await; + + editor.handle_message(TransformLayerMessage::BeginScale).await; + editor.handle_message(TransformLayerMessage::TypeDigit { digit: 2 }).await; + editor.handle_message(TransformLayerMessage::ApplyTransformOperation { final_transform: true }).await; + + let final_transform = get_layer_transform(&mut editor, layer).await.unwrap(); + + let scale_x = final_transform.matrix2.x_axis.length() / original_transform.matrix2.x_axis.length(); + let scale_y = final_transform.matrix2.y_axis.length() / original_transform.matrix2.y_axis.length(); + + assert!((scale_x - 2.).abs() < 0.1, "Expected scale factor X of 2, got: {}", scale_x); + assert!((scale_y - 2.).abs() < 0.1, "Expected scale factor Y of 2, got: {}", scale_y); + } + + #[tokio::test] + async fn test_scale_with_zoomed_view() { + let mut editor = EditorTestUtils::create(); + editor.new_document().await; + editor.drag_tool(ToolType::Rectangle, 0., 0., 100., 100., ModifierKeys::empty()).await; + let document = editor.active_document(); + let layer = document.metadata().all_layers().next().unwrap(); + + let original_transform = get_layer_transform(&mut editor, layer).await.unwrap(); + + editor.handle_message(NavigationMessage::CanvasZoomIncrease { center_on_mouse: false }).await; + editor.handle_message(NavigationMessage::CanvasZoomIncrease { center_on_mouse: false }).await; + + editor.handle_message(TransformLayerMessage::BeginScale).await; + editor.handle_message(TransformLayerMessage::TypeDigit { digit: 2 }).await; + editor.handle_message(TransformLayerMessage::ApplyTransformOperation { final_transform: true }).await; + + let final_transform = get_layer_transform(&mut editor, layer).await.unwrap(); + + let scale_x = final_transform.matrix2.x_axis.length() / original_transform.matrix2.x_axis.length(); + let scale_y = final_transform.matrix2.y_axis.length() / original_transform.matrix2.y_axis.length(); + + assert!((scale_x - 2.).abs() < 0.1, "Expected scale factor X of 2, got: {}", scale_x); + assert!((scale_y - 2.).abs() < 0.1, "Expected scale factor Y of 2, got: {}", scale_y); + } + + #[tokio::test] + async fn test_rotate_with_rotated_view() { + let mut editor = EditorTestUtils::create(); + editor.new_document().await; + editor.drag_tool(ToolType::Rectangle, 0., 0., 100., 100., ModifierKeys::empty()).await; + let document = editor.active_document(); + let layer = document.metadata().all_layers().next().unwrap(); + + let original_transform = get_layer_transform(&mut editor, layer).await.unwrap(); + + // Rotate the document view (45 degrees) + editor.handle_message(NavigationMessage::BeginCanvasTilt { was_dispatched_from_menu: false }).await; + editor + .handle_message(NavigationMessage::CanvasTiltSet { + angle_radians: (45. as f64).to_radians(), + }) + .await; + editor.handle_message(TransformLayerMessage::BeginRotate).await; + + editor.handle_message(TransformLayerMessage::TypeDigit { digit: 9 }).await; + editor.handle_message(TransformLayerMessage::TypeDigit { digit: 0 }).await; + editor.handle_message(TransformLayerMessage::ApplyTransformOperation { final_transform: true }).await; + + let final_transform = get_layer_transform(&mut editor, layer).await.unwrap(); + + let original_angle = original_transform.to_scale_angle_translation().1; + let final_angle = final_transform.to_scale_angle_translation().1; + let angle_change = (final_angle - original_angle).to_degrees(); + + // Normalize angle between 0 and 360 + let angle_change = ((angle_change % 360.) + 360.) % 360.; + assert!((angle_change - 90.).abs() < 0.1, "Expected rotation of 90 degrees, got: {}", angle_change); + } + + #[tokio::test] + async fn test_grs_single_anchor() { + let mut editor = EditorTestUtils::create(); + editor.new_document().await; + editor.handle_message(DocumentMessage::CreateEmptyFolder).await; + let document = editor.active_document(); + let layer = document.metadata().all_layers().next().unwrap(); + + let point_id = PointId::generate(); + let modification_type = VectorModificationType::InsertPoint { + id: point_id, + position: DVec2::new(100., 100.), + }; + editor.handle_message(GraphOperationMessage::Vector { layer, modification_type }).await; + editor.handle_message(ToolMessage::ActivateTool { tool_type: ToolType::Select }).await; + + // Testing grab operation - just checking that it doesn't crash. + editor.handle_message(TransformLayerMessage::BeginGrab).await; + editor.move_mouse(150., 150., ModifierKeys::empty(), MouseKeys::NONE).await; + editor + .handle_message(TransformLayerMessage::PointerMove { + slow_key: Key::Shift, + increments_key: Key::Control, + }) + .await; + editor.handle_message(TransformLayerMessage::ApplyTransformOperation { final_transform: true }).await; + + let final_transform = get_layer_transform(&mut editor, layer).await; + assert!(final_transform.is_some(), "Transform node should exist after grab operation"); + } + #[tokio::test] + async fn test_scale_to_zero_then_rescale() { + let mut editor = EditorTestUtils::create(); + editor.new_document().await; + editor.drag_tool(ToolType::Rectangle, 0., 0., 100., 100., ModifierKeys::empty()).await; + let document = editor.active_document(); + let layer = document.metadata().all_layers().next().unwrap(); + + // First scale to near-zero + editor.handle_message(TransformLayerMessage::BeginScale).await; + editor.handle_message(TransformLayerMessage::TypeDigit { digit: 0 }).await; + editor.handle_message(TransformLayerMessage::TypeDecimalPoint).await; + editor.handle_message(TransformLayerMessage::TypeDigit { digit: 0 }).await; + editor.handle_message(TransformLayerMessage::TypeDigit { digit: 0 }).await; + editor.handle_message(TransformLayerMessage::TypeDigit { digit: 0 }).await; + editor.handle_message(TransformLayerMessage::TypeDigit { digit: 1 }).await; + editor.handle_message(TransformLayerMessage::ApplyTransformOperation { final_transform: true }).await; + + let near_zero_transform = get_layer_transform(&mut editor, layer).await.unwrap(); + // Verify scale is near zero. + let scale_x = near_zero_transform.matrix2.x_axis.length(); + let scale_y = near_zero_transform.matrix2.y_axis.length(); + assert!(scale_x < 0.001, "Scale factor X should be near zero, got: {}", scale_x); + assert!(scale_y < 0.001, "Scale factor Y should be near zero, got: {}", scale_y); + assert!(scale_x > 0., "Scale factor X should not be exactly zero"); + assert!(scale_y > 0., "Scale factor Y should not be exactly zero"); + + editor.handle_message(TransformLayerMessage::BeginScale).await; + editor.handle_message(TransformLayerMessage::TypeDigit { digit: 2 }).await; + editor.handle_message(TransformLayerMessage::ApplyTransformOperation { final_transform: true }).await; + + let final_transform = get_layer_transform(&mut editor, layer).await.unwrap(); + assert!(final_transform.is_finite(), "Transform should be finite after rescaling"); + + let new_scale_x = final_transform.matrix2.x_axis.length(); + let new_scale_y = final_transform.matrix2.y_axis.length(); + assert!(new_scale_x > 0., "After rescaling, scale factor X should be non-zero"); + assert!(new_scale_y > 0., "After rescaling, scale factor Y should be non-zero"); + } + + #[tokio::test] + async fn test_transform_with_different_selections() { + let mut editor = EditorTestUtils::create(); + editor.new_document().await; + editor.draw_rect(0., 0., 100., 100.).await; + editor.draw_rect(150., 0., 250., 100.).await; + editor.draw_rect(0., 150., 100., 250.).await; + editor.draw_rect(150., 150., 250., 250.).await; + let document = editor.active_document(); + let layers: Vec = document.metadata().all_layers().collect(); + + assert!(layers.len() == 4); + + // Creating a group with two rectangles + editor + .handle_message(NodeGraphMessage::SelectedNodesSet { + nodes: vec![layers[2].to_node(), layers[3].to_node()], + }) + .await; + editor + .handle_message(DocumentMessage::GroupSelectedLayers { + group_folder_type: GroupFolderType::Layer, + }) + .await; + + // Get the group layer (should be the newest layer) + let document = editor.active_document(); + let group_layer = document.metadata().all_layers().next().unwrap(); + + // Test 1: Transform single layer + editor.handle_message(NodeGraphMessage::SelectedNodesSet { nodes: vec![layers[0].to_node()] }).await; + let original_transform = get_layer_transform(&mut editor, layers[0]).await.unwrap(); + editor.handle_message(TransformLayerMessage::BeginGrab).await; + editor.move_mouse(50., 50., ModifierKeys::empty(), MouseKeys::NONE).await; + editor + .handle_message(TransformLayerMessage::PointerMove { + slow_key: Key::Shift, + increments_key: Key::Control, + }) + .await; + editor.handle_message(TransformLayerMessage::ApplyTransformOperation { final_transform: true }).await; + let final_transform = get_layer_transform(&mut editor, layers[0]).await.unwrap(); + assert!(!final_transform.abs_diff_eq(original_transform, 1e-5), "Transform should change for single layer"); + + // Test 2: Transform multiple layers + editor + .handle_message(NodeGraphMessage::SelectedNodesSet { + nodes: vec![layers[0].to_node(), layers[1].to_node()], + }) + .await; + let original_transform_1 = get_layer_transform(&mut editor, layers[0]).await.unwrap(); + let original_transform_2 = get_layer_transform(&mut editor, layers[1]).await.unwrap(); + editor.handle_message(TransformLayerMessage::BeginRotate).await; + editor.move_mouse(200., 50., ModifierKeys::empty(), MouseKeys::NONE).await; + editor + .handle_message(TransformLayerMessage::PointerMove { + slow_key: Key::Shift, + increments_key: Key::Control, + }) + .await; + editor.handle_message(TransformLayerMessage::ApplyTransformOperation { final_transform: true }).await; + let final_transform_1 = get_layer_transform(&mut editor, layers[0]).await.unwrap(); + let final_transform_2 = get_layer_transform(&mut editor, layers[1]).await.unwrap(); + assert!(!final_transform_1.abs_diff_eq(original_transform_1, 1e-5), "Transform should change for first layer in multi-selection"); + assert!( + !final_transform_2.abs_diff_eq(original_transform_2, 1e-5), + "Transform should change for second layer in multi-selection" + ); + + // Test 3: Transform group + editor.handle_message(NodeGraphMessage::SelectedNodesSet { nodes: vec![group_layer.to_node()] }).await; + let original_group_transform = get_layer_transform(&mut editor, group_layer).await.unwrap(); + editor.handle_message(TransformLayerMessage::BeginScale).await; + editor.handle_message(TransformLayerMessage::TypeDigit { digit: 2 }).await; + editor.handle_message(TransformLayerMessage::ApplyTransformOperation { final_transform: true }).await; + let final_group_transform = get_layer_transform(&mut editor, group_layer).await.unwrap(); + assert!(!final_group_transform.abs_diff_eq(original_group_transform, 1e-5), "Transform should change for group"); + + // Test 4: Transform layers inside transformed group + let child_layer_id = { + let document = editor.active_document_mut(); + let group_children = document.network_interface.downstream_layers(&group_layer.to_node(), &[]); + if !group_children.is_empty() { + Some(LayerNodeIdentifier::new(group_children[0], &document.network_interface, &[])) + } else { + None + } + }; + assert!(child_layer_id.is_some(), "Group should have child layers"); + let child_layer_id = child_layer_id.unwrap(); + editor + .handle_message(NodeGraphMessage::SelectedNodesSet { + nodes: vec![child_layer_id.to_node()], + }) + .await; + let original_child_transform = get_layer_transform(&mut editor, child_layer_id).await.unwrap(); + editor.handle_message(TransformLayerMessage::BeginGrab).await; + editor.move_mouse(30., 30., ModifierKeys::empty(), MouseKeys::NONE).await; + editor + .handle_message(TransformLayerMessage::PointerMove { + slow_key: Key::Shift, + increments_key: Key::Control, + }) + .await; + editor.handle_message(TransformLayerMessage::ApplyTransformOperation { final_transform: true }).await; + let final_child_transform = get_layer_transform(&mut editor, child_layer_id).await.unwrap(); + assert!(!final_child_transform.abs_diff_eq(original_child_transform, 1e-5), "Child layer inside transformed group should change"); + } +} diff --git a/editor/src/messages/tool/utility_types.rs b/editor/src/messages/tool/utility_types.rs new file mode 100644 index 0000000000000000000000000000000000000000..fbbec768e4a986704c34013387146c03466f07aa --- /dev/null +++ b/editor/src/messages/tool/utility_types.rs @@ -0,0 +1,610 @@ +#![allow(clippy::too_many_arguments)] + +use super::common_functionality::shape_editor::ShapeState; +use super::tool_messages::*; +use crate::messages::broadcast::BroadcastMessage; +use crate::messages::broadcast::broadcast_event::BroadcastEvent; +use crate::messages::input_mapper::utility_types::input_keyboard::{Key, KeysGroup, LayoutKeysGroup, MouseMotion}; +use crate::messages::input_mapper::utility_types::macros::action_keys; +use crate::messages::input_mapper::utility_types::misc::ActionKeys; +use crate::messages::layout::utility_types::widget_prelude::*; +use crate::messages::portfolio::document::overlays::utility_types::OverlayProvider; +use crate::messages::preferences::PreferencesMessageHandler; +use crate::messages::prelude::*; +use crate::messages::tool::common_functionality::shapes::shape_utility::ShapeType; +use crate::node_graph_executor::NodeGraphExecutor; +use graphene_std::raster::color::Color; +use graphene_std::text::FontCache; +use std::borrow::Cow; +use std::fmt::{self, Debug}; + +pub struct ToolActionHandlerData<'a> { + pub document: &'a mut DocumentMessageHandler, + pub document_id: DocumentId, + pub global_tool_data: &'a DocumentToolData, + pub input: &'a InputPreprocessorMessageHandler, + pub font_cache: &'a FontCache, + pub shape_editor: &'a mut ShapeState, + pub node_graph: &'a NodeGraphExecutor, + pub preferences: &'a PreferencesMessageHandler, +} + +pub trait ToolCommon: for<'a, 'b> MessageHandler> + LayoutHolder + ToolTransition + ToolMetadata {} +impl ToolCommon for T where T: for<'a, 'b> MessageHandler> + LayoutHolder + ToolTransition + ToolMetadata {} + +type Tool = dyn ToolCommon + Send + Sync; + +/// The FSM (finite state machine) is a flowchart between different operating states that a specific tool might be in. +/// It is the central "core" logic area of each tool which is in charge of maintaining the state of the tool and responding to events coming from outside (like user input). +/// For example, a tool might be `Ready` or `Drawing` depending on if the user is idle or actively drawing with the mouse held down. +/// The FSM keeps track of what the tool is doing and allows the tool to take action when events are directed at the FSM. +/// Every tool, which implements this trait, must implement the `transition()` function. +/// That is where new events are sent, and where the flowchart transition logic occurs to respond to events and end in a new state. +pub trait Fsm { + /// The implementing tool must set this to a struct designed to store the internal values stored in the tool. + /// For example, it might be used to store the starting location of a point when a drag began so the displacement distance can be calculated. + type ToolData; + /// The implementing tool must set this to a struct (or `()` if none) designed to store the values of the tool options set by the user in the tool controls portion on the left of the control bar. + type ToolOptions; + + /// Implementing this mandatory trait function lets a specific tool react accordingly (and potentially change its state or internal variables) upon receiving an event to do something. + /// Based on its current state, and what the event is, the FSM (finite state machine) should direct the tool to an appropriate outcome. + /// For example, if the tool's FSM is in a `Ready` state and receives a `DragStart` message as its event, it may decide to send some messages, + /// update some internal tool variables, and end by transitioning to a `Drawing` state. + #[must_use] + fn transition(self, message: ToolMessage, tool_data: &mut Self::ToolData, transition_data: &mut ToolActionHandlerData, options: &Self::ToolOptions, responses: &mut VecDeque) -> Self; + + /// Implementing this trait function lets a specific tool provide a list of hints (user input actions presently available) to draw in the footer bar. + fn update_hints(&self, responses: &mut VecDeque); + /// Implementing this trait function lets a specific tool set the current mouse cursor icon. + fn update_cursor(&self, responses: &mut VecDeque); + + /// If this message is a standard tool message, process it and return true. Standard tool messages are those which are common across every tool. + fn standard_tool_messages(&self, message: &ToolMessage, responses: &mut VecDeque) -> bool { + // Check for standard hits or cursor events + match message { + ToolMessage::UpdateHints => { + self.update_hints(responses); + true + } + ToolMessage::UpdateCursor => { + self.update_cursor(responses); + true + } + _ => false, + } + } + + /// When an event makes the tool change or do something, it is processed here to perform a step (transition) on the tool's finite state machine (FSM). + /// This function is called by the specific tool's message handler when the dispatcher routes a message to the active tool. + fn process_event( + &mut self, + message: ToolMessage, + tool_data: &mut Self::ToolData, + transition_data: &mut ToolActionHandlerData, + options: &Self::ToolOptions, + responses: &mut VecDeque, + update_cursor_on_transition: bool, + ) where + Self: PartialEq + Sized + Copy, + { + // If this message is one of the standard tool messages, process it and exit early + if self.standard_tool_messages(&message, responses) { + return; + } + + // Transition the tool + let new_state = self.transition(message, tool_data, transition_data, options, responses); + + // Update state + if *self != new_state { + *self = new_state; + self.update_hints(responses); + if update_cursor_on_transition { + self.update_cursor(responses); + } + } + } +} + +#[derive(Debug, Clone)] +pub struct DocumentToolData { + pub primary_color: Color, + pub secondary_color: Color, +} + +impl DocumentToolData { + pub fn update_working_colors(&self, responses: &mut VecDeque) { + let layout = WidgetLayout::new(vec![ + LayoutGroup::Row { + widgets: vec![WorkingColorsInput::new(self.primary_color.to_gamma_srgb(), self.secondary_color.to_gamma_srgb()).widget_holder()], + }, + LayoutGroup::Row { + widgets: vec![ + IconButton::new("SwapVertical", 16) + .tooltip("Swap") + .tooltip_shortcut(action_keys!(ToolMessageDiscriminant::SwapColors)) + .on_update(|_| ToolMessage::SwapColors.into()) + .widget_holder(), + IconButton::new("WorkingColors", 16) + .tooltip("Reset") + .tooltip_shortcut(action_keys!(ToolMessageDiscriminant::ResetColors)) + .on_update(|_| ToolMessage::ResetColors.into()) + .widget_holder(), + ], + }, + ]); + + responses.add(LayoutMessage::SendLayout { + layout: Layout::WidgetLayout(layout), + layout_target: LayoutTarget::WorkingColors, + }); + + responses.add(BroadcastMessage::TriggerEvent(BroadcastEvent::WorkingColorChanged)); + } +} + +#[derive(Clone, Debug, Default)] +pub struct EventToMessageMap { + pub canvas_transformed: Option, + pub selection_changed: Option, + pub tool_abort: Option, + pub working_color_changed: Option, + pub overlay_provider: Option, +} + +pub trait ToolTransition { + fn event_to_message_map(&self) -> EventToMessageMap; + + fn activate(&self, responses: &mut VecDeque) { + let mut subscribe_message = |broadcast_to_tool_mapping: Option, event: BroadcastEvent| { + if let Some(mapping) = broadcast_to_tool_mapping { + responses.add(BroadcastMessage::SubscribeEvent { + on: event, + send: Box::new(mapping.into()), + }); + } + }; + + let event_to_tool_map = self.event_to_message_map(); + subscribe_message(event_to_tool_map.canvas_transformed, BroadcastEvent::CanvasTransformed); + subscribe_message(event_to_tool_map.tool_abort, BroadcastEvent::ToolAbort); + subscribe_message(event_to_tool_map.selection_changed, BroadcastEvent::SelectionChanged); + subscribe_message(event_to_tool_map.working_color_changed, BroadcastEvent::WorkingColorChanged); + if let Some(overlay_provider) = event_to_tool_map.overlay_provider { + responses.add(OverlaysMessage::AddProvider(overlay_provider)); + } + } + + fn deactivate(&self, responses: &mut VecDeque) { + let mut unsubscribe_message = |broadcast_to_tool_mapping: Option, event: BroadcastEvent| { + if let Some(mapping) = broadcast_to_tool_mapping { + responses.add(BroadcastMessage::UnsubscribeEvent { + on: event, + message: Box::new(mapping.into()), + }); + } + }; + + let event_to_tool_map = self.event_to_message_map(); + unsubscribe_message(event_to_tool_map.canvas_transformed, BroadcastEvent::CanvasTransformed); + unsubscribe_message(event_to_tool_map.tool_abort, BroadcastEvent::ToolAbort); + unsubscribe_message(event_to_tool_map.selection_changed, BroadcastEvent::SelectionChanged); + unsubscribe_message(event_to_tool_map.working_color_changed, BroadcastEvent::WorkingColorChanged); + if let Some(overlay_provider) = event_to_tool_map.overlay_provider { + responses.add(OverlaysMessage::RemoveProvider(overlay_provider)); + } + } +} + +pub trait ToolMetadata { + fn icon_name(&self) -> String; + fn tooltip(&self) -> String; + fn tool_type(&self) -> ToolType; +} + +pub struct ToolData { + pub active_tool_type: ToolType, + pub active_shape_type: Option, + pub tools: HashMap>, +} + +impl fmt::Debug for ToolData { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("ToolData").field("active_tool_type", &self.active_tool_type).field("tool_options", &"[…]").finish() + } +} + +impl ToolData { + pub fn active_tool_mut(&mut self) -> &mut Box { + self.tools.get_mut(&self.active_tool_type).expect("The active tool is not initialized") + } + + pub fn active_tool(&self) -> &Tool { + self.tools.get(&self.active_tool_type).map(|x| x.as_ref()).expect("The active tool is not initialized") + } +} + +impl LayoutHolder for ToolData { + fn layout(&self) -> Layout { + let active_tool = self.active_shape_type.unwrap_or(self.active_tool_type); + + let tool_groups_layout = list_tools_in_groups() + .iter() + .map(|tool_group| + tool_group + .iter() + .map(|tool_availability| { + match tool_availability { + ToolAvailability::Available(tool) => + ToolEntry::new(tool.tool_type(), tool.icon_name()) + .tooltip(tool.tooltip()) + .tooltip_shortcut(action_keys!(tool_type_to_activate_tool_message(tool.tool_type()))), + ToolAvailability::AvailableAsShape(shape) => + ToolEntry::new(shape.tool_type(), shape.icon_name()) + .tooltip(shape.tooltip()) + .tooltip_shortcut(action_keys!(tool_type_to_activate_tool_message(shape.tool_type()))), + ToolAvailability::ComingSoon(tool) => tool.clone(), + } + }) + .collect::>() + ) + .flat_map(|group| { + let separator = std::iter::once(Separator::new(SeparatorType::Section).direction(SeparatorDirection::Vertical).widget_holder()); + let buttons = group.into_iter().map(|ToolEntry { tooltip, tooltip_shortcut, tool_type, icon_name }| { + IconButton::new(icon_name, 32) + .disabled(false) + .active(match tool_type { + ToolType::Line | ToolType::Ellipse | ToolType::Rectangle => { self.active_shape_type.is_some() && active_tool == tool_type } + _ => active_tool == tool_type, + }) + .tooltip(tooltip.clone()) + .tooltip_shortcut(tooltip_shortcut) + .on_update(move |_| { + match tool_type { + ToolType::Line => ToolMessage::ActivateToolShapeLine.into(), + ToolType::Rectangle => ToolMessage::ActivateToolShapeRectangle.into(), + ToolType::Ellipse => ToolMessage::ActivateToolShapeEllipse.into(), + ToolType::Shape => ToolMessage::ActivateToolShape.into(), + _ => { + if !tooltip.contains("Coming Soon") { (ToolMessage::ActivateTool { tool_type }).into() } else { (DialogMessage::RequestComingSoonDialog { issue: None }).into() } + } + } + }) + .widget_holder() + }); + + separator.chain(buttons) + }) + // Skip the initial separator + .skip(1) + .collect(); + + Layout::WidgetLayout(WidgetLayout { + layout: vec![LayoutGroup::Row { widgets: tool_groups_layout }], + }) + } +} + +#[derive(Debug, Clone, Default, WidgetBuilder)] +#[widget_builder(not_widget_holder)] +pub struct ToolEntry { + #[widget_builder(constructor)] + pub tool_type: ToolType, + #[widget_builder(constructor)] + pub icon_name: String, + pub tooltip: String, + pub tooltip_shortcut: Option, +} + +#[derive(Debug)] +pub struct ToolFsmState { + pub document_tool_data: DocumentToolData, + pub tool_data: ToolData, +} + +impl Default for ToolFsmState { + fn default() -> Self { + Self { + tool_data: ToolData { + active_tool_type: ToolType::Select, + active_shape_type: None, + tools: list_tools_in_groups() + .into_iter() + .flatten() + .filter_map(|tool| match tool { + ToolAvailability::Available(tool) => Some((tool.tool_type(), tool)), + ToolAvailability::AvailableAsShape(_) => None, + ToolAvailability::ComingSoon(_) => None, + }) + .collect(), + }, + document_tool_data: DocumentToolData { + primary_color: Color::BLACK, + secondary_color: Color::WHITE, + }, + } + } +} + +impl ToolFsmState { + pub fn new() -> Self { + Self::default() + } +} + +#[repr(usize)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, serde::Serialize, serde::Deserialize, Default, specta::Type)] +pub enum ToolType { + // General tool group + #[default] + Select, + Artboard, + Navigate, + Eyedropper, + Fill, + Gradient, + + // Vector tool group + Path, + Pen, + Freehand, + Spline, + Shape, + Line, // Shape tool alias + Rectangle, // Shape tool alias + Ellipse, // Shape tool alias + Text, + + // Raster tool group + Brush, + Heal, + Clone, + Patch, + Detail, + Relight, + Frame, +} + +impl ToolType { + pub fn get_shape(&self) -> Option { + match self { + Self::Rectangle | Self::Line | Self::Ellipse => Some(*self), + _ => None, + } + } + + pub fn get_tool(self) -> Self { + if self.get_shape().is_some() { ToolType::Shape } else { self } + } +} + +enum ToolAvailability { + Available(Box), + AvailableAsShape(ShapeType), + ComingSoon(ToolEntry), +} + +/// List of all the tools in their conventional ordering and grouping. +fn list_tools_in_groups() -> Vec> { + vec![ + vec![ + // General tool group + ToolAvailability::Available(Box::::default()), + ToolAvailability::Available(Box::::default()), + ToolAvailability::Available(Box::::default()), + ToolAvailability::Available(Box::::default()), + ToolAvailability::Available(Box::::default()), + ToolAvailability::Available(Box::::default()), + ], + vec![ + // Vector tool group + ToolAvailability::Available(Box::::default()), + ToolAvailability::Available(Box::::default()), + ToolAvailability::Available(Box::::default()), + ToolAvailability::Available(Box::::default()), + ToolAvailability::AvailableAsShape(ShapeType::Line), + ToolAvailability::AvailableAsShape(ShapeType::Rectangle), + ToolAvailability::AvailableAsShape(ShapeType::Ellipse), + ToolAvailability::Available(Box::::default()), + ToolAvailability::Available(Box::::default()), + ], + vec![ + // Raster tool group + ToolAvailability::Available(Box::::default()), + ToolAvailability::ComingSoon(ToolEntry::new(ToolType::Heal, "RasterHealTool").tooltip("Coming Soon: Heal Tool (J)")), + ToolAvailability::ComingSoon(ToolEntry::new(ToolType::Clone, "RasterCloneTool").tooltip("Coming Soon: Clone Tool (C)")), + ToolAvailability::ComingSoon(ToolEntry::new(ToolType::Patch, "RasterPatchTool").tooltip("Coming Soon: Patch Tool")), + ToolAvailability::ComingSoon(ToolEntry::new(ToolType::Detail, "RasterDetailTool").tooltip("Coming Soon: Detail Tool (D)")), + ToolAvailability::ComingSoon(ToolEntry::new(ToolType::Relight, "RasterRelightTool").tooltip("Coming Soon: Relight Tool (O)")), + ], + ] +} + +pub fn tool_message_to_tool_type(tool_message: &ToolMessage) -> ToolType { + match tool_message { + // General tool group + ToolMessage::Select(_) => ToolType::Select, + ToolMessage::Artboard(_) => ToolType::Artboard, + ToolMessage::Navigate(_) => ToolType::Navigate, + ToolMessage::Eyedropper(_) => ToolType::Eyedropper, + ToolMessage::Fill(_) => ToolType::Fill, + ToolMessage::Gradient(_) => ToolType::Gradient, + + // Vector tool group + ToolMessage::Path(_) => ToolType::Path, + ToolMessage::Pen(_) => ToolType::Pen, + ToolMessage::Freehand(_) => ToolType::Freehand, + ToolMessage::Spline(_) => ToolType::Spline, + ToolMessage::Shape(_) => ToolType::Shape, // Includes the Line, Rectangle, and Ellipse aliases + ToolMessage::Text(_) => ToolType::Text, + + // Raster tool group + ToolMessage::Brush(_) => ToolType::Brush, + // ToolMessage::Heal(_) => ToolType::Heal, + // ToolMessage::Clone(_) => ToolType::Clone, + // ToolMessage::Patch(_) => ToolType::Patch, + // ToolMessage::Detail(_) => ToolType::Detail, + // ToolMessage::Relight(_) => ToolType::Relight, + _ => panic!("Conversion from ToolMessage to ToolType impossible because the given ToolMessage does not have a matching ToolType. Got: {tool_message:?}"), + } +} + +pub fn tool_type_to_activate_tool_message(tool_type: ToolType) -> ToolMessageDiscriminant { + match tool_type { + // General tool group + ToolType::Select => ToolMessageDiscriminant::ActivateToolSelect, + ToolType::Artboard => ToolMessageDiscriminant::ActivateToolArtboard, + ToolType::Navigate => ToolMessageDiscriminant::ActivateToolNavigate, + ToolType::Eyedropper => ToolMessageDiscriminant::ActivateToolEyedropper, + ToolType::Fill => ToolMessageDiscriminant::ActivateToolFill, + ToolType::Gradient => ToolMessageDiscriminant::ActivateToolGradient, + + // Vector tool group + ToolType::Path => ToolMessageDiscriminant::ActivateToolPath, + ToolType::Pen => ToolMessageDiscriminant::ActivateToolPen, + ToolType::Freehand => ToolMessageDiscriminant::ActivateToolFreehand, + ToolType::Spline => ToolMessageDiscriminant::ActivateToolSpline, + ToolType::Line => ToolMessageDiscriminant::ActivateToolShapeLine, // Shape tool alias + ToolType::Rectangle => ToolMessageDiscriminant::ActivateToolShapeRectangle, // Shape tool alias + ToolType::Ellipse => ToolMessageDiscriminant::ActivateToolShapeEllipse, // Shape tool alias + ToolType::Shape => ToolMessageDiscriminant::ActivateToolShape, + ToolType::Text => ToolMessageDiscriminant::ActivateToolText, + + // Raster tool group + ToolType::Brush => ToolMessageDiscriminant::ActivateToolBrush, + // ToolType::Heal => ToolMessageDiscriminant::ActivateToolHeal, + // ToolType::Clone => ToolMessageDiscriminant::ActivateToolClone, + // ToolType::Patch => ToolMessageDiscriminant::ActivateToolPatch, + // ToolType::Detail => ToolMessageDiscriminant::ActivateToolDetail, + // ToolType::Relight => ToolMessageDiscriminant::ActivateToolRelight, + _ => panic!("Conversion from ToolType to ToolMessage impossible because the given ToolType does not have a matching ToolMessage. Got: {tool_type:?}"), + } +} + +#[derive(Debug, Default, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize, specta::Type)] +pub struct HintData(pub Vec); + +#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize, specta::Type)] +pub struct HintGroup(pub Vec); + +#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize, specta::Type)] +pub struct HintInfo { + /// A `KeysGroup` specifies all the keys pressed simultaneously to perform an action (like "Ctrl C" to copy). + /// Usually at most one is given, but less commonly, multiple can be used to describe additional hotkeys not used simultaneously (like the four different arrow keys to nudge a layer). + #[serde(rename = "keyGroups")] + pub key_groups: Vec, + /// `None` means that the regular `key_groups` should be used for all platforms, `Some` is an override for a Mac-only input hint. + #[serde(rename = "keyGroupsMac")] + pub key_groups_mac: Option>, + /// An optional `MouseMotion` that can indicate the mouse action, like which mouse button is used and whether a drag occurs. + /// No such icon is shown if `None` is given, and it can be combined with `key_groups` if desired. + pub mouse: Option, + /// The text describing what occurs with this input combination. + pub label: Cow<'static, str>, + /// Draws a prepended "+" symbol which indicates that this is a refinement upon a previous hint in the group. + pub plus: bool, + /// Draws a prepended "/" symbol which indicates that this is an alternative to a previous hint in the group. + pub slash: bool, +} + +impl HintInfo { + /// Used for a hint where a single key or key stroke is used to perform one action. + /// Examples: + /// - The Escape key can be used to cancel an action + /// - The Ctrl+C key stroke can be used to copy + pub fn keys(keys: impl IntoIterator, label: impl Into>) -> Self { + let keys = keys.into_iter().collect(); + Self { + key_groups: vec![KeysGroup(keys).into()], + key_groups_mac: None, + mouse: None, + label: label.into(), + plus: false, + slash: false, + } + } + + /// Used for a hint where multiple different individual keys can be used to perform variations of the same action. These keys are represented with a slight separation between them compared to [`Self::keys`]. + /// Examples: + /// - The four arrow keys can be used to nudge a layer in different directions + /// - The G, R, and S keys can be used to enter GRS transformation mode + pub fn multi_keys(multi_keys: impl IntoIterator>, label: impl Into>) -> Self { + let key_groups = multi_keys.into_iter().map(|keys| KeysGroup(keys.into_iter().collect()).into()).collect(); + Self { + key_groups, + key_groups_mac: None, + mouse: None, + label: label.into(), + plus: false, + slash: false, + } + } + + pub fn mouse(mouse_motion: MouseMotion, label: impl Into>) -> Self { + Self { + key_groups: vec![], + key_groups_mac: None, + mouse: Some(mouse_motion), + label: label.into(), + plus: false, + slash: false, + } + } + + pub fn label(label: impl Into>) -> Self { + Self { + key_groups: vec![], + key_groups_mac: None, + mouse: None, + label: label.into(), + plus: false, + slash: false, + } + } + + pub fn keys_and_mouse(keys: impl IntoIterator, mouse_motion: MouseMotion, label: impl Into>) -> Self { + let keys = keys.into_iter().collect(); + Self { + key_groups: vec![KeysGroup(keys).into()], + key_groups_mac: None, + mouse: Some(mouse_motion), + label: label.into(), + plus: false, + slash: false, + } + } + + pub fn multi_keys_and_mouse(multi_keys: impl IntoIterator>, mouse_motion: MouseMotion, label: impl Into>) -> Self { + let key_groups = multi_keys.into_iter().map(|keys| KeysGroup(keys.into_iter().collect()).into()).collect(); + Self { + key_groups, + key_groups_mac: None, + mouse: Some(mouse_motion), + label: label.into(), + plus: false, + slash: false, + } + } + + pub fn arrow_keys(label: impl Into>) -> Self { + let multi_keys = [[Key::ArrowUp], [Key::ArrowRight], [Key::ArrowDown], [Key::ArrowLeft]]; + Self::multi_keys(multi_keys, label) + } + + pub fn prepend_plus(mut self) -> Self { + self.plus = true; + self + } + + pub fn prepend_slash(mut self) -> Self { + self.slash = true; + self + } + + pub fn add_mac_keys(mut self, keys: impl IntoIterator) -> Self { + let mac_keys = keys.into_iter().collect(); + self.key_groups_mac = Some(vec![KeysGroup(mac_keys).into()]); + self + } +} diff --git a/editor/src/messages/workspace/mod.rs b/editor/src/messages/workspace/mod.rs new file mode 100644 index 0000000000000000000000000000000000000000..891ac11f991c898d37ed31b2f613c69cc68cba05 --- /dev/null +++ b/editor/src/messages/workspace/mod.rs @@ -0,0 +1,7 @@ +mod workspace_message; +mod workspace_message_handler; + +#[doc(inline)] +pub use workspace_message::{WorkspaceMessage, WorkspaceMessageDiscriminant}; +#[doc(inline)] +pub use workspace_message_handler::WorkspaceMessageHandler; diff --git a/editor/src/messages/workspace/workspace_message.rs b/editor/src/messages/workspace/workspace_message.rs new file mode 100644 index 0000000000000000000000000000000000000000..66eb0858add26507f9a2b8cf96e191c7a837e57c --- /dev/null +++ b/editor/src/messages/workspace/workspace_message.rs @@ -0,0 +1,8 @@ +use crate::messages::prelude::*; + +#[impl_message(Message, Workspace)] +#[derive(PartialEq, Eq, Clone, Debug, serde::Serialize, serde::Deserialize)] +pub enum WorkspaceMessage { + // Messages + NodeGraphToggleVisibility, +} diff --git a/editor/src/messages/workspace/workspace_message_handler.rs b/editor/src/messages/workspace/workspace_message_handler.rs new file mode 100644 index 0000000000000000000000000000000000000000..397e7cf00b6932bb287702c114151f5e929a5b73 --- /dev/null +++ b/editor/src/messages/workspace/workspace_message_handler.rs @@ -0,0 +1,23 @@ +use crate::messages::prelude::*; + +#[derive(Debug, Clone, Default)] +pub struct WorkspaceMessageHandler { + node_graph_visible: bool, +} + +impl MessageHandler for WorkspaceMessageHandler { + fn process_message(&mut self, message: WorkspaceMessage, _responses: &mut VecDeque, _data: ()) { + match message { + // Messages + WorkspaceMessage::NodeGraphToggleVisibility => { + self.node_graph_visible = !self.node_graph_visible; + } + } + } + + fn actions(&self) -> ActionList { + actions!(WorkspaceMessageDiscriminant; + NodeGraphToggleVisibility, + ) + } +} diff --git a/editor/src/node_graph_executor.rs b/editor/src/node_graph_executor.rs new file mode 100644 index 0000000000000000000000000000000000000000..dbb87c07f08cc2da8794f984007cdca0d8a8d295 --- /dev/null +++ b/editor/src/node_graph_executor.rs @@ -0,0 +1,526 @@ +use crate::consts::FILE_SAVE_SUFFIX; +use crate::messages::frontend::utility_types::{ExportBounds, FileType}; +use crate::messages::prelude::*; +use glam::{DAffine2, DVec2, UVec2}; +use graph_craft::document::value::{RenderOutput, TaggedValue}; +use graph_craft::document::{DocumentNode, DocumentNodeImplementation, NodeId, NodeInput, generate_uuid}; +use graph_craft::proto::GraphErrors; +use graph_craft::wasm_application_io::EditorPreferences; +use graphene_std::application_io::TimingInformation; +use graphene_std::application_io::{NodeGraphUpdateMessage, RenderConfig}; +use graphene_std::renderer::RenderSvgSegmentList; +use graphene_std::renderer::{GraphicElementRendered, RenderParams, SvgRender}; +use graphene_std::renderer::{RenderMetadata, format_transform_matrix}; +use graphene_std::text::FontCache; +use graphene_std::transform::Footprint; +use graphene_std::vector::VectorData; +use graphene_std::vector::style::ViewMode; +use interpreted_executor::dynamic_executor::ResolvedDocumentNodeTypesDelta; + +mod runtime_io; +pub use runtime_io::NodeRuntimeIO; + +mod runtime; +pub use runtime::*; + +#[derive(Debug, serde::Serialize, serde::Deserialize)] +pub struct ExecutionRequest { + execution_id: u64, + render_config: RenderConfig, +} + +#[cfg_attr(feature = "decouple-execution", derive(serde::Serialize, serde::Deserialize))] +pub struct ExecutionResponse { + execution_id: u64, + result: Result, + responses: VecDeque, + transform: DAffine2, + vector_modify: HashMap, + /// The resulting value from the temporary inspected during execution + inspect_result: Option, +} + +#[derive(serde::Serialize, serde::Deserialize)] +pub struct CompilationResponse { + result: Result, + node_graph_errors: GraphErrors, +} + +#[cfg_attr(feature = "decouple-execution", derive(serde::Serialize, serde::Deserialize))] +pub enum NodeGraphUpdate { + ExecutionResponse(ExecutionResponse), + CompilationResponse(CompilationResponse), + NodeGraphUpdateMessage(NodeGraphUpdateMessage), +} + +#[derive(Debug)] +pub struct NodeGraphExecutor { + runtime_io: NodeRuntimeIO, + futures: HashMap, + node_graph_hash: u64, + old_inspect_node: Option, +} + +#[derive(Debug, Clone)] +struct ExecutionContext { + export_config: Option, +} + +impl Default for NodeGraphExecutor { + fn default() -> Self { + Self { + futures: Default::default(), + runtime_io: NodeRuntimeIO::new(), + node_graph_hash: 0, + old_inspect_node: None, + } + } +} + +impl NodeGraphExecutor { + /// A local runtime is useful on threads since having global state causes flakes + #[cfg(test)] + pub(crate) fn new_with_local_runtime() -> (NodeRuntime, Self) { + let (request_sender, request_receiver) = std::sync::mpsc::channel(); + let (response_sender, response_receiver) = std::sync::mpsc::channel(); + let node_runtime = NodeRuntime::new(request_receiver, response_sender); + + let node_executor = Self { + futures: Default::default(), + runtime_io: NodeRuntimeIO::with_channels(request_sender, response_receiver), + node_graph_hash: 0, + old_inspect_node: None, + }; + (node_runtime, node_executor) + } + /// Execute the network by flattening it and creating a borrow stack. + fn queue_execution(&self, render_config: RenderConfig) -> u64 { + let execution_id = generate_uuid(); + let request = ExecutionRequest { execution_id, render_config }; + self.runtime_io.send(GraphRuntimeRequest::ExecutionRequest(request)).expect("Failed to send generation request"); + + execution_id + } + + pub fn update_font_cache(&self, font_cache: FontCache) { + self.runtime_io.send(GraphRuntimeRequest::FontCacheUpdate(font_cache)).expect("Failed to send font cache update"); + } + + pub fn update_editor_preferences(&self, editor_preferences: EditorPreferences) { + self.runtime_io + .send(GraphRuntimeRequest::EditorPreferencesUpdate(editor_preferences)) + .expect("Failed to send editor preferences"); + } + + /// Updates the network to monitor all inputs. Useful for the testing. + #[cfg(test)] + pub(crate) fn update_node_graph_instrumented(&mut self, document: &mut DocumentMessageHandler) -> Result { + // We should always invalidate the cache. + self.node_graph_hash = generate_uuid(); + let mut network = document.network_interface.document_network().clone(); + let instrumented = Instrumented::new(&mut network); + + self.runtime_io + .send(GraphRuntimeRequest::GraphUpdate(GraphUpdate { network, inspect_node: None })) + .map_err(|e| e.to_string())?; + Ok(instrumented) + } + + /// Update the cached network if necessary. + fn update_node_graph(&mut self, document: &mut DocumentMessageHandler, inspect_node: Option, ignore_hash: bool) -> Result<(), String> { + let network_hash = document.network_interface.document_network().current_hash(); + // Refresh the graph when it changes or the inspect node changes + if network_hash != self.node_graph_hash || self.old_inspect_node != inspect_node || ignore_hash { + let network = document.network_interface.document_network().clone(); + self.old_inspect_node = inspect_node; + self.node_graph_hash = network_hash; + + self.runtime_io + .send(GraphRuntimeRequest::GraphUpdate(GraphUpdate { network, inspect_node })) + .map_err(|e| e.to_string())?; + } + Ok(()) + } + + /// Adds an evaluate request for whatever current network is cached. + pub(crate) fn submit_current_node_graph_evaluation(&mut self, document: &mut DocumentMessageHandler, viewport_resolution: UVec2, time: TimingInformation) -> Result<(), String> { + let render_config = RenderConfig { + viewport: Footprint { + transform: document.metadata().document_to_viewport, + resolution: viewport_resolution, + ..Default::default() + }, + time, + #[cfg(any(feature = "resvg", feature = "vello"))] + export_format: graphene_std::application_io::ExportFormat::Canvas, + #[cfg(not(any(feature = "resvg", feature = "vello")))] + export_format: graphene_std::application_io::ExportFormat::Svg, + view_mode: document.view_mode, + hide_artboards: false, + for_export: false, + }; + + // Execute the node graph + let execution_id = self.queue_execution(render_config); + + self.futures.insert(execution_id, ExecutionContext { export_config: None }); + + Ok(()) + } + + /// Evaluates a node graph, computing the entire graph + pub fn submit_node_graph_evaluation( + &mut self, + document: &mut DocumentMessageHandler, + viewport_resolution: UVec2, + time: TimingInformation, + inspect_node: Option, + ignore_hash: bool, + ) -> Result<(), String> { + self.update_node_graph(document, inspect_node, ignore_hash)?; + self.submit_current_node_graph_evaluation(document, viewport_resolution, time)?; + + Ok(()) + } + + /// Evaluates a node graph for export + pub fn submit_document_export(&mut self, document: &mut DocumentMessageHandler, mut export_config: ExportConfig) -> Result<(), String> { + let network = document.network_interface.document_network().clone(); + + // Calculate the bounding box of the region to be exported + let bounds = match export_config.bounds { + ExportBounds::AllArtwork => document.network_interface.document_bounds_document_space(!export_config.transparent_background), + ExportBounds::Selection => document.network_interface.selected_bounds_document_space(!export_config.transparent_background, &[]), + ExportBounds::Artboard(id) => document.metadata().bounding_box_document(id), + } + .ok_or_else(|| "No bounding box".to_string())?; + let size = bounds[1] - bounds[0]; + let transform = DAffine2::from_translation(bounds[0]).inverse(); + + let render_config = RenderConfig { + viewport: Footprint { + transform: DAffine2::from_scale(DVec2::splat(export_config.scale_factor)) * transform, + resolution: (size * export_config.scale_factor).as_uvec2(), + ..Default::default() + }, + time: Default::default(), + export_format: graphene_std::application_io::ExportFormat::Svg, + view_mode: document.view_mode, + hide_artboards: export_config.transparent_background, + for_export: true, + }; + export_config.size = size; + + // Execute the node graph + self.runtime_io + .send(GraphRuntimeRequest::GraphUpdate(GraphUpdate { network, inspect_node: None })) + .map_err(|e| e.to_string())?; + let execution_id = self.queue_execution(render_config); + let execution_context = ExecutionContext { export_config: Some(export_config) }; + self.futures.insert(execution_id, execution_context); + + Ok(()) + } + + fn export(&self, node_graph_output: TaggedValue, export_config: ExportConfig, responses: &mut VecDeque) -> Result<(), String> { + let TaggedValue::RenderOutput(RenderOutput { + data: graphene_std::wasm_application_io::RenderOutputType::Svg(svg), + .. + }) = node_graph_output + else { + return Err("Incorrect render type for exporting (expected RenderOutput::Svg)".to_string()); + }; + + let ExportConfig { + file_type, + file_name, + size, + scale_factor, + .. + } = export_config; + + let file_suffix = &format!(".{file_type:?}").to_lowercase(); + let name = match file_name.ends_with(FILE_SAVE_SUFFIX) { + true => file_name.replace(FILE_SAVE_SUFFIX, file_suffix), + false => file_name + file_suffix, + }; + + if file_type == FileType::Svg { + responses.add(FrontendMessage::TriggerDownloadTextFile { document: svg, name }); + } else { + let mime = file_type.to_mime().to_string(); + let size = (size * scale_factor).into(); + responses.add(FrontendMessage::TriggerDownloadImage { svg, name, mime, size }); + } + Ok(()) + } + + pub fn poll_node_graph_evaluation(&mut self, document: &mut DocumentMessageHandler, responses: &mut VecDeque) -> Result<(), String> { + let results = self.runtime_io.receive().collect::>(); + for response in results { + match response { + NodeGraphUpdate::ExecutionResponse(execution_response) => { + let ExecutionResponse { + execution_id, + result, + responses: existing_responses, + transform, + vector_modify, + inspect_result, + } = execution_response; + + responses.add(OverlaysMessage::Draw); + + let node_graph_output = match result { + Ok(output) => output, + Err(e) => { + // Clear the click targets while the graph is in an un-renderable state + document.network_interface.update_click_targets(HashMap::new()); + document.network_interface.update_vector_modify(HashMap::new()); + return Err(format!("Node graph evaluation failed:\n{e}")); + } + }; + + responses.extend(existing_responses.into_iter().map(Into::into)); + document.network_interface.update_vector_modify(vector_modify); + + let execution_context = self.futures.remove(&execution_id).ok_or_else(|| "Invalid generation ID".to_string())?; + if let Some(export_config) = execution_context.export_config { + // Special handling for exporting the artwork + self.export(node_graph_output, export_config, responses)? + } else { + self.process_node_graph_output(node_graph_output, transform, responses)? + } + + // Update the spreadsheet on the frontend using the value of the inspect result. + if self.old_inspect_node.is_some() { + if let Some(inspect_result) = inspect_result { + responses.add(SpreadsheetMessage::UpdateLayout { inspect_result }); + } + } + } + NodeGraphUpdate::CompilationResponse(execution_response) => { + let CompilationResponse { node_graph_errors, result } = execution_response; + let type_delta = match result { + Err(e) => { + // Clear the click targets while the graph is in an un-renderable state + + document.network_interface.update_click_targets(HashMap::new()); + document.network_interface.update_vector_modify(HashMap::new()); + + log::trace!("{e}"); + + responses.add(NodeGraphMessage::UpdateTypes { + resolved_types: Default::default(), + node_graph_errors, + }); + responses.add(NodeGraphMessage::SendGraph); + + return Err(format!("Node graph evaluation failed:\n{e}")); + } + Ok(result) => result, + }; + + responses.add(NodeGraphMessage::UpdateTypes { + resolved_types: type_delta, + node_graph_errors, + }); + responses.add(NodeGraphMessage::SendGraph); + } + } + } + Ok(()) + } + + fn debug_render(render_object: impl GraphicElementRendered, transform: DAffine2, responses: &mut VecDeque) { + // Setup rendering + let mut render = SvgRender::new(); + let render_params = RenderParams { + view_mode: ViewMode::Normal, + culling_bounds: None, + thumbnail: false, + hide_artboards: false, + for_export: false, + for_mask: false, + alignment_parent_transform: None, + }; + + // Render SVG + render_object.render_svg(&mut render, &render_params); + + // Concatenate the defs and the SVG into one string + render.wrap_with_transform(transform, None); + let svg = render.svg.to_svg_string(); + + // Send to frontend + responses.add(FrontendMessage::UpdateDocumentArtwork { svg }); + } + + fn process_node_graph_output(&mut self, node_graph_output: TaggedValue, transform: DAffine2, responses: &mut VecDeque) -> Result<(), String> { + let mut render_output_metadata = RenderMetadata::default(); + match node_graph_output { + TaggedValue::RenderOutput(render_output) => { + match render_output.data { + graphene_std::wasm_application_io::RenderOutputType::Svg(svg) => { + // Send to frontend + responses.add(FrontendMessage::UpdateDocumentArtwork { svg }); + } + graphene_std::wasm_application_io::RenderOutputType::CanvasFrame(frame) => { + let matrix = format_transform_matrix(frame.transform); + let transform = if matrix.is_empty() { String::new() } else { format!(" transform=\"{}\"", matrix) }; + let svg = format!( + r#"
"#, + frame.resolution.x, frame.resolution.y, frame.surface_id.0 + ); + responses.add(FrontendMessage::UpdateDocumentArtwork { svg }); + } + _ => { + return Err(format!("Invalid node graph output type: {:#?}", render_output.data)); + } + } + + render_output_metadata = render_output.metadata; + } + TaggedValue::Bool(render_object) => Self::debug_render(render_object, transform, responses), + TaggedValue::String(render_object) => Self::debug_render(render_object, transform, responses), + TaggedValue::F64(render_object) => Self::debug_render(render_object, transform, responses), + TaggedValue::DVec2(render_object) => Self::debug_render(render_object, transform, responses), + TaggedValue::OptionalColor(render_object) => Self::debug_render(render_object, transform, responses), + TaggedValue::VectorData(render_object) => Self::debug_render(render_object, transform, responses), + TaggedValue::GraphicGroup(render_object) => Self::debug_render(render_object, transform, responses), + TaggedValue::RasterData(render_object) => Self::debug_render(render_object, transform, responses), + TaggedValue::Palette(render_object) => Self::debug_render(render_object, transform, responses), + _ => { + return Err(format!("Invalid node graph output type: {node_graph_output:#?}")); + } + }; + responses.add(Message::EndBuffer(render_output_metadata)); + responses.add(DocumentMessage::RenderScrollbars); + responses.add(DocumentMessage::RenderRulers); + responses.add(OverlaysMessage::Draw); + Ok(()) + } +} + +// Re-export for usage by tests in other modules +#[cfg(test)] +pub use test::Instrumented; + +#[cfg(test)] +mod test { + use std::sync::Arc; + + use super::*; + use crate::messages::portfolio::document::utility_types::network_interface::NodeNetworkInterface; + use crate::test_utils::test_prelude::{self, NodeGraphLayer}; + use graph_craft::document::NodeNetwork; + use graphene_std::Context; + use graphene_std::NodeInputDecleration; + use graphene_std::memo::IORecord; + use test_prelude::LayerNodeIdentifier; + + /// Stores all of the monitor nodes that have been attached to a graph + #[derive(Default)] + pub struct Instrumented { + protonodes_by_name: HashMap>>>, + protonodes_by_path: HashMap, Vec>>, + } + + impl Instrumented { + /// Adds montior nodes to the network + fn add(&mut self, network: &mut NodeNetwork, path: &mut Vec) { + // Required to do seperately to satiate the borrow checker. + let mut monitor_nodes = Vec::new(); + for (id, node) in network.nodes.iter_mut() { + // Recursively instrument + if let DocumentNodeImplementation::Network(nested) = &mut node.implementation { + path.push(*id); + self.add(nested, path); + path.pop(); + } + let mut monitor_node_ids = Vec::with_capacity(node.inputs.len()); + for input in &mut node.inputs { + let node_id = NodeId::new(); + let old_input = std::mem::replace(input, NodeInput::node(node_id, 0)); + monitor_nodes.push((old_input, node_id)); + path.push(node_id); + monitor_node_ids.push(path.clone()); + path.pop(); + } + if let DocumentNodeImplementation::ProtoNode(identifier) = &mut node.implementation { + path.push(*id); + self.protonodes_by_name.entry(identifier.name.to_string()).or_default().push(monitor_node_ids.clone()); + self.protonodes_by_path.insert(path.clone(), monitor_node_ids); + path.pop(); + } + } + for (input, monitor_id) in monitor_nodes { + let monitor_node = DocumentNode { + inputs: vec![input], + implementation: DocumentNodeImplementation::proto("graphene_core::memo::MonitorNode"), + manual_composition: Some(graph_craft::generic!(T)), + skip_deduplication: true, + ..Default::default() + }; + network.nodes.insert(monitor_id, monitor_node); + } + } + + /// Instrument a graph and return a new [Instrumented] state. + pub fn new(network: &mut NodeNetwork) -> Self { + let mut instrumented = Self::default(); + instrumented.add(network, &mut Vec::new()); + instrumented + } + + fn downcast(dynamic: Arc) -> Option + where + Input::Result: Send + Sync + Clone + 'static, + { + // This is quite inflexible since it only allows the footprint as inputs. + if let Some(x) = dynamic.downcast_ref::>() { + Some(x.output.clone()) + } else if let Some(x) = dynamic.downcast_ref::>() { + Some(x.output.clone()) + } else if let Some(x) = dynamic.downcast_ref::>() { + Some(x.output.clone()) + } else { + panic!("cannot downcast type for introspection"); + } + } + + /// Grab all of the values of the input every time it occurs in the graph. + pub fn grab_all_input<'a, Input: NodeInputDecleration + 'a>(&'a self, runtime: &'a NodeRuntime) -> impl Iterator + 'a + where + Input::Result: Send + Sync + Clone + 'static, + { + self.protonodes_by_name + .get(Input::identifier()) + .map_or([].as_slice(), |x| x.as_slice()) + .iter() + .filter_map(|inputs| inputs.get(Input::INDEX)) + .filter_map(|input_monitor_node| runtime.executor.introspect(input_monitor_node).ok()) + .filter_map(Instrumented::downcast::) + } + + pub fn grab_protonode_input(&self, path: &Vec, runtime: &NodeRuntime) -> Option + where + Input::Result: Send + Sync + Clone + 'static, + { + let input_monitor_node = self.protonodes_by_path.get(path)?.get(Input::INDEX)?; + + let dynamic = runtime.executor.introspect(input_monitor_node).ok()?; + + Self::downcast::(dynamic) + } + + pub fn grab_input_from_layer(&self, layer: LayerNodeIdentifier, network_interface: &NodeNetworkInterface, runtime: &NodeRuntime) -> Option + where + Input::Result: Send + Sync + Clone + 'static, + { + let node_graph_layer = NodeGraphLayer::new(layer, network_interface); + let node = node_graph_layer.upstream_node_id_from_protonode(Input::identifier())?; + self.grab_protonode_input::(&vec![node], runtime) + } + } +} diff --git a/editor/src/node_graph_executor/runtime.rs b/editor/src/node_graph_executor/runtime.rs new file mode 100644 index 0000000000000000000000000000000000000000..a93f73546c73c1aaeba9070d62017f4d3b93643c --- /dev/null +++ b/editor/src/node_graph_executor/runtime.rs @@ -0,0 +1,462 @@ +use super::*; +use crate::messages::frontend::utility_types::{ExportBounds, FileType}; +use glam::{DAffine2, DVec2}; +use graph_craft::concrete; +use graph_craft::document::value::TaggedValue; +use graph_craft::document::{NodeId, NodeNetwork}; +use graph_craft::graphene_compiler::Compiler; +use graph_craft::proto::GraphErrors; +use graph_craft::wasm_application_io::EditorPreferences; +use graphene_std::Context; +use graphene_std::application_io::{NodeGraphUpdateMessage, NodeGraphUpdateSender, RenderConfig}; +use graphene_std::instances::Instance; +use graphene_std::memo::IORecord; +use graphene_std::renderer::{GraphicElementRendered, RenderParams, SvgRender}; +use graphene_std::renderer::{RenderSvgSegmentList, SvgSegment}; +use graphene_std::text::FontCache; +use graphene_std::vector::style::ViewMode; +use graphene_std::vector::{VectorData, VectorDataTable}; +use graphene_std::wasm_application_io::{WasmApplicationIo, WasmEditorApi}; +use interpreted_executor::dynamic_executor::{DynamicExecutor, IntrospectError, ResolvedDocumentNodeTypesDelta}; +use interpreted_executor::util::wrap_network_in_scope; +use once_cell::sync::Lazy; +use spin::Mutex; +use std::sync::Arc; +use std::sync::mpsc::{Receiver, Sender}; + +/// Persistent data between graph executions. It's updated via message passing from the editor thread with [`GraphRuntimeRequest`]`. +/// Some of these fields are put into a [`WasmEditorApi`] which is passed to the final compiled graph network upon each execution. +/// Once the implementation is finished, this will live in a separate thread. Right now it's part of the main JS thread, but its own separate JS stack frame independent from the editor. +pub struct NodeRuntime { + #[cfg(test)] + pub(super) executor: DynamicExecutor, + #[cfg(not(test))] + executor: DynamicExecutor, + receiver: Receiver, + sender: InternalNodeGraphUpdateSender, + editor_preferences: EditorPreferences, + old_graph: Option, + update_thumbnails: bool, + + editor_api: Arc, + node_graph_errors: GraphErrors, + monitor_nodes: Vec>, + + /// Which node is inspected and which monitor node is used (if any) for the current execution + inspect_state: Option, + + /// Mapping of the fully-qualified node paths to their preprocessor substitutions. + substitutions: HashMap, + + // TODO: Remove, it doesn't need to be persisted anymore + /// The current renders of the thumbnails for layer nodes. + thumbnail_renders: HashMap>, + vector_modify: HashMap, +} + +/// Messages passed from the editor thread to the node runtime thread. +#[derive(Debug, serde::Serialize, serde::Deserialize)] +pub enum GraphRuntimeRequest { + GraphUpdate(GraphUpdate), + ExecutionRequest(ExecutionRequest), + FontCacheUpdate(FontCache), + EditorPreferencesUpdate(EditorPreferences), +} + +#[derive(Debug, serde::Serialize, serde::Deserialize)] +pub struct GraphUpdate { + pub(super) network: NodeNetwork, + /// The node that should be temporary inspected during execution + pub(super) inspect_node: Option, +} + +#[derive(Default, Debug, Clone, serde::Serialize, serde::Deserialize)] +pub struct ExportConfig { + pub file_name: String, + pub file_type: FileType, + pub scale_factor: f64, + pub bounds: ExportBounds, + pub transparent_background: bool, + pub size: DVec2, +} + +#[derive(Clone)] +struct InternalNodeGraphUpdateSender(Sender); + +impl InternalNodeGraphUpdateSender { + fn send_generation_response(&self, response: CompilationResponse) { + self.0.send(NodeGraphUpdate::CompilationResponse(response)).expect("Failed to send response") + } + + fn send_execution_response(&self, response: ExecutionResponse) { + self.0.send(NodeGraphUpdate::ExecutionResponse(response)).expect("Failed to send response") + } +} + +impl NodeGraphUpdateSender for InternalNodeGraphUpdateSender { + fn send(&self, message: NodeGraphUpdateMessage) { + self.0.send(NodeGraphUpdate::NodeGraphUpdateMessage(message)).expect("Failed to send response") + } +} + +pub static NODE_RUNTIME: Lazy>> = Lazy::new(|| Mutex::new(None)); + +impl NodeRuntime { + pub fn new(receiver: Receiver, sender: Sender) -> Self { + Self { + executor: DynamicExecutor::default(), + receiver, + sender: InternalNodeGraphUpdateSender(sender.clone()), + editor_preferences: EditorPreferences::default(), + old_graph: None, + update_thumbnails: true, + + editor_api: WasmEditorApi { + font_cache: FontCache::default(), + editor_preferences: Box::new(EditorPreferences::default()), + node_graph_message_sender: Box::new(InternalNodeGraphUpdateSender(sender)), + + application_io: None, + } + .into(), + + node_graph_errors: Vec::new(), + monitor_nodes: Vec::new(), + + substitutions: preprocessor::generate_node_substitutions(), + + thumbnail_renders: Default::default(), + vector_modify: Default::default(), + inspect_state: None, + } + } + + pub async fn run(&mut self) { + if self.editor_api.application_io.is_none() { + self.editor_api = WasmEditorApi { + #[cfg(not(test))] + application_io: Some(WasmApplicationIo::new().await.into()), + #[cfg(test)] + application_io: Some(WasmApplicationIo::new_offscreen().await.into()), + font_cache: self.editor_api.font_cache.clone(), + node_graph_message_sender: Box::new(self.sender.clone()), + editor_preferences: Box::new(self.editor_preferences.clone()), + } + .into(); + } + + let mut font = None; + let mut preferences = None; + let mut graph = None; + let mut execution = None; + for request in self.receiver.try_iter() { + match request { + GraphRuntimeRequest::GraphUpdate(_) => graph = Some(request), + GraphRuntimeRequest::ExecutionRequest(_) => execution = Some(request), + GraphRuntimeRequest::FontCacheUpdate(_) => font = Some(request), + GraphRuntimeRequest::EditorPreferencesUpdate(_) => preferences = Some(request), + } + } + let requests = [font, preferences, graph, execution].into_iter().flatten(); + + for request in requests { + match request { + GraphRuntimeRequest::FontCacheUpdate(font_cache) => { + self.editor_api = WasmEditorApi { + font_cache, + application_io: self.editor_api.application_io.clone(), + node_graph_message_sender: Box::new(self.sender.clone()), + editor_preferences: Box::new(self.editor_preferences.clone()), + } + .into(); + if let Some(graph) = self.old_graph.clone() { + // We ignore this result as compilation errors should have been reported in an earlier iteration + let _ = self.update_network(graph).await; + } + } + GraphRuntimeRequest::EditorPreferencesUpdate(preferences) => { + self.editor_preferences = preferences.clone(); + self.editor_api = WasmEditorApi { + font_cache: self.editor_api.font_cache.clone(), + application_io: self.editor_api.application_io.clone(), + node_graph_message_sender: Box::new(self.sender.clone()), + editor_preferences: Box::new(preferences), + } + .into(); + if let Some(graph) = self.old_graph.clone() { + // We ignore this result as compilation errors should have been reported in an earlier iteration + let _ = self.update_network(graph).await; + } + } + GraphRuntimeRequest::GraphUpdate(GraphUpdate { mut network, inspect_node }) => { + // Insert the monitor node to manage the inspection + self.inspect_state = inspect_node.map(|inspect| InspectState::monitor_inspect_node(&mut network, inspect)); + + self.old_graph = Some(network.clone()); + self.node_graph_errors.clear(); + let result = self.update_network(network).await; + self.update_thumbnails = true; + self.sender.send_generation_response(CompilationResponse { + result, + node_graph_errors: self.node_graph_errors.clone(), + }); + } + GraphRuntimeRequest::ExecutionRequest(ExecutionRequest { execution_id, render_config, .. }) => { + let transform = render_config.viewport.transform; + + let result = self.execute_network(render_config).await; + let mut responses = VecDeque::new(); + // TODO: Only process monitor nodes if the graph has changed, not when only the Footprint changes + self.process_monitor_nodes(&mut responses, self.update_thumbnails); + self.update_thumbnails = false; + + // Resolve the result from the inspection by accessing the monitor node + let inspect_result = self.inspect_state.and_then(|state| state.access(&self.executor)); + + self.sender.send_execution_response(ExecutionResponse { + execution_id, + result, + responses, + transform, + vector_modify: self.vector_modify.clone(), + inspect_result, + }); + } + } + } + } + + async fn update_network(&mut self, mut graph: NodeNetwork) -> Result { + preprocessor::expand_network(&mut graph, &self.substitutions); + + let scoped_network = wrap_network_in_scope(graph, self.editor_api.clone()); + + // We assume only one output + assert_eq!(scoped_network.exports.len(), 1, "Graph with multiple outputs not yet handled"); + + let c = Compiler {}; + let proto_network = match c.compile_single(scoped_network) { + Ok(network) => network, + Err(e) => return Err(e), + }; + self.monitor_nodes = proto_network + .nodes + .iter() + .filter(|(_, node)| node.identifier == "graphene_core::memo::MonitorNode".into()) + .map(|(_, node)| node.original_location.path.clone().unwrap_or_default()) + .collect::>(); + + assert_ne!(proto_network.nodes.len(), 0, "No proto nodes exist?"); + self.executor.update(proto_network).await.map_err(|e| { + self.node_graph_errors.clone_from(&e); + format!("{e:?}") + }) + } + + async fn execute_network(&mut self, render_config: RenderConfig) -> Result { + use graph_craft::graphene_compiler::Executor; + + let result = match self.executor.input_type() { + Some(t) if t == concrete!(RenderConfig) => (&self.executor).execute(render_config).await.map_err(|e| e.to_string()), + Some(t) if t == concrete!(()) => (&self.executor).execute(()).await.map_err(|e| e.to_string()), + Some(t) => Err(format!("Invalid input type {t:?}")), + _ => Err(format!("No input type:\n{:?}", self.node_graph_errors)), + }; + let result = match result { + Ok(value) => value, + Err(e) => return Err(e), + }; + + Ok(result) + } + + /// Updates state data + pub fn process_monitor_nodes(&mut self, responses: &mut VecDeque, update_thumbnails: bool) { + // TODO: Consider optimizing this since it's currently O(m*n^2), with a sort it could be made O(m * n*log(n)) + self.thumbnail_renders.retain(|id, _| self.monitor_nodes.iter().any(|monitor_node_path| monitor_node_path.contains(id))); + + for monitor_node_path in &self.monitor_nodes { + // Skip the inspect monitor node + if self.inspect_state.is_some_and(|inspect_state| monitor_node_path.last().copied() == Some(inspect_state.monitor_node)) { + continue; + } + // The monitor nodes are located within a document node, and are thus children in that network, so this gets the parent document node's ID + let Some(parent_network_node_id) = monitor_node_path.len().checked_sub(2).and_then(|index| monitor_node_path.get(index)).copied() else { + warn!("Monitor node has invalid node id"); + + continue; + }; + + // Extract the monitor node's stored `GraphicElement` data. + let Ok(introspected_data) = self.executor.introspect(monitor_node_path) else { + // TODO: Fix the root of the issue causing the spam of this warning (this at least temporarily disables it in release builds) + #[cfg(debug_assertions)] + warn!("Failed to introspect monitor node {}", self.executor.introspect(monitor_node_path).unwrap_err()); + + continue; + }; + + if let Some(io) = introspected_data.downcast_ref::>() { + Self::process_graphic_element(&mut self.thumbnail_renders, parent_network_node_id, &io.output, responses, update_thumbnails) + } else if let Some(io) = introspected_data.downcast_ref::>() { + Self::process_graphic_element(&mut self.thumbnail_renders, parent_network_node_id, &io.output, responses, update_thumbnails) + // Insert the vector modify if we are dealing with vector data + } else if let Some(record) = introspected_data.downcast_ref::>() { + let default = Instance::default(); + self.vector_modify.insert( + parent_network_node_id, + record.output.instance_ref_iter().next().unwrap_or_else(|| default.to_instance_ref()).instance.clone(), + ); + } else { + log::warn!("Failed to downcast monitor node output {parent_network_node_id:?}"); + } + } + } + + // If this is `GraphicElement` data: + // Regenerate click targets and thumbnails for the layers in the graph, modifying the state and updating the UI. + fn process_graphic_element( + thumbnail_renders: &mut HashMap>, + parent_network_node_id: NodeId, + graphic_element: &impl GraphicElementRendered, + responses: &mut VecDeque, + update_thumbnails: bool, + ) { + // RENDER THUMBNAIL + + if !update_thumbnails { + return; + } + + let bounds = graphic_element.bounding_box(DAffine2::IDENTITY, true); + + // Render the thumbnail from a `GraphicElement` into an SVG string + let render_params = RenderParams { + view_mode: ViewMode::Normal, + culling_bounds: bounds, + thumbnail: true, + hide_artboards: false, + for_export: false, + for_mask: false, + alignment_parent_transform: None, + }; + let mut render = SvgRender::new(); + graphic_element.render_svg(&mut render, &render_params); + + // And give the SVG a viewbox and outer ... wrapper tag + let [min, max] = bounds.unwrap_or_default(); + render.format_svg(min, max); + + // UPDATE FRONTEND THUMBNAIL + + let new_thumbnail_svg = render.svg; + let old_thumbnail_svg = thumbnail_renders.entry(parent_network_node_id).or_default(); + + if old_thumbnail_svg != &new_thumbnail_svg { + responses.push_back(FrontendMessage::UpdateNodeThumbnail { + id: parent_network_node_id, + value: new_thumbnail_svg.to_svg_string(), + }); + *old_thumbnail_svg = new_thumbnail_svg; + } + } +} + +pub async fn introspect_node(path: &[NodeId]) -> Result, IntrospectError> { + let runtime = NODE_RUNTIME.lock(); + if let Some(ref mut runtime) = runtime.as_ref() { + return runtime.executor.introspect(path); + } + Err(IntrospectError::RuntimeNotReady) +} + +pub async fn run_node_graph() -> bool { + let Some(mut runtime) = NODE_RUNTIME.try_lock() else { return false }; + if let Some(ref mut runtime) = runtime.as_mut() { + runtime.run().await; + } + true +} + +pub async fn replace_node_runtime(runtime: NodeRuntime) -> Option { + let mut node_runtime = NODE_RUNTIME.lock(); + node_runtime.replace(runtime) +} + +/// Which node is inspected and which monitor node is used (if any) for the current execution +#[derive(Debug, Clone, Copy)] +struct InspectState { + inspect_node: NodeId, + monitor_node: NodeId, +} +/// The resulting value from the temporary inspected during execution +#[derive(Clone, Debug, Default)] +#[cfg_attr(feature = "decouple-execution", derive(serde::Serialize, serde::Deserialize))] +pub struct InspectResult { + #[cfg(not(feature = "decouple-execution"))] + introspected_data: Option>, + #[cfg(feature = "decouple-execution")] + introspected_data: Option, + pub inspect_node: NodeId, +} + +impl InspectResult { + pub fn take_data(&mut self) -> Option> { + #[cfg(not(feature = "decouple-execution"))] + return self.introspected_data.clone(); + + #[cfg(feature = "decouple-execution")] + return self.introspected_data.take().map(|value| value.to_any()); + } +} + +// This is very ugly but is required to be inside a message +impl PartialEq for InspectResult { + fn eq(&self, other: &Self) -> bool { + self.inspect_node == other.inspect_node + } +} + +impl InspectState { + /// Insert the monitor node to manage the inspection + pub fn monitor_inspect_node(network: &mut NodeNetwork, inspect_node: NodeId) -> Self { + let monitor_id = NodeId::new(); + + // It is necessary to replace the inputs before inserting the monitor node to avoid changing the input of the new monitor node + for input in network.nodes.values_mut().flat_map(|node| node.inputs.iter_mut()).chain(&mut network.exports) { + let NodeInput::Node { node_id, output_index, .. } = input else { continue }; + // We only care about the primary output of our inspect node + if *output_index != 0 || *node_id != inspect_node { + continue; + } + + *node_id = monitor_id; + } + + let monitor_node = DocumentNode { + inputs: vec![NodeInput::node(inspect_node, 0)], // Connect to the primary output of the inspect node + implementation: DocumentNodeImplementation::proto("graphene_core::memo::MonitorNode"), + manual_composition: Some(graph_craft::generic!(T)), + skip_deduplication: true, + ..Default::default() + }; + network.nodes.insert(monitor_id, monitor_node); + + Self { + inspect_node, + monitor_node: monitor_id, + } + } + /// Resolve the result from the inspection by accessing the monitor node + fn access(&self, executor: &DynamicExecutor) -> Option { + let introspected_data = executor.introspect(&[self.monitor_node]).inspect_err(|e| warn!("Failed to introspect monitor node {e}")).ok(); + // TODO: Consider displaying the error instead of ignoring it + #[cfg(feature = "decouple-execution")] + let introspected_data = introspected_data.as_ref().and_then(|data| TaggedValue::try_from_std_any_ref(data).ok()); + + Some(InspectResult { + inspect_node: self.inspect_node, + introspected_data, + }) + } +} diff --git a/editor/src/node_graph_executor/runtime_io.rs b/editor/src/node_graph_executor/runtime_io.rs new file mode 100644 index 0000000000000000000000000000000000000000..e4e6f1df408066b19fadafa838e67c4c3fa4b2a4 --- /dev/null +++ b/editor/src/node_graph_executor/runtime_io.rs @@ -0,0 +1,102 @@ +use super::*; +use std::sync::mpsc::{Receiver, Sender}; +use wasm_bindgen::prelude::*; + +#[wasm_bindgen] +extern "C" { + // Invoke with arguments (default) + #[wasm_bindgen(js_namespace = ["window", "__TAURI__", "core"])] + async fn invoke(cmd: &str, args: JsValue) -> JsValue; + #[wasm_bindgen(js_namespace = ["window", "__TAURI__", "core"], js_name="invoke")] + async fn invoke_without_arg(cmd: &str) -> JsValue; +} + +/// Handles communication with the NodeRuntime, either locally or via Tauri +#[derive(Debug)] +pub struct NodeRuntimeIO { + // Send to + #[cfg(any(not(feature = "tauri"), test))] + sender: Sender, + #[cfg(all(feature = "tauri", not(test)))] + sender: Sender, + receiver: Receiver, +} + +impl Default for NodeRuntimeIO { + fn default() -> Self { + Self::new() + } +} + +impl NodeRuntimeIO { + /// Creates a new NodeRuntimeIO instance + pub fn new() -> Self { + #[cfg(any(not(feature = "tauri"), test))] + { + let (response_sender, response_receiver) = std::sync::mpsc::channel(); + let (request_sender, request_receiver) = std::sync::mpsc::channel(); + futures::executor::block_on(replace_node_runtime(NodeRuntime::new(request_receiver, response_sender))); + + Self { + sender: request_sender, + receiver: response_receiver, + } + } + + #[cfg(all(feature = "tauri", not(test)))] + { + let (response_sender, response_receiver) = std::sync::mpsc::channel(); + Self { + sender: response_sender, + receiver: response_receiver, + } + } + } + #[cfg(test)] + pub fn with_channels(sender: Sender, receiver: Receiver) -> Self { + Self { sender, receiver } + } + + /// Sends a message to the NodeRuntime + pub fn send(&self, message: GraphRuntimeRequest) -> Result<(), String> { + #[cfg(any(not(feature = "tauri"), test))] + { + self.sender.send(message).map_err(|e| e.to_string()) + } + + #[cfg(all(feature = "tauri", not(test)))] + { + let serialized = ron::to_string(&message).map_err(|e| e.to_string()).unwrap(); + wasm_bindgen_futures::spawn_local(async move { + let js_message = create_message_object(&serialized); + invoke("runtime_message", js_message).await; + }); + Ok(()) + } + } + + /// Receives any pending updates from the NodeRuntime + pub fn receive(&self) -> impl Iterator + use<'_> { + // TODO: This introduces extra latency + #[cfg(all(feature = "tauri", not(test)))] + { + let sender = self.sender.clone(); + // In the Tauri case, responses are handled separately via poll_node_runtime_updates + wasm_bindgen_futures::spawn_local(async move { + let messages = invoke_without_arg("poll_node_graph").await; + let vec: Vec<_> = ron::from_str(&messages.as_string().unwrap()).unwrap(); + for message in vec { + sender.send(message).unwrap(); + } + }); + } + self.receiver.try_iter() + } +} + +#[cfg(all(feature = "tauri", not(test)))] +pub fn create_message_object(message: &str) -> JsValue { + let obj = js_sys::Object::new(); + js_sys::Reflect::set(&obj, &JsValue::from_str("message"), &JsValue::from_str(message)).unwrap(); + obj.into() +} diff --git a/editor/src/test_utils.rs b/editor/src/test_utils.rs new file mode 100644 index 0000000000000000000000000000000000000000..04ef698da025fedd7039ba4cf41ca53fa13f96c9 --- /dev/null +++ b/editor/src/test_utils.rs @@ -0,0 +1,348 @@ +use crate::application::Editor; +use crate::application::set_uuid_seed; +use crate::messages::input_mapper::utility_types::input_keyboard::ModifierKeys; +use crate::messages::input_mapper::utility_types::input_mouse::{EditorMouseState, MouseKeys, ScrollDelta, ViewportPosition}; +use crate::messages::portfolio::utility_types::Platform; +use crate::messages::prelude::*; +use crate::messages::tool::tool_messages::tool_prelude::Key; +use crate::messages::tool::utility_types::ToolType; +use crate::node_graph_executor::Instrumented; +use crate::node_graph_executor::NodeRuntime; +use crate::test_utils::test_prelude::LayerNodeIdentifier; +use glam::DVec2; +use graph_craft::document::DocumentNode; +use graphene_std::InputAccessor; +use graphene_std::raster::color::Color; + +/// A set of utility functions to make the writing of editor test more declarative +pub struct EditorTestUtils { + pub editor: Editor, + pub runtime: NodeRuntime, +} + +impl EditorTestUtils { + pub fn create() -> Self { + let _ = env_logger::builder().is_test(true).try_init(); + set_uuid_seed(0); + + let (mut editor, runtime) = Editor::new_local_executor(); + + // We have to set this directly instead of using `GlobalsMessage::SetPlatform` because race conditions with multiple tests can cause that message handler to set it more than once, which is a failure. + // It isn't sufficient to guard the message dispatch here with a check if the once_cell is empty, because that isn't atomic and the time between checking and handling the dispatch can let multiple through. + let _ = GLOBAL_PLATFORM.set(Platform::Windows).is_ok(); + + editor.handle_message(Message::Init); + + Self { editor, runtime } + } + + pub fn eval_graph<'a>(&'a mut self) -> impl std::future::Future> + 'a { + // An inner function is required since async functions in traits are a bit weird + async fn run<'a>(editor: &'a mut Editor, runtime: &'a mut NodeRuntime) -> Result { + let portfolio = &mut editor.dispatcher.message_handlers.portfolio_message_handler; + let exector = &mut portfolio.executor; + let document = portfolio.documents.get_mut(&portfolio.active_document_id.unwrap()).unwrap(); + + let instrumented = match exector.update_node_graph_instrumented(document) { + Ok(instrumented) => instrumented, + Err(e) => return Err(format!("update_node_graph_instrumented failed\n\n{e}")), + }; + + let viewport_resolution = glam::UVec2::ONE; + if let Err(e) = exector.submit_current_node_graph_evaluation(document, viewport_resolution, Default::default()) { + return Err(format!("submit_current_node_graph_evaluation failed\n\n{e}")); + } + runtime.run().await; + + let mut messages = VecDeque::new(); + if let Err(e) = editor.poll_node_graph_evaluation(&mut messages) { + return Err(format!("Graph should render\n\n{e}")); + } + let frontend_messages = messages.into_iter().flat_map(|message| editor.handle_message(message)); + + for message in frontend_messages { + message.check_node_graph_error(); + } + + Ok(instrumented) + } + + run(&mut self.editor, &mut self.runtime) + } + + pub async fn handle_message(&mut self, message: impl Into) { + self.editor.handle_message(message); + + // Required to process any buffered messages + if let Err(e) = self.eval_graph().await { + panic!("Failed to evaluate graph: {e}"); + } + } + + pub async fn new_document(&mut self) { + self.handle_message(Message::Portfolio(PortfolioMessage::NewDocumentWithName { name: String::from("Test document") })) + .await; + } + + pub async fn draw_rect(&mut self, x1: f64, y1: f64, x2: f64, y2: f64) { + self.drag_tool(ToolType::Rectangle, x1, y1, x2, y2, ModifierKeys::default()).await; + } + + pub async fn draw_polygon(&mut self, x1: f64, y1: f64, x2: f64, y2: f64) { + self.drag_tool(ToolType::Shape, x1, y1, x2, y2, ModifierKeys::default()).await; + } + + pub async fn draw_ellipse(&mut self, x1: f64, y1: f64, x2: f64, y2: f64) { + self.drag_tool(ToolType::Ellipse, x1, y1, x2, y2, ModifierKeys::default()).await; + } + + pub async fn click_tool(&mut self, typ: ToolType, button: MouseKeys, position: DVec2, modifier_keys: ModifierKeys) { + self.select_tool(typ).await; + + self.move_mouse(position.x, position.y, modifier_keys, MouseKeys::empty()).await; + + self.mousedown( + EditorMouseState { + editor_position: position, + mouse_keys: button, + ..Default::default() + }, + modifier_keys, + ) + .await; + + self.mouseup( + EditorMouseState { + editor_position: position, + ..Default::default() + }, + modifier_keys, + ) + .await; + } + + pub async fn drag_tool(&mut self, typ: ToolType, x1: f64, y1: f64, x2: f64, y2: f64, modifier_keys: ModifierKeys) { + self.select_tool(typ).await; + + self.move_mouse(x1, y1, modifier_keys, MouseKeys::empty()).await; + + self.left_mousedown(x1, y1, modifier_keys).await; + + self.move_mouse(x2, y2, modifier_keys, MouseKeys::LEFT).await; + + self.mouseup( + EditorMouseState { + editor_position: (x2, y2).into(), + mouse_keys: MouseKeys::empty(), + scroll_delta: ScrollDelta::default(), + }, + modifier_keys, + ) + .await; + } + + pub async fn drag_tool_cancel_rmb(&mut self, typ: ToolType) { + self.select_tool(typ).await; + + self.move_mouse(50., 50., ModifierKeys::default(), MouseKeys::empty()).await; + + self.left_mousedown(50., 50., ModifierKeys::default()).await; + + self.move_mouse(100., 100., ModifierKeys::default(), MouseKeys::LEFT).await; + + self.mousedown( + EditorMouseState { + editor_position: (100., 100.).into(), + mouse_keys: MouseKeys::LEFT | MouseKeys::RIGHT, + scroll_delta: ScrollDelta::default(), + }, + ModifierKeys::default(), + ) + .await; + } + + pub fn active_document(&self) -> &DocumentMessageHandler { + self.editor.dispatcher.message_handlers.portfolio_message_handler.active_document().unwrap() + } + + pub fn active_document_mut(&mut self) -> &mut DocumentMessageHandler { + self.editor.dispatcher.message_handlers.portfolio_message_handler.active_document_mut().unwrap() + } + + pub fn get_node<'a, T: InputAccessor<'a, DocumentNode>>(&'a self) -> impl Iterator + 'a { + self.active_document() + .network_interface + .document_network() + .recursive_nodes() + .inspect(|(_, node, _)| println!("{:#?}", node.implementation)) + .filter_map(move |(_, document, _)| T::new_with_source(document)) + } + + pub async fn move_mouse(&mut self, x: f64, y: f64, modifier_keys: ModifierKeys, mouse_keys: MouseKeys) { + let editor_mouse_state = EditorMouseState { + editor_position: ViewportPosition::new(x, y), + mouse_keys, + ..Default::default() + }; + self.input(InputPreprocessorMessage::PointerMove { editor_mouse_state, modifier_keys }).await; + } + + pub async fn mousedown(&mut self, editor_mouse_state: EditorMouseState, modifier_keys: ModifierKeys) { + self.input(InputPreprocessorMessage::PointerDown { editor_mouse_state, modifier_keys }).await; + } + + pub async fn mouseup(&mut self, editor_mouse_state: EditorMouseState, modifier_keys: ModifierKeys) { + self.handle_message(InputPreprocessorMessage::PointerUp { editor_mouse_state, modifier_keys }).await; + } + + pub async fn press(&mut self, key: Key, modifier_keys: ModifierKeys) { + let key_repeat = false; + + self.handle_message(InputPreprocessorMessage::KeyDown { key, modifier_keys, key_repeat }).await; + self.handle_message(InputPreprocessorMessage::KeyUp { key, modifier_keys, key_repeat }).await; + } + + pub async fn left_mousedown(&mut self, x: f64, y: f64, modifier_keys: ModifierKeys) { + self.mousedown( + EditorMouseState { + editor_position: (x, y).into(), + mouse_keys: MouseKeys::LEFT, + scroll_delta: ScrollDelta::default(), + }, + modifier_keys, + ) + .await; + } + + pub async fn input(&mut self, message: InputPreprocessorMessage) { + self.handle_message(Message::InputPreprocessor(message)).await; + } + + pub async fn select_tool(&mut self, tool_type: ToolType) { + match tool_type { + ToolType::Line => self.handle_message(Message::Tool(ToolMessage::ActivateToolShapeLine)).await, + ToolType::Rectangle => self.handle_message(Message::Tool(ToolMessage::ActivateToolShapeRectangle)).await, + ToolType::Ellipse => self.handle_message(Message::Tool(ToolMessage::ActivateToolShapeEllipse)).await, + _ => self.handle_message(Message::Tool(ToolMessage::ActivateTool { tool_type })).await, + } + } + + pub async fn select_primary_color(&mut self, color: Color) { + self.handle_message(Message::Tool(ToolMessage::SelectWorkingColor { color, primary: true })).await; + } + + pub async fn select_secondary_color(&mut self, color: Color) { + self.handle_message(Message::Tool(ToolMessage::SelectWorkingColor { color, primary: false })).await; + } + + pub async fn create_raster_image(&mut self, image: graphene_std::raster::Image, mouse: Option<(f64, f64)>) { + self.handle_message(PortfolioMessage::PasteImage { + name: None, + image, + mouse, + parent_and_insert_index: None, + }) + .await; + } + pub async fn draw_spline(&mut self, points: &[DVec2]) { + self.select_tool(ToolType::Spline).await; + + for &point in points { + self.click_tool(ToolType::Spline, MouseKeys::LEFT, point, ModifierKeys::empty()).await; + } + + self.press(Key::Enter, ModifierKeys::empty()).await; + } + + pub async fn get_selected_layer(&mut self) -> Option { + self.active_document().network_interface.selected_nodes().selected_layers(self.active_document().metadata()).next() + } + + pub async fn double_click(&mut self, position: DVec2) { + self.handle_message(InputPreprocessorMessage::DoubleClick { + editor_mouse_state: EditorMouseState { + editor_position: position, + mouse_keys: MouseKeys::LEFT, + scroll_delta: ScrollDelta::default(), + }, + modifier_keys: ModifierKeys::empty(), + }) + .await; + } + + pub async fn drag_path(&mut self, points: &[DVec2], modifier_keys: ModifierKeys) { + if points.is_empty() { + return; + } + + let first_point = points[0]; + self.move_mouse(first_point.x, first_point.y, modifier_keys, MouseKeys::empty()).await; + self.left_mousedown(first_point.x, first_point.y, modifier_keys).await; + + for &point in &points[1..] { + self.move_mouse(point.x, point.y, modifier_keys, MouseKeys::LEFT).await; + } + + self.mouseup( + EditorMouseState { + editor_position: points[points.len() - 1], + mouse_keys: MouseKeys::empty(), + scroll_delta: ScrollDelta::default(), + }, + modifier_keys, + ) + .await; + } +} + +pub trait FrontendMessageTestUtils { + fn check_node_graph_error(&self); +} + +impl FrontendMessageTestUtils for FrontendMessage { + fn check_node_graph_error(&self) { + let FrontendMessage::UpdateNodeGraphNodes { nodes, .. } = self else { return }; + + for node in nodes { + if let Some(error) = &node.errors { + panic!("error on {}: {}", node.display_name, error); + } + } + } +} + +#[cfg(test)] +pub mod test_prelude { + pub use super::FrontendMessageTestUtils; + pub use crate::application::Editor; + pub use crate::float_eq; + pub use crate::messages::input_mapper::utility_types::input_keyboard::{Key, ModifierKeys}; + pub use crate::messages::input_mapper::utility_types::input_mouse::MouseKeys; + pub use crate::messages::portfolio::document::utility_types::clipboards::Clipboard; + pub use crate::messages::portfolio::document::utility_types::document_metadata::LayerNodeIdentifier; + pub use crate::messages::prelude::*; + pub use crate::messages::tool::common_functionality::graph_modification_utils::{NodeGraphLayer, is_layer_fed_by_node_of_name}; + pub use crate::messages::tool::utility_types::ToolType; + pub use crate::node_graph_executor::NodeRuntime; + pub use crate::test_utils::EditorTestUtils; + pub use core::f64; + pub use glam::DVec2; + pub use glam::IVec2; + pub use graph_craft::document::DocumentNode; + pub use graphene_std::raster::{Color, Image}; + pub use graphene_std::transform::Footprint; + pub use graphene_std::{InputAccessor, InputAccessorSource}; + + #[macro_export] + macro_rules! float_eq { + ($left:expr, $right:expr $(,)?) => { + match (&$left, &$right) { + (left_val, right_val) => { + if (*left_val - *right_val).abs() > 1e-10 { + panic!("assertion `left == right` failed\n left: {}\n right: {}", *left_val, *right_val) + } + } + } + }; + } +} diff --git a/editor/src/utility_traits.rs b/editor/src/utility_traits.rs new file mode 100644 index 0000000000000000000000000000000000000000..711a8cc34bdd5cb194b33d01d654830d669ca0d4 --- /dev/null +++ b/editor/src/utility_traits.rs @@ -0,0 +1,47 @@ +pub use crate::dispatcher::*; +use crate::messages::prelude::*; + +/// Implements a message handler struct for a separate message struct. +/// - The first generic argument (`M`) is that message struct type, representing a message enum variant to be matched and handled in `process_message()`. +/// - The second generic argument (`D`) is the type of data that can be passed along by the caller to `process_message()`. +pub trait MessageHandler +where + M::Discriminant: AsMessage, + ::TopParent: TransitiveChild::TopParent, TopParent = ::TopParent> + AsMessage, +{ + /// Return true if the Action is consumed. + fn process_message(&mut self, message: M, responses: &mut VecDeque, data: D); + + fn actions(&self) -> ActionList; +} + +pub type ActionList = Vec>; + +pub trait AsMessage: TransitiveChild +where + Self::TopParent: TransitiveChild + AsMessage, +{ + fn local_name(self) -> String; + fn global_name(self) -> String { + >::into(self).local_name() + } +} + +// TODO: Add Send + Sync requirement +// Use something like rw locks for synchronization +pub trait MessageHandlerData {} + +pub trait ToDiscriminant { + type Discriminant; + + fn to_discriminant(&self) -> Self::Discriminant; +} + +pub trait TransitiveChild: Into + Into { + type TopParent; + type Parent; +} + +pub trait Hint { + fn hints(&self) -> HashMap; +} diff --git a/frontend/.eslintrc.cjs b/frontend/.eslintrc.cjs new file mode 100644 index 0000000000000000000000000000000000000000..c71b3ff332f5b47cbf5e0e4854c8caf0c22eaf85 --- /dev/null +++ b/frontend/.eslintrc.cjs @@ -0,0 +1,109 @@ +module.exports = { + root: true, + env: { browser: true, node: true }, + extends: [ + "eslint:recommended", + "plugin:import/recommended", + "plugin:@typescript-eslint/recommended", + "plugin:import/typescript", + "plugin:svelte/recommended", + "plugin:svelte/prettier", + "prettier", + ], + plugins: ["import", "@typescript-eslint", "prettier"], + settings: { + "import/parsers": { "@typescript-eslint/parser": [".ts"] }, + "import/resolver": { typescript: true, node: true }, + }, + parser: "@typescript-eslint/parser", + parserOptions: { + ecmaVersion: "latest", + project: "./tsconfig.json", + extraFileExtensions: [".svelte"], + }, + ignorePatterns: [ + // Ignore generated directories + "node_modules/", + "dist/", + "pkg/", + "wasm/pkg/", + // Don't ignore JS and TS dotfiles in this folder + "!.*.js", + "!.*.ts", + ], + overrides: [ + { + files: ["*.svelte"], + parser: "svelte-eslint-parser", + // Parse the ` + + diff --git a/frontend/package-installer.js b/frontend/package-installer.js new file mode 100644 index 0000000000000000000000000000000000000000..64970e38a697c21839a8d404e3eb66b0be9bebe5 --- /dev/null +++ b/frontend/package-installer.js @@ -0,0 +1,41 @@ +// This script automatically installs the npm packages listed in package-lock.json and runs before `npm start`. +// It skips the installation if this has already run and neither package.json nor package-lock.json has been modified since. + +import { execSync } from "child_process"; +import { existsSync, statSync, writeFileSync } from "fs"; + +const INSTALL_TIMESTAMP_FILE = "node_modules/.install-timestamp"; + +// Checks if the install is needed by comparing modification times +const isInstallNeeded = () => { + if (!existsSync(INSTALL_TIMESTAMP_FILE)) return true; + + const timestamp = statSync(INSTALL_TIMESTAMP_FILE).mtime; + return ["package.json", "package-lock.json"].some((file) => { + return existsSync(file) && statSync(file).mtime > timestamp; + }); +}; + +// Run `npm ci` if needed and update the install timestamp +if (isInstallNeeded()) { + try { + // eslint-disable-next-line no-console + console.log("Installing npm packages..."); + + // Check if packages are up to date, doing so quickly by using `npm ci`, preferring local cached packages, and skipping the package audit and other checks + execSync("npm ci --prefer-offline --no-audit --no-fund", { stdio: "inherit" }); + + // Touch the install timestamp file + writeFileSync(INSTALL_TIMESTAMP_FILE, ""); + + // eslint-disable-next-line no-console + console.log("Finished installing npm packages."); + } catch (_) { + // eslint-disable-next-line no-console + console.error("Failed to install npm packages. Please run `npm install` from the `/frontend` directory."); + process.exit(1); + } +} else { + // eslint-disable-next-line no-console + console.log("All npm packages are up-to-date."); +} diff --git a/frontend/package-lock.json b/frontend/package-lock.json new file mode 100644 index 0000000000000000000000000000000000000000..3d12766ca6f7c82f3979225dae6d04d3fef0ca8c --- /dev/null +++ b/frontend/package-lock.json @@ -0,0 +1,5742 @@ +{ + "name": "graphite-web-frontend", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "graphite-web-frontend", + "license": "Apache-2.0", + "dependencies": { + "@fontsource/inconsolata": "^5.2.5", + "@fontsource/source-sans-pro": "^5.2.5", + "class-transformer": "^0.5.1", + "idb-keyval": "^6.2.1", + "reflect-metadata": "^0.2.2" + }, + "devDependencies": { + "@sveltejs/vite-plugin-svelte": "^3.1.2", + "@types/node": "^22.6.1", + "@typescript-eslint/eslint-plugin": "^8.7.0", + "@typescript-eslint/parser": "^8.7.0", + "buffer": "^6.0.3", + "concurrently": "^9.0.1", + "eslint-config-prettier": "^9.1.0", + "eslint-import-resolver-typescript": "^3.6.3", + "eslint-plugin-import": "^2.30.0", + "eslint-plugin-prettier": "^5.2.1", + "eslint-plugin-svelte": "^2.44.0", + "postcss": "^8.4.47", + "prettier": "^3.3.3", + "prettier-plugin-svelte": "^3.2.6", + "process": "^0.11.10", + "rollup-plugin-license": "^3.5.3", + "sass": "1.78.0", + "svelte": "^4.2.19", + "svelte-preprocess": "^6.0.2", + "ts-node": "^10.9.2", + "typescript": "^5.6.2", + "vite": "^5.4.14", + "vite-multiple-assets": "1.3.1" + } + }, + "node_modules/@ampproject/remapping": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz", + "integrity": "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@cspotcode/source-map-support": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", + "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/trace-mapping": "0.3.9" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@cspotcode/source-map-support/node_modules/@jridgewell/trace-mapping": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", + "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.0.3", + "@jridgewell/sourcemap-codec": "^1.4.10" + } + }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.21.5.tgz", + "integrity": "sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.21.5.tgz", + "integrity": "sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.21.5.tgz", + "integrity": "sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.21.5.tgz", + "integrity": "sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.21.5.tgz", + "integrity": "sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.21.5.tgz", + "integrity": "sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.21.5.tgz", + "integrity": "sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.21.5.tgz", + "integrity": "sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.21.5.tgz", + "integrity": "sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.21.5.tgz", + "integrity": "sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.21.5.tgz", + "integrity": "sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.21.5.tgz", + "integrity": "sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.21.5.tgz", + "integrity": "sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==", + "cpu": [ + "mips64el" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.21.5.tgz", + "integrity": "sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.21.5.tgz", + "integrity": "sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.21.5.tgz", + "integrity": "sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.21.5.tgz", + "integrity": "sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.21.5.tgz", + "integrity": "sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.21.5.tgz", + "integrity": "sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.21.5.tgz", + "integrity": "sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.21.5.tgz", + "integrity": "sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.21.5.tgz", + "integrity": "sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.21.5.tgz", + "integrity": "sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@eslint-community/eslint-utils": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", + "integrity": "sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==", + "dev": true, + "license": "MIT", + "dependencies": { + "eslint-visitor-keys": "^3.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" + } + }, + "node_modules/@eslint-community/regexpp": { + "version": "4.11.1", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.11.1.tgz", + "integrity": "sha512-m4DVN9ZqskZoLU5GlWZadwDnYo3vAEydiUayB9widCl9ffWx2IvPnp6n3on5rJmziJSw9Bv+Z3ChDVdMwXCY8Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + } + }, + "node_modules/@eslint/eslintrc": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.4.tgz", + "integrity": "sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^9.6.0", + "globals": "^13.19.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "minimatch": "^3.1.2", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint/eslintrc/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/@eslint/eslintrc/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "license": "ISC", + "peer": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/@eslint/js": { + "version": "8.57.1", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.57.1.tgz", + "integrity": "sha512-d9zaMRSTIKDLhctzH12MtXvJKSSUhaHcjV+2Z+GK+EEY7XKpP5yR4x+N3TAcHTcu963nIr+TMcCb4DBCYX1z6Q==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/@fontsource/inconsolata": { + "version": "5.2.5", + "resolved": "https://registry.npmjs.org/@fontsource/inconsolata/-/inconsolata-5.2.5.tgz", + "integrity": "sha512-OvzkZY5qYghv/jEV6cfGZzFhdFTvSnU+ExPC7WcZ7w8PdRhtiu/SpcBWOBt+3LXgS0n9qyepgq4zZmxlDTlGGQ==", + "license": "OFL-1.1", + "funding": { + "url": "https://github.com/sponsors/ayuhito" + } + }, + "node_modules/@fontsource/source-sans-pro": { + "version": "5.2.5", + "resolved": "https://registry.npmjs.org/@fontsource/source-sans-pro/-/source-sans-pro-5.2.5.tgz", + "integrity": "sha512-ypendqc4pYUc+EgF7qqPY9iVYEz1t/Qr03VojKxG/2g3dnpHa1B6DOlDxWQjQXDj5QrG6inEqGT0g+edjALZyg==", + "license": "OFL-1.1" + }, + "node_modules/@humanwhocodes/config-array": { + "version": "0.13.0", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.13.0.tgz", + "integrity": "sha512-DZLEEqFWQFiyK6h5YIeynKx7JlvCYWL0cImfSRXZ9l4Sg2efkFGTuFf6vzXjK1cq6IYkU+Eg/JizXw+TD2vRNw==", + "deprecated": "Use @eslint/config-array instead", + "dev": true, + "license": "Apache-2.0", + "peer": true, + "dependencies": { + "@humanwhocodes/object-schema": "^2.0.3", + "debug": "^4.3.1", + "minimatch": "^3.0.5" + }, + "engines": { + "node": ">=10.10.0" + } + }, + "node_modules/@humanwhocodes/config-array/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/@humanwhocodes/config-array/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "license": "ISC", + "peer": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/@humanwhocodes/module-importer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", + "dev": true, + "license": "Apache-2.0", + "peer": true, + "engines": { + "node": ">=12.22" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@humanwhocodes/object-schema": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.3.tgz", + "integrity": "sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==", + "deprecated": "Use @eslint/object-schema instead", + "dev": true, + "license": "BSD-3-Clause", + "peer": true + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz", + "integrity": "sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/set-array": "^1.2.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.24" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/set-array": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz", + "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz", + "integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.25", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", + "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nolyfill/is-core-module": { + "version": "1.0.39", + "resolved": "https://registry.npmjs.org/@nolyfill/is-core-module/-/is-core-module-1.0.39.tgz", + "integrity": "sha512-nn5ozdjYQpUCZlWGuxcJY/KpxkWQs4DcbMCmKojjyrYDEAGy4Ce19NN4v5MduafTwJlbKc99UA8YhSVqq9yPZA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.4.0" + } + }, + "node_modules/@pkgr/core": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@pkgr/core/-/core-0.1.1.tgz", + "integrity": "sha512-cq8o4cWH0ibXh9VGi5P20Tu9XF/0fFXl9EUinr9QfTM7a7p0oTA4iJRCQWppXR1Pg8dSM0UCItCkPwsk9qWWYA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.20.0 || ^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/unts" + } + }, + "node_modules/@rollup/rollup-android-arm-eabi": { + "version": "4.34.9", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.34.9.tgz", + "integrity": "sha512-qZdlImWXur0CFakn2BJ2znJOdqYZKiedEPEVNTBrpfPjc/YuTGcaYZcdmNFTkUj3DU0ZM/AElcM8Ybww3xVLzA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-android-arm64": { + "version": "4.34.9", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.34.9.tgz", + "integrity": "sha512-4KW7P53h6HtJf5Y608T1ISKvNIYLWRKMvfnG0c44M6In4DQVU58HZFEVhWINDZKp7FZps98G3gxwC1sb0wXUUg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-darwin-arm64": { + "version": "4.34.9", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.34.9.tgz", + "integrity": "sha512-0CY3/K54slrzLDjOA7TOjN1NuLKERBgk9nY5V34mhmuu673YNb+7ghaDUs6N0ujXR7fz5XaS5Aa6d2TNxZd0OQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-darwin-x64": { + "version": "4.34.9", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.34.9.tgz", + "integrity": "sha512-eOojSEAi/acnsJVYRxnMkPFqcxSMFfrw7r2iD9Q32SGkb/Q9FpUY1UlAu1DH9T7j++gZ0lHjnm4OyH2vCI7l7Q==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-freebsd-arm64": { + "version": "4.34.9", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.34.9.tgz", + "integrity": "sha512-2lzjQPJbN5UnHm7bHIUKFMulGTQwdvOkouJDpPysJS+QFBGDJqcfh+CxxtG23Ik/9tEvnebQiylYoazFMAgrYw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-freebsd-x64": { + "version": "4.34.9", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.34.9.tgz", + "integrity": "sha512-SLl0hi2Ah2H7xQYd6Qaiu01kFPzQ+hqvdYSoOtHYg/zCIFs6t8sV95kaoqjzjFwuYQLtOI0RZre/Ke0nPaQV+g==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-linux-arm-gnueabihf": { + "version": "4.34.9", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.34.9.tgz", + "integrity": "sha512-88I+D3TeKItrw+Y/2ud4Tw0+3CxQ2kLgu3QvrogZ0OfkmX/DEppehus7L3TS2Q4lpB+hYyxhkQiYPJ6Mf5/dPg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm-musleabihf": { + "version": "4.34.9", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.34.9.tgz", + "integrity": "sha512-3qyfWljSFHi9zH0KgtEPG4cBXHDFhwD8kwg6xLfHQ0IWuH9crp005GfoUUh/6w9/FWGBwEHg3lxK1iHRN1MFlA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-gnu": { + "version": "4.34.9", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.34.9.tgz", + "integrity": "sha512-6TZjPHjKZUQKmVKMUowF3ewHxctrRR09eYyvT5eFv8w/fXarEra83A2mHTVJLA5xU91aCNOUnM+DWFMSbQ0Nxw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-musl": { + "version": "4.34.9", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.34.9.tgz", + "integrity": "sha512-LD2fytxZJZ6xzOKnMbIpgzFOuIKlxVOpiMAXawsAZ2mHBPEYOnLRK5TTEsID6z4eM23DuO88X0Tq1mErHMVq0A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loongarch64-gnu": { + "version": "4.34.9", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.34.9.tgz", + "integrity": "sha512-dRAgTfDsn0TE0HI6cmo13hemKpVHOEyeciGtvlBTkpx/F65kTvShtY/EVyZEIfxFkV5JJTuQ9tP5HGBS0hfxIg==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-powerpc64le-gnu": { + "version": "4.34.9", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.34.9.tgz", + "integrity": "sha512-PHcNOAEhkoMSQtMf+rJofwisZqaU8iQ8EaSps58f5HYll9EAY5BSErCZ8qBDMVbq88h4UxaNPlbrKqfWP8RfJA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-gnu": { + "version": "4.34.9", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.34.9.tgz", + "integrity": "sha512-Z2i0Uy5G96KBYKjeQFKbbsB54xFOL5/y1P5wNBsbXB8yE+At3oh0DVMjQVzCJRJSfReiB2tX8T6HUFZ2k8iaKg==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-s390x-gnu": { + "version": "4.34.9", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.34.9.tgz", + "integrity": "sha512-U+5SwTMoeYXoDzJX5dhDTxRltSrIax8KWwfaaYcynuJw8mT33W7oOgz0a+AaXtGuvhzTr2tVKh5UO8GVANTxyQ==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-gnu": { + "version": "4.34.9", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.34.9.tgz", + "integrity": "sha512-FwBHNSOjUTQLP4MG7y6rR6qbGw4MFeQnIBrMe161QGaQoBQLqSUEKlHIiVgF3g/mb3lxlxzJOpIBhaP+C+KP2A==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-musl": { + "version": "4.34.9", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.34.9.tgz", + "integrity": "sha512-cYRpV4650z2I3/s6+5/LONkjIz8MBeqrk+vPXV10ORBnshpn8S32bPqQ2Utv39jCiDcO2eJTuSlPXpnvmaIgRA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-win32-arm64-msvc": { + "version": "4.34.9", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.34.9.tgz", + "integrity": "sha512-z4mQK9dAN6byRA/vsSgQiPeuO63wdiDxZ9yg9iyX2QTzKuQM7T4xlBoeUP/J8uiFkqxkcWndWi+W7bXdPbt27Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-ia32-msvc": { + "version": "4.34.9", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.34.9.tgz", + "integrity": "sha512-KB48mPtaoHy1AwDNkAJfHXvHp24H0ryZog28spEs0V48l3H1fr4i37tiyHsgKZJnCmvxsbATdZGBpbmxTE3a9w==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-msvc": { + "version": "4.34.9", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.34.9.tgz", + "integrity": "sha512-AyleYRPU7+rgkMWbEh71fQlrzRfeP6SyMnRf9XX4fCdDPAJumdSBqYEcWPMzVQ4ScAl7E4oFfK0GUVn77xSwbw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rtsao/scc": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@rtsao/scc/-/scc-1.1.0.tgz", + "integrity": "sha512-zt6OdqaDoOnJ1ZYsCYGt9YmWzDXl4vQdKTyJev62gFhRGKdx7mcT54V9KIjg+d2wi9EXsPvAPKe7i7WjfVWB8g==", + "dev": true, + "license": "MIT" + }, + "node_modules/@sveltejs/vite-plugin-svelte": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@sveltejs/vite-plugin-svelte/-/vite-plugin-svelte-3.1.2.tgz", + "integrity": "sha512-Txsm1tJvtiYeLUVRNqxZGKR/mI+CzuIQuc2gn+YCs9rMTowpNZ2Nqt53JdL8KF9bLhAf2ruR/dr9eZCwdTriRA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@sveltejs/vite-plugin-svelte-inspector": "^2.1.0", + "debug": "^4.3.4", + "deepmerge": "^4.3.1", + "kleur": "^4.1.5", + "magic-string": "^0.30.10", + "svelte-hmr": "^0.16.0", + "vitefu": "^0.2.5" + }, + "engines": { + "node": "^18.0.0 || >=20" + }, + "peerDependencies": { + "svelte": "^4.0.0 || ^5.0.0-next.0", + "vite": "^5.0.0" + } + }, + "node_modules/@sveltejs/vite-plugin-svelte-inspector": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@sveltejs/vite-plugin-svelte-inspector/-/vite-plugin-svelte-inspector-2.1.0.tgz", + "integrity": "sha512-9QX28IymvBlSCqsCll5t0kQVxipsfhFFL+L2t3nTWfXnddYwxBuAEtTtlaVQpRz9c37BhJjltSeY4AJSC03SSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "^4.3.4" + }, + "engines": { + "node": "^18.0.0 || >=20" + }, + "peerDependencies": { + "@sveltejs/vite-plugin-svelte": "^3.0.0", + "svelte": "^4.0.0 || ^5.0.0-next.0", + "vite": "^5.0.0" + } + }, + "node_modules/@tsconfig/node10": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.11.tgz", + "integrity": "sha512-DcRjDCujK/kCk/cUe8Xz8ZSpm8mS3mNNpta+jGCA6USEDfktlNvm1+IuZ9eTcDbNk41BHwpHHeW+N1lKCz4zOw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@tsconfig/node12": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", + "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==", + "dev": true, + "license": "MIT" + }, + "node_modules/@tsconfig/node14": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", + "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==", + "dev": true, + "license": "MIT" + }, + "node_modules/@tsconfig/node16": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.4.tgz", + "integrity": "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/estree": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.6.tgz", + "integrity": "sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/json5": { + "version": "0.0.29", + "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", + "integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/node": { + "version": "22.6.1", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.6.1.tgz", + "integrity": "sha512-V48tCfcKb/e6cVUigLAaJDAILdMP0fUW6BidkPK4GpGjXcfbnoHasCZDwz3N3yVt5we2RHm4XTQCpv0KJz9zqw==", + "dev": true, + "license": "MIT", + "dependencies": { + "undici-types": "~6.19.2" + } + }, + "node_modules/@typescript-eslint/eslint-plugin": { + "version": "8.7.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.7.0.tgz", + "integrity": "sha512-RIHOoznhA3CCfSTFiB6kBGLQtB/sox+pJ6jeFu6FxJvqL8qRxq/FfGO/UhsGgQM9oGdXkV4xUgli+dt26biB6A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/regexpp": "^4.10.0", + "@typescript-eslint/scope-manager": "8.7.0", + "@typescript-eslint/type-utils": "8.7.0", + "@typescript-eslint/utils": "8.7.0", + "@typescript-eslint/visitor-keys": "8.7.0", + "graphemer": "^1.4.0", + "ignore": "^5.3.1", + "natural-compare": "^1.4.0", + "ts-api-utils": "^1.3.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "@typescript-eslint/parser": "^8.0.0 || ^8.0.0-alpha.0", + "eslint": "^8.57.0 || ^9.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/parser": { + "version": "8.7.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.7.0.tgz", + "integrity": "sha512-lN0btVpj2unxHlNYLI//BQ7nzbMJYBVQX5+pbNXvGYazdlgYonMn4AhhHifQ+J4fGRYA/m1DjaQjx+fDetqBOQ==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "@typescript-eslint/scope-manager": "8.7.0", + "@typescript-eslint/types": "8.7.0", + "@typescript-eslint/typescript-estree": "8.7.0", + "@typescript-eslint/visitor-keys": "8.7.0", + "debug": "^4.3.4" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/scope-manager": { + "version": "8.7.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.7.0.tgz", + "integrity": "sha512-87rC0k3ZlDOuz82zzXRtQ7Akv3GKhHs0ti4YcbAJtaomllXoSO8hi7Ix3ccEvCd824dy9aIX+j3d2UMAfCtVpg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.7.0", + "@typescript-eslint/visitor-keys": "8.7.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/type-utils": { + "version": "8.7.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.7.0.tgz", + "integrity": "sha512-tl0N0Mj3hMSkEYhLkjREp54OSb/FI6qyCzfiiclvJvOqre6hsZTGSnHtmFLDU8TIM62G7ygEa1bI08lcuRwEnQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/typescript-estree": "8.7.0", + "@typescript-eslint/utils": "8.7.0", + "debug": "^4.3.4", + "ts-api-utils": "^1.3.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/types": { + "version": "8.7.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.7.0.tgz", + "integrity": "sha512-LLt4BLHFwSfASHSF2K29SZ+ZCsbQOM+LuarPjRUuHm+Qd09hSe3GCeaQbcCr+Mik+0QFRmep/FyZBO6fJ64U3w==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/typescript-estree": { + "version": "8.7.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.7.0.tgz", + "integrity": "sha512-MC8nmcGHsmfAKxwnluTQpNqceniT8SteVwd2voYlmiSWGOtjvGXdPl17dYu2797GVscK30Z04WRM28CrKS9WOg==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "@typescript-eslint/types": "8.7.0", + "@typescript-eslint/visitor-keys": "8.7.0", + "debug": "^4.3.4", + "fast-glob": "^3.3.2", + "is-glob": "^4.0.3", + "minimatch": "^9.0.4", + "semver": "^7.6.0", + "ts-api-utils": "^1.3.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/utils": { + "version": "8.7.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.7.0.tgz", + "integrity": "sha512-ZbdUdwsl2X/s3CiyAu3gOlfQzpbuG3nTWKPoIvAu1pu5r8viiJvv2NPN2AqArL35NCYtw/lrPPfM4gxrMLNLPw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.4.0", + "@typescript-eslint/scope-manager": "8.7.0", + "@typescript-eslint/types": "8.7.0", + "@typescript-eslint/typescript-estree": "8.7.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0" + } + }, + "node_modules/@typescript-eslint/visitor-keys": { + "version": "8.7.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.7.0.tgz", + "integrity": "sha512-b1tx0orFCCh/THWPQa2ZwWzvOeyzzp36vkJYOpVg0u8UVOIsfVrnuC9FqAw9gRKn+rG2VmWQ/zDJZzkxUnj/XQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.7.0", + "eslint-visitor-keys": "^3.4.3" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@ungap/structured-clone": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.2.0.tgz", + "integrity": "sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==", + "dev": true, + "license": "ISC", + "peer": true + }, + "node_modules/acorn": { + "version": "8.12.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.12.1.tgz", + "integrity": "sha512-tcpGyI9zbizT9JbV6oYE477V6mTlXvvi0T0G3SNIYE2apm/G5huBa1+K89VGeovbg+jycCrfhl3ADxErOuO6Jg==", + "dev": true, + "license": "MIT", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/acorn-walk": { + "version": "8.3.4", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.4.tgz", + "integrity": "sha512-ueEepnujpqee2o5aIYnvHU6C0A42MNdsIDeqy5BydrkuC5R1ZuUFnm27EeFJGoEHJQgn3uleRvmTXaJgfXbt4g==", + "dev": true, + "license": "MIT", + "dependencies": { + "acorn": "^8.11.0" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "dev": true, + "license": "ISC", + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/arg": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", + "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", + "dev": true, + "license": "MIT" + }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true, + "license": "Python-2.0", + "peer": true + }, + "node_modules/aria-query": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.3.2.tgz", + "integrity": "sha512-COROpnaoap1E2F000S62r6A60uHZnmlvomhfyT2DlTcrY1OrBKn2UhH7qn5wTC9zMvD0AY7csdPSNwKP+7WiQw==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/array-buffer-byte-length": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.1.tgz", + "integrity": "sha512-ahC5W1xgou+KTXix4sAO8Ki12Q+jf4i0+tmk3sC+zgcynshkHxzpXdImBehiUYKKKDwvfFiJl1tZt6ewscS1Mg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.5", + "is-array-buffer": "^3.0.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array-find-index": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/array-find-index/-/array-find-index-1.0.2.tgz", + "integrity": "sha512-M1HQyIXcBGtVywBt8WVdim+lrNaK7VHp99Qt5pSNziXznKHViIBbXWtfRTpEFpF/c4FdfxNAsCCwPp5phBYJtw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/array-includes": { + "version": "3.1.8", + "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.8.tgz", + "integrity": "sha512-itaWrbYbqpGXkGhZPGUulwnhVf5Hpy1xiCFsGqyIGglbBxmG5vSjxQen3/WGOjPpNEv1RtBLKxbmVXm8HpJStQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2", + "es-object-atoms": "^1.0.0", + "get-intrinsic": "^1.2.4", + "is-string": "^1.0.7" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array.prototype.findlastindex": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/array.prototype.findlastindex/-/array.prototype.findlastindex-1.2.5.tgz", + "integrity": "sha512-zfETvRFA8o7EiNn++N5f/kaCw221hrpGsDmcpndVupkPzEc1Wuf3VgC0qby1BbHs7f5DVYjgtEU2LLh5bqeGfQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0", + "es-shim-unscopables": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array.prototype.flat": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.2.tgz", + "integrity": "sha512-djYB+Zx2vLewY8RWlNCUdHjDXs2XOgm602S9E7P/UpHgfeHL00cRiIF+IN/G/aUJ7kGPb6yO/ErDI5V2s8iycA==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "es-shim-unscopables": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array.prototype.flatmap": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.3.2.tgz", + "integrity": "sha512-Ewyx0c9PmpcsByhSW4r+9zDU7sGjFc86qf/kKtuSCRdhfbk0SNLLkaT5qvcHnRGgc5NP/ly/y+qkXkqONX54CQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "es-shim-unscopables": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/arraybuffer.prototype.slice": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.3.tgz", + "integrity": "sha512-bMxMKAjg13EBSVscxTaYA4mRc5t1UAXa2kXiGTNfZ079HIWXEkKmkgFrh/nJqamaLSrXO5H4WFFkPEaLJWbs3A==", + "dev": true, + "license": "MIT", + "dependencies": { + "array-buffer-byte-length": "^1.0.1", + "call-bind": "^1.0.5", + "define-properties": "^1.2.1", + "es-abstract": "^1.22.3", + "es-errors": "^1.2.1", + "get-intrinsic": "^1.2.3", + "is-array-buffer": "^3.0.4", + "is-shared-array-buffer": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/available-typed-arrays": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz", + "integrity": "sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "possible-typed-array-names": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/axobject-query": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-4.1.0.tgz", + "integrity": "sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/binary-extensions": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", + "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/braces": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "dev": true, + "license": "MIT", + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/buffer": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", + "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.2.1" + } + }, + "node_modules/call-bind": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz", + "integrity": "sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "set-function-length": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/chalk/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/chokidar": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", + "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", + "dev": true, + "license": "MIT", + "dependencies": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/chokidar/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/class-transformer": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/class-transformer/-/class-transformer-0.5.1.tgz", + "integrity": "sha512-SQa1Ws6hUbfC98vKGxZH3KFY0Y1lm5Zm0SY8XX9zbK7FJCyVEac3ATW0RIpwzW+oOfmHE5PMPufDG9hCfoEOMw==", + "license": "MIT" + }, + "node_modules/cliui": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/code-red": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/code-red/-/code-red-1.0.4.tgz", + "integrity": "sha512-7qJWqItLA8/VPVlKJlFXU+NBlo/qyfs39aJcuMT/2ere32ZqvF5OSxgdM5xOfJJ7O429gg2HM47y8v9P+9wrNw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.4.15", + "@types/estree": "^1.0.1", + "acorn": "^8.10.0", + "estree-walker": "^3.0.3", + "periscopic": "^3.1.0" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true, + "license": "MIT" + }, + "node_modules/commenting": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/commenting/-/commenting-1.1.0.tgz", + "integrity": "sha512-YeNK4tavZwtH7jEgK1ZINXzLKm6DZdEMfsaaieOsCAN0S8vsY7UeuO3Q7d/M018EFgE+IeUAuBOKkFccBZsUZA==", + "dev": true, + "license": "MIT" + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true, + "license": "MIT" + }, + "node_modules/concurrently": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/concurrently/-/concurrently-9.0.1.tgz", + "integrity": "sha512-wYKvCd/f54sTXJMSfV6Ln/B8UrfLBKOYa+lzc6CHay3Qek+LorVSBdMVfyewFhRbH0Rbabsk4D+3PL/VjQ5gzg==", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "^4.1.2", + "lodash": "^4.17.21", + "rxjs": "^7.8.1", + "shell-quote": "^1.8.1", + "supports-color": "^8.1.1", + "tree-kill": "^1.2.2", + "yargs": "^17.7.2" + }, + "bin": { + "conc": "dist/bin/concurrently.js", + "concurrently": "dist/bin/concurrently.js" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/open-cli-tools/concurrently?sponsor=1" + } + }, + "node_modules/create-require": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", + "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/cross-spawn": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/css-tree": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-2.3.1.tgz", + "integrity": "sha512-6Fv1DV/TYw//QF5IzQdqsNDjx/wc8TrMBZsqjL9eW01tWb7R7k/mq+/VXfJCl7SoD5emsJop9cOByJZfs8hYIw==", + "dev": true, + "license": "MIT", + "dependencies": { + "mdn-data": "2.0.30", + "source-map-js": "^1.0.1" + }, + "engines": { + "node": "^10 || ^12.20.0 || ^14.13.0 || >=15.0.0" + } + }, + "node_modules/cssesc": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", + "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", + "dev": true, + "license": "MIT", + "bin": { + "cssesc": "bin/cssesc" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/data-view-buffer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/data-view-buffer/-/data-view-buffer-1.0.1.tgz", + "integrity": "sha512-0lht7OugA5x3iJLOWFhWK/5ehONdprk0ISXqVFn/NFrDu+cuc8iADFrGQz5BnRK7LLU3JmkbXSxaqX+/mXYtUA==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.6", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/data-view-byte-length": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/data-view-byte-length/-/data-view-byte-length-1.0.1.tgz", + "integrity": "sha512-4J7wRJD3ABAzr8wP+OcIcqq2dlUKp4DVflx++hs5h5ZKydWMI6/D/fAot+yh6g2tHh8fLFTvNOaVN357NvSrOQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/data-view-byte-offset": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/data-view-byte-offset/-/data-view-byte-offset-1.0.0.tgz", + "integrity": "sha512-t/Ygsytq+R995EJ5PZlD4Cu56sWa8InXySaViRzw9apusqsOO2bQP+SbYzAhR0pFKoB+43lYy8rWban9JSuXnA==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.6", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/debug": { + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz", + "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true, + "license": "MIT", + "peer": true + }, + "node_modules/deepmerge": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", + "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/define-data-property": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", + "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "gopd": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/define-properties": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz", + "integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==", + "dev": true, + "license": "MIT", + "dependencies": { + "define-data-property": "^1.0.1", + "has-property-descriptors": "^1.0.0", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/diff": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", + "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.3.1" + } + }, + "node_modules/doctrine": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "dev": true, + "license": "Apache-2.0", + "peer": true, + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true, + "license": "MIT" + }, + "node_modules/enhanced-resolve": { + "version": "5.17.1", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.17.1.tgz", + "integrity": "sha512-LMHl3dXhTcfv8gM4kEzIUeTQ+7fpdA0l2tUf34BddXPkz2A5xJ5L/Pchd5BL6rdccM9QGvu0sWZzK1Z1t4wwyg==", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.4", + "tapable": "^2.2.0" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/es-abstract": { + "version": "1.23.3", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.23.3.tgz", + "integrity": "sha512-e+HfNH61Bj1X9/jLc5v1owaLYuHdeHHSQlkhCBiTK8rBvKaULl/beGMxwrMXjpYrv4pz22BlY570vVePA2ho4A==", + "dev": true, + "license": "MIT", + "dependencies": { + "array-buffer-byte-length": "^1.0.1", + "arraybuffer.prototype.slice": "^1.0.3", + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.7", + "data-view-buffer": "^1.0.1", + "data-view-byte-length": "^1.0.1", + "data-view-byte-offset": "^1.0.0", + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0", + "es-set-tostringtag": "^2.0.3", + "es-to-primitive": "^1.2.1", + "function.prototype.name": "^1.1.6", + "get-intrinsic": "^1.2.4", + "get-symbol-description": "^1.0.2", + "globalthis": "^1.0.3", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.2", + "has-proto": "^1.0.3", + "has-symbols": "^1.0.3", + "hasown": "^2.0.2", + "internal-slot": "^1.0.7", + "is-array-buffer": "^3.0.4", + "is-callable": "^1.2.7", + "is-data-view": "^1.0.1", + "is-negative-zero": "^2.0.3", + "is-regex": "^1.1.4", + "is-shared-array-buffer": "^1.0.3", + "is-string": "^1.0.7", + "is-typed-array": "^1.1.13", + "is-weakref": "^1.0.2", + "object-inspect": "^1.13.1", + "object-keys": "^1.1.1", + "object.assign": "^4.1.5", + "regexp.prototype.flags": "^1.5.2", + "safe-array-concat": "^1.1.2", + "safe-regex-test": "^1.0.3", + "string.prototype.trim": "^1.2.9", + "string.prototype.trimend": "^1.0.8", + "string.prototype.trimstart": "^1.0.8", + "typed-array-buffer": "^1.0.2", + "typed-array-byte-length": "^1.0.1", + "typed-array-byte-offset": "^1.0.2", + "typed-array-length": "^1.0.6", + "unbox-primitive": "^1.0.2", + "which-typed-array": "^1.1.15" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/es-define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.0.tgz", + "integrity": "sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "get-intrinsic": "^1.2.4" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-object-atoms": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.0.0.tgz", + "integrity": "sha512-MZ4iQ6JwHOBQjahnjwaC1ZtIBH+2ohjamzAO3oaHcXYup7qxjF2fixyH+Q71voWHeOkI2q/TnJao/KfXYIZWbw==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-set-tostringtag": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.0.3.tgz", + "integrity": "sha512-3T8uNMC3OQTHkFUsFq8r/BwAXLHvU/9O9mE0fBc/MY5iq/8H7ncvO947LmYA6ldWw9Uh8Yhf25zu6n7nML5QWQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "get-intrinsic": "^1.2.4", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.1" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-shim-unscopables": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.0.2.tgz", + "integrity": "sha512-J3yBRXCzDu4ULnQwxyToo/OjdMx6akgVC7K6few0a7F/0wLtmKKN7I73AH5T2836UuXRqN7Qg+IIUw/+YJksRw==", + "dev": true, + "license": "MIT", + "dependencies": { + "hasown": "^2.0.0" + } + }, + "node_modules/es-to-primitive": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", + "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-callable": "^1.1.4", + "is-date-object": "^1.0.1", + "is-symbol": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/esbuild": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.21.5.tgz", + "integrity": "sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=12" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.21.5", + "@esbuild/android-arm": "0.21.5", + "@esbuild/android-arm64": "0.21.5", + "@esbuild/android-x64": "0.21.5", + "@esbuild/darwin-arm64": "0.21.5", + "@esbuild/darwin-x64": "0.21.5", + "@esbuild/freebsd-arm64": "0.21.5", + "@esbuild/freebsd-x64": "0.21.5", + "@esbuild/linux-arm": "0.21.5", + "@esbuild/linux-arm64": "0.21.5", + "@esbuild/linux-ia32": "0.21.5", + "@esbuild/linux-loong64": "0.21.5", + "@esbuild/linux-mips64el": "0.21.5", + "@esbuild/linux-ppc64": "0.21.5", + "@esbuild/linux-riscv64": "0.21.5", + "@esbuild/linux-s390x": "0.21.5", + "@esbuild/linux-x64": "0.21.5", + "@esbuild/netbsd-x64": "0.21.5", + "@esbuild/openbsd-x64": "0.21.5", + "@esbuild/sunos-x64": "0.21.5", + "@esbuild/win32-arm64": "0.21.5", + "@esbuild/win32-ia32": "0.21.5", + "@esbuild/win32-x64": "0.21.5" + } + }, + "node_modules/escalade": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint": { + "version": "8.57.1", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.57.1.tgz", + "integrity": "sha512-ypowyDxpVSYpkXr9WPv2PAZCtNip1Mv5KTW0SCurXv/9iOpcrH9PaqUElksqEB6pChqHGDRCFTyrZlGhnLNGiA==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@eslint-community/eslint-utils": "^4.2.0", + "@eslint-community/regexpp": "^4.6.1", + "@eslint/eslintrc": "^2.1.4", + "@eslint/js": "8.57.1", + "@humanwhocodes/config-array": "^0.13.0", + "@humanwhocodes/module-importer": "^1.0.1", + "@nodelib/fs.walk": "^1.2.8", + "@ungap/structured-clone": "^1.2.0", + "ajv": "^6.12.4", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.2", + "debug": "^4.3.2", + "doctrine": "^3.0.0", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^7.2.2", + "eslint-visitor-keys": "^3.4.3", + "espree": "^9.6.1", + "esquery": "^1.4.2", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^6.0.1", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "globals": "^13.19.0", + "graphemer": "^1.4.0", + "ignore": "^5.2.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "is-path-inside": "^3.0.3", + "js-yaml": "^4.1.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.4.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.1.2", + "natural-compare": "^1.4.0", + "optionator": "^0.9.3", + "strip-ansi": "^6.0.1", + "text-table": "^0.2.0" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-compat-utils": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/eslint-compat-utils/-/eslint-compat-utils-0.5.1.tgz", + "integrity": "sha512-3z3vFexKIEnjHE3zCMRo6fn/e44U7T1khUjg+Hp0ZQMCigh28rALD0nPFBcGZuiLC5rLZa2ubQHDRln09JfU2Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "semver": "^7.5.4" + }, + "engines": { + "node": ">=12" + }, + "peerDependencies": { + "eslint": ">=6.0.0" + } + }, + "node_modules/eslint-config-prettier": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-9.1.0.tgz", + "integrity": "sha512-NSWl5BFQWEPi1j4TjVNItzYV7dZXZ+wP6I6ZhrBGpChQhZRUaElihE9uRRkcbRnNb76UMKDF3r+WTmNcGPKsqw==", + "dev": true, + "license": "MIT", + "bin": { + "eslint-config-prettier": "bin/cli.js" + }, + "peerDependencies": { + "eslint": ">=7.0.0" + } + }, + "node_modules/eslint-import-resolver-node": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.9.tgz", + "integrity": "sha512-WFj2isz22JahUv+B788TlO3N6zL3nNJGU8CcZbPZvVEkBPaJdCV4vy5wyghty5ROFbCRnm132v8BScu5/1BQ8g==", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "^3.2.7", + "is-core-module": "^2.13.0", + "resolve": "^1.22.4" + } + }, + "node_modules/eslint-import-resolver-node/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/eslint-import-resolver-typescript": { + "version": "3.6.3", + "resolved": "https://registry.npmjs.org/eslint-import-resolver-typescript/-/eslint-import-resolver-typescript-3.6.3.tgz", + "integrity": "sha512-ud9aw4szY9cCT1EWWdGv1L1XR6hh2PaRWif0j2QjQ0pgTY/69iw+W0Z4qZv5wHahOl8isEr+k/JnyAqNQkLkIA==", + "dev": true, + "license": "ISC", + "dependencies": { + "@nolyfill/is-core-module": "1.0.39", + "debug": "^4.3.5", + "enhanced-resolve": "^5.15.0", + "eslint-module-utils": "^2.8.1", + "fast-glob": "^3.3.2", + "get-tsconfig": "^4.7.5", + "is-bun-module": "^1.0.2", + "is-glob": "^4.0.3" + }, + "engines": { + "node": "^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/unts/projects/eslint-import-resolver-ts" + }, + "peerDependencies": { + "eslint": "*", + "eslint-plugin-import": "*", + "eslint-plugin-import-x": "*" + }, + "peerDependenciesMeta": { + "eslint-plugin-import": { + "optional": true + }, + "eslint-plugin-import-x": { + "optional": true + } + } + }, + "node_modules/eslint-module-utils": { + "version": "2.11.0", + "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.11.0.tgz", + "integrity": "sha512-gbBE5Hitek/oG6MUVj6sFuzEjA/ClzNflVrLovHi/JgLdC7fiN5gLAY1WIPW1a0V5I999MnsrvVrCOGmmVqDBQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "^3.2.7" + }, + "engines": { + "node": ">=4" + }, + "peerDependenciesMeta": { + "eslint": { + "optional": true + } + } + }, + "node_modules/eslint-module-utils/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/eslint-plugin-import": { + "version": "2.30.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.30.0.tgz", + "integrity": "sha512-/mHNE9jINJfiD2EKkg1BKyPyUk4zdnT54YgbOgfjSakWT5oyX/qQLVNTkehyfpcMxZXMy1zyonZ2v7hZTX43Yw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@rtsao/scc": "^1.1.0", + "array-includes": "^3.1.8", + "array.prototype.findlastindex": "^1.2.5", + "array.prototype.flat": "^1.3.2", + "array.prototype.flatmap": "^1.3.2", + "debug": "^3.2.7", + "doctrine": "^2.1.0", + "eslint-import-resolver-node": "^0.3.9", + "eslint-module-utils": "^2.9.0", + "hasown": "^2.0.2", + "is-core-module": "^2.15.1", + "is-glob": "^4.0.3", + "minimatch": "^3.1.2", + "object.fromentries": "^2.0.8", + "object.groupby": "^1.0.3", + "object.values": "^1.2.0", + "semver": "^6.3.1", + "tsconfig-paths": "^3.15.0" + }, + "engines": { + "node": ">=4" + }, + "peerDependencies": { + "eslint": "^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8" + } + }, + "node_modules/eslint-plugin-import/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/eslint-plugin-import/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/eslint-plugin-import/node_modules/doctrine": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", + "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/eslint-plugin-import/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/eslint-plugin-import/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/eslint-plugin-prettier": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-5.2.1.tgz", + "integrity": "sha512-gH3iR3g4JfF+yYPaJYkN7jEl9QbweL/YfkoRlNnuIEHEz1vHVlCmWOS+eGGiRuzHQXdJFCOTxRgvju9b8VUmrw==", + "dev": true, + "license": "MIT", + "dependencies": { + "prettier-linter-helpers": "^1.0.0", + "synckit": "^0.9.1" + }, + "engines": { + "node": "^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint-plugin-prettier" + }, + "peerDependencies": { + "@types/eslint": ">=8.0.0", + "eslint": ">=8.0.0", + "eslint-config-prettier": "*", + "prettier": ">=3.0.0" + }, + "peerDependenciesMeta": { + "@types/eslint": { + "optional": true + }, + "eslint-config-prettier": { + "optional": true + } + } + }, + "node_modules/eslint-plugin-svelte": { + "version": "2.44.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-svelte/-/eslint-plugin-svelte-2.44.0.tgz", + "integrity": "sha512-wav4MOs02vBb1WjvTCYItwJCxMkuk2Z4p+K/eyjL0N/z7ahXLP+0LtQQjiKc2ezuif7GnZLbD1F3o1VHzSvdVg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.4.0", + "@jridgewell/sourcemap-codec": "^1.4.15", + "eslint-compat-utils": "^0.5.1", + "esutils": "^2.0.3", + "known-css-properties": "^0.34.0", + "postcss": "^8.4.38", + "postcss-load-config": "^3.1.4", + "postcss-safe-parser": "^6.0.0", + "postcss-selector-parser": "^6.1.0", + "semver": "^7.6.2", + "svelte-eslint-parser": "^0.41.1" + }, + "engines": { + "node": "^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ota-meshi" + }, + "peerDependencies": { + "eslint": "^7.0.0 || ^8.0.0-0 || ^9.0.0-0", + "svelte": "^3.37.0 || ^4.0.0 || ^5.0.0-next.191" + }, + "peerDependenciesMeta": { + "svelte": { + "optional": true + } + } + }, + "node_modules/eslint-scope": { + "version": "7.2.2", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz", + "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/eslint/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "license": "ISC", + "peer": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/espree": { + "version": "9.6.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", + "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "acorn": "^8.9.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^3.4.1" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/esquery": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.6.0.tgz", + "integrity": "sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==", + "dev": true, + "license": "BSD-3-Clause", + "peer": true, + "dependencies": { + "estraverse": "^5.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estree-walker": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz", + "integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0" + } + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true, + "license": "MIT", + "peer": true + }, + "node_modules/fast-diff": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.3.0.tgz", + "integrity": "sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw==", + "dev": true, + "license": "Apache-2.0" + }, + "node_modules/fast-glob": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz", + "integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.4" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/fast-glob/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true, + "license": "MIT", + "peer": true + }, + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", + "dev": true, + "license": "MIT", + "peer": true + }, + "node_modules/fastq": { + "version": "1.17.1", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.17.1.tgz", + "integrity": "sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==", + "dev": true, + "license": "ISC", + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/file-entry-cache": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", + "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "flat-cache": "^3.0.4" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/fill-range": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "dev": true, + "license": "MIT", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/flat-cache": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.2.0.tgz", + "integrity": "sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "flatted": "^3.2.9", + "keyv": "^4.5.3", + "rimraf": "^3.0.2" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/flatted": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.1.tgz", + "integrity": "sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==", + "dev": true, + "license": "ISC", + "peer": true + }, + "node_modules/for-each": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", + "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-callable": "^1.1.3" + } + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "dev": true, + "license": "ISC", + "peer": true + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/function.prototype.name": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.6.tgz", + "integrity": "sha512-Z5kx79swU5P27WEayXM1tBi5Ze/lbIyiNgU3qyXUOf9b2rgXYyF9Dy9Cx+IQv/Lc8WCG6L82zwUPpSS9hGehIg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "functions-have-names": "^1.2.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/functions-have-names": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", + "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true, + "license": "ISC", + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/get-intrinsic": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz", + "integrity": "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "has-proto": "^1.0.1", + "has-symbols": "^1.0.3", + "hasown": "^2.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-symbol-description": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.2.tgz", + "integrity": "sha512-g0QYk1dZBxGwk+Ngc+ltRH2IBp2f7zBkBMBJZCDerh6EhlhSR6+9irMCuT/09zD6qkarHUSn529sK/yL4S27mg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.5", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-tsconfig": { + "version": "4.8.1", + "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.8.1.tgz", + "integrity": "sha512-k9PN+cFBmaLWtVz29SkUoqU5O0slLuHJXt/2P+tMVFT+phsSGXGkp9t3rQIqdz0e+06EHNGs3oM6ZX1s2zHxRg==", + "dev": true, + "license": "MIT", + "dependencies": { + "resolve-pkg-maps": "^1.0.0" + }, + "funding": { + "url": "https://github.com/privatenumber/get-tsconfig?sponsor=1" + } + }, + "node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Glob versions prior to v9 are no longer supported", + "dev": true, + "license": "ISC", + "peer": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "license": "ISC", + "peer": true, + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/glob/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/glob/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "license": "ISC", + "peer": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/globals": { + "version": "13.24.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", + "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "type-fest": "^0.20.2" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/globalthis": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.4.tgz", + "integrity": "sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "define-properties": "^1.2.1", + "gopd": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/gopd": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", + "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", + "dev": true, + "license": "MIT", + "dependencies": { + "get-intrinsic": "^1.1.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/graphemer": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", + "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", + "dev": true, + "license": "MIT" + }, + "node_modules/has-bigints": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz", + "integrity": "sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/has-property-descriptors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", + "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-define-property": "^1.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-proto": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.3.tgz", + "integrity": "sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-symbols": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", + "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-tostringtag": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", + "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-symbols": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/idb-keyval": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/idb-keyval/-/idb-keyval-6.2.1.tgz", + "integrity": "sha512-8Sb3veuYCyrZL+VBt9LJfZjLUPWVvqn8tG28VqYNFCo43KHcKuq+b4EiXGeuaLAQWL2YmyDgMp2aSpH9JHsEQg==", + "license": "Apache-2.0" + }, + "node_modules/ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "BSD-3-Clause" + }, + "node_modules/ignore": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", + "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/immutable": { + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/immutable/-/immutable-4.3.7.tgz", + "integrity": "sha512-1hqclzwYwjRDFLjcFxOM5AYkkG0rpFPpr1RLPMEuGczoS7YA8gLhy8SWXYRAA/XwfEHpfo3cw5JGioS32fnMRw==", + "dev": true, + "license": "MIT" + }, + "node_modules/import-fresh": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", + "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", + "dev": true, + "license": "ISC", + "peer": true, + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true, + "license": "ISC", + "peer": true + }, + "node_modules/internal-slot": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.7.tgz", + "integrity": "sha512-NGnrKwXzSms2qUUih/ILZ5JBqNTSa1+ZmP6flaIp6KmSElgE9qdndzS3cqjrDovwFdmwsGsLdeFgB6suw+1e9g==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "hasown": "^2.0.0", + "side-channel": "^1.0.4" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/is-array-buffer": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.4.tgz", + "integrity": "sha512-wcjaerHw0ydZwfhiKbXJWLDY8A7yV7KhjQOpb83hGgGfId/aQa4TOvwyzn2PuswW2gPCYEL/nEAiSVpdOj1lXw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-bigint": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz", + "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-bigints": "^1.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, + "license": "MIT", + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-boolean-object": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz", + "integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-bun-module": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/is-bun-module/-/is-bun-module-1.2.1.tgz", + "integrity": "sha512-AmidtEM6D6NmUiLOvvU7+IePxjEjOzra2h0pSrsfSAcXwl/83zLLXDByafUJy9k/rKK0pvXMLdwKwGHlX2Ke6Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "semver": "^7.6.3" + } + }, + "node_modules/is-callable": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", + "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-core-module": { + "version": "2.15.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.15.1.tgz", + "integrity": "sha512-z0vtXSwucUJtANQWldhbtbt7BnL0vxiFjIdDLAatwhDYty2bad6s+rijD6Ri4YuYJubLzIJLUidCh09e1djEVQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-data-view": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-data-view/-/is-data-view-1.0.1.tgz", + "integrity": "sha512-AHkaJrsUVW6wq6JS8y3JnM/GJF/9cf+k20+iDzlSaJrinEo5+7vRiteOSwBhHRiAyQATN1AmY4hwzxJKPmYf+w==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-typed-array": "^1.1.13" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-date-object": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz", + "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-negative-zero": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.3.tgz", + "integrity": "sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-number-object": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.7.tgz", + "integrity": "sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-path-inside": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", + "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-reference": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/is-reference/-/is-reference-3.0.2.tgz", + "integrity": "sha512-v3rht/LgVcsdZa3O2Nqs+NMowLOxeOm7Ay9+/ARQ2F+qEoANRcqrjAZKGN0v8ymUetZGgkp26LTnGT7H0Qo9Pg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "*" + } + }, + "node_modules/is-regex": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", + "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-shared-array-buffer": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.3.tgz", + "integrity": "sha512-nA2hv5XIhLR3uVzDDfCIknerhx8XUKnstuOERPNNIinXG7v9u+ohXF67vxm4TPTEPU6lm61ZkwP3c9PCB97rhg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-string": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", + "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-symbol": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz", + "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-symbols": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-typed-array": { + "version": "1.1.13", + "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.13.tgz", + "integrity": "sha512-uZ25/bUAlUY5fR4OKT4rZQEBrzQWYV9ZJYGGsUmEJ6thodVJ1HX64ePQ6Z0qPWP+m+Uq6e9UugrE38jeYsDSMw==", + "dev": true, + "license": "MIT", + "dependencies": { + "which-typed-array": "^1.1.14" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-weakref": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz", + "integrity": "sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/isarray": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", + "dev": true, + "license": "MIT" + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true, + "license": "ISC", + "peer": true + }, + "node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", + "dev": true, + "license": "MIT", + "peer": true + }, + "node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true, + "license": "MIT", + "peer": true + }, + "node_modules/json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", + "dev": true, + "license": "MIT", + "peer": true + }, + "node_modules/json5": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz", + "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==", + "dev": true, + "license": "MIT", + "dependencies": { + "minimist": "^1.2.0" + }, + "bin": { + "json5": "lib/cli.js" + } + }, + "node_modules/keyv": { + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", + "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "json-buffer": "3.0.1" + } + }, + "node_modules/kleur": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/kleur/-/kleur-4.1.5.tgz", + "integrity": "sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/known-css-properties": { + "version": "0.34.0", + "resolved": "https://registry.npmjs.org/known-css-properties/-/known-css-properties-0.34.0.tgz", + "integrity": "sha512-tBECoUqNFbyAY4RrbqsBQqDFpGXAEbdD5QKr8kACx3+rnArmuuR22nKQWKazvp07N9yjTyDZaw/20UIH8tL9DQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/lilconfig": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.1.0.tgz", + "integrity": "sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + } + }, + "node_modules/locate-character": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/locate-character/-/locate-character-3.0.0.tgz", + "integrity": "sha512-SW13ws7BjaeJ6p7Q6CO2nchbYEc3X3J6WrmTTDto7yMPqVSZTUyY5Tjbid+Ab8gLnATtygYtiDIJGQRRn2ZOiA==", + "dev": true, + "license": "MIT" + }, + "node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "dev": true, + "license": "MIT", + "peer": true + }, + "node_modules/magic-string": { + "version": "0.30.11", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.11.tgz", + "integrity": "sha512-+Wri9p0QHMy+545hKww7YAu5NyzF8iomPL/RQazugQ9+Ez4Ic3mERMd8ZTX5rfK944j+560ZJi8iAwgak1Ac7A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.0" + } + }, + "node_modules/make-error": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", + "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", + "dev": true, + "license": "ISC" + }, + "node_modules/mdn-data": { + "version": "2.0.30", + "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.30.tgz", + "integrity": "sha512-GaqWWShW4kv/G9IEucWScBx9G1/vsFZZJUO+tD26M8J8z3Kw5RDQjaoZe03YAClgeS/SWPOcb4nkFBTEi5DUEA==", + "dev": true, + "license": "CC0-1.0" + }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/micromatch": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", + "dev": true, + "license": "MIT", + "dependencies": { + "braces": "^3.0.3", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/minimatch": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/moment": { + "version": "2.30.1", + "resolved": "https://registry.npmjs.org/moment/-/moment-2.30.1.tgz", + "integrity": "sha512-uEmtNhbDOrWPFS+hdjFCBfy9f2YoyzRpwcl+DqpC6taX21FzsTLQVbMV/W7PzNSX6x/bhC1zA3c2UQ5NzH6how==", + "dev": true, + "license": "MIT", + "engines": { + "node": "*" + } + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true, + "license": "MIT" + }, + "node_modules/nanoid": { + "version": "3.3.9", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.9.tgz", + "integrity": "sha512-SppoicMGpZvbF1l3z4x7No3OlIjP7QJvC9XR7AhZr1kL133KHnKPztkKDc+Ir4aJ/1VhTySrtKhrsycmrMQfvg==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "dev": true, + "license": "MIT" + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-inspect": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.2.tgz", + "integrity": "sha512-IRZSRuzJiynemAXPYtPe5BoI/RESNYR7TYm50MC5Mqbd3Jmw5y790sErYw3V6SryFJD64b74qQQs9wn5Bg/k3g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/object.assign": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.5.tgz", + "integrity": "sha512-byy+U7gp+FVwmyzKPYhW2h5l3crpmGsxl7X2s8y43IgxvG4g3QZ6CffDtsNQy1WsmZpQbO+ybo0AlW7TY6DcBQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.5", + "define-properties": "^1.2.1", + "has-symbols": "^1.0.3", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object.fromentries": { + "version": "2.0.8", + "resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.8.tgz", + "integrity": "sha512-k6E21FzySsSK5a21KRADBd/NGneRegFO5pLHfdQLpRDETUNJueLXs3WCzyQ3tFRDYgbq3KHGXfTbi2bs8WQ6rQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object.groupby": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/object.groupby/-/object.groupby-1.0.3.tgz", + "integrity": "sha512-+Lhy3TQTuzXI5hevh8sBGqbmurHbbIjAi0Z4S63nthVLmLxfbj4T54a4CfZrXIrt9iP4mVAPYMo/v99taj3wjQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/object.values": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.2.0.tgz", + "integrity": "sha512-yBYjY9QX2hnRmZHAjG/f13MzmBzxzYgQhFrke06TTyKY5zSTEqkOeukBzIdVA3j3ulu8Qa3MbVFShV7T2RmGtQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dev": true, + "license": "ISC", + "peer": true, + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/optionator": { + "version": "0.9.4", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", + "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.5" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/package-name-regex": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/package-name-regex/-/package-name-regex-2.0.6.tgz", + "integrity": "sha512-gFL35q7kbE/zBaPA3UKhp2vSzcPYx2ecbYuwv1ucE9Il6IIgBDweBlH8D68UFGZic2MkllKa2KHCfC1IQBQUYA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/dword-design" + } + }, + "node_modules/parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "dev": true, + "license": "MIT" + }, + "node_modules/periscopic": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/periscopic/-/periscopic-3.1.0.tgz", + "integrity": "sha512-vKiQ8RRtkl9P+r/+oefh25C3fhybptkHKCZSPlcXiJux2tJF55GnEj3BVn4A5gKfq9NWWXXrxkHBwVPUfH0opw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0", + "estree-walker": "^3.0.0", + "is-reference": "^3.0.0" + } + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "dev": true, + "license": "ISC" + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/possible-typed-array-names": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.0.0.tgz", + "integrity": "sha512-d7Uw+eZoloe0EHDIYoe+bQ5WXnGMOpmiZFTuMWCwpjzzkL2nTjcKiAk4hh8TjnGye2TwWOk3UXucZ+3rbmBa8Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/postcss": { + "version": "8.5.3", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.3.tgz", + "integrity": "sha512-dle9A3yYxlBSrt8Fu+IpjGT8SY8hN0mlaA6GY8t0P5PjIOZemULz/E2Bnm/2dcUOena75OTNkHI76uZBNUUq3A==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "nanoid": "^3.3.8", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/postcss-load-config": { + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-3.1.4.tgz", + "integrity": "sha512-6DiM4E7v4coTE4uzA8U//WhtPwyhiim3eyjEMFCnUpzbrkK9wJHgKDT2mR+HbtSrd/NubVaYTOpSpjUl8NQeRg==", + "dev": true, + "license": "MIT", + "dependencies": { + "lilconfig": "^2.0.5", + "yaml": "^1.10.2" + }, + "engines": { + "node": ">= 10" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + "peerDependencies": { + "postcss": ">=8.0.9", + "ts-node": ">=9.0.0" + }, + "peerDependenciesMeta": { + "postcss": { + "optional": true + }, + "ts-node": { + "optional": true + } + } + }, + "node_modules/postcss-load-config/node_modules/yaml": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", + "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">= 6" + } + }, + "node_modules/postcss-safe-parser": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/postcss-safe-parser/-/postcss-safe-parser-6.0.0.tgz", + "integrity": "sha512-FARHN8pwH+WiS2OPCxJI8FuRJpTVnn6ZNFiqAM2aeW2LwTHWWmWgIyKC6cUo0L8aeKiF/14MNvnpls6R2PBeMQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + "peerDependencies": { + "postcss": "^8.3.3" + } + }, + "node_modules/postcss-scss": { + "version": "4.0.9", + "resolved": "https://registry.npmjs.org/postcss-scss/-/postcss-scss-4.0.9.tgz", + "integrity": "sha512-AjKOeiwAitL/MXxQW2DliT28EKukvvbEWx3LBmJIRN8KfBGZbRTxNYW0kSqi1COiTZ57nZ9NW06S6ux//N1c9A==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss-scss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "engines": { + "node": ">=12.0" + }, + "peerDependencies": { + "postcss": "^8.4.29" + } + }, + "node_modules/postcss-selector-parser": { + "version": "6.1.2", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.1.2.tgz", + "integrity": "sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==", + "dev": true, + "license": "MIT", + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/prettier": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.3.3.tgz", + "integrity": "sha512-i2tDNA0O5IrMO757lfrdQZCc2jPNDVntV0m/+4whiDfWaTKfMNgR7Qz0NAeGz/nRqF4m5/6CLzbP4/liHt12Ew==", + "dev": true, + "license": "MIT", + "bin": { + "prettier": "bin/prettier.cjs" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + }, + "node_modules/prettier-linter-helpers": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz", + "integrity": "sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-diff": "^1.1.2" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/prettier-plugin-svelte": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/prettier-plugin-svelte/-/prettier-plugin-svelte-3.2.6.tgz", + "integrity": "sha512-Y1XWLw7vXUQQZmgv1JAEiLcErqUniAF2wO7QJsw8BVMvpLET2dI5WpEIEJx1r11iHVdSMzQxivyfrH9On9t2IQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "prettier": "^3.0.0", + "svelte": "^3.2.0 || ^4.0.0-next.0 || ^5.0.0-next.0" + } + }, + "node_modules/process": { + "version": "0.11.10", + "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", + "integrity": "sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6.0" + } + }, + "node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dev": true, + "license": "MIT", + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/reflect-metadata": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/reflect-metadata/-/reflect-metadata-0.2.2.tgz", + "integrity": "sha512-urBwgfrvVP/eAyXx4hluJivBKzuEbSQs9rKWCrCkbSxNv8mxPcUZKeuoF3Uy4mJl3Lwprp6yy5/39VWigZ4K6Q==", + "license": "Apache-2.0" + }, + "node_modules/regexp.prototype.flags": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.2.tgz", + "integrity": "sha512-NcDiDkTLuPR+++OCKB0nWafEmhg/Da8aUPLPMQbK+bxKKCm1/S5he+AqYa4PlMCVBalb4/yxIRub6qkEx5yJbw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.6", + "define-properties": "^1.2.1", + "es-errors": "^1.3.0", + "set-function-name": "^2.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/resolve": { + "version": "1.22.8", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", + "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-core-module": "^2.13.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/resolve-pkg-maps": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz", + "integrity": "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1" + } + }, + "node_modules/reusify": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "dev": true, + "license": "MIT", + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "deprecated": "Rimraf versions prior to v4 are no longer supported", + "dev": true, + "license": "ISC", + "peer": true, + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/rollup": { + "version": "4.34.9", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.34.9.tgz", + "integrity": "sha512-nF5XYqWWp9hx/LrpC8sZvvvmq0TeTjQgaZHYmAgwysT9nh8sWnZhBnM8ZyVbbJFIQBLwHDNoMqsBZBbUo4U8sQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "1.0.6" + }, + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=18.0.0", + "npm": ">=8.0.0" + }, + "optionalDependencies": { + "@rollup/rollup-android-arm-eabi": "4.34.9", + "@rollup/rollup-android-arm64": "4.34.9", + "@rollup/rollup-darwin-arm64": "4.34.9", + "@rollup/rollup-darwin-x64": "4.34.9", + "@rollup/rollup-freebsd-arm64": "4.34.9", + "@rollup/rollup-freebsd-x64": "4.34.9", + "@rollup/rollup-linux-arm-gnueabihf": "4.34.9", + "@rollup/rollup-linux-arm-musleabihf": "4.34.9", + "@rollup/rollup-linux-arm64-gnu": "4.34.9", + "@rollup/rollup-linux-arm64-musl": "4.34.9", + "@rollup/rollup-linux-loongarch64-gnu": "4.34.9", + "@rollup/rollup-linux-powerpc64le-gnu": "4.34.9", + "@rollup/rollup-linux-riscv64-gnu": "4.34.9", + "@rollup/rollup-linux-s390x-gnu": "4.34.9", + "@rollup/rollup-linux-x64-gnu": "4.34.9", + "@rollup/rollup-linux-x64-musl": "4.34.9", + "@rollup/rollup-win32-arm64-msvc": "4.34.9", + "@rollup/rollup-win32-ia32-msvc": "4.34.9", + "@rollup/rollup-win32-x64-msvc": "4.34.9", + "fsevents": "~2.3.2" + } + }, + "node_modules/rollup-plugin-license": { + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/rollup-plugin-license/-/rollup-plugin-license-3.5.3.tgz", + "integrity": "sha512-r3wImZSo2d6sEk9BRJtlzeI/upjyjnpthy06Fdl0EzqRrlg3ULb9KQR7xHJI0zuayW/8bchEXSF5dO6dha4OyA==", + "dev": true, + "license": "MIT", + "dependencies": { + "commenting": "~1.1.0", + "fdir": "6.3.0", + "lodash": "~4.17.21", + "magic-string": "~0.30.0", + "moment": "~2.30.1", + "package-name-regex": "~2.0.6", + "spdx-expression-validate": "~2.0.0", + "spdx-satisfies": "~5.0.1" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "rollup": "^1.0.0 || ^2.0.0 || ^3.0.0 || ^4.0.0" + } + }, + "node_modules/rollup-plugin-license/node_modules/fdir": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.3.0.tgz", + "integrity": "sha512-QOnuT+BOtivR77wYvCWHfGt9s4Pz1VIMbD463vegT5MLqNXy8rYFT/lPVEqf/bhYeT6qmqrNHhsX+rWwe3rOCQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, + "node_modules/rollup-plugin-license/node_modules/picomatch": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.2.tgz", + "integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==", + "dev": true, + "license": "MIT", + "optional": true, + "peer": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/rxjs": { + "version": "7.8.1", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.1.tgz", + "integrity": "sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.1.0" + } + }, + "node_modules/safe-array-concat": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.1.2.tgz", + "integrity": "sha512-vj6RsCsWBCf19jIeHEfkRMw8DPiBb+DMXklQ/1SGDHOMlHdPUkZXFQ2YdplS23zESTijAcurb1aSgJA3AgMu1Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "get-intrinsic": "^1.2.4", + "has-symbols": "^1.0.3", + "isarray": "^2.0.5" + }, + "engines": { + "node": ">=0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/safe-regex-test": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.0.3.tgz", + "integrity": "sha512-CdASjNJPvRa7roO6Ra/gLYBTzYzzPyyBXxIMdGW3USQLyjWEls2RgW5UBTXaQVp+OrpeCK3bLem8smtmheoRuw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.6", + "es-errors": "^1.3.0", + "is-regex": "^1.1.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/sass": { + "version": "1.78.0", + "resolved": "https://registry.npmjs.org/sass/-/sass-1.78.0.tgz", + "integrity": "sha512-AaIqGSrjo5lA2Yg7RvFZrlXDBCp3nV4XP73GrLGvdRWWwk+8H3l0SDvq/5bA4eF+0RFPLuWUk3E+P1U/YqnpsQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "chokidar": ">=3.0.0 <4.0.0", + "immutable": "^4.0.0", + "source-map-js": ">=0.6.2 <2.0.0" + }, + "bin": { + "sass": "sass.js" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/semver": { + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", + "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/set-function-length": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", + "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", + "dev": true, + "license": "MIT", + "dependencies": { + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/set-function-name": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/set-function-name/-/set-function-name-2.0.2.tgz", + "integrity": "sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", + "functions-have-names": "^1.2.3", + "has-property-descriptors": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/shell-quote": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.8.1.tgz", + "integrity": "sha512-6j1W9l1iAs/4xYBI1SYOVZyFcCis9b4KCLQ8fgAGG07QvzaRLVVRQvAy85yNmmZSjYjg4MWh4gNvlPujU/5LpA==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.6.tgz", + "integrity": "sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.4", + "object-inspect": "^1.13.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/source-map-js": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/spdx-compare": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/spdx-compare/-/spdx-compare-1.0.0.tgz", + "integrity": "sha512-C1mDZOX0hnu0ep9dfmuoi03+eOdDoz2yvK79RxbcrVEG1NO1Ph35yW102DHWKN4pk80nwCgeMmSY5L25VE4D9A==", + "dev": true, + "license": "MIT", + "dependencies": { + "array-find-index": "^1.0.2", + "spdx-expression-parse": "^3.0.0", + "spdx-ranges": "^2.0.0" + } + }, + "node_modules/spdx-exceptions": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.5.0.tgz", + "integrity": "sha512-PiU42r+xO4UbUS1buo3LPJkjlO7430Xn5SVAhdpzzsPHsjbYVflnnFdATgabnLude+Cqu25p6N+g2lw/PFsa4w==", + "dev": true, + "license": "CC-BY-3.0" + }, + "node_modules/spdx-expression-parse": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", + "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" + } + }, + "node_modules/spdx-expression-validate": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/spdx-expression-validate/-/spdx-expression-validate-2.0.0.tgz", + "integrity": "sha512-b3wydZLM+Tc6CFvaRDBOF9d76oGIHNCLYFeHbftFXUWjnfZWganmDmvtM5sm1cRwJc/VDBMLyGGrsLFd1vOxbg==", + "dev": true, + "license": "(MIT AND CC-BY-3.0)", + "dependencies": { + "spdx-expression-parse": "^3.0.0" + } + }, + "node_modules/spdx-license-ids": { + "version": "3.0.20", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.20.tgz", + "integrity": "sha512-jg25NiDV/1fLtSgEgyvVyDunvaNHbuwF9lfNV17gSmPFAlYzdfNBlLtLzXTevwkPj7DhGbmN9VnmJIgLnhvaBw==", + "dev": true, + "license": "CC0-1.0" + }, + "node_modules/spdx-ranges": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/spdx-ranges/-/spdx-ranges-2.1.1.tgz", + "integrity": "sha512-mcdpQFV7UDAgLpXEE/jOMqvK4LBoO0uTQg0uvXUewmEFhpiZx5yJSZITHB8w1ZahKdhfZqP5GPEOKLyEq5p8XA==", + "dev": true, + "license": "(MIT AND CC-BY-3.0)" + }, + "node_modules/spdx-satisfies": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/spdx-satisfies/-/spdx-satisfies-5.0.1.tgz", + "integrity": "sha512-Nwor6W6gzFp8XX4neaKQ7ChV4wmpSh2sSDemMFSzHxpTw460jxFYeOn+jq4ybnSSw/5sc3pjka9MQPouksQNpw==", + "dev": true, + "license": "MIT", + "dependencies": { + "spdx-compare": "^1.0.0", + "spdx-expression-parse": "^3.0.0", + "spdx-ranges": "^2.0.0" + } + }, + "node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/string.prototype.trim": { + "version": "1.2.9", + "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.9.tgz", + "integrity": "sha512-klHuCNxiMZ8MlsOihJhJEBJAiMVqU3Z2nEXWfWnIqjN0gEFS9J9+IxKozWWtQGcgoa1WUZzLjKPTr4ZHNFTFxw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.0", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.trimend": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.8.tgz", + "integrity": "sha512-p73uL5VCHCO2BZZ6krwwQE3kCzM7NKmis8S//xEC6fQonchbum4eP6kR4DLEjQFO3Wnj3Fuo8NM0kOSjVdHjZQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.trimstart": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.8.tgz", + "integrity": "sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/svelte": { + "version": "4.2.19", + "resolved": "https://registry.npmjs.org/svelte/-/svelte-4.2.19.tgz", + "integrity": "sha512-IY1rnGr6izd10B0A8LqsBfmlT5OILVuZ7XsI0vdGPEvuonFV7NYEUK4dAkm9Zg2q0Um92kYjTpS1CAP3Nh/KWw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@ampproject/remapping": "^2.2.1", + "@jridgewell/sourcemap-codec": "^1.4.15", + "@jridgewell/trace-mapping": "^0.3.18", + "@types/estree": "^1.0.1", + "acorn": "^8.9.0", + "aria-query": "^5.3.0", + "axobject-query": "^4.0.0", + "code-red": "^1.0.3", + "css-tree": "^2.3.1", + "estree-walker": "^3.0.3", + "is-reference": "^3.0.1", + "locate-character": "^3.0.0", + "magic-string": "^0.30.4", + "periscopic": "^3.1.0" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/svelte-eslint-parser": { + "version": "0.41.1", + "resolved": "https://registry.npmjs.org/svelte-eslint-parser/-/svelte-eslint-parser-0.41.1.tgz", + "integrity": "sha512-08ndI6zTghzI8SuJAFpvMbA/haPSGn3xz19pjre19yYMw8Nw/wQJ2PrZBI/L8ijGTgtkWCQQiLLy+Z1tfaCwNA==", + "dev": true, + "license": "MIT", + "dependencies": { + "eslint-scope": "^7.2.2", + "eslint-visitor-keys": "^3.4.3", + "espree": "^9.6.1", + "postcss": "^8.4.39", + "postcss-scss": "^4.0.9" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ota-meshi" + }, + "peerDependencies": { + "svelte": "^3.37.0 || ^4.0.0 || ^5.0.0-next.191" + }, + "peerDependenciesMeta": { + "svelte": { + "optional": true + } + } + }, + "node_modules/svelte-hmr": { + "version": "0.16.0", + "resolved": "https://registry.npmjs.org/svelte-hmr/-/svelte-hmr-0.16.0.tgz", + "integrity": "sha512-Gyc7cOS3VJzLlfj7wKS0ZnzDVdv3Pn2IuVeJPk9m2skfhcu5bq3wtIZyQGggr7/Iim5rH5cncyQft/kRLupcnA==", + "dev": true, + "license": "ISC", + "engines": { + "node": "^12.20 || ^14.13.1 || >= 16" + }, + "peerDependencies": { + "svelte": "^3.19.0 || ^4.0.0" + } + }, + "node_modules/svelte-preprocess": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/svelte-preprocess/-/svelte-preprocess-6.0.2.tgz", + "integrity": "sha512-OvDTLfaOkkhjprbDKO0SOCkjNYuHy16dbD4SpqbIi6QiabOMHxRT4km5/dzbFFkmW1L0E2INF3MFltG2pgOyKQ==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "engines": { + "node": ">= 18.0.0" + }, + "peerDependencies": { + "@babel/core": "^7.10.2", + "coffeescript": "^2.5.1", + "less": "^3.11.3 || ^4.0.0", + "postcss": "^7 || ^8", + "postcss-load-config": ">=3", + "pug": "^3.0.0", + "sass": "^1.26.8", + "stylus": ">=0.55", + "sugarss": "^2.0.0 || ^3.0.0 || ^4.0.0", + "svelte": "^4.0.0 || ^5.0.0-next.100 || ^5.0.0", + "typescript": "^5.0.0" + }, + "peerDependenciesMeta": { + "@babel/core": { + "optional": true + }, + "coffeescript": { + "optional": true + }, + "less": { + "optional": true + }, + "postcss": { + "optional": true + }, + "postcss-load-config": { + "optional": true + }, + "pug": { + "optional": true + }, + "sass": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "typescript": { + "optional": true + } + } + }, + "node_modules/synckit": { + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/synckit/-/synckit-0.9.1.tgz", + "integrity": "sha512-7gr8p9TQP6RAHusBOSLs46F4564ZrjV8xFmw5zCmgmhGUcw2hxsShhJ6CEiHQMgPDwAQ1fWHPM0ypc4RMAig4A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@pkgr/core": "^0.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": "^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/unts" + } + }, + "node_modules/tapable": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz", + "integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", + "dev": true, + "license": "MIT", + "peer": true + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/tree-kill": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/tree-kill/-/tree-kill-1.2.2.tgz", + "integrity": "sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==", + "dev": true, + "license": "MIT", + "bin": { + "tree-kill": "cli.js" + } + }, + "node_modules/ts-api-utils": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.3.0.tgz", + "integrity": "sha512-UQMIo7pb8WRomKR1/+MFVLTroIvDVtMX3K6OUir8ynLyzB8Jeriont2bTAtmNPa1ekAgN7YPDyf6V+ygrdU+eQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=16" + }, + "peerDependencies": { + "typescript": ">=4.2.0" + } + }, + "node_modules/ts-node": { + "version": "10.9.2", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.2.tgz", + "integrity": "sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@cspotcode/source-map-support": "^0.8.0", + "@tsconfig/node10": "^1.0.7", + "@tsconfig/node12": "^1.0.7", + "@tsconfig/node14": "^1.0.0", + "@tsconfig/node16": "^1.0.2", + "acorn": "^8.4.1", + "acorn-walk": "^8.1.1", + "arg": "^4.1.0", + "create-require": "^1.1.0", + "diff": "^4.0.1", + "make-error": "^1.1.1", + "v8-compile-cache-lib": "^3.0.1", + "yn": "3.1.1" + }, + "bin": { + "ts-node": "dist/bin.js", + "ts-node-cwd": "dist/bin-cwd.js", + "ts-node-esm": "dist/bin-esm.js", + "ts-node-script": "dist/bin-script.js", + "ts-node-transpile-only": "dist/bin-transpile.js", + "ts-script": "dist/bin-script-deprecated.js" + }, + "peerDependencies": { + "@swc/core": ">=1.2.50", + "@swc/wasm": ">=1.2.50", + "@types/node": "*", + "typescript": ">=2.7" + }, + "peerDependenciesMeta": { + "@swc/core": { + "optional": true + }, + "@swc/wasm": { + "optional": true + } + } + }, + "node_modules/tsconfig-paths": { + "version": "3.15.0", + "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.15.0.tgz", + "integrity": "sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/json5": "^0.0.29", + "json5": "^1.0.2", + "minimist": "^1.2.6", + "strip-bom": "^3.0.0" + } + }, + "node_modules/tslib": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.7.0.tgz", + "integrity": "sha512-gLXCKdN1/j47AiHiOkJN69hJmcbGTHI0ImLmbYLHykhgeN0jVGola9yVjFgzCUklsZQMW55o+dW7IXv3RCXDzA==", + "dev": true, + "license": "0BSD" + }, + "node_modules/type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "dev": true, + "license": "(MIT OR CC0-1.0)", + "peer": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/typed-array-buffer": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.2.tgz", + "integrity": "sha512-gEymJYKZtKXzzBzM4jqa9w6Q1Jjm7x2d+sh19AdsD4wqnMPDYyvwpsIc2Q/835kHuo3BEQ7CjelGhfTsoBb2MQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "es-errors": "^1.3.0", + "is-typed-array": "^1.1.13" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/typed-array-byte-length": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/typed-array-byte-length/-/typed-array-byte-length-1.0.1.tgz", + "integrity": "sha512-3iMJ9q0ao7WE9tWcaYKIptkNBuOIcZCCT0d4MRvuuH88fEoEH62IuQe0OtraD3ebQEoTRk8XCBoknUNc1Y67pw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-proto": "^1.0.3", + "is-typed-array": "^1.1.13" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/typed-array-byte-offset": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/typed-array-byte-offset/-/typed-array-byte-offset-1.0.2.tgz", + "integrity": "sha512-Ous0vodHa56FviZucS2E63zkgtgrACj7omjwd/8lTEMEPFFyjfixMZ1ZXenpgCFBBt4EC1J2XsyVS2gkG0eTFA==", + "dev": true, + "license": "MIT", + "dependencies": { + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.7", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-proto": "^1.0.3", + "is-typed-array": "^1.1.13" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/typed-array-length": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.6.tgz", + "integrity": "sha512-/OxDN6OtAk5KBpGb28T+HZc2M+ADtvRxXrKKbUwtsLgdoxgX13hyy7ek6bFRl5+aBs2yZzB0c4CnQfAtVypW/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-proto": "^1.0.3", + "is-typed-array": "^1.1.13", + "possible-typed-array-names": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/typescript": { + "version": "5.6.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.6.2.tgz", + "integrity": "sha512-NW8ByodCSNCwZeghjN3o+JX5OFH0Ojg6sadjEKY4huZ52TqbJTJnDo5+Tw98lSy63NZvi4n+ez5m2u5d4PkZyw==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/unbox-primitive": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz", + "integrity": "sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.2", + "has-bigints": "^1.0.2", + "has-symbols": "^1.0.3", + "which-boxed-primitive": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/undici-types": { + "version": "6.19.8", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.19.8.tgz", + "integrity": "sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==", + "dev": true, + "license": "MIT" + }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "license": "BSD-2-Clause", + "peer": true, + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", + "dev": true, + "license": "MIT" + }, + "node_modules/v8-compile-cache-lib": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", + "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", + "dev": true, + "license": "MIT" + }, + "node_modules/vite": { + "version": "5.4.14", + "resolved": "https://registry.npmjs.org/vite/-/vite-5.4.14.tgz", + "integrity": "sha512-EK5cY7Q1D8JNhSaPKVK4pwBFvaTmZxEnoKXLG/U9gmdDcihQGNzFlgIvaxezFR4glP1LsuiedwMBqCXH3wZccA==", + "dev": true, + "license": "MIT", + "dependencies": { + "esbuild": "^0.21.3", + "postcss": "^8.4.43", + "rollup": "^4.20.0" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^18.0.0 || >=20.0.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + }, + "peerDependencies": { + "@types/node": "^18.0.0 || >=20.0.0", + "less": "*", + "lightningcss": "^1.21.0", + "sass": "*", + "sass-embedded": "*", + "stylus": "*", + "sugarss": "*", + "terser": "^5.4.0" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "less": { + "optional": true + }, + "lightningcss": { + "optional": true + }, + "sass": { + "optional": true + }, + "sass-embedded": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + } + } + }, + "node_modules/vite-multiple-assets": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/vite-multiple-assets/-/vite-multiple-assets-1.3.1.tgz", + "integrity": "sha512-iV7lJiunCUyTq2hIsnnoZF2LBKLs9e1ezee0I3TOG9SgBrM2w5vrf4RXDJdVdYmCthujnz2aIx4wYax+0Gpcwg==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "mime-types": "^2.1.35", + "vite": ">=2.9.6" + } + }, + "node_modules/vitefu": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/vitefu/-/vitefu-0.2.5.tgz", + "integrity": "sha512-SgHtMLoqaeeGnd2evZ849ZbACbnwQCIwRH57t18FxcXoZop0uQu0uzlIhJBlF/eWVzuce0sHeqPcDo+evVcg8Q==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "vite": "^3.0.0 || ^4.0.0 || ^5.0.0" + }, + "peerDependenciesMeta": { + "vite": { + "optional": true + } + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "license": "ISC", + "peer": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/which-boxed-primitive": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz", + "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-bigint": "^1.0.1", + "is-boolean-object": "^1.1.0", + "is-number-object": "^1.0.4", + "is-string": "^1.0.5", + "is-symbol": "^1.0.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/which-typed-array": { + "version": "1.1.15", + "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.15.tgz", + "integrity": "sha512-oV0jmFtUky6CXfkqehVvBP/LSWJ2sy4vWMioiENyJLePrBO/yKyV9OyJySfAKosh+RYkIl5zJCNZ8/4JncrpdA==", + "dev": true, + "license": "MIT", + "dependencies": { + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.7", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/word-wrap": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", + "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "dev": true, + "license": "ISC", + "peer": true + }, + "node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=10" + } + }, + "node_modules/yargs": { + "version": "17.7.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", + "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "cliui": "^8.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.1.1" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/yargs-parser": { + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/yn": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", + "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + } + } +} diff --git a/frontend/package.json b/frontend/package.json new file mode 100644 index 0000000000000000000000000000000000000000..ea18e0fba9c7ef26e7e30d9fa7b6bafdcc7217be --- /dev/null +++ b/frontend/package.json @@ -0,0 +1,71 @@ +{ + "name": "graphite-web-frontend", + "private": true, + "description": "Graphite's web app frontend.", + "author": "Graphite Authors ", + "browserslist": "> 1.5%, last 2 versions, not dead, not ie 11, not op_mini all, not ios_saf < 13", + "type": "module", + "scripts": { + "---------- DEV SERVER ----------": "", + "start": "npm run setup && npm run wasm:build-dev && concurrently -k -n \"VITE,RUST\" \"vite\" \"npm run wasm:watch-dev\"", + "profiling": "npm run setup && npm run wasm:build-profiling && concurrently -k -n \"VITE,RUST\" \"vite\" \"npm run wasm:watch-profiling\"", + "production": "npm run setup && npm run wasm:build-production && concurrently -k -n \"VITE,RUST\" \"vite\" \"npm run wasm:watch-production\"", + "---------- BUILDS ----------": "", + "build-dev": "npm run wasm:build-dev && vite build", + "build-profiling": "npm run wasm:build-profiling && vite build", + "build": "npm run wasm:build-production && vite build", + "---------- UTILITIES ----------": "", + "lint": "eslint . && tsc --noEmit", + "lint-fix": "eslint . --fix && tsc --noEmit", + "---------- INTERNAL ----------": "", + "setup": "node package-installer.js", + "tauri:dev": "vite", + "tauri:build": "wasm-pack build ./wasm --target=web --features=tauri", + "wasm:build-dev": "wasm-pack build ./wasm --dev --target=web", + "wasm:build-profiling": "wasm-pack build ./wasm --profiling --target=web", + "wasm:build-production": "wasm-pack build ./wasm --release --target=web", + "wasm:watch-dev": "cargo watch --postpone --watch-when-idle --workdir=wasm --shell \"wasm-pack build . --dev --target=web -- --color=always\"", + "wasm:watch-profiling": "cargo watch --postpone --watch-when-idle --workdir=wasm --shell \"wasm-pack build . --profiling --target=web -- --color=always\"", + "wasm:watch-production": "cargo watch --postpone --watch-when-idle --workdir=wasm --shell \"wasm-pack build . --release --target=web -- --color=always\"" + }, + "dependencies": { + "@fontsource/inconsolata": "^5.2.5", + "@fontsource/source-sans-pro": "^5.2.5", + "class-transformer": "^0.5.1", + "idb-keyval": "^6.2.1", + "reflect-metadata": "^0.2.2" + }, + "devDependencies": { + "@sveltejs/vite-plugin-svelte": "^3.1.2", + "@types/node": "^22.6.1", + "@typescript-eslint/eslint-plugin": "^8.7.0", + "@typescript-eslint/parser": "^8.7.0", + "buffer": "^6.0.3", + "concurrently": "^9.0.1", + "eslint-config-prettier": "^9.1.0", + "eslint-import-resolver-typescript": "^3.6.3", + "eslint-plugin-import": "^2.30.0", + "eslint-plugin-prettier": "^5.2.1", + "eslint-plugin-svelte": "^2.44.0", + "postcss": "^8.4.47", + "prettier": "^3.3.3", + "prettier-plugin-svelte": "^3.2.6", + "process": "^0.11.10", + "rollup-plugin-license": "^3.5.3", + "sass": "1.78.0", + "svelte": "^4.2.19", + "svelte-preprocess": "^6.0.2", + "ts-node": "^10.9.2", + "typescript": "^5.6.2", + "vite": "^5.4.14", + "vite-multiple-assets": "1.3.1" + }, + "//": "The dev dependency for `sass` can be removed once is fixed, but meanwhile we have to", + "///": "list it here and pin it to 1.78.0 so `vite` and `svelte-preprocess` use it instead of 1.79+ which spams the console with deprecation warnings.", + "homepage": "https://graphite.rs", + "license": "Apache-2.0", + "repository": { + "type": "git", + "url": "git+https://github.com/GraphiteEditor/Graphite.git" + } +} diff --git a/frontend/public/android-chrome-192x192.png b/frontend/public/android-chrome-192x192.png new file mode 100644 index 0000000000000000000000000000000000000000..9e3f315c80d628dedf53073ea7d0032a292e0ea3 Binary files /dev/null and b/frontend/public/android-chrome-192x192.png differ diff --git a/frontend/public/android-chrome-512x512.png b/frontend/public/android-chrome-512x512.png new file mode 100644 index 0000000000000000000000000000000000000000..c02e22a2e1107b45a40eb3c0e451bcdd198b7c4f Binary files /dev/null and b/frontend/public/android-chrome-512x512.png differ diff --git a/frontend/public/apple-touch-icon.png b/frontend/public/apple-touch-icon.png new file mode 100644 index 0000000000000000000000000000000000000000..a2c512dd209349daddc92a8aa6ba36769e61fae5 Binary files /dev/null and b/frontend/public/apple-touch-icon.png differ diff --git a/frontend/public/browserconfig.xml b/frontend/public/browserconfig.xml new file mode 100644 index 0000000000000000000000000000000000000000..3ec377f7d47219dd907f5ac63a81669a27bc633d --- /dev/null +++ b/frontend/public/browserconfig.xml @@ -0,0 +1,9 @@ + + + + + + #ffffff + + + diff --git a/frontend/public/favicon-16x16.png b/frontend/public/favicon-16x16.png new file mode 100644 index 0000000000000000000000000000000000000000..fe415500842870e71b0ba2f34024a3c8321794bc Binary files /dev/null and b/frontend/public/favicon-16x16.png differ diff --git a/frontend/public/favicon-32x32.png b/frontend/public/favicon-32x32.png new file mode 100644 index 0000000000000000000000000000000000000000..e94d3fba4019e3238642265aff7396067072c935 Binary files /dev/null and b/frontend/public/favicon-32x32.png differ diff --git a/frontend/public/favicon.ico b/frontend/public/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..484a28f36f5c76ca24a36dc1b1af0636e90d2585 Binary files /dev/null and b/frontend/public/favicon.ico differ diff --git a/frontend/public/mstile-144x144.png b/frontend/public/mstile-144x144.png new file mode 100644 index 0000000000000000000000000000000000000000..44f54fd110823d3cb2809ac26a6f6d95cd4b34e9 Binary files /dev/null and b/frontend/public/mstile-144x144.png differ diff --git a/frontend/public/mstile-150x150.png b/frontend/public/mstile-150x150.png new file mode 100644 index 0000000000000000000000000000000000000000..30bebbdc81986f9f8c672e67aaa043461eae56da Binary files /dev/null and b/frontend/public/mstile-150x150.png differ diff --git a/frontend/public/mstile-310x150.png b/frontend/public/mstile-310x150.png new file mode 100644 index 0000000000000000000000000000000000000000..4b08b270efc07cb530e2f221ab5d8855a43c6a4e Binary files /dev/null and b/frontend/public/mstile-310x150.png differ diff --git a/frontend/public/mstile-310x310.png b/frontend/public/mstile-310x310.png new file mode 100644 index 0000000000000000000000000000000000000000..5df1a3b78fab65c669e7437c211640ef3079b3c1 Binary files /dev/null and b/frontend/public/mstile-310x310.png differ diff --git a/frontend/public/mstile-70x70.png b/frontend/public/mstile-70x70.png new file mode 100644 index 0000000000000000000000000000000000000000..e6c2562807339004ddb930cb31bd39a85dff1c03 Binary files /dev/null and b/frontend/public/mstile-70x70.png differ diff --git a/frontend/public/safari-pinned-tab.svg b/frontend/public/safari-pinned-tab.svg new file mode 100644 index 0000000000000000000000000000000000000000..1aa9c242a00dcd55cee4d872ca7dff8b3468415a --- /dev/null +++ b/frontend/public/safari-pinned-tab.svg @@ -0,0 +1,85 @@ + + + + + + + + diff --git a/frontend/public/site.webmanifest b/frontend/public/site.webmanifest new file mode 100644 index 0000000000000000000000000000000000000000..a54dec1fc919631f10f3a156dbc970a144160f4d --- /dev/null +++ b/frontend/public/site.webmanifest @@ -0,0 +1,21 @@ +{ + "name": "Graphite", + "short_name": "Graphite", + "start_url": "/", + "id": "/", + "icons": [ + { + "src": "./android-chrome-192x192.png", + "sizes": "192x192", + "type": "image/png" + }, + { + "src": "./android-chrome-512x512.png", + "sizes": "512x512", + "type": "image/png" + } + ], + "theme_color": "#ffffff", + "background_color": "#222222", + "display": "standalone" +} diff --git a/frontend/src-tauri/.gitignore b/frontend/src-tauri/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..3419525157c6acf5f44d15fee2f8e882a491bc47 --- /dev/null +++ b/frontend/src-tauri/.gitignore @@ -0,0 +1,5 @@ +# Generated by Cargo +# will have compiled files and executables +/target/ +# Generated by tauri +gen/ diff --git a/frontend/src-tauri/Cargo.toml b/frontend/src-tauri/Cargo.toml new file mode 100644 index 0000000000000000000000000000000000000000..c2095e3d8763d23f3655340dcbaaa1a9411ebc65 --- /dev/null +++ b/frontend/src-tauri/Cargo.toml @@ -0,0 +1,45 @@ +[package] +name = "graphite-desktop" +version = "0.1.0" +description = "Graphite Desktop" +authors = ["Graphite Authors "] +license = "Apache-2.0" +repository = "" +default-run = "graphite-desktop" +edition = "2021" +rust-version = "1.79" + +[features] +# By default Tauri runs in production mode when `tauri dev` runs it is executed with `cargo run --no-default-features` if `devPath` is an URL +default = ["custom-protocol", "gpu"] +# This feature is used for production builds where `devPath` points to the filesystem +# DO NOT remove this +custom-protocol = ["tauri/custom-protocol"] +gpu = ["graphite-editor/gpu"] + +[dependencies] +# Local dependencies +graphite-editor = { path = "../../editor", features = [ + "gpu", + "ron", + "vello", + "decouple-execution", +] } + +# Workspace dependencies +axum = { workspace = true } +chrono = { workspace = true } +tokio = { workspace = true } +ron = { workspace = true } +log = { workspace = true } +fern = { workspace = true } +futures = { workspace = true } + +# Required dependencies +tauri = { version = "2", features = ["devtools", "wry"] } +tauri-plugin-shell = "2" +tauri-plugin-http = "2" + +[build-dependencies] +# Required dependencies +tauri-build = { version = "2", features = [] } diff --git a/frontend/src-tauri/build.rs b/frontend/src-tauri/build.rs new file mode 100644 index 0000000000000000000000000000000000000000..59fdfbea60e56a4894526735110b8192497e1e2f --- /dev/null +++ b/frontend/src-tauri/build.rs @@ -0,0 +1,9 @@ +use std::fs; +use std::path::PathBuf; + +fn main() { + // Directory required for compilation, but not tracked by git if empty. + let dist_dir: PathBuf = ["..", "dist"].iter().collect(); + fs::create_dir_all(dist_dir).unwrap(); + tauri_build::build() +} diff --git a/frontend/src-tauri/capabilities/desktop.json b/frontend/src-tauri/capabilities/desktop.json new file mode 100644 index 0000000000000000000000000000000000000000..938d5a3367ffbad24b702619452b128b9c77bb4c --- /dev/null +++ b/frontend/src-tauri/capabilities/desktop.json @@ -0,0 +1,6 @@ +{ + "identifier": "desktop-capability", + "platforms": ["macOS", "windows", "linux"], + "windows": ["main"], + "permissions": ["http:default"] +} diff --git a/frontend/src-tauri/capabilities/migrated.json b/frontend/src-tauri/capabilities/migrated.json new file mode 100644 index 0000000000000000000000000000000000000000..4e47d1a91a0bdbf82e0672453c20ae3b34a25556 --- /dev/null +++ b/frontend/src-tauri/capabilities/migrated.json @@ -0,0 +1,49 @@ +{ + "identifier": "migrated", + "description": "permissions that were migrated from v1", + "local": true, + "windows": ["main"], + "permissions": [ + "core:default", + "core:window:allow-create", + "core:window:allow-center", + "core:window:allow-request-user-attention", + "core:window:allow-set-resizable", + "core:window:allow-set-maximizable", + "core:window:allow-set-minimizable", + "core:window:allow-set-closable", + "core:window:allow-set-title", + "core:window:allow-maximize", + "core:window:allow-unmaximize", + "core:window:allow-minimize", + "core:window:allow-unminimize", + "core:window:allow-show", + "core:window:allow-hide", + "core:window:allow-close", + "core:window:allow-set-decorations", + "core:window:allow-set-always-on-top", + "core:window:allow-set-content-protected", + "core:window:allow-set-size", + "core:window:allow-set-min-size", + "core:window:allow-set-max-size", + "core:window:allow-set-position", + "core:window:allow-set-fullscreen", + "core:window:allow-set-focus", + "core:window:allow-set-icon", + "core:window:allow-set-skip-taskbar", + "core:window:allow-set-cursor-grab", + "core:window:allow-set-cursor-visible", + "core:window:allow-set-cursor-icon", + "core:window:allow-set-cursor-position", + "core:window:allow-set-ignore-cursor-events", + "core:window:allow-start-dragging", + "core:webview:allow-print", + "shell:allow-execute", + "shell:allow-open", + "http:default", + "core:app:allow-app-show", + "core:app:allow-app-hide", + "shell:default", + "http:default" + ] +} diff --git a/frontend/src-tauri/icons/128x128.png b/frontend/src-tauri/icons/128x128.png new file mode 100644 index 0000000000000000000000000000000000000000..f7bd3fdad736e8b9d7624bea0f0e7405a336906f Binary files /dev/null and b/frontend/src-tauri/icons/128x128.png differ diff --git a/frontend/src-tauri/icons/128x128@2x.png b/frontend/src-tauri/icons/128x128@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..56b991cd81d6abfcf7b781a1d1279f6cf85fec3f Binary files /dev/null and b/frontend/src-tauri/icons/128x128@2x.png differ diff --git a/frontend/src-tauri/icons/32x32.png b/frontend/src-tauri/icons/32x32.png new file mode 100644 index 0000000000000000000000000000000000000000..53d1df4aebcc8602514690c384845130912d3718 Binary files /dev/null and b/frontend/src-tauri/icons/32x32.png differ diff --git a/frontend/src-tauri/icons/Square107x107Logo.png b/frontend/src-tauri/icons/Square107x107Logo.png new file mode 100644 index 0000000000000000000000000000000000000000..5a931061854e8499258194c99223e73618a732ef Binary files /dev/null and b/frontend/src-tauri/icons/Square107x107Logo.png differ diff --git a/frontend/src-tauri/icons/Square142x142Logo.png b/frontend/src-tauri/icons/Square142x142Logo.png new file mode 100644 index 0000000000000000000000000000000000000000..5d4be439c8c52d7ce0541994408b8a40bdbaac42 Binary files /dev/null and b/frontend/src-tauri/icons/Square142x142Logo.png differ diff --git a/frontend/src-tauri/icons/Square150x150Logo.png b/frontend/src-tauri/icons/Square150x150Logo.png new file mode 100644 index 0000000000000000000000000000000000000000..d1f9dbc536ae8933197e2e22e767e1b5e32ca5ad Binary files /dev/null and b/frontend/src-tauri/icons/Square150x150Logo.png differ diff --git a/frontend/src-tauri/icons/Square284x284Logo.png b/frontend/src-tauri/icons/Square284x284Logo.png new file mode 100644 index 0000000000000000000000000000000000000000..e4bbc7a36ed8c2ef8f3d569bab2541837edcf892 Binary files /dev/null and b/frontend/src-tauri/icons/Square284x284Logo.png differ diff --git a/frontend/src-tauri/icons/Square30x30Logo.png b/frontend/src-tauri/icons/Square30x30Logo.png new file mode 100644 index 0000000000000000000000000000000000000000..cc7bb9c9cad694fbd016a54ebc8428e281404f6a Binary files /dev/null and b/frontend/src-tauri/icons/Square30x30Logo.png differ diff --git a/frontend/src-tauri/icons/Square310x310Logo.png b/frontend/src-tauri/icons/Square310x310Logo.png new file mode 100644 index 0000000000000000000000000000000000000000..d4dd3fcae38cb674667662aba8df2a2c76efb947 Binary files /dev/null and b/frontend/src-tauri/icons/Square310x310Logo.png differ diff --git a/frontend/src-tauri/icons/Square44x44Logo.png b/frontend/src-tauri/icons/Square44x44Logo.png new file mode 100644 index 0000000000000000000000000000000000000000..3edfca75e1226a76153334c253bdd6efa34da9fa Binary files /dev/null and b/frontend/src-tauri/icons/Square44x44Logo.png differ diff --git a/frontend/src-tauri/icons/Square71x71Logo.png b/frontend/src-tauri/icons/Square71x71Logo.png new file mode 100644 index 0000000000000000000000000000000000000000..a189c3e7f9582a7f560f693bcf5854b37c59a60e Binary files /dev/null and b/frontend/src-tauri/icons/Square71x71Logo.png differ diff --git a/frontend/src-tauri/icons/Square89x89Logo.png b/frontend/src-tauri/icons/Square89x89Logo.png new file mode 100644 index 0000000000000000000000000000000000000000..454158e5657ed0051eeb2b217a40bf3d85b9fb2c Binary files /dev/null and b/frontend/src-tauri/icons/Square89x89Logo.png differ diff --git a/frontend/src-tauri/icons/StoreLogo.png b/frontend/src-tauri/icons/StoreLogo.png new file mode 100644 index 0000000000000000000000000000000000000000..f2a2283e50ae47b00d97f38ae759ac3fc9a8fd50 Binary files /dev/null and b/frontend/src-tauri/icons/StoreLogo.png differ diff --git a/frontend/src-tauri/icons/icon.icns b/frontend/src-tauri/icons/icon.icns new file mode 100644 index 0000000000000000000000000000000000000000..4e5ebc3bbad0b3ca6fcb6f8aaaacbb87f9f3184c --- /dev/null +++ b/frontend/src-tauri/icons/icon.icns @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:7b6c3c1003f4ac14a9fe3ac9494ae90339194b88499a59d31a1298eeadb0d36f +size 349608 diff --git a/frontend/src-tauri/icons/icon.ico b/frontend/src-tauri/icons/icon.ico new file mode 100644 index 0000000000000000000000000000000000000000..e45b58dd9d2a29eaf7212d01361340aa85640f10 Binary files /dev/null and b/frontend/src-tauri/icons/icon.ico differ diff --git a/frontend/src-tauri/icons/icon.png b/frontend/src-tauri/icons/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..05483f325f04abc1109971a2c52417838c12a99b Binary files /dev/null and b/frontend/src-tauri/icons/icon.png differ diff --git a/frontend/src-tauri/src/main.rs b/frontend/src-tauri/src/main.rs new file mode 100644 index 0000000000000000000000000000000000000000..edc544daefc1295afe8c26e7390444a4d35f897a --- /dev/null +++ b/frontend/src-tauri/src/main.rs @@ -0,0 +1,88 @@ +#![cfg_attr(all(not(debug_assertions), target_os = "windows"), windows_subsystem = "windows")] + +use axum::routing::get; +use axum::Router; +use fern::colors::{Color, ColoredLevelConfig}; +use graphite_editor::application::Editor; +use graphite_editor::messages::prelude::*; +use graphite_editor::node_graph_executor::GraphRuntimeRequest; +use graphite_editor::node_graph_executor::NODE_RUNTIME; +use graphite_editor::node_graph_executor::*; +use std::sync::Mutex; + +static NODE_RUNTIME_IO: Mutex> = const { Mutex::new(None) }; + +#[tokio::main] +async fn main() { + println!("Starting server..."); + + let colors = ColoredLevelConfig::new().debug(Color::Magenta).info(Color::Green).error(Color::Red); + + fern::Dispatch::new() + .chain(std::io::stdout()) + .level(log::LevelFilter::Trace) + .level_for("naga", log::LevelFilter::Error) + .level_for("wgpu-hal", log::LevelFilter::Error) + .level_for("wgpu_hal", log::LevelFilter::Error) + .level_for("wgpu_core", log::LevelFilter::Error) + .format(move |out, message, record| { + out.finish(format_args!( + "[{}]{} {} {}", + // This will color the log level only, not the whole line. Just a touch. + colors.color(record.level()), + chrono::Utc::now().format("[%Y-%m-%d %H:%M:%S]"), + message, + record.module_path().unwrap_or("") + )) + }) + .apply() + .unwrap(); + + std::thread::spawn(|| loop { + futures::executor::block_on(graphite_editor::node_graph_executor::run_node_graph()); + std::thread::sleep(std::time::Duration::from_millis(16)) + }); + graphite_editor::application::set_uuid_seed(0); + + let mut runtime_lock = NODE_RUNTIME_IO.lock().unwrap(); + *runtime_lock = Some(NodeRuntimeIO::new()); + drop(runtime_lock); + + let app = Router::new().route("/", get(|| async { "Hello, World!" })); + + // Run it with hyper on localhost:3000 + tauri::async_runtime::spawn(async { + let listener = tokio::net::TcpListener::bind("0.0.0.0:3000").await.unwrap(); + axum::serve(listener, app).await.unwrap(); + }); + + tauri::Builder::default() + .plugin(tauri_plugin_http::init()) + .plugin(tauri_plugin_shell::init()) + .invoke_handler(tauri::generate_handler![poll_node_graph, runtime_message]) + .setup(|_app| { + use tauri::Manager; + _app.get_webview_window("main").unwrap().open_devtools(); + Ok(()) + }) + .run(tauri::generate_context!()) + .expect("error while running tauri application"); +} +#[tauri::command] +fn poll_node_graph() -> String { + let vec: Vec<_> = NODE_RUNTIME_IO.lock().as_mut().unwrap().as_mut().unwrap().receive().collect(); + ron::to_string(&vec).unwrap() +} + +#[tauri::command] +fn runtime_message(message: String) -> Result<(), String> { + let message = match ron::from_str(&message) { + Ok(message) => message, + Err(e) => { + log::error!("Failed to deserialize message: {}\nwith error: {}", message, e); + return Err("Failed to deserialize message".into()); + } + }; + let response = NODE_RUNTIME_IO.lock().as_ref().unwrap().as_ref().unwrap().send(message); + response +} diff --git a/frontend/src-tauri/tauri.conf.json b/frontend/src-tauri/tauri.conf.json new file mode 100644 index 0000000000000000000000000000000000000000..b7614dff0140ebcb462b8d168f3a51aaeff20494 --- /dev/null +++ b/frontend/src-tauri/tauri.conf.json @@ -0,0 +1,59 @@ +{ + "$schema": "../node_modules/@tauri-apps/cli/schema.json", + "build": { + "beforeBuildCommand": "npm run tauri:build", + "beforeDevCommand": "npm run tauri:dev", + "frontendDist": "../dist", + "devUrl": "http://127.0.0.1:8080/" + }, + "bundle": { + "active": true, + "category": "DeveloperTool", + "copyright": "", + "targets": "all", + "externalBin": [], + "icon": ["icons/32x32.png", "icons/128x128.png", "icons/128x128@2x.png", "icons/icon.icns", "icons/icon.ico"], + "windows": { + "certificateThumbprint": null, + "digestAlgorithm": "sha256", + "timestampUrl": "" + }, + "longDescription": "", + "macOS": { + "entitlements": null, + "exceptionDomain": "", + "frameworks": [], + "providerShortName": null, + "signingIdentity": null + }, + "resources": [], + "shortDescription": "", + "linux": { + "deb": { + "depends": ["librustc_codegen_spirv"] + } + } + }, + "productName": "Graphite", + "mainBinaryName": "Graphite", + "version": "0.1.0", + "identifier": "rs.graphite.editor", + "plugins": {}, + "app": { + "withGlobalTauri": true, + "windows": [ + { + "decorations": false, + "fullscreen": false, + "height": 1080, + "resizable": true, + "title": "Graphite", + "width": 1920, + "useHttpsScheme": true + } + ], + "security": { + "csp": null + } + } +} diff --git a/frontend/src/App.svelte b/frontend/src/App.svelte new file mode 100644 index 0000000000000000000000000000000000000000..a43fb1a6adbe6a5cf95ccdbbc4242804b98fe4a2 --- /dev/null +++ b/frontend/src/App.svelte @@ -0,0 +1,24 @@ + + +{#if editor !== undefined} + +{/if} diff --git a/frontend/src/README.md b/frontend/src/README.md new file mode 100644 index 0000000000000000000000000000000000000000..71bc2927a7b5fe330704062feb6a5fe1039eb44a --- /dev/null +++ b/frontend/src/README.md @@ -0,0 +1,53 @@ +# Overview of `/frontend/src/` + +## Svelte components: `components/` + +Svelte components that build the Graphite editor GUI, which are mounted in `App.svelte`. These each contain a Svelte-templated HTML section, an SCSS (Stylus CSS) section, and a script section. The aim is to avoid implementing much editor business logic here, just enough to make things interactive and communicate to the backend where the real business logic should occur. + +## I/O managers: `io-managers/` + +TypeScript files which manage the input/output of browser APIs and link this functionality with the editor backend. These files subscribe to backend events to execute JS APIs, and in response to these APIs or user interactions, they may call functions into the backend (defined in `/frontend/wasm/editor_api.rs`). + +Each I/O manager is a self-contained module where one instance is created in `Editor.svelte` when it's mounted to the DOM at app startup. + +During development when HMR (hot-module replacement) occurs, these are also unmounted to clean up after themselves, so they can be mounted again with the updated code. Therefore, any side-effects that these managers cause (e.g. adding event listeners to the page) need a destructor function that cleans them up. The destructor function, when applicable, is returned by the module and automatically called in `Editor.svelte` on unmount. + +## State providers: `state-providers/` + +TypeScript files which provide reactive state and importable functions to Svelte components. Each module defines a Svelte writable store `const { subscribe, update } = writable({ .. });` and exports the `subscribe` method from the module in the returned object. Other functions may also be defined in the module and exported after `subscribe`, which provide a way for Svelte components to call functions to manipulate the state. + +In `Editor.svelte`, an instance of each of these are given to Svelte's [`setContext()`](https://svelte.dev/docs#run-time-svelte-setcontext) function. This allows any component to access the state provider instance using `const exampleStateProvider = getContext("exampleStateProvider");`. + +## _I/O managers vs. state providers_ + +_Some state providers, similarly to I/O managers, may subscribe to backend events, call functions from `editor_api.rs` into the backend, and interact with browser APIs and user input. The difference is that state providers are meant to be made available to components via `getContext()` to use them for reactive state, while I/O managers are meant to be self-contained systems that operate for the lifetime of the application and aren't touched by Svelte components._ + +## Utility functions: `utility-functions/` + +TypeScript files which define and `export` individual helper functions for use elsewhere in the codebase. These files should not persist state outside each function. + +## WASM editor: `editor.ts` + +Instantiates the WASM and editor backend instances. The function `initWasm()` asynchronously constructs and initializes an instance of the WASM bindings JS module provided by wasm-bindgen/wasm-pack. The function `createEditor()` constructs an instance of the editor backend. In theory there could be multiple editor instances sharing the same WASM module instance. The function returns an object where `raw` is the WASM module, `instance` is the editor, and `subscriptions` is the subscription router (described below). + +`initWasm()` occurs in `main.ts` right before the Svelte application exists, then `createEditor()` is run in `Editor.svelte` during the Svelte app's creation. Similarly to the state providers described above, the editor is given via `setContext()` so other components can get it via `getContext` and call functions on `editor.raw`, `editor.handle`, or `editor.subscriptions`. + +## Message definitions: `messages.ts` + +Defines the message formats and data types received from the backend. Since Rust and JS support different styles of data representation, this bridges the gap from Rust into JS land. Messages (and the data contained within) are serialized in Rust by `serde` into JSON, and these definitions are manually kept up-to-date to parallel the message structs and their data types. (However, directives like `#[serde(skip)]` or `#[serde(rename = "someOtherName")]` may cause the TypeScript format to look slightly different from the Rust structs.) These definitions are basically just for the sake of TypeScript to understand the format, although in some cases we may perform data conversion here using translation functions that we can provide. + +## Subscription router: `subscription-router.ts` + +Associates messages from the backend with subscribers in the frontend, and routes messages to subscriber callbacks. This module provides a `subscribeJsMessage(messageType, callback)` function which JS code throughout the frontend can call to be registered as the exclusive handler for a chosen message type. This file's other exported function, `handleJsMessage(messageType, messageData, wasm, instance)`, is called in `editor.ts` by the associated editor instance when the backend sends a `FrontendMessage`. When this occurs, the subscription router delivers the message to the subscriber for given `messageType` by executing its registered `callback` function. As an argument to the function, it provides the `messageData` payload transformed into its TypeScript-friendly format defined in `messages.ts`. + +## Svelte app entry point: `App.svelte` + +The entry point for the Svelte application. + +## Editor base instance: `Editor.svelte` + +This is where we define global CSS style rules, create/destroy the editor instance, construct/destruct the I/O managers, and construct and `setContext()` the state providers. + +## JS bundle entry point: `main.ts` + +The entry point for the entire project's code bundle. Here we simply initialize the Svelte application with `export default new App({ target: document.body });`. diff --git a/frontend/src/components/Editor.svelte b/frontend/src/components/Editor.svelte new file mode 100644 index 0000000000000000000000000000000000000000..148cd8e4b353aa6b4fdf6e8552d792b03426fa39 --- /dev/null +++ b/frontend/src/components/Editor.svelte @@ -0,0 +1,339 @@ + + + + + diff --git a/frontend/src/components/README.md b/frontend/src/components/README.md new file mode 100644 index 0000000000000000000000000000000000000000..bcf02e639d1868c043dab990f9658b273ad56c08 --- /dev/null +++ b/frontend/src/components/README.md @@ -0,0 +1,60 @@ +# Overview of `/frontend/src/components/` + +Each component represents a (usually reusable) part of the Graphite editor GUI. These all get mounted in `Editor.svelte` (in the `/src` directory above this one). + +## Floating Menus: `floating-menus/` + +The temporary UI areas with dark backgrounds which hover over the top of the editor window content. Examples include menu lists, popovers, and dialogs. + +## Layout: `layout/` + +Useful containers that control the flow of content held within. + +## Panels: `panels/` + +The dockable tabbed regions like the Document, Properties, Layers, and Node Graph panels. + +## Widgets: `widgets/` + +The interactive input items used to display information and provide user control. + +## Window: `window/` + +The building blocks for the Title Bar, Workspace, and Status Bar within an editor application window. + +# Svelte tips and tricks + +This section contains a growing list of quick reference information for helpful Svelte solutions and best practices. Feel free to add to this to help contributors learn things, or yourself remember tricks you'll likely forget in a few months. + +## Bi-directional props + +The component declares this: + +```ts +// The dispatcher that sends the changed value as a custom event to the parent +const dispatch = createEventDispatcher<{ theBidirectionalProperty: number }>(); + +// The prop +export let theBidirectionalProperty: number; + +// Called only when `theBidirectionalProperty` is changed from outside this component via its props +$: console.log(theBidirectionalProperty); + +// Example of a method that would update the value +function doSomething() { + dispatch("theBidirectionalProperty", SOME_NEW_VALUE); +}, +``` + +Users of the component do this for `theCorrespondingDataEntry` to be a two-way binding: + +```ts +let theCorrespondingDataEntry = 42; +``` + +```svelte + { theCorrespondingDataEntry = detail; }} +/> +``` diff --git a/frontend/src/components/floating-menus/ColorPicker.svelte b/frontend/src/components/floating-menus/ColorPicker.svelte new file mode 100644 index 0000000000000000000000000000000000000000..53a20010f9a694111addaad40859c52239449a0d --- /dev/null +++ b/frontend/src/components/floating-menus/ColorPicker.svelte @@ -0,0 +1,967 @@ + + + + + + + + {#if !isNone} +
+ {/if} + {#if alignedAxis} +
+ {/if} + + + {#if !isNone} +
+ {/if} + + + {#if !isNone} +
+ {/if} + + + {#if gradient} + + { + gradient = gradient; + if (gradient) dispatch("colorOrGradient", gradient); + }} + on:activeMarkerIndexChange={gradientActiveMarkerIndexChange} + activeMarkerIndex={activeIndex} + on:dragging={({ detail }) => (gradientSpectrumDragging = detail)} + bind:this={gradientSpectrumInputWidget} + /> + {#if gradientSpectrumInputWidget && activeIndex !== undefined} + { + if (gradientSpectrumInputWidget && activeIndex !== undefined && detail !== undefined) gradientSpectrumInputWidget.setPosition(activeIndex, detail / 100); + }} + displayDecimalPlaces={0} + min={0} + max={100} + unit="%" + /> + {/if} + + {/if} + + + + {#if !newColor.equals(oldColor)} +
+ + {/if} + + {#if !newColor.equals(oldColor)} + New + {/if} + + {#if !newColor.equals(oldColor)} + + Old + + {/if} +
+ + + Hex + + + { + dispatch("startHistoryTransaction"); + setColorCode(detail); + }} + centered={true} + tooltip={"Color code in hexadecimal format. 6 digits if opaque, 8 with alpha.\nAccepts input of CSS color values including named colors."} + bind:this={hexCodeInputWidget} + /> + + + + RGB + + + {#each rgbChannels as [channel, strength], index} + {#if index > 0} + + {/if} + { + strength = detail; + setColorRGB(channel, detail); + }} + on:startHistoryTransaction={() => { + dispatch("startHistoryTransaction"); + }} + min={0} + max={255} + minWidth={1} + tooltip={`${{ r: "Red", g: "Green", b: "Blue" }[channel]} channel, integers 0–255`} + /> + {/each} + + + + + HSV + + + + {#each hsvChannels as [channel, strength], index} + {#if index > 0} + + {/if} + { + strength = detail; + setColorHSV(channel, detail); + }} + on:startHistoryTransaction={() => { + dispatch("startHistoryTransaction"); + }} + min={0} + max={channel === "h" ? 360 : 100} + unit={channel === "h" ? "°" : "%"} + minWidth={1} + displayDecimalPlaces={1} + tooltip={{ + h: `Hue component, the shade along the spectrum of the rainbow`, + s: `Saturation component, the vividness from grayscale to full color`, + v: "Value component, the brightness from black to full color", + }[channel]} + /> + {/each} + + + + Alpha + + { + if (detail !== undefined) alpha = detail / 100; + setColorAlphaPercent(detail); + }} + on:startHistoryTransaction={() => { + dispatch("startHistoryTransaction"); + }} + min={0} + max={100} + rangeMin={0} + rangeMax={100} + unit="%" + mode="Range" + displayDecimalPlaces={1} + tooltip={`Scale of translucency, from transparent (0%) to opaque (100%), for the color's alpha channel`} + /> + + + + {#if allowNone && !gradient} + + + {/if} + + + + + + + + +
+ + + + diff --git a/frontend/src/components/floating-menus/Dialog.svelte b/frontend/src/components/floating-menus/Dialog.svelte new file mode 100644 index 0000000000000000000000000000000000000000..e9d0ba5fab80178c5dcb59e313669f957b6e291e --- /dev/null +++ b/frontend/src/components/floating-menus/Dialog.svelte @@ -0,0 +1,156 @@ + + + + + + + + {$dialog.title} + + + + {#if $dialog.column1.layout.length > 0} + + {/if} + {#if $dialog.panicDetails} +
+
The editor crashed — sorry about that
+
Please report this by filing an issue on GitHub:
+
window.open(githubUrl($dialog.panicDetails), "_blank")} />
+
Reload the editor to continue. If this occurs
immediately on repeated reloads, clear storage:
+
+ { + await wipeDocuments(); + window.location.reload(); + }} + /> +
+
+ {/if} +
+ {#if $dialog.column2.layout.length > 0} + + + + {/if} +
+ + {#if $dialog.buttons.layout.length > 0} + + {/if} + {#if $dialog.panicDetails} + navigator.clipboard.writeText($dialog.panicDetails)} /> + window.location.reload()} /> + {/if} + +
+ + diff --git a/frontend/src/components/floating-menus/EyedropperPreview.svelte b/frontend/src/components/floating-menus/EyedropperPreview.svelte new file mode 100644 index 0000000000000000000000000000000000000000..4ae69182c1cd0f91a0433f528dea74318e67a78e --- /dev/null +++ b/frontend/src/components/floating-menus/EyedropperPreview.svelte @@ -0,0 +1,133 @@ + + + + + +
+
+ +
+
+
+ + + diff --git a/frontend/src/components/floating-menus/MenuList.svelte b/frontend/src/components/floating-menus/MenuList.svelte new file mode 100644 index 0000000000000000000000000000000000000000..0695d38305c687b7afde5fd3d682393a821b3d99 --- /dev/null +++ b/frontend/src/components/floating-menus/MenuList.svelte @@ -0,0 +1,589 @@ + + + + + (open = detail)} + on:naturalWidth + type="Dropdown" + windowEdgeMargin={0} + escapeCloses={false} + {direction} + {minWidth} + scrollableY={scrollableY && virtualScrollingEntryHeight === 0} + bind:this={self} +> + {#if search.length > 0} + (search = detail)} bind:this={searchTextInput}> + {/if} + + + {#if virtualScrollingEntryHeight} + + {/if} + {#each entries as section, sectionIndex (sectionIndex)} + {#if includeSeparator(entries, section, sectionIndex, search)} + + {/if} + {#each currentEntries(section, virtualScrollingEntryHeight, virtualScrollingStartIndex, virtualScrollingEndIndex, search) as entry, entryIndex (entryIndex + startIndex)} + !entry.disabled && onEntryClick(entry)} + on:pointerenter={() => !entry.disabled && onEntryPointerEnter(entry)} + on:pointerleave={() => !entry.disabled && onEntryPointerLeave(entry)} + > + {#if entry.icon && drawIcon} + + {:else if drawIcon} +
+ {/if} + + {#if entry.font} + + {/if} + + + + {#if entry.shortcut?.keys.length} + + {/if} + + {#if entry.children?.length} + + {:else} +
+ {/if} + + {#if entry.children} + { + // We do a manual dispatch here instead of just `on:naturalWidth` as a workaround for the + +
+ (searchTerm = detail)} bind:this={nodeSearchInput} /> +
+ {#each nodeCategories as nodeCategory} +
+ + {nodeCategory[0]} + + {#each nodeCategory[1].nodes as nodeType} + dispatch("selectNodeType", nodeType.name)} /> + {/each} +
+ {:else} + No search results + {/each} +
+
+ + diff --git a/frontend/src/components/layout/ConditionalWrapper.svelte b/frontend/src/components/layout/ConditionalWrapper.svelte new file mode 100644 index 0000000000000000000000000000000000000000..46d5e80b04b2cfb05b63f2d27a235bd7a871cca7 --- /dev/null +++ b/frontend/src/components/layout/ConditionalWrapper.svelte @@ -0,0 +1,14 @@ + + +{#if condition} +
+ +
+{:else} + +{/if} + + diff --git a/frontend/src/components/layout/FloatingMenu.svelte b/frontend/src/components/layout/FloatingMenu.svelte new file mode 100644 index 0000000000000000000000000000000000000000..e4070cb15304a21a0302036274036016fc7e5b63 --- /dev/null +++ b/frontend/src/components/layout/FloatingMenu.svelte @@ -0,0 +1,641 @@ + + + + +
+ {#if displayTail} +
+ {/if} + {#if displayContainer} +
+ + + +
+ {/if} +
+ + diff --git a/frontend/src/components/layout/LayoutCol.svelte b/frontend/src/components/layout/LayoutCol.svelte new file mode 100644 index 0000000000000000000000000000000000000000..b69b6bfabbf8f765ecf83d662b854dfac6925bbc --- /dev/null +++ b/frontend/src/components/layout/LayoutCol.svelte @@ -0,0 +1,93 @@ + + + +
+ +
+ + + + diff --git a/frontend/src/components/layout/LayoutRow.svelte b/frontend/src/components/layout/LayoutRow.svelte new file mode 100644 index 0000000000000000000000000000000000000000..fad0220a769866ff43565bbab12ce223bbf82d1e --- /dev/null +++ b/frontend/src/components/layout/LayoutRow.svelte @@ -0,0 +1,93 @@ + + + +
+ +
+ + + + diff --git a/frontend/src/components/panels/Document.svelte b/frontend/src/components/panels/Document.svelte new file mode 100644 index 0000000000000000000000000000000000000000..70d4ea99bae2426c65402c6994650302d9209143 --- /dev/null +++ b/frontend/src/components/panels/Document.svelte @@ -0,0 +1,829 @@ + + + e.preventDefault()} on:drop={dropFile}> + + {#if !$document.graphViewOverlayOpen} + + + + + {:else} + + {/if} + + + + {#if !$document.graphViewOverlayOpen} + + + + {:else} + + {/if} + + + + + + {#if rulersVisible} + + + + + {/if} + + {#if rulersVisible} + + + + {/if} + + {#if cursorEyedropper} + + {/if} +
canvasPointerDown(e)} bind:this={viewport} data-viewport> + + {@html artworkSvg} + +
+ {#if showTextInput} +
+ {/if} +
+ + +
+
+ +
+ + + editor.handle.panCanvasByFraction(0, detail)} + on:thumbPosition={({ detail }) => panCanvasY(detail)} + on:thumbDragStart={() => editor.handle.panCanvasAbortPrepare(false)} + on:thumbDragAbort={() => editor.handle.panCanvasAbort(false)} + /> + + + + editor.handle.panCanvasByFraction(detail, 0)} + on:thumbPosition={({ detail }) => panCanvasX(detail)} + on:thumbDragEnd={() => editor.handle.setGridAlignedEdges()} + on:thumbDragStart={() => editor.handle.panCanvasAbortPrepare(true)} + on:thumbDragAbort={() => editor.handle.panCanvasAbort(true)} + /> + + + + + + diff --git a/frontend/src/components/panels/Layers.svelte b/frontend/src/components/panels/Layers.svelte new file mode 100644 index 0000000000000000000000000000000000000000..092a83fbac4085873bbdb6089c4bb296401129de --- /dev/null +++ b/frontend/src/components/panels/Layers.svelte @@ -0,0 +1,805 @@ + + + (dragInPanel = false)}> + + + + + + + deselectAllLayers()} + on:dragover={updateInsertLine} + on:dragend={drop} + on:drop={drop} + > + {#each layers as listing, index} + {@const selected = fakeHighlightOfNotYetSelectedLayerBeingDragged !== undefined ? fakeHighlightOfNotYetSelectedLayerBeingDragged === listing.entry.id : listing.entry.selected} + draggable && dragStart(e, listing)} + on:click={(e) => selectLayerWithModifiers(e, listing)} + > + {#if listing.entry.childrenAllowed} + + {:else} +
+ {/if} + {#if listing.entry.clipped} + + {/if} +
+ {#if $nodeGraph.thumbnails.has(listing.entry.id)} + {@html $nodeGraph.thumbnails.get(listing.entry.id)} + {/if} +
+ {#if listing.entry.name === "Artboard"} + + {/if} + onEditLayerName(listing)}> + onEditLayerNameDeselect(listing)} + on:keydown={(e) => e.key === "Escape" && onEditLayerNameDeselect(listing)} + on:keydown={(e) => e.key === "Enter" && onEditLayerNameChange(listing, e)} + on:change={(e) => onEditLayerNameChange(listing, e)} + /> + + {#if !listing.entry.unlocked || !listing.entry.parentsUnlocked} + (toggleLayerLock(listing.entry.id), e?.stopPropagation())} + size={24} + icon={listing.entry.unlocked ? "PadlockUnlocked" : "PadlockLocked"} + hoverIcon={listing.entry.unlocked ? "PadlockLocked" : "PadlockUnlocked"} + tooltip={(listing.entry.unlocked ? "Lock" : "Unlock") + (!listing.entry.parentsUnlocked ? "\n(A parent of this layer is locked and that status is being inherited)" : "")} + /> + {/if} + (toggleNodeVisibilityLayerPanel(listing.entry.id), e?.stopPropagation())} + size={24} + icon={listing.entry.visible ? "EyeVisible" : "EyeHidden"} + hoverIcon={listing.entry.visible ? "EyeHide" : "EyeShow"} + tooltip={(listing.entry.visible ? "Hide" : "Show") + (!listing.entry.parentsVisible ? "\n(A parent of this layer is hidden and that status is being inherited)" : "")} + /> +
+ {/each} +
+ {#if draggingData && !draggingData.highlightFolder && dragInPanel} +
+ {/if} + + + + + + + diff --git a/frontend/src/components/panels/Properties.svelte b/frontend/src/components/panels/Properties.svelte new file mode 100644 index 0000000000000000000000000000000000000000..72607849a53545b2a40747dda915153e20c9dd48 --- /dev/null +++ b/frontend/src/components/panels/Properties.svelte @@ -0,0 +1,51 @@ + + + + + + + + + diff --git a/frontend/src/components/panels/Spreadsheet.svelte b/frontend/src/components/panels/Spreadsheet.svelte new file mode 100644 index 0000000000000000000000000000000000000000..6dd49c6058ce2676ad63856c87745aa82c7c5422 --- /dev/null +++ b/frontend/src/components/panels/Spreadsheet.svelte @@ -0,0 +1,50 @@ + + + + + Spreadsheet Data for Node ID {$portfolio.spreadsheetNode}: + + + + + + + diff --git a/frontend/src/components/views/Graph.svelte b/frontend/src/components/views/Graph.svelte new file mode 100644 index 0000000000000000000000000000000000000000..eaedc3a6dfe410221940bec004e54ad88a9a2efd --- /dev/null +++ b/frontend/src/components/views/Graph.svelte @@ -0,0 +1,1353 @@ + + +
+ + {#if $nodeGraph.contextMenuInformation} + + {#if typeof $nodeGraph.contextMenuInformation.contextMenuData === "string" && $nodeGraph.contextMenuInformation.contextMenuData === "CreateNode"} + createNode(e.detail)} /> + {:else if $nodeGraph.contextMenuInformation.contextMenuData && "compatibleType" in $nodeGraph.contextMenuInformation.contextMenuData} + createNode(e.detail)} /> + {:else} + {@const contextMenuData = $nodeGraph.contextMenuInformation.contextMenuData} + + Display as + { + toggleLayerDisplay(false, contextMenuData.nodeId); + }, + }, + { + value: "layer", + label: "Layer", + action: () => { + toggleLayerDisplay(true, contextMenuData.nodeId); + }, + }, + ]} + disabled={!canBeToggledBetweenNodeAndLayer(contextMenuData.nodeId)} + /> + + + + editor.handle.mergeSelectedNodes()} /> + + {/if} + + {/if} + + + {#if $nodeGraph.clickTargets} +
+ + {#each $nodeGraph.clickTargets.nodeClickTargets as pathString} + + {/each} + {#each $nodeGraph.clickTargets.layerClickTargets as pathString} + + {/each} + {#each $nodeGraph.clickTargets.portClickTargets as pathString} + + {/each} + {#each $nodeGraph.clickTargets.iconClickTargets as pathString} + + {/each} + + + {#each $nodeGraph.clickTargets.modifyImportExport as pathString} + + {/each} + +
+ {/if} + + +
+ + {#each $nodeGraph.wires.values() as map} + {#each map.values() as { pathString, dataType, thick, dashed }} + {#if thick} + + {/if} + {/each} + {/each} + +
+ + +
+ {#each $nodeGraph.imports as { outputMetadata, position }, index} + + {`${dataTypeTooltip(outputMetadata)}\n\n${outputConnectedToText(outputMetadata)}`} + {#if outputMetadata.connectedTo !== undefined} + + {:else} + + {/if} + + +
(hoveringImportIndex = index)} + on:pointerleave={() => (hoveringImportIndex = undefined)} + style:--offset-left={position.x / 24} + style:--offset-top={position.y / 24} + > + {#if editingNameImportIndex == index} + e.key === "Enter" && setEditingImportName(e)} + /> + {:else} +

setEditingImportNameIndex(index, outputMetadata.name)}>{outputMetadata.name}

+ {/if} + {#if hoveringImportIndex === index || editingNameImportIndex === index} + { + /* Button is purely visual, clicking is handled in NodeGraphMessage::PointerDown */ + }} + /> +
+ {/if} +
+ {/each} + {#if $nodeGraph.reorderImportIndex !== undefined} + {@const position = { + x: Number($nodeGraph.imports[0].position.x), + y: Number($nodeGraph.imports[0].position.y) + Number($nodeGraph.reorderImportIndex) * 24, + }} +
+ {/if} + {#if $nodeGraph.addImport !== undefined} +
+ { + /* Button is purely visual, clicking is handled in NodeGraphMessage::PointerDown */ + }} + /> +
+ {/if} + {#each $nodeGraph.exports as { inputMetadata, position }, index} + + {`${dataTypeTooltip(inputMetadata)}\n\n${inputConnectedToText(inputMetadata)}`} + {#if inputMetadata.connectedTo !== undefined} + + {:else} + + {/if} + +
(hoveringExportIndex = index)} + on:pointerleave={() => (hoveringExportIndex = undefined)} + style:--offset-left={position.x / 24} + style:--offset-top={position.y / 24} + > + {#if hoveringExportIndex === index || editingNameExportIndex === index} +
+ { + /* Button is purely visual, clicking is handled in NodeGraphMessage::PointerDown */ + }} + /> + {/if} + {#if editingNameExportIndex === index} + e.key === "Enter" && setEditingExportName(e)} + /> + {:else} +

setEditingExportNameIndex(index, inputMetadata.name)}>{inputMetadata.name}

+ {/if} +
+ {/each} + {#if $nodeGraph.reorderExportIndex !== undefined} + {@const position = { + x: Number($nodeGraph.exports[0].position.x), + y: Number($nodeGraph.exports[0].position.y) + Number($nodeGraph.reorderExportIndex) * 24, + }} +
+ {/if} + {#if $nodeGraph.addExport !== undefined} +
+ { + /* Button is purely visual, clicking is handled in NodeGraphMessage::PointerDown */ + }} + /> +
+ {/if} +
+ + +
+ + {#each Array.from($nodeGraph.nodes) + .filter(([nodeId, node]) => node.isLayer && $nodeGraph.visibleNodes.has(nodeId)) + .map(([_, node], nodeIndex) => ({ node, nodeIndex })) as { node, nodeIndex } (nodeIndex)} + {@const clipPathId = String(Math.random()).substring(2)} + {@const stackDataInput = node.exposedInputs[0]} + {@const layerAreaWidth = $nodeGraph.layerWidths.get(node.id) || 8} + {@const layerChainWidth = $nodeGraph.chainWidths.get(node.id) || 0} + {@const hasLeftInputWire = $nodeGraph.hasLeftInputWire.get(node.id) || false} + {@const description = (node.reference && $nodeGraph.nodeDescriptions.get(node.reference)) || undefined} +
+ {#if node.errors} + {node.errors} + {node.errors} + {/if} +
+ {#if $nodeGraph.thumbnails.has(node.id)} + {@html $nodeGraph.thumbnails.get(node.id)} + {/if} + + {#if node.primaryOutput} + + {`${dataTypeTooltip(node.primaryOutput)}\n\n${outputConnectedToText(node.primaryOutput)}`} + {#if node.primaryOutput.connectedTo.length > 0} + + {#if primaryOutputConnectedToLayer(node)} + + {/if} + {:else} + + {/if} + + {/if} + + + {#if node.primaryInput} + {`${dataTypeTooltip(node.primaryInput)}\n\n${validTypesText(node.primaryInput)}\n\n${inputConnectedToText(node.primaryInput)}`} + {/if} + {#if node.primaryInput?.connectedTo !== undefined} + + {#if primaryInputConnectedToLayer(node)} + + {/if} + {:else} + + {/if} + +
+ + {#if node.exposedInputs.length > 0} +
+ + {`${dataTypeTooltip(stackDataInput)}\n\n${validTypesText(stackDataInput)}\n\n${inputConnectedToText(stackDataInput)}`} + {#if stackDataInput.connectedTo !== undefined} + + {:else} + + {/if} + +
+ {/if} +
+ + {node.displayName} +
+
+ { + /* Button is purely visual, clicking is handled in NodeGraphMessage::PointerDown */ + }} + tooltip={node.visible ? "Visible" : "Hidden"} + /> + + + + + + + + + +
+ {/each} + + +
+ + {#each $nodeGraph.wires.values() as map} + {#each map.values() as { pathString, dataType, thick, dashed }} + {#if !thick} + + {/if} + {/each} + {/each} + {#if $nodeGraph.wirePathInProgress} + + {/if} + +
+ + + {#each Array.from($nodeGraph.nodes) + .filter(([nodeId, node]) => !node.isLayer && $nodeGraph.visibleNodes.has(nodeId)) + .map(([_, node], nodeIndex) => ({ node, nodeIndex })) as { node, nodeIndex } (nodeIndex)} + {@const exposedInputsOutputs = zipWithUndefined(node.exposedInputs, node.exposedOutputs)} + {@const clipPathId = String(Math.random()).substring(2)} + {@const description = (node.reference && $nodeGraph.nodeDescriptions.get(node.reference)) || undefined} +
+ {#if node.errors} + {node.errors} + {node.errors} + {/if} + +
+ + + {node.displayName} +
+ + {#if exposedInputsOutputs.length > 0} +
+ {#each exposedInputsOutputs as [input, output]} +
+ + {input !== undefined ? input.name : output.name} + +
+ {/each} +
+ {/if} + +
+ {#if node.primaryInput?.dataType} + + {`${dataTypeTooltip(node.primaryInput)}\n\n${validTypesText(node.primaryInput)}\n\n${inputConnectedToText(node.primaryInput)}`} + {#if node.primaryInput.connectedTo !== undefined} + + {:else} + + {/if} + + {/if} + {#each node.exposedInputs as secondary, index} + {#if index < node.exposedInputs.length} + + {`${dataTypeTooltip(secondary)}\n\n${validTypesText(secondary)}\n\n${inputConnectedToText(secondary)}`} + {#if secondary.connectedTo !== undefined} + + {:else} + + {/if} + + {/if} + {/each} +
+ +
+ {#if node.primaryOutput} + + {`${dataTypeTooltip(node.primaryOutput)}\n\n${outputConnectedToText(node.primaryOutput)}`} + {#if node.primaryOutput.connectedTo !== undefined} + + {:else} + + {/if} + + {/if} + {#each node.exposedOutputs as secondary} + + {`${dataTypeTooltip(secondary)}\n\n${outputConnectedToText(secondary)}`} + {#if secondary.connectedTo !== undefined} + + {:else} + + {/if} + + {/each} +
+ + + + + + + +
+ {/each} +
+
+ + + +{#if $nodeGraph.box} +
+{/if} + + diff --git a/frontend/src/components/widgets/WidgetLayout.svelte b/frontend/src/components/widgets/WidgetLayout.svelte new file mode 100644 index 0000000000000000000000000000000000000000..63b75e274f539b25dd245bed7c062e491051e93a --- /dev/null +++ b/frontend/src/components/widgets/WidgetLayout.svelte @@ -0,0 +1,27 @@ + + +{#each layout.layout as layoutGroup} + {#if isWidgetSpanRow(layoutGroup) || isWidgetSpanColumn(layoutGroup)} + + {:else if isWidgetSection(layoutGroup)} + + {:else if isWidgetTable(layoutGroup)} + + {:else} + Error: The widget layout that belongs here has an invalid layout group type + {/if} +{/each} + + diff --git a/frontend/src/components/widgets/WidgetSection.svelte b/frontend/src/components/widgets/WidgetSection.svelte new file mode 100644 index 0000000000000000000000000000000000000000..39448166dab5f1d533095d8b5cccfb44c1cd633c --- /dev/null +++ b/frontend/src/components/widgets/WidgetSection.svelte @@ -0,0 +1,190 @@ + + + + + + {#if expanded} + + {#each widgetData.layout as layoutGroup} + {#if isWidgetSpanRow(layoutGroup)} + + {:else if isWidgetSpanColumn(layoutGroup)} + Error: The WidgetSpan used here should be a row not a column + {:else if isWidgetSection(layoutGroup)} + + {:else} + Error: The widget that belongs here has an invalid layout group type + {/if} + {/each} + + {/if} + + + diff --git a/frontend/src/components/widgets/WidgetSpan.svelte b/frontend/src/components/widgets/WidgetSpan.svelte new file mode 100644 index 0000000000000000000000000000000000000000..831e1dbbce5f38a142853f353d6c27b9eb1daa0e --- /dev/null +++ b/frontend/src/components/widgets/WidgetSpan.svelte @@ -0,0 +1,220 @@ + + + + +
+ {#each widgets as component, index} + {@const checkboxInput = narrowWidgetProps(component.props, "CheckboxInput")} + {#if checkboxInput} + widgetValueCommitAndUpdate(index, detail)} /> + {/if} + {@const colorInput = narrowWidgetProps(component.props, "ColorInput")} + {#if colorInput} + widgetValueUpdate(index, detail)} on:startHistoryTransaction={() => widgetValueCommit(index, colorInput.value)} /> + {/if} + {@const curvesInput = narrowWidgetProps(component.props, "CurveInput")} + {#if curvesInput} + debouncer((value) => widgetValueCommitAndUpdate(index, value), { debounceTime: 120 }).debounceUpdateValue(detail)} /> + {/if} + {@const dropdownInput = narrowWidgetProps(component.props, "DropdownInput")} + {#if dropdownInput} + { + return widgetValueUpdate(index, detail); + }} + on:hoverOutEntry={({ detail }) => { + return widgetValueUpdate(index, detail); + }} + on:selectedIndex={({ detail }) => widgetValueCommitAndUpdate(index, detail)} + /> + {/if} + {@const fontInput = narrowWidgetProps(component.props, "FontInput")} + {#if fontInput} + widgetValueCommitAndUpdate(index, detail)} /> + {/if} + {@const parameterExposeButton = narrowWidgetProps(component.props, "ParameterExposeButton")} + {#if parameterExposeButton} + widgetValueCommitAndUpdate(index, undefined)} /> + {/if} + {@const iconButton = narrowWidgetProps(component.props, "IconButton")} + {#if iconButton} + widgetValueCommitAndUpdate(index, undefined)} /> + {/if} + {@const iconLabel = narrowWidgetProps(component.props, "IconLabel")} + {#if iconLabel} + + {/if} + {@const imageButton = narrowWidgetProps(component.props, "ImageButton")} + {#if imageButton} + widgetValueCommitAndUpdate(index, undefined)} /> + {/if} + {@const nodeCatalog = narrowWidgetProps(component.props, "NodeCatalog")} + {#if nodeCatalog} + widgetValueCommitAndUpdate(index, e.detail)} /> + {/if} + {@const numberInput = narrowWidgetProps(component.props, "NumberInput")} + {#if numberInput} + debouncer((value) => widgetValueUpdate(index, value)).debounceUpdateValue(detail)} + on:startHistoryTransaction={() => widgetValueCommit(index, numberInput.value)} + incrementCallbackIncrease={() => widgetValueCommitAndUpdate(index, "Increment")} + incrementCallbackDecrease={() => widgetValueCommitAndUpdate(index, "Decrement")} + /> + {/if} + {@const referencePointInput = narrowWidgetProps(component.props, "ReferencePointInput")} + {#if referencePointInput} + widgetValueCommitAndUpdate(index, detail)} /> + {/if} + {@const popoverButton = narrowWidgetProps(component.props, "PopoverButton")} + {#if popoverButton} + + + + {/if} + {@const radioInput = narrowWidgetProps(component.props, "RadioInput")} + {#if radioInput} + widgetValueCommitAndUpdate(index, detail)} /> + {/if} + {@const separator = narrowWidgetProps(component.props, "Separator")} + {#if separator} + + {/if} + {@const workingColorsInput = narrowWidgetProps(component.props, "WorkingColorsInput")} + {#if workingColorsInput} + + {/if} + {@const textAreaInput = narrowWidgetProps(component.props, "TextAreaInput")} + {#if textAreaInput} + widgetValueCommitAndUpdate(index, detail)} /> + {/if} + {@const textButton = narrowWidgetProps(component.props, "TextButton")} + {#if textButton} + widgetValueCommitAndUpdate(index, undefined)} /> + {/if} + {@const breadcrumbTrailButtons = narrowWidgetProps(component.props, "BreadcrumbTrailButtons")} + {#if breadcrumbTrailButtons} + widgetValueCommitAndUpdate(index, breadcrumbIndex)} /> + {/if} + {@const textInput = narrowWidgetProps(component.props, "TextInput")} + {#if textInput} + widgetValueCommitAndUpdate(index, detail)} /> + {/if} + {@const textLabel = narrowWidgetProps(component.props, "TextLabel")} + {#if textLabel} + {textLabel.value} + {/if} + {/each} +
+ + diff --git a/frontend/src/components/widgets/WidgetTable.svelte b/frontend/src/components/widgets/WidgetTable.svelte new file mode 100644 index 0000000000000000000000000000000000000000..6530b4c89947f0919db296ee8da63e34df3c019a --- /dev/null +++ b/frontend/src/components/widgets/WidgetTable.svelte @@ -0,0 +1,42 @@ + + + + {#each widgetData.tableWidgets as row} + + {#each row as cell} + + {/each} + + {/each} +
+ +
+ + diff --git a/frontend/src/components/widgets/buttons/BreadcrumbTrailButtons.svelte b/frontend/src/components/widgets/buttons/BreadcrumbTrailButtons.svelte new file mode 100644 index 0000000000000000000000000000000000000000..f3b68c752340a60c510e04afa268bb16263d18a1 --- /dev/null +++ b/frontend/src/components/widgets/buttons/BreadcrumbTrailButtons.svelte @@ -0,0 +1,63 @@ + + + + {#each labels as label, index} + !disabled && index !== labels.length - 1 && action(index)} /> + {/each} + + + diff --git a/frontend/src/components/widgets/buttons/IconButton.svelte b/frontend/src/components/widgets/buttons/IconButton.svelte new file mode 100644 index 0000000000000000000000000000000000000000..97fbc2c8c9ccc6b4f565002a0c6a06312c412a90 --- /dev/null +++ b/frontend/src/components/widgets/buttons/IconButton.svelte @@ -0,0 +1,112 @@ + + + + + diff --git a/frontend/src/components/widgets/buttons/ImageButton.svelte b/frontend/src/components/widgets/buttons/ImageButton.svelte new file mode 100644 index 0000000000000000000000000000000000000000..00e9de6aa70b244eca09f6fd243deb5331b8c53c --- /dev/null +++ b/frontend/src/components/widgets/buttons/ImageButton.svelte @@ -0,0 +1,31 @@ + + + + + diff --git a/frontend/src/components/widgets/buttons/ParameterExposeButton.svelte b/frontend/src/components/widgets/buttons/ParameterExposeButton.svelte new file mode 100644 index 0000000000000000000000000000000000000000..09e89e648b26318430ac571dbc2259c9a4538927 --- /dev/null +++ b/frontend/src/components/widgets/buttons/ParameterExposeButton.svelte @@ -0,0 +1,79 @@ + + + + + + + diff --git a/frontend/src/components/widgets/buttons/PopoverButton.svelte b/frontend/src/components/widgets/buttons/PopoverButton.svelte new file mode 100644 index 0000000000000000000000000000000000000000..b0bb0a551ef6103cfb0fe320591034e4a237c63a --- /dev/null +++ b/frontend/src/components/widgets/buttons/PopoverButton.svelte @@ -0,0 +1,100 @@ + + + + onClick()} icon={style || "DropdownArrow"} size={16} {tooltip} data-floating-menu-spawner /> + {#if icon !== undefined} + + {/if} + + (open = detail)} minWidth={popoverMinWidth} type="Popover" direction={menuDirection || "Bottom"}> + + + + + diff --git a/frontend/src/components/widgets/buttons/TextButton.svelte b/frontend/src/components/widgets/buttons/TextButton.svelte new file mode 100644 index 0000000000000000000000000000000000000000..aaac0a50ca9fa8cdd2ebba9ee6b17da34a9803cb --- /dev/null +++ b/frontend/src/components/widgets/buttons/TextButton.svelte @@ -0,0 +1,180 @@ + + + + + {#if menuListChildrenExists} + self && (self.open = detail)} + open={self?.open || false} + entries={menuListChildren || []} + direction="Bottom" + minWidth={240} + drawIcon={true} + bind:this={self} + /> + {/if} + + + diff --git a/frontend/src/components/widgets/inputs/CheckboxInput.svelte b/frontend/src/components/widgets/inputs/CheckboxInput.svelte new file mode 100644 index 0000000000000000000000000000000000000000..f8e53eeadba74040fc1b3af84063fc05ec274810 --- /dev/null +++ b/frontend/src/components/widgets/inputs/CheckboxInput.svelte @@ -0,0 +1,125 @@ + + + + dispatch("checked", inputElement?.checked || false)} + {disabled} + tabindex={disabled ? -1 : 0} + bind:this={inputElement} + /> + + + + diff --git a/frontend/src/components/widgets/inputs/ColorInput.svelte b/frontend/src/components/widgets/inputs/ColorInput.svelte new file mode 100644 index 0000000000000000000000000000000000000000..1dd01ae244b78f5d47992358a8f1d89efdef22ee --- /dev/null +++ b/frontend/src/components/widgets/inputs/ColorInput.svelte @@ -0,0 +1,141 @@ + + + + + (open = detail)} + colorOrGradient={value} + on:colorOrGradient={({ detail }) => { + value = detail; + dispatch("value", detail); + }} + on:startHistoryTransaction={() => { + // This event is sent to the backend so it knows to start a transaction for the history system. See discussion for some explanation: + // + dispatch("startHistoryTransaction"); + }} + {allowNone} + /> + + + diff --git a/frontend/src/components/widgets/inputs/CurveInput.svelte b/frontend/src/components/widgets/inputs/CurveInput.svelte new file mode 100644 index 0000000000000000000000000000000000000000..634bb45f1df5ae3e6b03ac52d74e553aae45ed6a --- /dev/null +++ b/frontend/src/components/widgets/inputs/CurveInput.svelte @@ -0,0 +1,259 @@ + + + + + {#each { length: GRID_SIZE - 1 } as _, i} + + + {/each} + + {#if selectedNodeIndex !== undefined} + {@const group = groups[selectedNodeIndex]} + {#each [0, 1] as i} + + handleManipulatorPointerDown(e, -i - 1)} /> + {/each} + {/if} + {#each groups as group, i} + handleManipulatorPointerDown(e, i)} /> + {/each} + + + + + diff --git a/frontend/src/components/widgets/inputs/DropdownInput.svelte b/frontend/src/components/widgets/inputs/DropdownInput.svelte new file mode 100644 index 0000000000000000000000000000000000000000..4317a519f4891edcde9e7852d7c6bb167ee2993e --- /dev/null +++ b/frontend/src/components/widgets/inputs/DropdownInput.svelte @@ -0,0 +1,179 @@ + + + 0 ? { "min-width": `${minWidth}px` } : {}), ...(maxWidth > 0 ? { "max-width": `${maxWidth}px` } : {}) }} + bind:this={self} + data-dropdown-input +> + !disabled && (open = true)} + on:blur={unFocusDropdownBox} + tabindex={disabled ? -1 : 0} + data-floating-menu-spawner + > + {#if activeEntry.icon} + + {/if} + {activeEntry.label} + + + (minWidth = detail)} + {activeEntry} + on:activeEntry={({ detail }) => (activeEntry = detail)} + on:hoverInEntry={({ detail }) => dispatchHoverInEntry(detail)} + on:hoverOutEntry={() => dispatchHoverOutEntry()} + {open} + on:open={({ detail }) => (open = detail)} + {entries} + {drawIcon} + {interactive} + direction="Bottom" + scrollableY={true} + bind:this={menuList} + /> + + + diff --git a/frontend/src/components/widgets/inputs/FieldInput.svelte b/frontend/src/components/widgets/inputs/FieldInput.svelte new file mode 100644 index 0000000000000000000000000000000000000000..b35279401aa918b7f61fc5fc9dd41dc7946aa65a --- /dev/null +++ b/frontend/src/components/widgets/inputs/FieldInput.svelte @@ -0,0 +1,216 @@ + + + + + {#if !textarea} + dispatch("textFocused")} + on:blur={() => dispatch("textChanged")} + on:change={() => dispatch("textChanged")} + on:keydown={(e) => e.key === "Enter" && dispatch("textChanged")} + on:keydown={(e) => e.key === "Escape" && cancel()} + on:pointerdown + on:contextmenu={(e) => hideContextMenu && e.preventDefault()} + data-input-element + /> + {:else} +