9 Commits

Author SHA1 Message Date
fdd9785fc7 wip 2026-02-17 13:45:21 +01:00
3be978ffb0 feat: some shit 2026-02-17 13:45:21 +01:00
Max Richter
39b8095497 feat: add debug node 2026-02-17 13:45:21 +01:00
Max Richter
251f999739 feat: some shit 2026-02-17 13:45:21 +01:00
Max Richter
e3947534f6 chore: make sure to specify wasm flags only on wasm build 2026-02-17 13:45:21 +01:00
Max Richter
664ed4e029 chore: cargo fix 2026-02-17 13:45:20 +01:00
Max Richter
1063d33536 feat: make all nodes work with new runtime 2026-02-17 13:45:20 +01:00
Max Richter
ab08fc7486 feat: first working version of new allocator 2026-02-17 13:45:20 +01:00
Max Richter
2a14ed7202 feat: add "*"/any type input for dev page 2026-02-17 13:45:19 +01:00
63 changed files with 763 additions and 1740 deletions

View File

@@ -58,7 +58,6 @@ tmp_changelog="CHANGELOG.tmp"
echo ""
if [ -n "$COMMITS" ]; then
echo "---"
echo ""
echo "$COMMITS"
echo ""
fi
@@ -73,24 +72,12 @@ mv "$tmp_changelog" CHANGELOG.md
pnpm exec dprint fmt CHANGELOG.md
# -------------------------------------------------------------------
# 5. Setup GPG signing
# 5. Create release commit
# -------------------------------------------------------------------
echo "$BOT_PGP_PRIVATE_KEY" | base64 -d | gpg --batch --import
GPG_KEY_ID=$(gpg --list-secret-keys --keyid-format LONG | grep sec | awk '{print $2}' | cut -d'/' -f2)
git config user.name "release-bot"
git config user.email "release-bot@ci"
export GPG_TTY=$(tty)
echo "allow-loopback-pinentry" >>~/.gnupg/gpg-agent.conf
gpg-connect-agent reloadagent /bye
git config user.name "nodarium-bot"
git config user.email "nodarium-bot@max-richter.dev"
git config --global user.signingkey "$GPG_KEY_ID"
git config --global commit.gpgsign true
# -------------------------------------------------------------------
# 6. Create release commit
# -------------------------------------------------------------------
git add CHANGELOG.md $(git ls-files '**/package.json')
git add CHANGELOG.md $(find . -name package.json ! -path "*/node_modules/*")
if git diff --cached --quiet; then
echo "No changes to commit for release $TAG"
@@ -99,4 +86,6 @@ else
git push origin main
fi
rm app/static/CHANGELOG.md
cp CHANGELOG.md app/static/CHANGELOG.md
echo "✅ Release process for $TAG complete"

View File

@@ -1,59 +0,0 @@
name: 📊 Benchmark the Runtime
on:
push:
branches: ["*"]
pull_request:
branches: ["*"]
env:
PNPM_CACHE_FOLDER: .pnpm-store
CARGO_HOME: .cargo
CARGO_TARGET_DIR: target
jobs:
release:
runs-on: ubuntu-latest
container: git.max-richter.dev/max/nodarium-ci:bce06da456e3c008851ac006033cfff256015a47
steps:
- name: 📑 Checkout Code
uses: actions/checkout@v4
with:
fetch-depth: 0
token: ${{ secrets.GITEA_TOKEN }}
- name: 💾 Setup pnpm Cache
uses: actions/cache@v4
with:
path: ${{ env.PNPM_CACHE_FOLDER }}
key: ${{ runner.os }}-pnpm-${{ hashFiles('**/pnpm-lock.yaml') }}
restore-keys: |
${{ runner.os }}-pnpm-
- name: 🦀 Cache Cargo
uses: actions/cache@v4
with:
path: |
~/.cargo/registry
~/.cargo/git
target
key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }}
restore-keys: |
${{ runner.os }}-cargo-
- name: 📦 Install Dependencies
run: pnpm install --frozen-lockfile --store-dir ${{ env.PNPM_CACHE_FOLDER }}
- name: 🛠Build Nodes
run: pnpm build:nodes
- name: 🏃 Execute Runtime
run: pnpm run --filter @nodarium/app bench
- name: 📤 Upload Benchmark Results
uses: actions/upload-artifact@v3
with:
name: benchmark-data
path: app/benchmark/out/
compression: 9

View File

@@ -15,7 +15,7 @@ env:
jobs:
release:
runs-on: ubuntu-latest
container: git.max-richter.dev/max/nodarium-ci:bce06da456e3c008851ac006033cfff256015a47
container: git.max-richter.dev/max/nodarium-ci:fd7268d6208aede435e1685817ae6b271c68bd83
steps:
- name: 📑 Checkout Code
@@ -48,20 +48,18 @@ jobs:
- name: 🧹 Quality Control
run: |
pnpm build
pnpm lint
pnpm format:check
pnpm check
pnpm build
xvfb-run --auto-servernum --server-args="-screen 0 1280x1024x24" pnpm test
- name: 🛠️ Build
run: ./.gitea/scripts/build.sh
- name: 🚀 Create Release Commit
if: gitea.ref_type == 'tag'
run: ./.gitea/scripts/create-release.sh
env:
BOT_PGP_PRIVATE_KEY: ${{ secrets.BOT_PGP_PRIVATE_KEY }}
- name: 🛠️ Build
run: ./.gitea/scripts/build.sh
- name: 🏷️ Create Gitea Release
if: gitea.ref_type == 'tag'

2
.gitignore vendored
View File

@@ -5,5 +5,3 @@ node_modules/
/target
.direnv/
.pnpm-store/

View File

@@ -1,131 +1,3 @@
# v0.0.5 (2026-02-13)
## Features
- Implement debug node with full runtime integration, wildcard (`*`) inputs, variable-height nodes and parameters, and a quick-connect shortcut.
- Add color-coded node sockets and edges to visually indicate data types.
- Recursively merge `localState` with the initial state to safely handle outdated settings stored in `localStorage` when the settings schema changes.
- Clamp the Add Menu to the viewport.
- Add application favicon.
- Consolidate all developer settings into a single **Advanced Mode** setting.
## Fixes
- Fix InputNumber arrow visibility in the light theme.
- Correct changelog formatting issues.
## Chores
- Add `pnpm qa` pre-commit command.
- Run linting and type checks before build in CI.
- Sign release commits with a PGP key.
- General formatting, lint/type cleanup, test snapshot updates, and `.gitignore` maintenance.
---
- [f16ba26](https://git.max-richter.dev/max/nodarium/commit/f16ba2601ff0e8f0f4454e24689499112a2a257a) fix(ci): still trying to get gpg to work
- [cc6b832](https://git.max-richter.dev/max/nodarium/commit/cc6b832f1576356e5453ee4289b02f854152ff9a) fix(ci): trying to get gpg to work
- [dd5fd5b](https://git.max-richter.dev/max/nodarium/commit/dd5fd5bf1715d371566bd40419b72ca05e63401e) fix(ci): better add updates to package.json
- [38d0fff](https://git.max-richter.dev/max/nodarium/commit/38d0fffcf4ca0a346857c3658ccefdfcdf16e217) chore: update ci image
- [bce06da](https://git.max-richter.dev/max/nodarium/commit/bce06da456e3c008851ac006033cfff256015a47) ci: add gpg-agent to ci image
- [af585d5](https://git.max-richter.dev/max/nodarium/commit/af585d56ec825662961c8796226ed9d8cb900795) feat: use new ci image with gpg
- [0aa73a2](https://git.max-richter.dev/max/nodarium/commit/0aa73a27c1f23bea177ecc66034f8e0384c29a8e) feat: install gpg in ci image
- [c1ae702](https://git.max-richter.dev/max/nodarium/commit/c1ae70282cb5d58527180614a80823d80ca478c5) feat: add color to sockets
- [4c7b03d](https://git.max-richter.dev/max/nodarium/commit/4c7b03dfb82174317d8ba01f4725af804201154d) feat: add gradient mesh line
- [144e8cc](https://git.max-richter.dev/max/nodarium/commit/144e8cc797cfcc5a7a1fd9a0a2098dc99afb6170) fix: correctly highlight possible outputs
- [12ff9c1](https://git.max-richter.dev/max/nodarium/commit/12ff9c151873d253ed2e54dcf56aa9c9c4716c7c) Merge pull request 'feat/debug-node' (#41) from feat/debug-node into main
- [8d3ffe8](https://git.max-richter.dev/max/nodarium/commit/8d3ffe84ab9ca9e6d6d28333752e34da878fd3ea) Merge branch 'main' into feat/debug-node
- [95ec93e](https://git.max-richter.dev/max/nodarium/commit/95ec93eeada9bf062e01e1e77b67b8f0343a51bf) feat: better handle ctrl+shift clicks and selections
- [d39185e](https://git.max-richter.dev/max/nodarium/commit/d39185efafc360f49ab9437c0bad1f64665df167) feat: add "pnpm qa" command to check before commit
- [81580cc](https://git.max-richter.dev/max/nodarium/commit/81580ccd8c1db30ce83433c4c4df84bd660d3460) fix: cleanup some type errors
- [bf6f632](https://git.max-richter.dev/max/nodarium/commit/bf6f632d2772c3da812d5864c401f17e1aa8666a) feat: add shortcut to quick connect to debug
- [e098be6](https://git.max-richter.dev/max/nodarium/commit/e098be60135f57cf863904a58489e032ed27e8b4) fix: also execute all nodes before debug node
- [ec13850](https://git.max-richter.dev/max/nodarium/commit/ec13850e1c0ca5846da614d25887ff492cf8be04) fix: make debug node work with runtime
- [15e08a8](https://git.max-richter.dev/max/nodarium/commit/15e08a816339bdf9de9ecb6a57a7defff42dbe8c) feat: implement debug node
- [48cee58](https://git.max-richter.dev/max/nodarium/commit/48cee58ad337c1c6c59a0eb55bf9b5ecd16b99d0) chore: update test snapshots
- [3235cae](https://git.max-richter.dev/max/nodarium/commit/3235cae9049e193c242b6091cee9f01e67ee850e) chore: fix lint and typecheck errors
- [3f44072](https://git.max-richter.dev/max/nodarium/commit/3f440728fc8a94d59022bb545f418be049a1f1ba) feat: implement variable height for node shader
- [da09f8b](https://git.max-richter.dev/max/nodarium/commit/da09f8ba1eda5ed347433d37064a3b4ab49e627e) refactor: move debug node into runtime
- [ddc3b4c](https://git.max-richter.dev/max/nodarium/commit/ddc3b4ce357ef1c1e8066c0a52151713d0b6ed95) feat: allow variable height node parameters
- [2690fc8](https://git.max-richter.dev/max/nodarium/commit/2690fc871291e73d3d028df9668e8fffb1e77476) chore: gitignore pnpm-store
- [072ab90](https://git.max-richter.dev/max/nodarium/commit/072ab9063ba56df0673020eb639548f3a8601e04) feat: add initial debug node
- [e23cad2](https://git.max-richter.dev/max/nodarium/commit/e23cad254d610e00f196b7fdb4532f36fd735a4b) feat: add "*" datatype for inputs for debug node
- [5b5c63c](https://git.max-richter.dev/max/nodarium/commit/5b5c63c1a9c4ef757382bd4452149dc9777693ff) fix(ui): make arrows on inputnumber visible on lighttheme
- [c9021f2](https://git.max-richter.dev/max/nodarium/commit/c9021f2383828f2e2b5594d125165bbc8f70b8e7) refactor: merge all dev settings into one setting
- [9eecdd4](https://git.max-richter.dev/max/nodarium/commit/9eecdd4fb85dc60b8196101050334e26732c9a34) Merge pull request 'feat: merge localState recursively with initial' (#38) from feat/debug-node into main
- [7e71a41](https://git.max-richter.dev/max/nodarium/commit/7e71a41e5229126d404f56598c624709961dbf3b) feat: merge localState recursively with initial
- [07cd9e8](https://git.max-richter.dev/max/nodarium/commit/07cd9e84eb51bc02b7fed39c36cf83caba175ad7) feat: clamp AddMenu to viewport
- [a31a49a](https://git.max-richter.dev/max/nodarium/commit/a31a49ad503d69f92f2491dd685729060ea49896) ci: lint and typecheck before build
- [850d641](https://git.max-richter.dev/max/nodarium/commit/850d641a25cd0c781478c58c117feaf085bdbc62) chore: pnpm format
- [ee5ca81](https://git.max-richter.dev/max/nodarium/commit/ee5ca817573b83cacfa3709e0ae88c6263bc39c1) ci: sign release commits with pgp key
- [22a1183](https://git.max-richter.dev/max/nodarium/commit/22a11832b861ae8b44e2d374b55d12937ecab247) fix(ci): correctly format changelog
- [b5ce572](https://git.max-richter.dev/max/nodarium/commit/b5ce5723fa4a35443df39a9096d0997f808f0b4f) chore: format favicon svg
- [102130c](https://git.max-richter.dev/max/nodarium/commit/102130cc7777ceebcdb3de8466c90cef5b380111) feat: add favicon
- [1668a2e](https://git.max-richter.dev/max/nodarium/commit/1668a2e6d59db071ab3da45204c2b7bfcd2150a2) chore: format changelog.md
# v0.0.4 (2026-02-10)
## Features
- Added shape and leaf nodes, including rotation support.
- Added high-contrast light theme and improved overall node readability.
- Enhanced UI with dots background, clearer details, and consistent node coloring.
- Improved changelog display and parsing robustness.
## Fixes
- Fixed UI issues (backside rendering, missing types, linter errors).
- Improved CI handling of commit messages and changelog placement.
## Chores
- Simplified CI quality checks.
- Updated dprint linters.
- Refactored changelog code.
---
- [51de3ce](https://git.max-richter.dev/max/nodarium/commit/51de3ced133af07b9432e1137068ef43ddfecbc9) fix(ci): update changelog before building
- [8d403ba](https://git.max-richter.dev/max/nodarium/commit/8d403ba8039a05b687f050993a6afca7fb743e12) Merge pull request 'feat/shape-node' (#36) from feat/shape-node into main
- [6bb3011](https://git.max-richter.dev/max/nodarium/commit/6bb301153ac13c31511b6b28ae95c6e0d4c03e9e) Merge remote-tracking branch 'origin/main' into feat/shape-node
- [02eee5f](https://git.max-richter.dev/max/nodarium/commit/02eee5f9bf4b1bc813d5d28673c4d5d77b392a92) fix: disable macro logs in wasm
- [4f48a51](https://git.max-richter.dev/max/nodarium/commit/4f48a519a950123390530f1b6040e2430a767745) feat(nodes): add rotation to instance node
- [97199ac](https://git.max-richter.dev/max/nodarium/commit/97199ac20fb079d6c157962d1a998d63670d8797) feat(nodes): implement leaf node
- [f36f0cb](https://git.max-richter.dev/max/nodarium/commit/f36f0cb2305692c7be60889bcde7f91179e18b81) feat(ui): show circles only when hovering InputShape
- [ed3d48e](https://git.max-richter.dev/max/nodarium/commit/ed3d48e07fa6db84bbb24db6dbe044cbc36f049f) fix(runtime): correctly encode 2d shape for wasm nodes
- [c610d6c](https://git.max-richter.dev/max/nodarium/commit/c610d6c99152d8233235064b81503c2b0dc4ada8) fix(app): show backside in three instances
- [8865b9b](https://git.max-richter.dev/max/nodarium/commit/8865b9b032bdf5a1385b4e9db0b1923f0e224fdd) feat(node): initial leaf / shape nodes
- [235ee5d](https://git.max-richter.dev/max/nodarium/commit/235ee5d979fbd70b3e0fb6f09a352218c3ff1e6d) fix(app): wrong linter errors in changelog
- [23a4857](https://git.max-richter.dev/max/nodarium/commit/23a48572f3913d91d839873cc155a16139c286a6) feat(app): dots background for node interface
- [e89a46e](https://git.max-richter.dev/max/nodarium/commit/e89a46e146e9e95de57ffdf55b05d16d6fe975f4) feat(app): add error page
- [cefda41](https://git.max-richter.dev/max/nodarium/commit/cefda41fcf3d5d011c9f7598a4f3f37136602dbd) feat(theme): optimize node readability
- [21d0f0d](https://git.max-richter.dev/max/nodarium/commit/21d0f0da5a26492fa68ad4897a9b1d9e88857030) feat: add high-contrast-light theme
- [4620245](https://git.max-richter.dev/max/nodarium/commit/46202451ba3eea73bd1bc6ef5129b3e26ee9315c) ci: simplify ci quality checks
- [0f4239d](https://git.max-richter.dev/max/nodarium/commit/0f4239d179ddedd3d012ca98b5bc3312afbc8f10) ci: simplify ci quality checks
- [d9c9bb5](https://git.max-richter.dev/max/nodarium/commit/d9c9bb5234bc8776daf26be99ba77a2145c70649) fix(theme): allow raw html in head style
- [18802fd](https://git.max-richter.dev/max/nodarium/commit/18802fdc10294a58425f052a4fde4bcf4be58caf) fix(ui): add missing types
- [b1cbd23](https://git.max-richter.dev/max/nodarium/commit/b1cbd235420c99a11154ef6a899cc7e14faf1c37) feat(app): use same color for node outline and header
- [33f10da](https://git.max-richter.dev/max/nodarium/commit/33f10da396fdc13edcb8faaee212280102b24f3a) feat(ui): make details stand out
- [af5b3b2](https://git.max-richter.dev/max/nodarium/commit/af5b3b23ba18d73d6abec60949fb0c9edfc25ff8) fix: make sure that CHANGELOG.md is in correct place
- [64d75b9](https://git.max-richter.dev/max/nodarium/commit/64d75b9686c494075223a0a318297fe59ec99e81) feat(ui): add InputColor and custom theme
- [2e6466c](https://git.max-richter.dev/max/nodarium/commit/2e6466ceca1d2131581d1862e93c756affdf6cd6) chore: update dprint linters
- [20d8e2a](https://git.max-richter.dev/max/nodarium/commit/20d8e2abedf0de30299d947575afef9c8ffd61d9) feat(theme): improve light theme a bit
- [715e1d0](https://git.max-richter.dev/max/nodarium/commit/715e1d095b8a77feb0cf66bbb444baf0f163adcb) feat(theme): merge edge and connection color
- [07e2826](https://git.max-richter.dev/max/nodarium/commit/07e2826f16dafa6a07377c9fb591168fa5c2abcf) feat(ui): improve colors of input shape
- [e0ad97b](https://git.max-richter.dev/max/nodarium/commit/e0ad97b003fd8cb4d950c03e5488a5accf6a37d0) feat(ui): highlight circle on hover on InputShape
- [93df4a1](https://git.max-richter.dev/max/nodarium/commit/93df4a19ff816e2bdfa093594721f0829f84c9e6) fix(ci): handle newline in commit messages for git.json
- [d661a4e](https://git.max-richter.dev/max/nodarium/commit/d661a4e4a9dfa6c9c73b5e24a3edcf56e1bbf48c) feat(ui): improve InputShape ux
- [c7f808c](https://git.max-richter.dev/max/nodarium/commit/c7f808ce2d52925425b49f92edf49d9557f8901d) wip
- [72d6cd6](https://git.max-richter.dev/max/nodarium/commit/72d6cd6ea2886626823e6e86856f19338c7af3c1) feat(ui): add initial InputShape element
- [615f2d3](https://git.max-richter.dev/max/nodarium/commit/615f2d3c4866a9e85f3eca398f3f02100c4df355) feat(ui): allow custom snippets in ui section header
- [2fadb68](https://git.max-richter.dev/max/nodarium/commit/2fadb6802de640d692fdab7d654311df0d7b4836) refactor: make changelog code simpler
- [9271d3a](https://git.max-richter.dev/max/nodarium/commit/9271d3a7e4cb0cc751b635c2adb518de7b4100c7) fix(app): handle error while parsing commit
- [13c83ef](https://git.max-richter.dev/max/nodarium/commit/13c83efdb962a6578ade59f10cc574fef0e17534) fix(app): handle error while parsing changelog
- [e44b73b](https://git.max-richter.dev/max/nodarium/commit/e44b73bebfb1cc8e872cd2fa7d8b6ff3565df374) feat: optimize changelog display
- [979e9fd](https://git.max-richter.dev/max/nodarium/commit/979e9fd92289eba9f77221c563337c00028e4cf5) feat: improve changelog readbility
- [544500e](https://git.max-richter.dev/max/nodarium/commit/544500e7fe9ee14412cef76f3c7a32ba6f291656) chore: remove pgp from changelog
- [aaebbc4](https://git.max-richter.dev/max/nodarium/commit/aaebbc4bc082ee93c2317ce45071c9bc61b0b77e) fix: some stuff with ci
# v0.0.3 (2026-02-07)
## Features

View File

@@ -6,8 +6,6 @@ ENV RUSTUP_HOME=/usr/local/rustup \
RUN apt-get update && apt-get install -y \
ca-certificates=20230311+deb12u1 \
gpg=2.2.40-1.1+deb12u2 \
gpg-agent=2.2.40-1.1+deb12u2 \
curl=7.88.1-10+deb12u14 \
git=1:2.39.5-0+deb12u3 \
jq=1.6-2.1+deb12u1 \

View File

@@ -1 +0,0 @@
out/

View File

@@ -1,47 +0,0 @@
import { NodeDefinition, NodeId, NodeRegistry } from '@nodarium/types';
import { createWasmWrapper } from '@nodarium/utils';
import { readFile } from 'node:fs/promises';
import { resolve } from 'node:path';
export class BenchmarkRegistry implements NodeRegistry {
status: 'loading' | 'ready' | 'error' = 'loading';
private nodes = new Map<string, NodeDefinition>();
async load(nodeIds: NodeId[]): Promise<NodeDefinition[]> {
const nodes = await Promise.all(nodeIds.map(async id => {
const p = resolve('static/nodes/' + id + '.wasm');
const file = await readFile(p);
const node = createWasmWrapper(file as unknown as ArrayBuffer);
const d = node.get_definition();
return {
...d,
execute: node.execute
};
}));
for (const n of nodes) {
this.nodes.set(n.id, n);
}
this.status = 'ready';
return nodes;
}
async register(id: string, wasmBuffer: ArrayBuffer): Promise<NodeDefinition> {
const wasm = createWasmWrapper(wasmBuffer);
const d = wasm.get_definition();
const node = {
...d,
execute: wasm.execute
};
this.nodes.set(id, node);
return node;
}
getNode(id: NodeId | string): NodeDefinition | undefined {
return this.nodes.get(id);
}
getAllNodes(): NodeDefinition[] {
return [];
}
}

View File

@@ -1,56 +0,0 @@
import type { Graph, Graph as GraphType, NodeId } from '@nodarium/types';
import { createLogger, createPerformanceStore } from '@nodarium/utils';
import { mkdir, writeFile } from 'node:fs/promises';
import { resolve } from 'node:path';
import { MemoryRuntimeExecutor } from '../src/lib/runtime/runtime-executor.ts';
import { BenchmarkRegistry } from './benchmarkRegistry.ts';
import defaultPlantTemplate from './templates/default.json' assert { type: 'json' };
import lottaFacesTemplate from './templates/lotta-faces.json' assert { type: 'json' };
import plantTemplate from './templates/plant.json' assert { type: 'json' };
const registry = new BenchmarkRegistry();
const r = new MemoryRuntimeExecutor(registry);
const perfStore = createPerformanceStore();
const log = createLogger('bench');
const templates: Record<string, Graph> = {
'plant': plantTemplate as unknown as GraphType,
'lotta-faces': lottaFacesTemplate as unknown as GraphType,
'default': defaultPlantTemplate as unknown as GraphType
};
async function run(g: GraphType, amount: number) {
await registry.load(plantTemplate.nodes.map(n => n.type) as NodeId[]);
log.log('loaded ' + g.nodes.length + ' nodes');
log.log('warming up');
// Warm up the runtime? maybe this does something?
for (let index = 0; index < 10; index++) {
await r.execute(g, { randomSeed: true });
}
log.log('executing');
r.perf = perfStore;
for (let i = 0; i < amount; i++) {
r.perf?.startRun();
await r.execute(g, { randomSeed: true });
r.perf?.stopRun();
}
log.log('finished');
return r.perf.get();
}
async function main() {
const outPath = resolve('benchmark/out/');
await mkdir(outPath, { recursive: true });
for (const key in templates) {
log.log('executing ' + key);
const perfData = await run(templates[key], 100);
await writeFile(resolve(outPath, key + '.json'), JSON.stringify(perfData));
await new Promise(res => setTimeout(res, 200));
}
}
main();

View File

@@ -1,95 +0,0 @@
{
"settings": { "resolution.circle": 26, "resolution.curve": 39 },
"nodes": [
{ "id": 9, "position": [220, 80], "type": "max/plantarium/output", "props": {} },
{
"id": 10,
"position": [95, 80],
"type": "max/plantarium/stem",
"props": { "amount": 5, "length": 11, "thickness": 0.1 }
},
{
"id": 14,
"position": [195, 80],
"type": "max/plantarium/gravity",
"props": {
"strength": 0.38,
"scale": 39,
"fixBottom": 0,
"directionalStrength": [1, 1, 1],
"depth": 1,
"curviness": 1
}
},
{
"id": 15,
"position": [120, 80],
"type": "max/plantarium/noise",
"props": {
"strength": 4.9,
"scale": 2.2,
"fixBottom": 1,
"directionalStrength": [1, 1, 1],
"depth": 1,
"octaves": 1
}
},
{
"id": 16,
"position": [70, 80],
"type": "max/plantarium/vec3",
"props": { "0": 0, "1": 0, "2": 0 }
},
{
"id": 17,
"position": [45, 80],
"type": "max/plantarium/random",
"props": { "min": -2, "max": 2 }
},
{
"id": 18,
"position": [170, 80],
"type": "max/plantarium/branch",
"props": {
"length": 1.6,
"thickness": 0.69,
"amount": 36,
"offsetSingle": 0.5,
"lowestBranch": 0.46,
"highestBranch": 1,
"depth": 1,
"rotation": 180
}
},
{
"id": 19,
"position": [145, 80],
"type": "max/plantarium/gravity",
"props": {
"strength": 0.38,
"scale": 39,
"fixBottom": 0,
"directionalStrength": [1, 1, 1],
"depth": 1,
"curviness": 1
}
},
{
"id": 20,
"position": [70, 120],
"type": "max/plantarium/random",
"props": { "min": 0.073, "max": 0.15 }
}
],
"edges": [
[14, 0, 9, "input"],
[10, 0, 15, "plant"],
[16, 0, 10, "origin"],
[17, 0, 16, "0"],
[17, 0, 16, "2"],
[18, 0, 14, "plant"],
[15, 0, 19, "plant"],
[19, 0, 18, "plant"],
[20, 0, 10, "thickness"]
]
}

View File

@@ -1,44 +0,0 @@
{
"settings": { "resolution.circle": 64, "resolution.curve": 64, "randomSeed": false },
"nodes": [
{ "id": 9, "position": [260, 0], "type": "max/plantarium/output", "props": {} },
{
"id": 18,
"position": [185, 0],
"type": "max/plantarium/stem",
"props": { "amount": 64, "length": 12, "thickness": 0.15 }
},
{
"id": 19,
"position": [210, 0],
"type": "max/plantarium/noise",
"props": { "scale": 1.3, "strength": 5.4 }
},
{
"id": 20,
"position": [235, 0],
"type": "max/plantarium/branch",
"props": { "length": 0.8, "thickness": 0.8, "amount": 3 }
},
{
"id": 21,
"position": [160, 0],
"type": "max/plantarium/vec3",
"props": { "0": 0.39, "1": 0, "2": 0.41 }
},
{
"id": 22,
"position": [130, 0],
"type": "max/plantarium/random",
"props": { "min": -2, "max": 2 }
}
],
"edges": [
[18, 0, 19, "plant"],
[19, 0, 20, "plant"],
[20, 0, 9, "input"],
[21, 0, 18, "origin"],
[22, 0, 21, "0"],
[22, 0, 21, "2"]
]
}

View File

@@ -1,71 +0,0 @@
{
"settings": { "resolution.circle": 26, "resolution.curve": 39 },
"nodes": [
{ "id": 9, "position": [180, 80], "type": "max/plantarium/output", "props": {} },
{
"id": 10,
"position": [55, 80],
"type": "max/plantarium/stem",
"props": { "amount": 1, "length": 11, "thickness": 0.71 }
},
{
"id": 11,
"position": [80, 80],
"type": "max/plantarium/noise",
"props": {
"strength": 35,
"scale": 4.6,
"fixBottom": 1,
"directionalStrength": [1, 0.74, 0.083],
"depth": 1
}
},
{
"id": 12,
"position": [105, 80],
"type": "max/plantarium/branch",
"props": {
"length": 3,
"thickness": 0.6,
"amount": 10,
"rotation": 180,
"offsetSingle": 0.34,
"lowestBranch": 0.53,
"highestBranch": 1,
"depth": 1
}
},
{
"id": 13,
"position": [130, 80],
"type": "max/plantarium/noise",
"props": {
"strength": 8,
"scale": 7.7,
"fixBottom": 1,
"directionalStrength": [1, 0, 1],
"depth": 1
}
},
{
"id": 14,
"position": [155, 80],
"type": "max/plantarium/gravity",
"props": {
"strength": 0.11,
"scale": 39,
"fixBottom": 0,
"directionalStrength": [1, 1, 1],
"depth": 1,
"curviness": 1
}
}
],
"edges": [
[10, 0, 11, "plant"],
[11, 0, 12, "plant"],
[12, 0, 13, "plant"],
[13, 0, 14, "plant"],
[14, 0, 9, "input"]
]
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 43 KiB

After

Width:  |  Height:  |  Size: 42 KiB

View File

@@ -1,7 +1,7 @@
{
"name": "@nodarium/app",
"private": true,
"version": "0.0.5",
"version": "0.0.3",
"type": "module",
"scripts": {
"dev": "vite dev",
@@ -14,8 +14,7 @@
"format": "dprint fmt -c '../.dprint.jsonc' .",
"format:check": "dprint check -c '../.dprint.jsonc' .",
"lint": "eslint .",
"check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json",
"bench": "tsx ./benchmark/index.ts"
"check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json"
},
"dependencies": {
"@nodarium/ui": "workspace:*",
@@ -52,7 +51,6 @@
"svelte": "^5.49.2",
"svelte-check": "^4.3.6",
"tslib": "^2.8.1",
"tsx": "^4.21.0",
"typescript": "^5.9.3",
"typescript-eslint": "^8.54.0",
"vite": "^7.3.1",

View File

@@ -2,7 +2,7 @@
<html lang="en">
<head>
<meta charset="utf-8" />
<link rel="icon" href="%sveltekit.assets%/favicon.svg" />
<link rel="icon" href="%sveltekit.assets%/svelte.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
%sveltekit.head%
<title>Nodes</title>

View File

@@ -5,33 +5,19 @@
import { getGraphManager, getGraphState } from '../graph-state.svelte';
type Props = {
paddingLeft?: number;
paddingRight?: number;
paddingTop?: number;
paddingBottom?: number;
onnode: (n: NodeInstance) => void;
};
const padding = 10;
const {
paddingLeft = padding,
paddingRight = padding,
paddingTop = padding,
paddingBottom = padding,
onnode
}: Props = $props();
const { onnode }: Props = $props();
const graph = getGraphManager();
const graphState = getGraphState();
let input: HTMLInputElement;
let wrapper: HTMLDivElement;
let value = $state<string>();
let activeNodeId = $state<NodeId>();
const MENU_WIDTH = 150;
const MENU_HEIGHT = 350;
const allNodes = graphState.activeSocket
? graph.getPossibleNodes(graphState.activeSocket)
: graph.getNodeDefinitions();
@@ -93,52 +79,19 @@
}
}
function clampAddMenuPosition() {
if (!graphState.addMenuPosition) return;
const camX = graphState.cameraPosition[0];
const camY = graphState.cameraPosition[1];
const zoom = graphState.cameraPosition[2];
const halfViewportWidth = (graphState.width / 2) / zoom;
const halfViewportHeight = (graphState.height / 2) / zoom;
const halfMenuWidth = (MENU_WIDTH / 2) / zoom;
const halfMenuHeight = (MENU_HEIGHT / 2) / zoom;
const minX = camX - halfViewportWidth - halfMenuWidth + paddingLeft / zoom;
const maxX = camX + halfViewportWidth - halfMenuWidth - paddingRight / zoom;
const minY = camY - halfViewportHeight - halfMenuHeight + paddingTop / zoom;
const maxY = camY + halfViewportHeight - halfMenuHeight - paddingBottom / zoom;
const clampedX = Math.max(
minX + halfMenuWidth,
Math.min(graphState.addMenuPosition[0], maxX - halfMenuWidth)
);
const clampedY = Math.max(
minY + halfMenuHeight,
Math.min(graphState.addMenuPosition[1], maxY - halfMenuHeight)
);
if (clampedX !== graphState.addMenuPosition[0] || clampedY !== graphState.addMenuPosition[1]) {
graphState.addMenuPosition = [clampedX, clampedY];
}
}
$effect(() => {
const pos = graphState.addMenuPosition;
const zoom = graphState.cameraPosition[2];
const width = graphState.width;
const height = graphState.height;
if (pos && zoom && width && height) {
clampAddMenuPosition();
}
});
onMount(() => {
input.disabled = false;
setTimeout(() => input.focus(), 50);
const rect = wrapper.getBoundingClientRect();
const deltaY = rect.bottom - window.innerHeight;
const deltaX = rect.right - window.innerWidth;
if (deltaY > 0) {
wrapper.style.marginTop = `-${deltaY + 30}px`;
}
if (deltaX > 0) {
wrapper.style.marginLeft = `-${deltaX + 30}px`;
}
});
</script>
@@ -147,7 +100,7 @@
position.z={graphState.addMenuPosition?.[1]}
transform={false}
>
<div class="add-menu-wrapper">
<div class="add-menu-wrapper" bind:this={wrapper}>
<div class="header">
<input
id="add-menu"

View File

@@ -6,12 +6,15 @@
toneMapped: false
});
let lineColor = $state(colors.outline.clone().convertSRGBToLinear());
$effect.root(() => {
$effect(() => {
if (appSettings.value.theme === undefined) {
return;
}
circleMaterial.color = colors.outline.clone().convertSRGBToLinear();
lineColor = colors.outline.clone().convertSRGBToLinear();
});
});
@@ -32,7 +35,6 @@
import { CubicBezierCurve } from 'three/src/extras/curves/CubicBezierCurve.js';
import { Vector2 } from 'three/src/math/Vector2.js';
import { getGraphState } from '../graph-state.svelte';
import MeshGradientLineMaterial from './MeshGradientLine/MeshGradientLineMaterial.svelte';
const graphState = getGraphState();
@@ -43,17 +45,12 @@
y2: number;
z: number;
id?: string;
inputType?: string;
outputType?: string;
};
const { x1, y1, x2, y2, z, inputType = 'unknown', outputType = 'unknown', id }: Props = $props();
const { x1, y1, x2, y2, z, id }: Props = $props();
const thickness = $derived(Math.max(0.001, 0.00082 * Math.exp(0.055 * z)));
const inputColor = $derived(graphState.colors.getColor(inputType));
const outputColor = $derived(graphState.colors.getColor(outputType));
let points = $state<Vector3[]>([]);
let lastId: string | null = null;
@@ -109,9 +106,9 @@
position.z={y1}
position.y={0.8}
rotation.x={-Math.PI / 2}
material={circleMaterial}
>
<T.CircleGeometry args={[0.5, 16]} />
<T.MeshBasicMaterial color={inputColor} toneMapped={false} />
</T.Mesh>
<T.Mesh
@@ -122,7 +119,6 @@
material={circleMaterial}
>
<T.CircleGeometry args={[0.5, 16]} />
<T.MeshBasicMaterial color={outputColor} toneMapped={false} />
</T.Mesh>
{#if graphState.hoveredEdgeId === id}
@@ -130,8 +126,7 @@
<MeshLineGeometry {points} />
<MeshLineMaterial
width={thickness * 5}
color={inputColor}
tonemapped={false}
color={lineColor}
opacity={0.5}
transparent
/>
@@ -140,10 +135,5 @@
<T.Mesh position.x={x1} position.z={y1} position.y={0.1}>
<MeshLineGeometry {points} />
<MeshGradientLineMaterial
width={thickness}
colorStart={inputColor}
colorEnd={outputColor}
tonemapped={false}
/>
<MeshLineMaterial width={thickness} color={lineColor} />
</T.Mesh>

View File

@@ -1,112 +0,0 @@
<script lang="ts">
import { T, useThrelte } from '@threlte/core';
import { Color, ShaderMaterial, Vector2 } from 'three';
import fragmentShader from './fragment.frag';
import type { MeshLineMaterialProps } from './types';
import vertexShader from './vertex.vert';
let {
opacity = 1,
colorStart = '#ffffff',
colorEnd = '#ffffff',
dashOffset = 0,
dashArray = 0,
dashRatio = 0,
attenuate = true,
width = 1,
scaleDown = 0,
alphaMap,
ref = $bindable(),
children,
...props
}: MeshLineMaterialProps = $props();
let { invalidate, size } = useThrelte();
// svelte-ignore state_referenced_locally
const uniforms = {
lineWidth: { value: width },
colorStart: { value: new Color(colorStart) },
colorEnd: { value: new Color(colorEnd) },
opacity: { value: opacity },
resolution: { value: new Vector2(1, 1) },
sizeAttenuation: { value: attenuate ? 1 : 0 },
dashArray: { value: dashArray },
useDash: { value: dashArray > 0 ? 1 : 0 },
dashOffset: { value: dashOffset },
dashRatio: { value: dashRatio },
scaleDown: { value: scaleDown / 10 },
alphaTest: { value: 0 },
alphaMap: { value: alphaMap },
useAlphaMap: { value: alphaMap ? 1 : 0 }
};
const material = new ShaderMaterial({ uniforms });
$effect.pre(() => {
uniforms.lineWidth.value = width;
invalidate();
});
$effect.pre(() => {
uniforms.opacity.value = opacity;
invalidate();
});
$effect.pre(() => {
uniforms.resolution.value.set($size.width, $size.height);
invalidate();
});
$effect.pre(() => {
uniforms.sizeAttenuation.value = attenuate ? 1 : 0;
invalidate();
});
$effect.pre(() => {
uniforms.dashArray.value = dashArray;
uniforms.useDash.value = dashArray > 0 ? 1 : 0;
invalidate();
});
$effect.pre(() => {
uniforms.dashOffset.value = dashOffset;
invalidate();
});
$effect.pre(() => {
uniforms.dashRatio.value = dashRatio;
invalidate();
});
$effect.pre(() => {
uniforms.scaleDown.value = scaleDown / 10;
invalidate();
});
$effect.pre(() => {
uniforms.alphaMap.value = alphaMap;
uniforms.useAlphaMap.value = alphaMap ? 1 : 0;
invalidate();
});
$effect.pre(() => {
uniforms.colorStart.value.set(colorStart);
invalidate();
});
$effect.pre(() => {
uniforms.colorEnd.value.set(colorEnd);
invalidate();
});
</script>
<T
is={material}
bind:ref
{fragmentShader}
{vertexShader}
{...props}
>
{@render children?.({ ref: material })}
</T>

View File

@@ -1,30 +0,0 @@
uniform vec3 colorStart;
uniform vec3 colorEnd;
uniform float useDash;
uniform float dashArray;
uniform float dashOffset;
uniform float dashRatio;
uniform sampler2D alphaMap;
uniform float useAlphaMap;
varying vec2 vUV;
varying vec4 vColor;
varying float vCounters;
vec4 CustomLinearTosRGB( in vec4 value ) {
return vec4( mix( pow( value.rgb, vec3( 0.41666 ) ) * 1.055 - vec3( 0.055 ), value.rgb * 12.92, vec3( lessThanEqual( value.rgb, vec3( 0.0031308 ) ) ) ), value.a );
}
void main() {
vec4 c = mix(vec4(colorStart,1.0),vec4(colorEnd, 1.0), vCounters);
if( useAlphaMap == 1. ) c.a *= texture2D( alphaMap, vUV ).r;
if( useDash == 1. ){
c.a *= ceil(mod(vCounters + dashOffset, dashArray) - (dashArray * dashRatio));
}
gl_FragColor = CustomLinearTosRGB(c);
}

View File

@@ -1,68 +0,0 @@
import type { Props } from '@threlte/core';
import type { BufferGeometry, Vector3 } from 'three';
import type { ColorRepresentation, ShaderMaterial, Texture } from 'three';
export type MeshLineGeometryProps = Props<BufferGeometry> & {
/**
* @default []
*/
points: Vector3[];
/**
* @default 'none'
*/
shape?: 'none' | 'taper' | 'custom';
/**
* @default () => 1
*/
shapeFunction?: (p: number) => number;
};
export type MeshLineMaterialProps =
& Omit<
Props<ShaderMaterial>,
'uniforms' | 'fragmentShader' | 'vertexShader'
>
& {
/**
* @default 1
*/
opacity?: number;
/**
* @default '#ffffff'
*/
color?: ColorRepresentation;
/**
* @default 0
*/
dashOffset?: number;
/**
* @default 0
*/
dashArray?: number;
/**
* @default 0
*/
dashRatio?: number;
/**
* @default true
*/
attenuate?: boolean;
/**
* @default 1
*/
width?: number;
/**
* @default 0
*/
scaleDown?: number;
alphaMap?: Texture | undefined;
};

View File

@@ -1,83 +0,0 @@
attribute vec3 previous;
attribute vec3 next;
attribute float side;
attribute float width;
attribute float counters;
uniform vec2 resolution;
uniform float lineWidth;
uniform vec3 color;
uniform float opacity;
uniform float sizeAttenuation;
uniform float scaleDown;
varying vec2 vUV;
varying vec4 vColor;
varying float vCounters;
vec2 intoScreen(vec4 i) {
return resolution * (0.5 * i.xy / i.w + 0.5);
}
void main() {
float aspect = resolution.y / resolution.x;
mat4 m = projectionMatrix * modelViewMatrix;
vec4 currentClip = m * vec4( position, 1.0 );
vec4 prevClip = m * vec4( previous, 1.0 );
vec4 nextClip = m * vec4( next, 1.0 );
vec4 currentNormed = currentClip / currentClip.w;
vec4 prevNormed = prevClip / prevClip.w;
vec4 nextNormed = nextClip / nextClip.w;
vec2 currentScreen = intoScreen(currentNormed);
vec2 prevScreen = intoScreen(prevNormed);
vec2 nextScreen = intoScreen(nextNormed);
float actualWidth = lineWidth * width;
vec2 dir;
if(nextScreen == currentScreen) {
dir = normalize( currentScreen - prevScreen );
} else if(prevScreen == currentScreen) {
dir = normalize( nextScreen - currentScreen );
} else {
vec2 inDir = currentScreen - prevScreen;
vec2 outDir = nextScreen - currentScreen;
vec2 fullDir = nextScreen - prevScreen;
if(length(fullDir) > 0.0) {
dir = normalize(fullDir);
} else if(length(inDir) > 0.0){
dir = normalize(inDir);
} else {
dir = normalize(outDir);
}
}
vec2 normal = vec2(-dir.y, dir.x);
if(sizeAttenuation != 0.0) {
normal /= currentClip.w;
normal *= min(resolution.x, resolution.y);
}
if (scaleDown > 0.0) {
float dist = length(nextNormed - prevNormed);
normal *= smoothstep(0.0, scaleDown, dist);
}
vec2 offsetInScreen = actualWidth * normal * side * 0.5;
vec2 withOffsetScreen = currentScreen + offsetInScreen;
vec3 withOffsetNormed = vec3((2.0 * withOffsetScreen/resolution - 1.0), currentNormed.z);
vCounters = counters;
vColor = vec4( color, opacity );
vUV = uv;
gl_Position = currentClip.w * vec4(withOffsetNormed, 1.0);
}

View File

@@ -29,7 +29,6 @@ export function areSocketsCompatible(
output: string | undefined,
inputs: string | (string | undefined)[] | undefined
) {
if (output === '*') return true;
if (Array.isArray(inputs) && output) {
return inputs.includes('*') || inputs.includes(output);
}

View File

@@ -3,8 +3,6 @@ import { getContext, setContext } from 'svelte';
import { SvelteMap, SvelteSet } from 'svelte/reactivity';
import type { OrthographicCamera, Vector3 } from 'three';
import type { GraphManager } from './graph-manager.svelte';
import { ColorGenerator } from './graph/colors';
import { getNodeHeight, getSocketPosition } from './helpers/nodeHelpers';
const graphStateKey = Symbol('graph-state');
export function getGraphState() {
@@ -29,32 +27,7 @@ type EdgeData = {
points: Vector3[];
};
const predefinedColors = {
path: {
hue: 80,
lightness: 20,
saturation: 80
},
float: {
hue: 70,
lightness: 10,
saturation: 0
},
geometry: {
hue: 0,
lightness: 50,
saturation: 70
},
'*': {
hue: 200,
lightness: 20,
saturation: 100
}
} as const;
export class GraphState {
colors = new ColorGenerator(predefinedColors);
constructor(private graph: GraphManager) {
$effect.root(() => {
$effect(() => {
@@ -186,27 +159,57 @@ export class GraphState {
return 1;
}
tryConnectToDebugNode(nodeId: number) {
const node = this.graph.nodes.get(nodeId);
if (!node) return;
if (node.type.endsWith('/debug')) return;
if (!node.state.type?.outputs?.length) return;
for (const _node of this.graph.nodes.values()) {
if (_node.type.endsWith('/debug')) {
this.graph.createEdge(node, 0, _node, 'input');
return;
getSocketPosition(
node: NodeInstance,
index: string | number
): [number, number] {
if (typeof index === 'number') {
return [
(node?.state?.x ?? node.position[0]) + 20,
(node?.state?.y ?? node.position[1]) + 2.5 + 10 * index
];
} else {
const inputs = node.state.type?.inputs || this.graph.registry.getNode(node.type)?.inputs
|| {};
const _index = Object.keys(inputs).indexOf(index);
const pos = [
node?.state?.x ?? node.position[0],
(node?.state?.y ?? node.position[1]) + 10 + 10 * _index
] as [number, number];
return pos;
}
}
const debugNode = this.graph.createNode({
type: 'max/plantarium/debug',
position: [node.position[0] + 30, node.position[1]],
props: {}
});
if (debugNode) {
this.graph.createEdge(node, 0, debugNode, 'input');
private nodeHeightCache: Record<string, number> = {};
getNodeHeight(nodeTypeId: string) {
if (nodeTypeId in this.nodeHeightCache) {
return this.nodeHeightCache[nodeTypeId];
}
const node = this.graph.getNodeType(nodeTypeId);
if (!node?.inputs) {
return 5;
}
let height = 5;
for (const key of Object.keys(node.inputs)) {
if (key === 'seed') continue;
if (!node.inputs) continue;
if (node?.inputs?.[key] === undefined) continue;
if ('setting' in node.inputs[key]) continue;
if (node.inputs[key].hidden) continue;
if (
node.inputs[key].type === 'shape'
&& node.inputs[key].external !== true
&& node.inputs[key].internal !== false
) {
height += 20;
continue;
}
height += 10;
}
this.nodeHeightCache[nodeTypeId] = height;
return height;
}
copyNodes() {
@@ -266,7 +269,7 @@ export class GraphState {
if (edge[3] === index) {
node = edge[0];
index = edge[1];
position = getSocketPosition(node, index);
position = this.getSocketPosition(node, index);
this.graph.removeEdge(edge);
break;
}
@@ -286,7 +289,7 @@ export class GraphState {
return {
node,
index,
position: getSocketPosition(node, index)
position: this.getSocketPosition(node, index)
};
});
}
@@ -323,7 +326,7 @@ export class GraphState {
for (const node of this.graph.nodes.values()) {
const x = node.position[0];
const y = node.position[1];
const height = getNodeHeight(node.state.type!);
const height = this.getNodeHeight(node.type);
if (downX > x && downX < x + 20 && downY > y && downY < y + height) {
clickedNodeId = node.id;
break;
@@ -335,12 +338,14 @@ export class GraphState {
}
isNodeInView(node: NodeInstance) {
const height = getNodeHeight(node.state.type!);
const height = this.getNodeHeight(node.type);
const width = 20;
return node.position[0] > this.cameraBounds[0] - width
return (
node.position[0] > this.cameraBounds[0] - width
&& node.position[0] < this.cameraBounds[1]
&& node.position[1] > this.cameraBounds[2] - height
&& node.position[1] < this.cameraBounds[3];
&& node.position[1] < this.cameraBounds[3]
);
}
openNodePalette() {

View File

@@ -11,18 +11,15 @@
import Debug from '../debug/Debug.svelte';
import EdgeEl from '../edges/Edge.svelte';
import { getGraphManager, getGraphState } from '../graph-state.svelte';
import { getSocketPosition } from '../helpers/nodeHelpers';
import NodeEl from '../node/Node.svelte';
import { maxZoom, minZoom } from './constants';
import { FileDropEventManager } from './drop.events';
import { MouseEventManager } from './mouse.events';
const {
keymap,
addMenuPadding
keymap
}: {
keymap: ReturnType<typeof createKeyMap>;
addMenuPadding?: { left?: number; right?: number; bottom?: number; top?: number };
} = $props();
const graph = getGraphManager();
@@ -39,8 +36,8 @@
return [0, 0, 0, 0];
}
const pos1 = getSocketPosition(fromNode, edge[1]);
const pos2 = getSocketPosition(toNode, edge[3]);
const pos1 = graphState.getSocketPosition(fromNode, edge[1]);
const pos2 = graphState.getSocketPosition(toNode, edge[3]);
return [pos1[0], pos1[1], pos2[0], pos2[1]];
}
@@ -95,13 +92,6 @@
graphState.activeSocket = null;
graphState.addMenuPosition = null;
}
function getSocketType(node: NodeInstance, index: number | string): string {
if (typeof index === 'string') {
return node.state.type?.inputs?.[index].type || 'unknown';
}
return node.state.type?.outputs?.[index] || 'unknown';
}
</script>
<svelte:window
@@ -170,20 +160,12 @@
{#if graph.status === 'idle'}
{#if graphState.addMenuPosition}
<AddMenu
onnode={handleNodeCreation}
paddingTop={addMenuPadding?.top}
paddingRight={addMenuPadding?.right}
paddingBottom={addMenuPadding?.bottom}
paddingLeft={addMenuPadding?.left}
/>
<AddMenu onnode={handleNodeCreation} />
{/if}
{#if graphState.activeSocket}
<EdgeEl
z={graphState.cameraPosition[2]}
inputType={getSocketType(graphState.activeSocket.node, graphState.activeSocket.index)}
outputType={getSocketType(graphState.activeSocket.node, graphState.activeSocket.index)}
x1={graphState.activeSocket.position[0]}
y1={graphState.activeSocket.position[1]}
x2={graphState.edgeEndPosition?.[0] ?? graphState.mousePosition[0]}
@@ -196,8 +178,6 @@
<EdgeEl
id={graph.getEdgeId(edge)}
z={graphState.cameraPosition[2]}
inputType={getSocketType(edge[0], edge[1])}
outputType={getSocketType(edge[2], edge[3])}
{x1}
{y1}
{x2}
@@ -220,6 +200,7 @@
<NodeEl
{node}
inView={graphState.isNodeInView(node)}
z={graphState.cameraPosition[2]}
/>
{/each}
</div>

View File

@@ -18,8 +18,6 @@
showHelp?: boolean;
settingTypes?: Record<string, unknown>;
addMenuPadding?: { left?: number; right?: number; bottom?: number; top?: number };
onsave?: (save: Graph) => void;
onresult?: (result: unknown) => void;
};
@@ -27,8 +25,6 @@
let {
graph,
registry,
addMenuPadding,
settings = $bindable(),
activeNode = $bindable(),
backgroundType = $bindable('grid'),
snapToGrid = $bindable(true),
@@ -87,4 +83,4 @@
});
</script>
<GraphEl {keymap} {addMenuPadding} />
<GraphEl {keymap} />

View File

@@ -1,44 +0,0 @@
type Color = { hue: number; saturation: number; lightness: number };
export class ColorGenerator {
private colors: Map<string, Color> = new Map();
private lightnessLevels = [10, 60];
constructor(predefined: Record<string, Color>) {
for (const [id, colorStr] of Object.entries(predefined)) {
this.colors.set(id, colorStr);
}
}
public getColor(id: string): string {
if (this.colors.has(id)) {
return this.colorToHsl(this.colors.get(id)!);
}
const newColor = this.generateNewColor();
this.colors.set(id, newColor);
return this.colorToHsl(newColor);
}
private generateNewColor(): Color {
const existingHues = Array.from(this.colors.values()).map(c => c.hue).sort();
let hue = existingHues[0];
let attempts = 0;
while (
existingHues.some(h => Math.abs(h - hue) < 30 || Math.abs(h - hue) > 330)
&& attempts < 360
) {
hue = (hue + 30) % 360;
attempts++;
}
const lightness = 60;
return { hue, lightness, saturation: 100 };
}
private colorToHsl(c: Color): string {
return `hsl(${c.hue}, ${c.saturation}%, ${c.lightness}%)`;
}
}

View File

@@ -3,7 +3,6 @@ import { type NodeInstance } from '@nodarium/types';
import type { GraphManager } from '../graph-manager.svelte';
import { type GraphState } from '../graph-state.svelte';
import { snapToGrid as snapPointToGrid } from '../helpers';
import { getNodeHeight } from '../helpers/nodeHelpers';
import { maxZoom, minZoom, zoomSpeed } from './constants';
import { EdgeInteractionManager } from './edge.events';
@@ -189,10 +188,6 @@ export class MouseEventManager {
// if we clicked on a node
if (clickedNodeId !== -1) {
if (event.ctrlKey && event.shiftKey) {
this.state.tryConnectToDebugNode(clickedNodeId);
return;
}
if (this.state.activeNodeId === -1) {
this.state.activeNodeId = clickedNodeId;
// if the selected node is the same as the clicked node
@@ -294,7 +289,7 @@ export class MouseEventManager {
if (!node?.state) continue;
const x = node.position[0];
const y = node.position[1];
const height = getNodeHeight(node.state.type!);
const height = this.state.getNodeHeight(node.type);
if (x > x1 - 20 && x < x2 && y > y1 - height && y < y2) {
this.state.selectedNodes?.add(node.id);
} else {

View File

@@ -35,9 +35,6 @@ export function createNodePath({
rightBump = false,
aspectRatio = 1
} = {}) {
const leftBumpTopY = y + height / 2;
const leftBumpBottomY = y - height / 2;
return `M0,${cornerTop}
${
cornerTop
@@ -67,7 +64,9 @@ export function createNodePath({
}
${
leftBump
? ` V${leftBumpTopY} C${depth},${leftBumpTopY} ${depth},${leftBumpBottomY} 0,${leftBumpBottomY}`
? ` V${y + height / 2} C${depth},${y + height / 2} ${depth},${y - height / 2} 0,${
y - height / 2
}`
: ` H0`
}
Z`.replace(/\s+/g, ' ');

View File

@@ -1,71 +0,0 @@
import type { NodeDefinition, NodeInstance } from '@nodarium/types';
export function getParameterHeight(node: NodeDefinition, inputKey: string) {
const input = node.inputs?.[inputKey];
if (!input) {
return 0;
}
if (inputKey === 'seed') return 0;
if (!node.inputs) return 0;
if ('setting' in input) return 0;
if (input.hidden) return 0;
if (input.type === 'shape' && input.external !== true) {
return 200;
}
if (
input?.label !== '' && !input.external && input.type !== 'path'
&& input.type !== 'geometry'
) {
return 100;
}
return 50;
}
export function getSocketPosition(
node: NodeInstance,
index: string | number
): [number, number] {
if (typeof index === 'number') {
return [
(node?.state?.x ?? node.position[0]) + 20,
(node?.state?.y ?? node.position[1]) + 2.5 + 10 * index
];
} else {
let height = 5;
const nodeType = node.state.type!;
const inputs = nodeType.inputs || {};
for (const inputKey in inputs) {
const h = getParameterHeight(nodeType, inputKey) / 10;
if (inputKey === index) {
height += h / 2;
break;
}
height += h;
}
return [
node?.state?.x ?? node.position[0],
(node?.state?.y ?? node.position[1]) + height
];
}
}
const nodeHeightCache: Record<string, number> = {};
export function getNodeHeight(node: NodeDefinition) {
if (node.id in nodeHeightCache) {
return nodeHeightCache[node.id];
}
if (!node?.inputs) {
return 5;
}
let height = 5;
for (const key in node.inputs) {
const h = getParameterHeight(node, key) / 10;
height += h;
}
nodeHeightCache[node.id] = height;
return height;
}

View File

@@ -1,88 +1,56 @@
varying vec2 vUv;
uniform float uWidth;
uniform float uHeight;
uniform float uZoom;
uniform vec3 uColorDark;
uniform vec3 uColorBright;
uniform vec3 uStrokeColor;
const float uHeaderHeight = 5.0;
uniform float uSectionHeights[16];
uniform int uNumSections;
uniform vec3 uStrokeColor;
uniform float uStrokeWidth;
float msign(in float x) { return (x < 0.0) ? -1.0 : 1.0; }
float sdCircle(vec2 p, float r) { return length(p) - r; }
vec4 roundedBoxSDF( in vec2 p, in vec2 b, in float r, in float s) {
vec2 q = abs(p) - b + r;
float l = b.x + b.y + 1.570796 * r;
float k1 = min(max(q.x, q.y), 0.0) + length(max(q, 0.0)) - r;
float k2 = ((q.x > 0.0) ? atan(q.y, q.x) : 1.570796);
float k3 = 3.0 + 2.0 * msign(min(p.x, -p.y)) - msign(p.x);
float k4 = msign(p.x * p.y);
float k5 = r * k2 + max(-q.x, 0.0);
float ra = s * round(k1 / s);
float l2 = l + 1.570796 * ra;
return vec4(k1 - ra, k3 * l2 + k4 * (b.y + ((q.y > 0.0) ? k5 + k2 * ra : q.y)), 4.0 * l2, k1);
}
void main(){
float strokeWidth = mix(2.0, 0.5, uZoom);
float borderRadius = 0.5;
float dentRadius = 0.8;
float y = (1.0-vUv.y) * uHeight;
float x = vUv.x * uWidth;
vec2 size = vec2(uWidth, uHeight);
vec2 uvCenter = (vUv - 0.5) * 2.0;
vec2 uv = (vUv - 0.5) * 2.0;
vec4 boxData = roundedBoxSDF(uvCenter * size, size, borderRadius * 2.0, 0.0);
float sceneSDF = boxData.w;
float u_border_radius = 0.4;
vec4 distance = roundedBoxSDF(uv * size, size, u_border_radius*2.0, 0.0);
vec2 headerDentPos = vec2(uWidth, uHeaderHeight * 0.5);
float headerDentDist = sdCircle(vec2(x, y) - headerDentPos, dentRadius);
sceneSDF = max(sceneSDF, -headerDentDist*2.0);
float currentYBoundary = uHeaderHeight;
float previousYBoundary = uHeaderHeight;
for (int i = 0; i < 16; i++) {
if (i >= uNumSections) break;
float sectionHeight = uSectionHeights[i];
currentYBoundary += sectionHeight;
float centerY = previousYBoundary + (sectionHeight * 0.5);
vec2 circlePos = vec2(0.0, centerY);
float circleDist = sdCircle(vec2(x, y) - circlePos, dentRadius);
sceneSDF = max(sceneSDF, -circleDist*2.0);
previousYBoundary = currentYBoundary;
}
if (sceneSDF > 0.05) {
if (distance.w > 0.0 ) {
// outside
gl_FragColor = vec4(0.0,0.0,0.0, 0.0);
return;
}
vec3 finalColor = (y < uHeaderHeight) ? uColorBright : uColorDark;
bool isDivider = false;
float dividerY = uHeaderHeight;
if (abs(y - dividerY) < strokeWidth * 0.25) isDivider = true;
for (int i = 0; i < 16; i++) {
if (i >= uNumSections - 1) break;
dividerY += uSectionHeights[i];
if (abs(y - dividerY) < strokeWidth * 0.25) isDivider = true;
}
if (sceneSDF > -strokeWidth || isDivider) {
gl_FragColor = vec4(uStrokeColor, 1.0);
}else{
gl_FragColor = vec4(finalColor, 1.0);
if (distance.w > -uStrokeWidth || mod(y+5.0, 10.0) < uStrokeWidth/2.0) {
// draw the outer stroke
gl_FragColor = vec4(uStrokeColor, 1.0);
}else if (y<5.0){
// draw the header
gl_FragColor = vec4(uColorBright, 1.0);
}else{
gl_FragColor = vec4(uColorDark, 1.0);
}
}
}

View File

@@ -5,7 +5,6 @@
import { type Mesh } from 'three';
import { getGraphState } from '../graph-state.svelte';
import { colors } from '../graph/colors.svelte';
import { getNodeHeight, getParameterHeight } from '../helpers/nodeHelpers';
import NodeFrag from './Node.frag';
import NodeVert from './Node.vert';
import NodeHtml from './NodeHTML.svelte';
@@ -15,10 +14,9 @@
type Props = {
node: NodeInstance;
inView: boolean;
z: number;
};
let { node = $bindable(), inView }: Props = $props();
const nodeType = $derived(node.state.type!);
let { node = $bindable(), inView, z }: Props = $props();
const isActive = $derived(graphState.activeNodeId === node.id);
const isSelected = $derived(graphState.selectedNodes.has(node.id));
@@ -31,18 +29,9 @@
: colors.outline)
);
const sectionHeights = $derived(
Object
.keys(nodeType.inputs || {})
.map(key => getParameterHeight(nodeType, key) / 10)
.filter(b => !!b)
);
let meshRef: Mesh | undefined = $state();
const height = getNodeHeight(node.state.type!);
const zoom = $derived(graphState.cameraPosition[2]);
const height = graphState.getNodeHeight(node.type);
$effect(() => {
if (meshRef && !node.state?.mesh) {
@@ -50,10 +39,6 @@
graphState.updateNodePosition(node);
}
});
const zoomValue = $derived(
(Math.log(graphState.cameraPosition[2]) - Math.log(1)) / (Math.log(40) - Math.log(1))
);
// const zoomValue = (graphState.cameraPosition[2] - 1) / 39;
</script>
<T.Mesh
@@ -62,7 +47,7 @@
position.y={0.8}
rotation.x={-Math.PI / 2}
bind:ref={meshRef}
visible={inView && zoom < 7}
visible={inView && z < 7}
>
<T.PlaneGeometry args={[20, height]} radius={1} />
<T.ShaderMaterial
@@ -72,19 +57,14 @@
uniforms={{
uColorBright: { value: colors['layer-2'] },
uColorDark: { value: colors['layer-1'] },
uStrokeColor: { value: colors.outline.clone() },
uSectionHeights: { value: [5, 10] },
uNumSections: { value: 2 },
uStrokeColor: { value: colors['layer-2'].clone() },
uStrokeWidth: { value: 1.0 },
uWidth: { value: 20 },
uHeight: { value: 200 },
uZoom: { value: 1.0 }
uHeight: { value: height }
}}
uniforms.uZoom.value={zoomValue}
uniforms.uHeight.value={height}
uniforms.uSectionHeights.value={sectionHeights}
uniforms.uNumSections.value={sectionHeights.length}
uniforms.uStrokeColor.value={strokeColor}
uniforms.uStrokeColor.value={strokeColor.clone()}
uniforms.uStrokeWidth.value={(7 - z) / 3}
/>
</T.Mesh>
<NodeHtml bind:node {inView} {isActive} {isSelected} z={zoom} />
<NodeHtml bind:node {inView} {isActive} {isSelected} {z} />

View File

@@ -1,9 +1,7 @@
<script lang="ts">
import { appSettings } from '$lib/settings/app-settings.svelte';
import type { NodeInstance, Socket } from '@nodarium/types';
import type { NodeInstance } from '@nodarium/types';
import { getGraphState } from '../graph-state.svelte';
import { createNodePath } from '../helpers/index.js';
import { getSocketPosition } from '../helpers/nodeHelpers';
const graphState = getGraphState();
@@ -16,7 +14,7 @@
graphState.setDownSocket?.({
node,
index: 0,
position: getSocketPosition?.(node, 0)
position: graphState.getSocketPosition?.(node, 0)
});
}
}
@@ -45,35 +43,14 @@
aspectRatio
})
);
const socketId = $derived(`${node.id}-${0}`);
function getSocketType(s: Socket | null) {
if (!s) return 'unknown';
if (typeof s.index === 'string') {
return s.node.state.type?.inputs?.[s.index].type || 'unknown';
}
return s.node.state.type?.outputs?.[s.index] || 'unknown';
}
const socketType = $derived(getSocketType(graphState.activeSocket));
const hoverColor = $derived(graphState.colors.getColor(socketType));
</script>
<div
class="wrapper"
data-node-id={node.id}
data-node-type={node.type}
style:--socket-color={hoverColor}
class:possible-socket={graphState?.possibleSocketIds.has(socketId)}
>
<div class="wrapper" data-node-id={node.id} data-node-type={node.type}>
<div class="content">
{#if appSettings.value.debug.advancedMode}
<span class="bg-white text-black! mr-2 px-1 rounded-sm opacity-30">{node.id}</span>
{/if}
{node.type.split('/').pop()}
</div>
<div
class="target"
class="click-target"
role="button"
tabindex="0"
onmousedown={handleMouseDown}
@@ -101,20 +78,7 @@
height: 50px;
}
.possible-socket .target::before {
content: "";
position: absolute;
width: 30px;
height: 30px;
border-radius: 100%;
box-shadow: 0px 0px 10px var(--socket-color);
background-color: var(--socket-color);
outline: solid thin var(--socket-color);
opacity: 0.7;
z-index: -10;
}
.target {
.click-target {
position: absolute;
right: 0px;
top: 50%;
@@ -125,7 +89,7 @@
border-radius: 50%;
}
.target:hover + svg path {
.click-target:hover + svg path {
d: var(--hover-path);
}

View File

@@ -1,8 +1,7 @@
<script lang="ts">
import type { NodeInput, NodeInstance, Socket } from '@nodarium/types';
import type { NodeInput, NodeInstance } from '@nodarium/types';
import { getGraphManager, getGraphState } from '../graph-state.svelte';
import { createNodePath } from '../helpers';
import { getParameterHeight, getSocketPosition } from '../helpers/nodeHelpers';
import NodeInputEl from './NodeInput.svelte';
type Props = {
@@ -13,18 +12,19 @@
};
const graph = getGraphManager();
const graphState = getGraphState();
const graphId = graph?.id;
const elementId = `input-${Math.random().toString(36).substring(7)}`;
let { node = $bindable(), input, id, isLast }: Props = $props();
const nodeType = $derived(node.state.type!);
const inputType = $derived(nodeType.inputs?.[id]);
const inputType = $derived(node?.state?.type?.inputs?.[id]);
const socketId = $derived(`${node.id}-${id}`);
const height = $derived(getParameterHeight(nodeType, id));
const isShape = $derived(input.type === 'shape' && input.external !== true);
const height = $derived(isShape ? 200 : 100);
const graphState = getGraphState();
const graphId = graph?.id;
const elementId = `input-${Math.random().toString(36).substring(7)}`;
function handleMouseDown(ev: MouseEvent) {
ev.preventDefault();
@@ -32,18 +32,18 @@
graphState.setDownSocket({
node,
index: id,
position: getSocketPosition(node, id)
position: graphState.getSocketPosition?.(node, id)
});
}
const leftBump = $derived(nodeType.inputs?.[id].internal !== true);
const leftBump = $derived(node.state?.type?.inputs?.[id].internal !== true);
const cornerBottom = $derived(isLast ? 5 : 0);
const aspectRatio = 0.5;
const path = $derived(
createNodePath({
depth: 6,
height: 2000 / height,
height: 18,
y: 50.5,
cornerBottom,
leftBump,
@@ -53,24 +53,13 @@
const pathHover = $derived(
createNodePath({
depth: 7,
height: 2200 / height,
height: 20,
y: 50.5,
cornerBottom,
leftBump,
aspectRatio
})
);
function getSocketType(s: Socket | null) {
if (!s) return 'unknown';
if (typeof s.index === 'string') {
return s.node.state.type?.inputs?.[s.index].type || 'unknown';
}
return s.node.state.type?.outputs?.[s.index] || 'unknown';
}
const socketType = $derived(getSocketType(graphState.activeSocket));
const hoverColor = $derived(graphState.colors.getColor(socketType));
</script>
<div
@@ -78,7 +67,6 @@
data-node-type={node.type}
data-node-input={id}
style:height="{height}px"
style:--socket-color={hoverColor}
class:possible-socket={graphState?.possibleSocketIds.has(socketId)}
>
{#key id && graphId}
@@ -86,6 +74,10 @@
{#if inputType?.label !== ''}
<label for={elementId} title={input.description}>{input.label || id}</label>
{/if}
<span
class="absolute i-[tabler--help-circle] size-4 block top-2 right-2 opacity-30"
title={JSON.stringify(input, null, 2)}
></span>
{#if inputType?.external !== true}
<NodeInputEl {graph} {elementId} bind:node {input} {id} />
{/if}
@@ -107,8 +99,10 @@
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 100 100"
preserveAspectRatio="none"
style:--path={`path("${path}")`}
style:--hover-path={`path("${pathHover}")`}
style={`
--path: path("${path}");
--hover-path: path("${pathHover}");
`}
>
<path vector-effect="non-scaling-stroke"></path>
</svg>
@@ -130,16 +124,9 @@
transform: translateY(-50%) translateX(-50%);
}
.possible-socket .target::before {
content: "";
position: absolute;
width: 30px;
height: 30px;
border-radius: 100%;
box-shadow: 0px 0px 10px var(--socket-color);
background-color: var(--socket-color);
outline: solid thin var(--socket-color);
opacity: 0.5;
.possible-socket .target {
box-shadow: 0px 0px 10px rgba(255, 255, 255, 0.5);
background-color: rgba(255, 255, 255, 0.2);
z-index: -10;
}
@@ -149,12 +136,11 @@
.content {
position: relative;
padding: 10px 20px;
display: flex;
flex-direction: column;
padding-inline: 20px;
height: 100%;
justify-content: center;
gap: 10px;
justify-content: space-around;
box-sizing: border-box;
}

View File

@@ -1,37 +1,5 @@
import { browser } from '$app/environment';
function mergeRecursive<T>(current: T, initial: T): T {
if (typeof initial === 'number') {
if (typeof current === 'number') return current;
return initial;
}
if (typeof initial === 'boolean') {
if (typeof current === 'boolean') return current;
return initial;
}
if (Array.isArray(initial)) {
if (Array.isArray(current)) return current;
return initial;
}
if (typeof initial === 'object' && initial) {
const merged = initial;
if (typeof current === 'object' && current) {
for (const key of Object.keys(initial)) {
if (key in current) {
// @ts-expect-error It's safe dont worry about it
merged[key] = mergeRecursive(current[key], initial[key]);
}
}
}
return merged;
}
return current;
}
export class LocalStore<T> {
value = $state<T>() as T;
key = '';
@@ -42,10 +10,7 @@ export class LocalStore<T> {
if (browser) {
const item = localStorage.getItem(key);
if (item) {
const storedValue = this.deserialize(item);
this.value = mergeRecursive(storedValue, value);
}
if (item) this.value = this.deserialize(item);
}
$effect.root(() => {

View File

@@ -1,11 +0,0 @@
export const debugNode = {
id: 'max/plantarium/debug',
inputs: {
input: {
type: '*'
}
},
execute(_data: Int32Array): Int32Array {
return _data;
}
} as const;

View File

@@ -17,15 +17,8 @@ export class RemoteNodeRegistry implements NodeRegistry {
constructor(
private url: string,
public cache?: AsyncCache<ArrayBuffer | string>,
nodes?: NodeDefinition[]
) {
if (nodes?.length) {
for (const node of nodes) {
this.nodes.set(node.id, node);
}
}
}
public cache?: AsyncCache<ArrayBuffer | string>
) {}
async fetchJson(url: string, skipCache = false) {
const finalUrl = `${this.url}/${url}`;

View File

@@ -1,19 +0,0 @@
<script lang="ts">
import { T } from '@threlte/core';
import type { Group } from 'three';
import { updateDebugScene } from './debug';
type Props = {
debugData?: Record<number, { type: string; data: Int32Array }>;
};
let group = $state<Group>(null!);
const { debugData }: Props = $props();
$effect(() => {
if (!group || !debugData) return;
updateDebugScene(group, $state.snapshot(debugData));
});
</script>
<T.Group bind:ref={group} />

View File

@@ -1,26 +1,33 @@
<script lang="ts">
import { colors } from '$lib/graph-interface/graph/colors.svelte';
import { T, useTask, useThrelte } from '@threlte/core';
import { Grid } from '@threlte/extras';
import { Box3, type BufferGeometry, type Group, Mesh, MeshBasicMaterial, Vector3 } from 'three';
import { Grid, MeshLineGeometry, MeshLineMaterial, Text } from '@threlte/extras';
import {
Box3,
type BufferGeometry,
type Group,
Mesh,
MeshBasicMaterial,
Vector3,
type Vector3Tuple
} from 'three';
import { appSettings } from '../settings/app-settings.svelte';
import Camera from './Camera.svelte';
import Debug from './Debug.svelte';
const { renderStage, invalidate: _invalidate } = useThrelte();
type Props = {
fps: number[];
debugData?: Record<number, { type: string; data: Int32Array }>;
lines: Vector3[][];
scene: Group;
centerCamera: boolean;
};
let {
lines,
centerCamera,
fps = $bindable(),
scene = $bindable(),
debugData
scene = $bindable()
}: Props = $props();
let geometries = $state.raw<BufferGeometry[]>([]);
@@ -84,12 +91,18 @@
});
_invalidate();
});
function getPosition(geo: BufferGeometry, i: number) {
return [
geo.attributes.position.array[i],
geo.attributes.position.array[i + 1],
geo.attributes.position.array[i + 2]
] as Vector3Tuple;
}
</script>
<Camera {center} {centerCamera} />
<Debug {debugData} />
{#if appSettings.value.showGrid}
<Grid
cellColor={colors['outline']}
@@ -103,4 +116,35 @@
fadeOrigin={new Vector3(0, 0, 0)}
/>
{/if}
<T.Group>
{#if geometries}
{#each geometries as geo (geo.id)}
{#if appSettings.value.debug.showIndices}
{#each geo.attributes.position.array, i (i)}
{#if i % 3 === 0}
<Text fontSize={0.25} position={getPosition(geo, i)} />
{/if}
{/each}
{/if}
{#if appSettings.value.debug.showVertices}
<T.Points visible={true}>
<T is={geo} />
<T.PointsMaterial size={0.25} />
</T.Points>
{/if}
{/each}
{/if}
<T.Group bind:ref={scene}></T.Group>
</T.Group>
{#if appSettings.value.debug.showStemLines && lines}
{#each lines as line (line[0].x + '-' + line[0].y + '-' + '' + line[0].z)}
<T.Mesh>
<MeshLineGeometry points={line} />
<MeshLineMaterial width={0.1} color="red" depthTest={false} />
</T.Mesh>
{/each}
{/if}

View File

@@ -1,10 +1,10 @@
<script lang="ts">
import SmallPerformanceViewer from '$lib/performance/SmallPerformanceViewer.svelte';
import { appSettings } from '$lib/settings/app-settings.svelte';
import { splitNestedArray } from '@nodarium/utils';
import { decodeFloat, splitNestedArray } from '@nodarium/utils';
import type { PerformanceStore } from '@nodarium/utils';
import { Canvas } from '@threlte/core';
import { DoubleSide } from 'three';
import { DoubleSide, Vector3 } from 'three';
import { type Group, MeshMatcapMaterial, TextureLoader } from 'three';
import { createGeometryPool, createInstancedGeometryPool } from './geometryPool';
import Scene from './Scene.svelte';
@@ -23,7 +23,6 @@
let geometryPool: ReturnType<typeof createGeometryPool>;
let instancePool: ReturnType<typeof createInstancedGeometryPool>;
export function updateGeometries(inputs: Int32Array[], group: Group) {
geometryPool = geometryPool || createGeometryPool(group, material);
instancePool = instancePool || createInstancedGeometryPool(group, material);
@@ -41,16 +40,44 @@
scene: Group;
centerCamera: boolean;
perf: PerformanceStore;
debugData?: Record<number, { type: string; data: Int32Array }>;
};
let { scene = $bindable(), centerCamera, debugData, perf }: Props = $props();
let { scene = $bindable(), centerCamera, perf }: Props = $props();
let lines = $state<Vector3[][]>([]);
function createLineGeometryFromEncodedData(encodedData: Int32Array) {
const positions: Vector3[] = [];
const amount = (encodedData.length - 1) / 4;
for (let i = 0; i < amount; i++) {
const x = decodeFloat(encodedData[2 + i * 4 + 0]);
const y = decodeFloat(encodedData[2 + i * 4 + 1]);
const z = decodeFloat(encodedData[2 + i * 4 + 2]);
positions.push(new Vector3(x, y, z));
}
return positions;
}
export const update = function update(result: Int32Array) {
perf.addPoint('split-result');
const inputs = splitNestedArray(result);
perf.endPoint();
if (appSettings.value.debug.showStemLines) {
perf.addPoint('create-lines');
lines = inputs
.map((input) => {
if (input[0] === 0) {
return createLineGeometryFromEncodedData(input);
}
})
.filter(Boolean) as Vector3[][];
perf.endPoint();
}
perf.addPoint('update-geometries');
const { totalVertices, totalFaces } = updateGeometries(inputs, scene);
@@ -62,7 +89,7 @@
};
</script>
{#if appSettings.value.debug.advancedMode}
{#if appSettings.value.debug.showPerformancePanel}
<SmallPerformanceViewer {fps} store={perf} />
{/if}
@@ -70,8 +97,8 @@
<Canvas>
<Scene
bind:this={sceneComponent}
{lines}
{centerCamera}
{debugData}
bind:scene
bind:fps
/>

View File

@@ -1,90 +0,0 @@
import { splitNestedArray } from '@nodarium/utils';
import {
BufferGeometry,
type Group,
InstancedMesh,
Line,
LineBasicMaterial,
Matrix4,
MeshBasicMaterial,
SphereGeometry,
Vector3
} from 'three';
function writePath(scene: Group, data: Int32Array): Vector3[] {
const positions: Vector3[] = [];
const f32 = new Float32Array(data.buffer);
for (let i = 2; i + 2 < f32.length; i += 4) {
const vec = new Vector3(f32[i], f32[i + 1], f32[i + 2]);
positions.push(vec);
}
// Path line
if (positions.length >= 2) {
const geometry = new BufferGeometry().setFromPoints(positions);
const line = new Line(
geometry,
new LineBasicMaterial({ color: 0xff0000, depthTest: false })
);
scene.add(line);
}
// Instanced spheres at points
if (positions.length > 0) {
const sphereGeometry = new SphereGeometry(0.05, 8, 8); // keep low-poly
const sphereMaterial = new MeshBasicMaterial({
color: 0xff0000,
depthTest: false
});
const spheres = new InstancedMesh(
sphereGeometry,
sphereMaterial,
positions.length
);
const matrix = new Matrix4();
for (let i = 0; i < positions.length; i++) {
matrix.makeTranslation(
positions[i].x,
positions[i].y,
positions[i].z
);
spheres.setMatrixAt(i, matrix);
}
spheres.instanceMatrix.needsUpdate = true;
scene.add(spheres);
}
return positions;
}
function clearGroup(group: Group) {
for (let i = group.children.length - 1; i >= 0; i--) {
const child = group.children[i];
group.remove(child);
// optional but correct: free GPU memory
// @ts-expect-error three.js runtime fields
child.geometry?.dispose?.();
// @ts-expect-error three.js runtime fields
child.material?.dispose?.();
}
}
export function updateDebugScene(
group: Group,
data: Record<number, { type: string; data: Int32Array }>
) {
clearGroup(group);
return Object.entries(data || {}).map(([, d]) => {
switch (d.type) {
case 'path':
splitNestedArray(d.data)
.forEach(p => writePath(group, p));
}
// eslint-disable-next-line @typescript-eslint/no-unused-vars
return (_g: Group) => {};
}).flat();
}

View File

@@ -77,9 +77,24 @@ export type Pointer = {
_title?: string;
};
private seed = Math.floor(Math.random() * 100000000);
private debugData: Record<number, { type: string; data: Int32Array }> = {};
export class MemoryRuntimeExecutor implements RuntimeExecutor {
private nodes = new Map<string, { definition: NodeDefinition; execute: WasmExecute }>();
private offset = 0;
private isRunning = false;
private readonly memory = new WebAssembly.Memory({
initial: 4096,
maximum: 8192
});
private memoryView!: Int32Array;
results: Record<number, Pointer> = {};
inputPtrs: Record<number, Pointer[]> = {};
allPtrs: Pointer[] = [];
seed = 42424242;
perf?: PerformanceStore;
constructor(
@@ -161,34 +176,20 @@ export type Pointer = {
child.state.inputNodes[childInput] = parent;
}
const nodes = new Map<number, RuntimeNode>();
const ordered: RuntimeNode[] = [];
const stack = [outputNode];
// loop through all the nodes and assign each nodes its depth
const stack = [outputNode, ...graphNodes.filter(n => n.type.endsWith('/debug'))];
while (stack.length) {
const node = stack.pop()!;
for (const parent of node.state.parents) {
parent.state.depth = node.state.depth + 1;
stack.push(parent);
}
nodes.set(node.id, node);
ordered.push(node);
}
for (const node of graphNodes) {
if (node.type.endsWith('/debug')) {
node.state = node.state || {};
const parent = node.state.parents[0];
if (parent) {
node.state.depth = parent.state.depth - 1;
parent.state.debugNode = true;
}
nodes.set(node.id, node);
}
}
const _nodes = [...nodes.values()];
return [outputNode, _nodes] as const;
log.info(`Output node: ${outputNode.id}, total nodes ordered: ${ordered.length}`);
return [outputNode, ordered] as const;
}
private writeToMemory(value: number | number[] | Int32Array, title?: string): Pointer {
@@ -201,8 +202,26 @@ export type Pointer = {
this.offset += value.length;
}
let a = performance.now();
this.debugData = {};
const ptr = { start, end: this.offset, _title: title };
this.allPtrs.push(ptr);
log.info(`Memory written for ${title}: start=${ptr.start}, end=${ptr.end}`);
return ptr;
}
private printMemory() {
this.memoryView = new Int32Array(this.memory.buffer);
console.log('MEMORY', this.memoryView.slice(0, 10));
}
async execute(graph: Graph, settings: Record<string, unknown>) {
this.offset = 0;
this.inputPtrs = {};
this.seed = this.seed += 2;
this.results = {};
this.allPtrs = [];
if (this.isRunning) return undefined as unknown as Int32Array;
this.isRunning = true;
// Then we add some metadata to the graph
const [_outputNode, nodes] = await this.addMetaData(graph);
@@ -308,12 +327,6 @@ export type Pointer = {
log.log(`Using cached value for ${node_type.id || node.id}`);
this.perf?.addPoint('cache-hit', 1);
results[node.id] = cachedValue as Int32Array;
if (node.state.debugNode && node_type.outputs) {
this.debugData[node.id] = {
type: node_type.outputs[0],
data: cachedValue
};
}
continue;
}
this.perf?.addPoint('cache-hit', 0);
@@ -322,12 +335,6 @@ export type Pointer = {
log.log(`Inputs:`, inputs);
a = performance.now();
results[node.id] = node_type.execute(encoded_inputs);
if (node.state.debugNode && node_type.outputs) {
this.debugData[node.id] = {
type: node_type.outputs[0],
data: results[node.id]
};
}
log.log('Executed', node.type, node.id);
b = performance.now();
@@ -466,10 +473,6 @@ export type Pointer = {
}
}
getDebugData() {
return this.debugData;
}
getPerformanceData() {
return this.perf?.get();
}

View File

@@ -5,7 +5,6 @@ type RuntimeState = {
parents: RuntimeNode[];
children: RuntimeNode[];
inputNodes: Record<string, RuntimeNode>;
debugNode?: boolean;
};
export type RuntimeNode = SerializedNode & { state: RuntimeState };

View File

@@ -1,4 +1,3 @@
import { debugNode } from '$lib/node-registry/debugNode';
import { IndexDBCache, RemoteNodeRegistry } from '$lib/node-registry/index';
import type { Graph } from '@nodarium/types';
import { createPerformanceStore } from '@nodarium/utils';
@@ -6,7 +5,7 @@ import { MemoryRuntimeExecutor } from './runtime-executor';
import { MemoryRuntimeCache } from './runtime-executor-cache';
const indexDbCache = new IndexDBCache('node-registry');
const nodeRegistry = new RemoteNodeRegistry('', indexDbCache, [debugNode]);
const nodeRegistry = new RemoteNodeRegistry('', indexDbCache);
const cache = new MemoryRuntimeCache();
const executor = new MemoryRuntimeExecutor(nodeRegistry, cache);
@@ -44,7 +43,3 @@ export async function executeGraph(
export function getPerformanceData() {
return performanceStore.get();
}
export function getDebugData() {
return executor.getDebugData();
}

View File

@@ -6,15 +6,12 @@ export class WorkerRuntimeExecutor implements RuntimeExecutor {
new URL(`./worker-runtime-executor-backend.ts`, import.meta.url)
);
execute(graph: Graph, settings: Record<string, unknown>) {
async execute(graph: Graph, settings: Record<string, unknown>) {
return this.worker.executeGraph(graph, settings);
}
getPerformanceData() {
async getPerformanceData() {
return this.worker.getPerformanceData();
}
getDebugData() {
return this.worker.getDebugData();
}
set useRuntimeCache(useCache: boolean) {
this.worker.setUseRuntimeCache(useCache);
}

View File

@@ -59,9 +59,34 @@ export const AppSettingTypes = {
label: 'Execute in WebWorker',
value: true
},
advancedMode: {
showIndices: {
type: 'boolean',
label: 'Advanced Mode',
label: 'Show Indices',
value: false
},
showPerformancePanel: {
type: 'boolean',
label: 'Show Performance Panel',
value: false
},
showBenchmarkPanel: {
type: 'boolean',
label: 'Show Benchmark Panel',
value: false
},
showVertices: {
type: 'boolean',
label: 'Show Vertices',
value: false
},
showStemLines: {
type: 'boolean',
label: 'Show Stem Lines',
value: false
},
showGraphJson: {
type: 'boolean',
label: 'Show Graph Source',
value: false
},
cache: {

View File

@@ -2,11 +2,7 @@
import { type Snippet } from 'svelte';
import { panelState as state } from './PanelState.svelte';
let { children, open = $bindable(false) } = $props<{ children?: Snippet; open?: boolean }>();
$effect(() => {
open = !!state.activePanel.value;
});
const { children } = $props<{ children?: Snippet }>();
</script>
<div class="wrapper" class:visible={state.activePanel.value}>

View File

@@ -42,13 +42,11 @@
const store: Store = {};
Object.keys(inputs).forEach((key) => {
if (props) {
const value = props[key] !== undefined ? props[key] : inputs[key].value;
const value = props[key] || inputs[key].value;
if (Array.isArray(value) || typeof value === 'number') {
store[key] = value;
} else if (typeof value === 'boolean') {
store[key] = value ? 1 : 0;
} else {
console.error('Wrong error', { value });
console.error('Wrong error');
}
}
});

View File

@@ -4,7 +4,6 @@
import Grid from '$lib/grid';
import { debounceAsyncFunction } from '$lib/helpers';
import { createKeyMap } from '$lib/helpers/createKeyMap';
import { debugNode } from '$lib/node-registry/debugNode.js';
import { IndexDBCache, RemoteNodeRegistry } from '$lib/node-registry/index';
import NodeStore from '$lib/node-store/NodeStore.svelte';
import PerformanceViewer from '$lib/performance/PerformanceViewer.svelte';
@@ -33,8 +32,7 @@
const { data } = $props();
const registryCache = new IndexDBCache('node-registry');
const nodeRegistry = new RemoteNodeRegistry('', registryCache, [debugNode]);
const nodeRegistry = new RemoteNodeRegistry('', registryCache);
const workerRuntime = new WorkerRuntimeExecutor();
const runtimeCache = new MemoryRuntimeCache();
const memoryRuntime = new MemoryRuntimeExecutor(nodeRegistry, runtimeCache);
@@ -65,10 +63,8 @@
let activeNode = $state<NodeInstance | undefined>(undefined);
let scene = $state<Group>(null!);
let sidebarOpen = $state(false);
let graphInterface = $state<ReturnType<typeof GraphInterface>>(null!);
let viewerComponent = $state<ReturnType<typeof Viewer>>();
let debugData = $state<Record<number, { type: string; data: Int32Array }>>();
const manager = $derived(graphInterface?.manager);
async function randomGenerate() {
@@ -103,7 +99,6 @@
if (appSettings.value.debug.useWorker) {
let perfData = await runtime.getPerformanceData();
debugData = await runtime.getDebugData();
let lastRun = perfData?.at(-1);
if (lastRun?.total) {
lastRun.runtime = lastRun.total;
@@ -162,7 +157,6 @@
bind:scene
bind:this={viewerComponent}
perf={performanceStore}
debugData={debugData}
centerCamera={appSettings.value.centerCamera}
/>
</Grid.Cell>
@@ -172,7 +166,6 @@
graph={pm.graph}
bind:this={graphInterface}
registry={nodeRegistry}
addMenuPadding={{ right: sidebarOpen ? 330 : undefined }}
backgroundType={appSettings.value.nodeInterface.backgroundType}
snapToGrid={appSettings.value.nodeInterface.snapToGrid}
bind:activeNode
@@ -183,7 +176,7 @@
onresult={(result) => handleUpdate(result as Graph)}
/>
{/if}
<Sidebar bind:open={sidebarOpen}>
<Sidebar>
<Panel id="general" title="General" icon="i-[tabler--settings]">
<NestedSettings
id="general"
@@ -216,7 +209,7 @@
<Panel
id="performance"
title="Performance"
hidden={!appSettings.value.debug.advancedMode}
hidden={!appSettings.value.debug.showPerformancePanel}
icon="i-[tabler--brand-speedtest] bg-red-400"
>
{#if $performanceStore}
@@ -229,7 +222,7 @@
<Panel
id="graph-source"
title="Graph Source"
hidden={!appSettings.value.debug.advancedMode}
hidden={!appSettings.value.debug.showGraphJson}
icon="i-[tabler--code]"
>
<GraphSource graph={pm.graph ?? manager?.serialize()} />
@@ -237,7 +230,7 @@
<Panel
id="benchmark"
title="Benchmark"
hidden={!appSettings.value.debug.advancedMode}
hidden={!appSettings.value.debug.showBenchmarkPanel}
icon="i-[tabler--graph] bg-red-400"
>
<BenchmarkPanel run={randomGenerate} />

View File

@@ -1,19 +0,0 @@
<svg width="100" height="100" viewBox="0 0 100 100" fill="none" xmlns="http://www.w3.org/2000/svg">
<path
d="M55.2154 77.6602L52.2788 78.3944L49.2607 60.6933L52.2788 33.0404L47.6293 18.0312L45.9162 18.6838L41.6745 28.7987L31.6412 33.4483H20.2211L21.6894 24.0675L31.6412 15.9919L45.9162 15.1762L49.7501 15.9919L55.2154 32.6326L54.5628 38.5873L64.8409 33.0404L69.5721 37.69L80.1764 43.1553L84.1734 52.8624L83.113 64.1193L73.8954 61.8353L66.3092 52.4545V38.5873L64.1068 36.7112L54.155 42.4212L52.2788 60.6933L55.2154 77.6602Z"
fill="url(#paint0_linear)"
/>
<defs>
<linearGradient
id="paint0_linear"
x1="34.3903"
y1="15.1762"
x2="52.1972"
y2="78.3944"
gradientUnits="userSpaceOnUse"
>
<stop stop-color="#4CAF7B" />
<stop offset="1" stop-color="#347452" />
</linearGradient>
</defs>
</svg>

Before

Width:  |  Height:  |  Size: 861 B

19
app/static/svelte.svg Normal file
View File

@@ -0,0 +1,19 @@
<svg
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
aria-hidden="true"
role="img"
class="iconify iconify--logos"
width="26.6"
height="32"
preserveAspectRatio="xMidYMid meet"
viewBox="0 0 256 308"
>
<path
fill="#FF3E00"
d="M239.682 40.707C211.113-.182 154.69-12.301 113.895 13.69L42.247 59.356a82.198 82.198 0 0 0-37.135 55.056a86.566 86.566 0 0 0 8.536 55.576a82.425 82.425 0 0 0-12.296 30.719a87.596 87.596 0 0 0 14.964 66.244c28.574 40.893 84.997 53.007 125.787 27.016l71.648-45.664a82.182 82.182 0 0 0 37.135-55.057a86.601 86.601 0 0 0-8.53-55.577a82.409 82.409 0 0 0 12.29-30.718a87.573 87.573 0 0 0-14.963-66.244"
></path><path
fill="#FFF"
d="M106.889 270.841c-23.102 6.007-47.497-3.036-61.103-22.648a52.685 52.685 0 0 1-9.003-39.85a49.978 49.978 0 0 1 1.713-6.693l1.35-4.115l3.671 2.697a92.447 92.447 0 0 0 28.036 14.007l2.663.808l-.245 2.659a16.067 16.067 0 0 0 2.89 10.656a17.143 17.143 0 0 0 18.397 6.828a15.786 15.786 0 0 0 4.403-1.935l71.67-45.672a14.922 14.922 0 0 0 6.734-9.977a15.923 15.923 0 0 0-2.713-12.011a17.156 17.156 0 0 0-18.404-6.832a15.78 15.78 0 0 0-4.396 1.933l-27.35 17.434a52.298 52.298 0 0 1-14.553 6.391c-23.101 6.007-47.497-3.036-61.101-22.649a52.681 52.681 0 0 1-9.004-39.849a49.428 49.428 0 0 1 22.34-33.114l71.664-45.677a52.218 52.218 0 0 1 14.563-6.398c23.101-6.007 47.497 3.036 61.101 22.648a52.685 52.685 0 0 1 9.004 39.85a50.559 50.559 0 0 1-1.713 6.692l-1.35 4.116l-3.67-2.693a92.373 92.373 0 0 0-28.037-14.013l-2.664-.809l.246-2.658a16.099 16.099 0 0 0-2.89-10.656a17.143 17.143 0 0 0-18.398-6.828a15.786 15.786 0 0 0-4.402 1.935l-71.67 45.674a14.898 14.898 0 0 0-6.73 9.975a15.9 15.9 0 0 0 2.709 12.012a17.156 17.156 0 0 0 18.404 6.832a15.841 15.841 0 0 0 4.402-1.935l27.345-17.427a52.147 52.147 0 0 1 14.552-6.397c23.101-6.006 47.497 3.037 61.102 22.65a52.681 52.681 0 0 1 9.003 39.848a49.453 49.453 0 0 1-22.34 33.12l-71.664 45.673a52.218 52.218 0 0 1-14.563 6.398"
></path>
</svg>

After

Width:  |  Height:  |  Size: 1.9 KiB

26
app/static/tauri.svg Normal file
View File

@@ -0,0 +1,26 @@
<svg width="206" height="231" viewBox="0 0 206 231" fill="none" xmlns="http://www.w3.org/2000/svg">
<path
d="M143.143 84C143.143 96.1503 133.293 106 121.143 106C108.992 106 99.1426 96.1503 99.1426 84C99.1426 71.8497 108.992 62 121.143 62C133.293 62 143.143 71.8497 143.143 84Z"
fill="#FFC131"
/>
<ellipse
cx="84.1426"
cy="147"
rx="22"
ry="22"
transform="rotate(180 84.1426 147)"
fill="#24C8DB"
/>
<path
fill-rule="evenodd"
clip-rule="evenodd"
d="M166.738 154.548C157.86 160.286 148.023 164.269 137.757 166.341C139.858 160.282 141 153.774 141 147C141 144.543 140.85 142.121 140.558 139.743C144.975 138.204 149.215 136.139 153.183 133.575C162.73 127.404 170.292 118.608 174.961 108.244C179.63 97.8797 181.207 86.3876 179.502 75.1487C177.798 63.9098 172.884 53.4021 165.352 44.8883C157.82 36.3744 147.99 30.2165 137.042 27.1546C126.095 24.0926 114.496 24.2568 103.64 27.6274C92.7839 30.998 83.1319 37.4317 75.8437 46.1553C74.9102 47.2727 74.0206 48.4216 73.176 49.5993C61.9292 50.8488 51.0363 54.0318 40.9629 58.9556C44.2417 48.4586 49.5653 38.6591 56.679 30.1442C67.0505 17.7298 80.7861 8.57426 96.2354 3.77762C111.685 -1.01901 128.19 -1.25267 143.769 3.10474C159.348 7.46215 173.337 16.2252 184.056 28.3411C194.775 40.457 201.767 55.4101 204.193 71.404C206.619 87.3978 204.374 103.752 197.73 118.501C191.086 133.25 180.324 145.767 166.738 154.548ZM41.9631 74.275L62.5557 76.8042C63.0459 72.813 63.9401 68.9018 65.2138 65.1274C57.0465 67.0016 49.2088 70.087 41.9631 74.275Z"
fill="#FFC131"
/>
<path
fill-rule="evenodd"
clip-rule="evenodd"
d="M38.4045 76.4519C47.3493 70.6709 57.2677 66.6712 67.6171 64.6132C65.2774 70.9669 64 77.8343 64 85.0001C64 87.1434 64.1143 89.26 64.3371 91.3442C60.0093 92.8732 55.8533 94.9092 51.9599 97.4256C42.4128 103.596 34.8505 112.392 30.1816 122.756C25.5126 133.12 23.9357 144.612 25.6403 155.851C27.3449 167.09 32.2584 177.598 39.7906 186.112C47.3227 194.626 57.153 200.784 68.1003 203.846C79.0476 206.907 90.6462 206.743 101.502 203.373C112.359 200.002 122.011 193.568 129.299 184.845C130.237 183.722 131.131 182.567 131.979 181.383C143.235 180.114 154.132 176.91 164.205 171.962C160.929 182.49 155.596 192.319 148.464 200.856C138.092 213.27 124.357 222.426 108.907 227.222C93.458 232.019 76.9524 232.253 61.3736 227.895C45.7948 223.538 31.8055 214.775 21.0867 202.659C10.3679 190.543 3.37557 175.59 0.949823 159.596C-1.47592 143.602 0.768139 127.248 7.41237 112.499C14.0566 97.7497 24.8183 85.2327 38.4045 76.4519ZM163.062 156.711L163.062 156.711C162.954 156.773 162.846 156.835 162.738 156.897C162.846 156.835 162.954 156.773 163.062 156.711Z"
fill="#24C8DB"
/>
</svg>

After

Width:  |  Height:  |  Size: 2.6 KiB

37
app/static/vite.svg Normal file
View File

@@ -0,0 +1,37 @@
<svg
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
aria-hidden="true"
role="img"
class="iconify iconify--logos"
width="31.88"
height="32"
preserveAspectRatio="xMidYMid meet"
viewBox="0 0 256 257"
>
<defs><linearGradient
id="IconifyId1813088fe1fbc01fb466"
x1="-.828%"
x2="57.636%"
y1="7.652%"
y2="78.411%"
><stop offset="0%" stop-color="#41D1FF"></stop><stop
offset="100%"
stop-color="#BD34FE"
></stop></linearGradient><linearGradient
id="IconifyId1813088fe1fbc01fb467"
x1="43.376%"
x2="50.316%"
y1="2.242%"
y2="89.03%"
><stop offset="0%" stop-color="#FFEA83"></stop><stop
offset="8.333%"
stop-color="#FFDD35"
></stop><stop offset="100%" stop-color="#FFA800"></stop></linearGradient></defs><path
fill="url(#IconifyId1813088fe1fbc01fb466)"
d="M255.153 37.938L134.897 252.976c-2.483 4.44-8.862 4.466-11.382.048L.875 37.958c-2.746-4.814 1.371-10.646 6.827-9.67l120.385 21.517a6.537 6.537 0 0 0 2.322-.004l117.867-21.483c5.438-.991 9.574 4.796 6.877 9.62Z"
></path><path
fill="url(#IconifyId1813088fe1fbc01fb467)"
d="M185.432.063L96.44 17.501a3.268 3.268 0 0 0-2.634 3.014l-5.474 92.456a3.268 3.268 0 0 0 3.997 3.378l24.777-5.718c2.318-.535 4.413 1.507 3.936 3.838l-7.361 36.047c-.495 2.426 1.782 4.5 4.151 3.78l15.304-4.649c2.372-.72 4.652 1.36 4.15 3.788l-11.698 56.621c-.732 3.542 3.979 5.473 5.943 2.437l1.313-2.028l72.516-144.72c1.215-2.423-.88-5.186-3.54-4.672l-25.505 4.922c-2.396.462-4.435-1.77-3.759-4.114l16.646-57.705c.677-2.35-1.37-4.583-3.769-4.113Z"
></path>
</svg>

After

Width:  |  Height:  |  Size: 1.6 KiB

View File

@@ -1,9 +1,8 @@
{
"version": "0.0.4",
"version": "0.0.3",
"scripts": {
"postinstall": "pnpm run -r --filter 'ui' build",
"lint": "pnpm run -r --parallel lint",
"qa": "pnpm lint && pnpm check && pnpm test",
"format": "pnpm dprint fmt",
"format:check": "pnpm dprint check",
"test": "pnpm run -r --parallel test",

View File

@@ -1,6 +1,6 @@
{
"name": "@nodarium/types",
"version": "0.0.5",
"version": "0.0.3",
"description": "",
"main": "src/index.ts",
"scripts": {

View File

@@ -90,12 +90,6 @@ export const NodeInputPathSchema = z.object({
value: z.array(z.number()).optional()
});
export const NodeInputAnySchema = z.object({
...DefaultOptionsSchema.shape,
type: z.literal('*'),
value: z.any().optional()
});
export const NodeInputSchema = z.union([
NodeInputSeedSchema,
NodeInputBooleanSchema,
@@ -107,8 +101,7 @@ export const NodeInputSchema = z.union([
NodeInputSeedSchema,
NodeInputVec3Schema,
NodeInputGeometrySchema,
NodeInputPathSchema,
NodeInputAnySchema
NodeInputPathSchema
]);
export type NodeInput = z.infer<typeof NodeInputSchema>;

View File

@@ -1,6 +1,6 @@
{
"name": "@nodarium/ui",
"version": "0.0.5",
"version": "0.0.3",
"scripts": {
"dev": "vite",
"build": "vite build && npm run package",

View File

@@ -3,10 +3,10 @@
prefix: "i";
}
@source inline("{hover:,}{bg-,outline-,text-,}layer-0{/30,/50,}");
@source inline("{hover:,}{bg-,outline-,text-,}layer-1{/30,/50,}");
@source inline("{hover:,}{bg-,outline-,text-,}layer-2{/30,/50,}");
@source inline("{hover:,}{bg-,outline-,text-,}layer-3{/30,/50,}");
@source inline("{hover:,}{bg-,outline-,text-,}layer-0");
@source inline("{hover:,}{bg-,outline-,text-,}layer-1");
@source inline("{hover:,}{bg-,outline-,text-,}layer-2");
@source inline("{hover:,}{bg-,outline-,text-,}layer-3");
@source inline("{hover:,}{bg-,outline-,text-,}active");
@source inline("{hover:,}{bg-,outline-,text-,}selected");
@source inline("{hover:,}{bg-,outline-,text-,}outline{!,}");
@@ -80,7 +80,6 @@ html {
--neutral-100: #e7e7e7;
--neutral-200: #cecece;
--neutral-300: #7c7c7c;
--neutral-350: #808080;
--neutral-400: #2d2d2d;
--neutral-500: #171717;
--neutral-800: #111111;
@@ -108,7 +107,7 @@ body {
html.theme-light {
--color-text: var(--neutral-800);
--color-outline: var(--neutral-350);
--color-outline: var(--neutral-300);
--color-layer-0: var(--neutral-050);
--color-layer-1: var(--neutral-100);
--color-layer-2: var(--neutral-200);

View File

@@ -126,7 +126,7 @@
<button
aria-label="step down"
onmousedown={stepDown}
class="cursor-pointer w-4 bg-layer-3/30 hover:bg-layer-3/50"
class="cursor-pointer w-4 bg-layer-3 opacity-30 hover:opacity-50"
>
<span class="i-[tabler--chevron-compact-left] block h-full w-full text-outline!"></span>
</button>
@@ -161,7 +161,7 @@
<button
aria-label="step up"
onmousedown={stepUp}
class="cursor-pointer w-4 bg-layer-3/30 hover:bg-layer-3/50"
class="cursor-pointer w-4 bg-layer-3 opacity-30 hover:opacity-50"
>
<span class="i-[tabler--chevron-compact-right] block h-full w-full text-outline!"></span>
</button>

View File

@@ -73,7 +73,7 @@
<InputCheckbox bind:value={mirrorShape} />
<p>mirror</p>
</label>
<p class="max-w-full overflow-hidden">{JSON.stringify(points)}</p>
<p>{JSON.stringify(points)}</p>
{/snippet}
<div style:width="300px">
<InputShape bind:value={points} mirror={mirrorShape} />

View File

@@ -12,7 +12,7 @@
<section class="border-outline border-1/2 bg-layer-1 rounded border mb-4 p-4 flex flex-col gap-4 {_class}">
<h3 class="flex gap-2 font-bold">
{title}
<div class="flex gap-4 w-full font-normal opacity-50 max-w-[75%]">
<div class="flex gap-4 w-full font-normal opacity-50 max-w-[75%] whitespace-pre overflow-hidden text-clip">
{#if header}
{@render header()}
{:else}

View File

@@ -1,9 +1,8 @@
{
"name": "@nodarium/utils",
"version": "0.0.5",
"version": "0.0.3",
"description": "",
"main": "./src/index.ts",
"type": "module",
"main": "src/index.ts",
"scripts": {
"test": "vitest",
"format": "dprint fmt -c '../../.dprint.jsonc' .",

View File

@@ -1,10 +1,5 @@
import { expect, test } from 'vitest';
import {
concatEncodedArrays,
decodeNestedArray,
encodeNestedArray,
splitNestedArray
} from './flatTree';
import { concatEncodedArrays, decodeNestedArray, encodeNestedArray } from './flatTree';
test('it correctly concats nested arrays', () => {
const input_a = encodeNestedArray([1, 2, 3]);
@@ -87,80 +82,3 @@ test('it correctly handles arrays with mixed data types', () => {
const decoded = decodeNestedArray(encodeNestedArray(input));
expect(decoded).toEqual(input);
});
// Test splitNestedArray function
test('it splits nested array into segments based on structure', () => {
const input = [[1, 2], [3, 4]];
const encoded = new Int32Array(encodeNestedArray(input));
const split = splitNestedArray(encoded);
// Based on the actual behavior, splitNestedArray returns segments
// but the specific behavior needs to match the implementation
expect(Array.isArray(split)).toBe(true);
expect(split.length).toBe(2);
expect(split[0][0]).toBe(1);
expect(split[0][1]).toBe(2);
expect(split[1][0]).toBe(3);
expect(split[1][1]).toBe(4);
});
// Test splitNestedArray function
test('it splits nested array into segments based on structure 2', () => {
// dprint-ignore
const encoded = new Int32Array([
0, 1,
0, 19,
0, 1,
0, 0, 0, 1060487823,
1067592955, 1079491492, -1086248132, 1056069822,
-1078247113, 1086620820, 1073133800, 1047681214,
-1068353940, 1094067306, 1078792112, 0,
1, 1,
0, 19,
0, 1,
0, 0, 0, 1060487823,
-1089446963, 1080524584, 1041006274, 1056069822,
-1092176382, 1087031528, -1088851934, 1047681214,
1081482392, 1094426140, -1107842261, 0,
1, 1,
1, 1
]);
// Should be split into two seperate arrays
const split = splitNestedArray(encoded);
// Based on the actual behavior, splitNestedArray returns segments
// but the specific behavior needs to match the implementation
expect(Array.isArray(split)).toBe(true);
expect(split.length).toBe(2);
expect(split[0][0]).toBe(0);
expect(split[0][1]).toBe(1);
expect(split[1][0]).toBe(0);
expect(split[1][1]).toBe(1);
});
// Test splitNestedArray function
test('it splits nested array into segments based on structure 2', () => {
// dprint-ignore
const encoded = new Int32Array( [
0, 1,
0, 27,
0, 1,
0, 0, 0, 1065353216,
0, 1067757391, 0, 1061997773,
0, 1076145999, 0, 1058642330,
0, 1081542391, 0, 1053609164,
0, 1084534607, 0, 1045220556,
0, 1087232803, 0, 0,
1, 1,
1, 1
]);
// Should be split into two seperate arrays
const split = splitNestedArray(encoded);
// Based on the actual behavior, splitNestedArray returns segments
// but the specific behavior needs to match the implementation
expect(Array.isArray(split)).toBe(true);
expect(split.length).toBe(1);
});

409
pnpm-lock.yaml generated
View File

@@ -31,10 +31,10 @@ importers:
version: link:../packages/utils
'@sveltejs/kit':
specifier: ^2.50.2
version: 2.50.2(@sveltejs/vite-plugin-svelte@6.2.4(svelte@5.49.2)(vite@7.3.1(@types/node@22.8.6)(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass@1.80.6)(terser@5.36.0)(tsx@4.21.0)))(svelte@5.49.2)(typescript@5.9.3)(vite@7.3.1(@types/node@22.8.6)(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass@1.80.6)(terser@5.36.0)(tsx@4.21.0))
version: 2.50.2(@sveltejs/vite-plugin-svelte@6.2.4(svelte@5.49.2)(vite@7.3.1(@types/node@22.8.6)(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass@1.80.6)(terser@5.36.0)(tsx@4.19.2)))(svelte@5.49.2)(typescript@5.9.3)(vite@7.3.1(@types/node@22.8.6)(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass@1.80.6)(terser@5.36.0)(tsx@4.19.2))
'@tailwindcss/vite':
specifier: ^4.1.18
version: 4.1.18(vite@7.3.1(@types/node@22.8.6)(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass@1.80.6)(terser@5.36.0)(tsx@4.21.0))
version: 4.1.18(vite@7.3.1(@types/node@22.8.6)(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass@1.80.6)(terser@5.36.0)(tsx@4.19.2))
'@threlte/core':
specifier: 8.3.1
version: 8.3.1(svelte@5.49.2)(three@0.182.0)
@@ -83,10 +83,10 @@ importers:
version: 1.58.1
'@sveltejs/adapter-static':
specifier: ^3.0.10
version: 3.0.10(@sveltejs/kit@2.50.2(@sveltejs/vite-plugin-svelte@6.2.4(svelte@5.49.2)(vite@7.3.1(@types/node@22.8.6)(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass@1.80.6)(terser@5.36.0)(tsx@4.21.0)))(svelte@5.49.2)(typescript@5.9.3)(vite@7.3.1(@types/node@22.8.6)(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass@1.80.6)(terser@5.36.0)(tsx@4.21.0)))
version: 3.0.10(@sveltejs/kit@2.50.2(@sveltejs/vite-plugin-svelte@6.2.4(svelte@5.49.2)(vite@7.3.1(@types/node@22.8.6)(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass@1.80.6)(terser@5.36.0)(tsx@4.19.2)))(svelte@5.49.2)(typescript@5.9.3)(vite@7.3.1(@types/node@22.8.6)(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass@1.80.6)(terser@5.36.0)(tsx@4.19.2)))
'@sveltejs/vite-plugin-svelte':
specifier: ^6.2.4
version: 6.2.4(svelte@5.49.2)(vite@7.3.1(@types/node@22.8.6)(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass@1.80.6)(terser@5.36.0)(tsx@4.21.0))
version: 6.2.4(svelte@5.49.2)(vite@7.3.1(@types/node@22.8.6)(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass@1.80.6)(terser@5.36.0)(tsx@4.19.2))
'@tsconfig/svelte':
specifier: ^5.0.7
version: 5.0.7
@@ -98,7 +98,7 @@ importers:
version: 0.182.0
'@vitest/browser-playwright':
specifier: ^4.0.18
version: 4.0.18(playwright@1.58.1)(vite@7.3.1(@types/node@22.8.6)(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass@1.80.6)(terser@5.36.0)(tsx@4.21.0))(vitest@4.0.18)
version: 4.0.18(playwright@1.58.1)(vite@7.3.1(@types/node@22.8.6)(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass@1.80.6)(terser@5.36.0)(tsx@4.19.2))(vitest@4.0.18)
dprint:
specifier: ^0.51.1
version: 0.51.1
@@ -120,9 +120,6 @@ importers:
tslib:
specifier: ^2.8.1
version: 2.8.1
tsx:
specifier: ^4.21.0
version: 4.21.0
typescript:
specifier: ^5.9.3
version: 5.9.3
@@ -131,19 +128,19 @@ importers:
version: 8.54.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3)
vite:
specifier: ^7.3.1
version: 7.3.1(@types/node@22.8.6)(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass@1.80.6)(terser@5.36.0)(tsx@4.21.0)
version: 7.3.1(@types/node@22.8.6)(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass@1.80.6)(terser@5.36.0)(tsx@4.19.2)
vite-plugin-comlink:
specifier: ^5.3.0
version: 5.3.0(comlink@4.4.2)(vite@7.3.1(@types/node@22.8.6)(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass@1.80.6)(terser@5.36.0)(tsx@4.21.0))
version: 5.3.0(comlink@4.4.2)(vite@7.3.1(@types/node@22.8.6)(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass@1.80.6)(terser@5.36.0)(tsx@4.19.2))
vite-plugin-glsl:
specifier: ^1.5.5
version: 1.5.5(@rollup/pluginutils@5.1.4(rollup@4.57.1))(esbuild@0.27.3)(vite@7.3.1(@types/node@22.8.6)(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass@1.80.6)(terser@5.36.0)(tsx@4.21.0))
version: 1.5.5(@rollup/pluginutils@5.1.4(rollup@4.57.1))(esbuild@0.27.3)(vite@7.3.1(@types/node@22.8.6)(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass@1.80.6)(terser@5.36.0)(tsx@4.19.2))
vite-plugin-wasm:
specifier: ^3.5.0
version: 3.5.0(vite@7.3.1(@types/node@22.8.6)(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass@1.80.6)(terser@5.36.0)(tsx@4.21.0))
version: 3.5.0(vite@7.3.1(@types/node@22.8.6)(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass@1.80.6)(terser@5.36.0)(tsx@4.19.2))
vitest:
specifier: ^4.0.18
version: 4.0.18(@types/node@22.8.6)(@vitest/browser-playwright@4.0.18)(jiti@2.6.1)(jsdom@25.0.1)(less@4.2.0)(lightningcss@1.30.2)(sass@1.80.6)(terser@5.36.0)(tsx@4.21.0)
version: 4.0.18(@types/node@22.8.6)(@vitest/browser-playwright@4.0.18)(jiti@2.6.1)(jsdom@25.0.1)(less@4.2.0)(lightningcss@1.30.2)(sass@1.80.6)(terser@5.36.0)(tsx@4.19.2)
vitest-browser-svelte:
specifier: ^2.0.2
version: 2.0.2(svelte@5.49.2)(vitest@4.0.18)
@@ -168,7 +165,7 @@ importers:
version: 1.2.1(tailwindcss@4.1.18)
'@tailwindcss/vite':
specifier: ^4.1.18
version: 4.1.18(vite@7.3.1(@types/node@22.8.6)(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass@1.80.6)(terser@5.36.0)(tsx@4.21.0))
version: 4.1.18(vite@7.3.1(@types/node@22.8.6)(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass@1.80.6)(terser@5.36.0)(tsx@4.19.2))
'@threlte/core':
specifier: ^8.3.1
version: 8.3.1(svelte@5.49.2)(three@0.182.0)
@@ -196,19 +193,19 @@ importers:
version: 1.58.1
'@sveltejs/adapter-static':
specifier: ^3.0.10
version: 3.0.10(@sveltejs/kit@2.50.2(@sveltejs/vite-plugin-svelte@6.2.4(svelte@5.49.2)(vite@7.3.1(@types/node@22.8.6)(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass@1.80.6)(terser@5.36.0)(tsx@4.21.0)))(svelte@5.49.2)(typescript@5.9.3)(vite@7.3.1(@types/node@22.8.6)(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass@1.80.6)(terser@5.36.0)(tsx@4.21.0)))
version: 3.0.10(@sveltejs/kit@2.50.2(@sveltejs/vite-plugin-svelte@6.2.4(svelte@5.49.2)(vite@7.3.1(@types/node@22.8.6)(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass@1.80.6)(terser@5.36.0)(tsx@4.19.2)))(svelte@5.49.2)(typescript@5.9.3)(vite@7.3.1(@types/node@22.8.6)(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass@1.80.6)(terser@5.36.0)(tsx@4.19.2)))
'@sveltejs/kit':
specifier: ^2.50.2
version: 2.50.2(@sveltejs/vite-plugin-svelte@6.2.4(svelte@5.49.2)(vite@7.3.1(@types/node@22.8.6)(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass@1.80.6)(terser@5.36.0)(tsx@4.21.0)))(svelte@5.49.2)(typescript@5.9.3)(vite@7.3.1(@types/node@22.8.6)(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass@1.80.6)(terser@5.36.0)(tsx@4.21.0))
version: 2.50.2(@sveltejs/vite-plugin-svelte@6.2.4(svelte@5.49.2)(vite@7.3.1(@types/node@22.8.6)(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass@1.80.6)(terser@5.36.0)(tsx@4.19.2)))(svelte@5.49.2)(typescript@5.9.3)(vite@7.3.1(@types/node@22.8.6)(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass@1.80.6)(terser@5.36.0)(tsx@4.19.2))
'@sveltejs/package':
specifier: ^2.5.7
version: 2.5.7(svelte@5.49.2)(typescript@5.9.3)
'@sveltejs/vite-plugin-svelte':
specifier: ^6.2.4
version: 6.2.4(svelte@5.49.2)(vite@7.3.1(@types/node@22.8.6)(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass@1.80.6)(terser@5.36.0)(tsx@4.21.0))
version: 6.2.4(svelte@5.49.2)(vite@7.3.1(@types/node@22.8.6)(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass@1.80.6)(terser@5.36.0)(tsx@4.19.2))
'@testing-library/svelte':
specifier: ^5.3.1
version: 5.3.1(svelte@5.49.2)(vite@7.3.1(@types/node@22.8.6)(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass@1.80.6)(terser@5.36.0)(tsx@4.21.0))(vitest@4.0.18)
version: 5.3.1(svelte@5.49.2)(vite@7.3.1(@types/node@22.8.6)(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass@1.80.6)(terser@5.36.0)(tsx@4.19.2))(vitest@4.0.18)
'@types/eslint':
specifier: ^9.6.1
version: 9.6.1
@@ -223,7 +220,7 @@ importers:
version: 8.54.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3)
'@vitest/browser-playwright':
specifier: ^4.0.18
version: 4.0.18(playwright@1.58.1)(vite@7.3.1(@types/node@22.8.6)(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass@1.80.6)(terser@5.36.0)(tsx@4.21.0))(vitest@4.0.18)
version: 4.0.18(playwright@1.58.1)(vite@7.3.1(@types/node@22.8.6)(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass@1.80.6)(terser@5.36.0)(tsx@4.19.2))(vitest@4.0.18)
dprint:
specifier: ^0.51.1
version: 0.51.1
@@ -259,10 +256,10 @@ importers:
version: 8.54.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3)
vite:
specifier: ^7.3.1
version: 7.3.1(@types/node@22.8.6)(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass@1.80.6)(terser@5.36.0)(tsx@4.21.0)
version: 7.3.1(@types/node@22.8.6)(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass@1.80.6)(terser@5.36.0)(tsx@4.19.2)
vitest:
specifier: ^4.0.18
version: 4.0.18(@types/node@22.8.6)(@vitest/browser-playwright@4.0.18)(jiti@2.6.1)(jsdom@25.0.1)(less@4.2.0)(lightningcss@1.30.2)(sass@1.80.6)(terser@5.36.0)(tsx@4.21.0)
version: 4.0.18(@types/node@22.8.6)(@vitest/browser-playwright@4.0.18)(jiti@2.6.1)(jsdom@25.0.1)(less@4.2.0)(lightningcss@1.30.2)(sass@1.80.6)(terser@5.36.0)(tsx@4.19.2)
vitest-browser-svelte:
specifier: ^2.0.2
version: 2.0.2(svelte@5.49.2)(vitest@4.0.18)
@@ -278,10 +275,10 @@ importers:
version: 0.51.1
vite:
specifier: ^7.3.1
version: 7.3.1(@types/node@22.8.6)(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass@1.80.6)(terser@5.36.0)(tsx@4.21.0)
version: 7.3.1(@types/node@22.8.6)(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass@1.80.6)(terser@5.36.0)(tsx@4.19.2)
vitest:
specifier: ^4.0.18
version: 4.0.18(@vitest/browser-playwright@4.0.18)(jiti@2.6.1)(jsdom@25.0.1)(less@4.2.0)(lightningcss@1.30.2)(sass@1.80.6)(terser@5.36.0)(tsx@4.21.0)
version: 4.0.18(@vitest/browser-playwright@4.0.18)(jiti@2.6.1)(jsdom@25.0.1)(less@4.2.0)(lightningcss@1.30.2)(sass@1.80.6)(terser@5.36.0)(tsx@4.19.2)
packages:
@@ -399,102 +396,204 @@ packages:
cpu: [x64]
os: [win32]
'@esbuild/aix-ppc64@0.23.1':
resolution: {integrity: sha512-6VhYk1diRqrhBAqpJEdjASR/+WVRtfjpqKuNw11cLiaWpAT/Uu+nokB+UJnevzy/P9C/ty6AOe0dwueMrGh/iQ==}
engines: {node: '>=18'}
cpu: [ppc64]
os: [aix]
'@esbuild/aix-ppc64@0.27.3':
resolution: {integrity: sha512-9fJMTNFTWZMh5qwrBItuziu834eOCUcEqymSH7pY+zoMVEZg3gcPuBNxH1EvfVYe9h0x/Ptw8KBzv7qxb7l8dg==}
engines: {node: '>=18'}
cpu: [ppc64]
os: [aix]
'@esbuild/android-arm64@0.23.1':
resolution: {integrity: sha512-xw50ipykXcLstLeWH7WRdQuysJqejuAGPd30vd1i5zSyKK3WE+ijzHmLKxdiCMtH1pHz78rOg0BKSYOSB/2Khw==}
engines: {node: '>=18'}
cpu: [arm64]
os: [android]
'@esbuild/android-arm64@0.27.3':
resolution: {integrity: sha512-YdghPYUmj/FX2SYKJ0OZxf+iaKgMsKHVPF1MAq/P8WirnSpCStzKJFjOjzsW0QQ7oIAiccHdcqjbHmJxRb/dmg==}
engines: {node: '>=18'}
cpu: [arm64]
os: [android]
'@esbuild/android-arm@0.23.1':
resolution: {integrity: sha512-uz6/tEy2IFm9RYOyvKl88zdzZfwEfKZmnX9Cj1BHjeSGNuGLuMD1kR8y5bteYmwqKm1tj8m4cb/aKEorr6fHWQ==}
engines: {node: '>=18'}
cpu: [arm]
os: [android]
'@esbuild/android-arm@0.27.3':
resolution: {integrity: sha512-i5D1hPY7GIQmXlXhs2w8AWHhenb00+GxjxRncS2ZM7YNVGNfaMxgzSGuO8o8SJzRc/oZwU2bcScvVERk03QhzA==}
engines: {node: '>=18'}
cpu: [arm]
os: [android]
'@esbuild/android-x64@0.23.1':
resolution: {integrity: sha512-nlN9B69St9BwUoB+jkyU090bru8L0NA3yFvAd7k8dNsVH8bi9a8cUAUSEcEEgTp2z3dbEDGJGfP6VUnkQnlReg==}
engines: {node: '>=18'}
cpu: [x64]
os: [android]
'@esbuild/android-x64@0.27.3':
resolution: {integrity: sha512-IN/0BNTkHtk8lkOM8JWAYFg4ORxBkZQf9zXiEOfERX/CzxW3Vg1ewAhU7QSWQpVIzTW+b8Xy+lGzdYXV6UZObQ==}
engines: {node: '>=18'}
cpu: [x64]
os: [android]
'@esbuild/darwin-arm64@0.23.1':
resolution: {integrity: sha512-YsS2e3Wtgnw7Wq53XXBLcV6JhRsEq8hkfg91ESVadIrzr9wO6jJDMZnCQbHm1Guc5t/CdDiFSSfWP58FNuvT3Q==}
engines: {node: '>=18'}
cpu: [arm64]
os: [darwin]
'@esbuild/darwin-arm64@0.27.3':
resolution: {integrity: sha512-Re491k7ByTVRy0t3EKWajdLIr0gz2kKKfzafkth4Q8A5n1xTHrkqZgLLjFEHVD+AXdUGgQMq+Godfq45mGpCKg==}
engines: {node: '>=18'}
cpu: [arm64]
os: [darwin]
'@esbuild/darwin-x64@0.23.1':
resolution: {integrity: sha512-aClqdgTDVPSEGgoCS8QDG37Gu8yc9lTHNAQlsztQ6ENetKEO//b8y31MMu2ZaPbn4kVsIABzVLXYLhCGekGDqw==}
engines: {node: '>=18'}
cpu: [x64]
os: [darwin]
'@esbuild/darwin-x64@0.27.3':
resolution: {integrity: sha512-vHk/hA7/1AckjGzRqi6wbo+jaShzRowYip6rt6q7VYEDX4LEy1pZfDpdxCBnGtl+A5zq8iXDcyuxwtv3hNtHFg==}
engines: {node: '>=18'}
cpu: [x64]
os: [darwin]
'@esbuild/freebsd-arm64@0.23.1':
resolution: {integrity: sha512-h1k6yS8/pN/NHlMl5+v4XPfikhJulk4G+tKGFIOwURBSFzE8bixw1ebjluLOjfwtLqY0kewfjLSrO6tN2MgIhA==}
engines: {node: '>=18'}
cpu: [arm64]
os: [freebsd]
'@esbuild/freebsd-arm64@0.27.3':
resolution: {integrity: sha512-ipTYM2fjt3kQAYOvo6vcxJx3nBYAzPjgTCk7QEgZG8AUO3ydUhvelmhrbOheMnGOlaSFUoHXB6un+A7q4ygY9w==}
engines: {node: '>=18'}
cpu: [arm64]
os: [freebsd]
'@esbuild/freebsd-x64@0.23.1':
resolution: {integrity: sha512-lK1eJeyk1ZX8UklqFd/3A60UuZ/6UVfGT2LuGo3Wp4/z7eRTRYY+0xOu2kpClP+vMTi9wKOfXi2vjUpO1Ro76g==}
engines: {node: '>=18'}
cpu: [x64]
os: [freebsd]
'@esbuild/freebsd-x64@0.27.3':
resolution: {integrity: sha512-dDk0X87T7mI6U3K9VjWtHOXqwAMJBNN2r7bejDsc+j03SEjtD9HrOl8gVFByeM0aJksoUuUVU9TBaZa2rgj0oA==}
engines: {node: '>=18'}
cpu: [x64]
os: [freebsd]
'@esbuild/linux-arm64@0.23.1':
resolution: {integrity: sha512-/93bf2yxencYDnItMYV/v116zff6UyTjo4EtEQjUBeGiVpMmffDNUyD9UN2zV+V3LRV3/on4xdZ26NKzn6754g==}
engines: {node: '>=18'}
cpu: [arm64]
os: [linux]
'@esbuild/linux-arm64@0.27.3':
resolution: {integrity: sha512-sZOuFz/xWnZ4KH3YfFrKCf1WyPZHakVzTiqji3WDc0BCl2kBwiJLCXpzLzUBLgmp4veFZdvN5ChW4Eq/8Fc2Fg==}
engines: {node: '>=18'}
cpu: [arm64]
os: [linux]
'@esbuild/linux-arm@0.23.1':
resolution: {integrity: sha512-CXXkzgn+dXAPs3WBwE+Kvnrf4WECwBdfjfeYHpMeVxWE0EceB6vhWGShs6wi0IYEqMSIzdOF1XjQ/Mkm5d7ZdQ==}
engines: {node: '>=18'}
cpu: [arm]
os: [linux]
'@esbuild/linux-arm@0.27.3':
resolution: {integrity: sha512-s6nPv2QkSupJwLYyfS+gwdirm0ukyTFNl3KTgZEAiJDd+iHZcbTPPcWCcRYH+WlNbwChgH2QkE9NSlNrMT8Gfw==}
engines: {node: '>=18'}
cpu: [arm]
os: [linux]
'@esbuild/linux-ia32@0.23.1':
resolution: {integrity: sha512-VTN4EuOHwXEkXzX5nTvVY4s7E/Krz7COC8xkftbbKRYAl96vPiUssGkeMELQMOnLOJ8k3BY1+ZY52tttZnHcXQ==}
engines: {node: '>=18'}
cpu: [ia32]
os: [linux]
'@esbuild/linux-ia32@0.27.3':
resolution: {integrity: sha512-yGlQYjdxtLdh0a3jHjuwOrxQjOZYD/C9PfdbgJJF3TIZWnm/tMd/RcNiLngiu4iwcBAOezdnSLAwQDPqTmtTYg==}
engines: {node: '>=18'}
cpu: [ia32]
os: [linux]
'@esbuild/linux-loong64@0.23.1':
resolution: {integrity: sha512-Vx09LzEoBa5zDnieH8LSMRToj7ir/Jeq0Gu6qJ/1GcBq9GkfoEAoXvLiW1U9J1qE/Y/Oyaq33w5p2ZWrNNHNEw==}
engines: {node: '>=18'}
cpu: [loong64]
os: [linux]
'@esbuild/linux-loong64@0.27.3':
resolution: {integrity: sha512-WO60Sn8ly3gtzhyjATDgieJNet/KqsDlX5nRC5Y3oTFcS1l0KWba+SEa9Ja1GfDqSF1z6hif/SkpQJbL63cgOA==}
engines: {node: '>=18'}
cpu: [loong64]
os: [linux]
'@esbuild/linux-mips64el@0.23.1':
resolution: {integrity: sha512-nrFzzMQ7W4WRLNUOU5dlWAqa6yVeI0P78WKGUo7lg2HShq/yx+UYkeNSE0SSfSure0SqgnsxPvmAUu/vu0E+3Q==}
engines: {node: '>=18'}
cpu: [mips64el]
os: [linux]
'@esbuild/linux-mips64el@0.27.3':
resolution: {integrity: sha512-APsymYA6sGcZ4pD6k+UxbDjOFSvPWyZhjaiPyl/f79xKxwTnrn5QUnXR5prvetuaSMsb4jgeHewIDCIWljrSxw==}
engines: {node: '>=18'}
cpu: [mips64el]
os: [linux]
'@esbuild/linux-ppc64@0.23.1':
resolution: {integrity: sha512-dKN8fgVqd0vUIjxuJI6P/9SSSe/mB9rvA98CSH2sJnlZ/OCZWO1DJvxj8jvKTfYUdGfcq2dDxoKaC6bHuTlgcw==}
engines: {node: '>=18'}
cpu: [ppc64]
os: [linux]
'@esbuild/linux-ppc64@0.27.3':
resolution: {integrity: sha512-eizBnTeBefojtDb9nSh4vvVQ3V9Qf9Df01PfawPcRzJH4gFSgrObw+LveUyDoKU3kxi5+9RJTCWlj4FjYXVPEA==}
engines: {node: '>=18'}
cpu: [ppc64]
os: [linux]
'@esbuild/linux-riscv64@0.23.1':
resolution: {integrity: sha512-5AV4Pzp80fhHL83JM6LoA6pTQVWgB1HovMBsLQ9OZWLDqVY8MVobBXNSmAJi//Csh6tcY7e7Lny2Hg1tElMjIA==}
engines: {node: '>=18'}
cpu: [riscv64]
os: [linux]
'@esbuild/linux-riscv64@0.27.3':
resolution: {integrity: sha512-3Emwh0r5wmfm3ssTWRQSyVhbOHvqegUDRd0WhmXKX2mkHJe1SFCMJhagUleMq+Uci34wLSipf8Lagt4LlpRFWQ==}
engines: {node: '>=18'}
cpu: [riscv64]
os: [linux]
'@esbuild/linux-s390x@0.23.1':
resolution: {integrity: sha512-9ygs73tuFCe6f6m/Tb+9LtYxWR4c9yg7zjt2cYkjDbDpV/xVn+68cQxMXCjUpYwEkze2RcU/rMnfIXNRFmSoDw==}
engines: {node: '>=18'}
cpu: [s390x]
os: [linux]
'@esbuild/linux-s390x@0.27.3':
resolution: {integrity: sha512-pBHUx9LzXWBc7MFIEEL0yD/ZVtNgLytvx60gES28GcWMqil8ElCYR4kvbV2BDqsHOvVDRrOxGySBM9Fcv744hw==}
engines: {node: '>=18'}
cpu: [s390x]
os: [linux]
'@esbuild/linux-x64@0.23.1':
resolution: {integrity: sha512-EV6+ovTsEXCPAp58g2dD68LxoP/wK5pRvgy0J/HxPGB009omFPv3Yet0HiaqvrIrgPTBuC6wCH1LTOY91EO5hQ==}
engines: {node: '>=18'}
cpu: [x64]
os: [linux]
'@esbuild/linux-x64@0.27.3':
resolution: {integrity: sha512-Czi8yzXUWIQYAtL/2y6vogER8pvcsOsk5cpwL4Gk5nJqH5UZiVByIY8Eorm5R13gq+DQKYg0+JyQoytLQas4dA==}
engines: {node: '>=18'}
@@ -507,18 +606,36 @@ packages:
cpu: [arm64]
os: [netbsd]
'@esbuild/netbsd-x64@0.23.1':
resolution: {integrity: sha512-aevEkCNu7KlPRpYLjwmdcuNz6bDFiE7Z8XC4CPqExjTvrHugh28QzUXVOZtiYghciKUacNktqxdpymplil1beA==}
engines: {node: '>=18'}
cpu: [x64]
os: [netbsd]
'@esbuild/netbsd-x64@0.27.3':
resolution: {integrity: sha512-P14lFKJl/DdaE00LItAukUdZO5iqNH7+PjoBm+fLQjtxfcfFE20Xf5CrLsmZdq5LFFZzb5JMZ9grUwvtVYzjiA==}
engines: {node: '>=18'}
cpu: [x64]
os: [netbsd]
'@esbuild/openbsd-arm64@0.23.1':
resolution: {integrity: sha512-3x37szhLexNA4bXhLrCC/LImN/YtWis6WXr1VESlfVtVeoFJBRINPJ3f0a/6LV8zpikqoUg4hyXw0sFBt5Cr+Q==}
engines: {node: '>=18'}
cpu: [arm64]
os: [openbsd]
'@esbuild/openbsd-arm64@0.27.3':
resolution: {integrity: sha512-AIcMP77AvirGbRl/UZFTq5hjXK+2wC7qFRGoHSDrZ5v5b8DK/GYpXW3CPRL53NkvDqb9D+alBiC/dV0Fb7eJcw==}
engines: {node: '>=18'}
cpu: [arm64]
os: [openbsd]
'@esbuild/openbsd-x64@0.23.1':
resolution: {integrity: sha512-aY2gMmKmPhxfU+0EdnN+XNtGbjfQgwZj43k8G3fyrDM/UdZww6xrWxmDkuz2eCZchqVeABjV5BpildOrUbBTqA==}
engines: {node: '>=18'}
cpu: [x64]
os: [openbsd]
'@esbuild/openbsd-x64@0.27.3':
resolution: {integrity: sha512-DnW2sRrBzA+YnE70LKqnM3P+z8vehfJWHXECbwBmH/CU51z6FiqTQTHFenPlHmo3a8UgpLyH3PT+87OViOh1AQ==}
engines: {node: '>=18'}
@@ -531,24 +648,48 @@ packages:
cpu: [arm64]
os: [openharmony]
'@esbuild/sunos-x64@0.23.1':
resolution: {integrity: sha512-RBRT2gqEl0IKQABT4XTj78tpk9v7ehp+mazn2HbUeZl1YMdaGAQqhapjGTCe7uw7y0frDi4gS0uHzhvpFuI1sA==}
engines: {node: '>=18'}
cpu: [x64]
os: [sunos]
'@esbuild/sunos-x64@0.27.3':
resolution: {integrity: sha512-PanZ+nEz+eWoBJ8/f8HKxTTD172SKwdXebZ0ndd953gt1HRBbhMsaNqjTyYLGLPdoWHy4zLU7bDVJztF5f3BHA==}
engines: {node: '>=18'}
cpu: [x64]
os: [sunos]
'@esbuild/win32-arm64@0.23.1':
resolution: {integrity: sha512-4O+gPR5rEBe2FpKOVyiJ7wNDPA8nGzDuJ6gN4okSA1gEOYZ67N8JPk58tkWtdtPeLz7lBnY6I5L3jdsr3S+A6A==}
engines: {node: '>=18'}
cpu: [arm64]
os: [win32]
'@esbuild/win32-arm64@0.27.3':
resolution: {integrity: sha512-B2t59lWWYrbRDw/tjiWOuzSsFh1Y/E95ofKz7rIVYSQkUYBjfSgf6oeYPNWHToFRr2zx52JKApIcAS/D5TUBnA==}
engines: {node: '>=18'}
cpu: [arm64]
os: [win32]
'@esbuild/win32-ia32@0.23.1':
resolution: {integrity: sha512-BcaL0Vn6QwCwre3Y717nVHZbAa4UBEigzFm6VdsVdT/MbZ38xoj1X9HPkZhbmaBGUD1W8vxAfffbDe8bA6AKnQ==}
engines: {node: '>=18'}
cpu: [ia32]
os: [win32]
'@esbuild/win32-ia32@0.27.3':
resolution: {integrity: sha512-QLKSFeXNS8+tHW7tZpMtjlNb7HKau0QDpwm49u0vUp9y1WOF+PEzkU84y9GqYaAVW8aH8f3GcBck26jh54cX4Q==}
engines: {node: '>=18'}
cpu: [ia32]
os: [win32]
'@esbuild/win32-x64@0.23.1':
resolution: {integrity: sha512-BHpFFeslkWrXWyUPnbKm+xYYVYruCinGcftSBaa8zoF9hZO4BcSCFUvHVTtzpIY6YzUnYtuEhZ+C9iEXjxnasg==}
engines: {node: '>=18'}
cpu: [x64]
os: [win32]
'@esbuild/win32-x64@0.27.3':
resolution: {integrity: sha512-4uJGhsxuptu3OcpVAzli+/gWusVGwZZHTlS63hh++ehExkVT8SgiEf7/uC/PclrPPkLhZqGgCTjd0VWLo6xMqA==}
engines: {node: '>=18'}
@@ -1566,6 +1707,11 @@ packages:
resolution: {integrity: sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==}
engines: {node: '>= 0.4'}
esbuild@0.23.1:
resolution: {integrity: sha512-VVNz/9Sa0bs5SELtn3f7qhJCDPCF5oMEl5cO9/SSinpE9hbPVvxbd572HH5AKiP7WD8INO53GgfDDhRjkylHEg==}
engines: {node: '>=18'}
hasBin: true
esbuild@0.27.3:
resolution: {integrity: sha512-8VwMnyGCONIs6cWue2IdpHxHnAjzxnw2Zr7MkVxB2vjmQ2ivqGFb4LEG3SMnv0Gb2F/G/2yA8zUaiL1gywDCCg==}
engines: {node: '>=18'}
@@ -2550,8 +2696,8 @@ packages:
tslib@2.8.1:
resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==}
tsx@4.21.0:
resolution: {integrity: sha512-5C1sg4USs1lfG0GFb2RLXsdpXqBSEhAaA/0kPL01wxzpMqLILNxIxIOKiILz+cdg/pLnOUxFYOR5yhHU666wbw==}
tsx@4.19.2:
resolution: {integrity: sha512-pOUl6Vo2LUq/bSa8S5q7b91cgNSjctn9ugq/+Mvow99qW6x/UZYwzxy/3NmqoT66eHYfCVvFvACC58UBPFf28g==}
engines: {node: '>=18.0.0'}
hasBin: true
@@ -2889,81 +3035,153 @@ snapshots:
'@dprint/win32-x64@0.51.1':
optional: true
'@esbuild/aix-ppc64@0.23.1':
optional: true
'@esbuild/aix-ppc64@0.27.3':
optional: true
'@esbuild/android-arm64@0.23.1':
optional: true
'@esbuild/android-arm64@0.27.3':
optional: true
'@esbuild/android-arm@0.23.1':
optional: true
'@esbuild/android-arm@0.27.3':
optional: true
'@esbuild/android-x64@0.23.1':
optional: true
'@esbuild/android-x64@0.27.3':
optional: true
'@esbuild/darwin-arm64@0.23.1':
optional: true
'@esbuild/darwin-arm64@0.27.3':
optional: true
'@esbuild/darwin-x64@0.23.1':
optional: true
'@esbuild/darwin-x64@0.27.3':
optional: true
'@esbuild/freebsd-arm64@0.23.1':
optional: true
'@esbuild/freebsd-arm64@0.27.3':
optional: true
'@esbuild/freebsd-x64@0.23.1':
optional: true
'@esbuild/freebsd-x64@0.27.3':
optional: true
'@esbuild/linux-arm64@0.23.1':
optional: true
'@esbuild/linux-arm64@0.27.3':
optional: true
'@esbuild/linux-arm@0.23.1':
optional: true
'@esbuild/linux-arm@0.27.3':
optional: true
'@esbuild/linux-ia32@0.23.1':
optional: true
'@esbuild/linux-ia32@0.27.3':
optional: true
'@esbuild/linux-loong64@0.23.1':
optional: true
'@esbuild/linux-loong64@0.27.3':
optional: true
'@esbuild/linux-mips64el@0.23.1':
optional: true
'@esbuild/linux-mips64el@0.27.3':
optional: true
'@esbuild/linux-ppc64@0.23.1':
optional: true
'@esbuild/linux-ppc64@0.27.3':
optional: true
'@esbuild/linux-riscv64@0.23.1':
optional: true
'@esbuild/linux-riscv64@0.27.3':
optional: true
'@esbuild/linux-s390x@0.23.1':
optional: true
'@esbuild/linux-s390x@0.27.3':
optional: true
'@esbuild/linux-x64@0.23.1':
optional: true
'@esbuild/linux-x64@0.27.3':
optional: true
'@esbuild/netbsd-arm64@0.27.3':
optional: true
'@esbuild/netbsd-x64@0.23.1':
optional: true
'@esbuild/netbsd-x64@0.27.3':
optional: true
'@esbuild/openbsd-arm64@0.23.1':
optional: true
'@esbuild/openbsd-arm64@0.27.3':
optional: true
'@esbuild/openbsd-x64@0.23.1':
optional: true
'@esbuild/openbsd-x64@0.27.3':
optional: true
'@esbuild/openharmony-arm64@0.27.3':
optional: true
'@esbuild/sunos-x64@0.23.1':
optional: true
'@esbuild/sunos-x64@0.27.3':
optional: true
'@esbuild/win32-arm64@0.23.1':
optional: true
'@esbuild/win32-arm64@0.27.3':
optional: true
'@esbuild/win32-ia32@0.23.1':
optional: true
'@esbuild/win32-ia32@0.27.3':
optional: true
'@esbuild/win32-x64@0.23.1':
optional: true
'@esbuild/win32-x64@0.27.3':
optional: true
@@ -3253,15 +3471,15 @@ snapshots:
dependencies:
acorn: 8.15.0
'@sveltejs/adapter-static@3.0.10(@sveltejs/kit@2.50.2(@sveltejs/vite-plugin-svelte@6.2.4(svelte@5.49.2)(vite@7.3.1(@types/node@22.8.6)(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass@1.80.6)(terser@5.36.0)(tsx@4.21.0)))(svelte@5.49.2)(typescript@5.9.3)(vite@7.3.1(@types/node@22.8.6)(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass@1.80.6)(terser@5.36.0)(tsx@4.21.0)))':
'@sveltejs/adapter-static@3.0.10(@sveltejs/kit@2.50.2(@sveltejs/vite-plugin-svelte@6.2.4(svelte@5.49.2)(vite@7.3.1(@types/node@22.8.6)(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass@1.80.6)(terser@5.36.0)(tsx@4.19.2)))(svelte@5.49.2)(typescript@5.9.3)(vite@7.3.1(@types/node@22.8.6)(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass@1.80.6)(terser@5.36.0)(tsx@4.19.2)))':
dependencies:
'@sveltejs/kit': 2.50.2(@sveltejs/vite-plugin-svelte@6.2.4(svelte@5.49.2)(vite@7.3.1(@types/node@22.8.6)(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass@1.80.6)(terser@5.36.0)(tsx@4.21.0)))(svelte@5.49.2)(typescript@5.9.3)(vite@7.3.1(@types/node@22.8.6)(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass@1.80.6)(terser@5.36.0)(tsx@4.21.0))
'@sveltejs/kit': 2.50.2(@sveltejs/vite-plugin-svelte@6.2.4(svelte@5.49.2)(vite@7.3.1(@types/node@22.8.6)(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass@1.80.6)(terser@5.36.0)(tsx@4.19.2)))(svelte@5.49.2)(typescript@5.9.3)(vite@7.3.1(@types/node@22.8.6)(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass@1.80.6)(terser@5.36.0)(tsx@4.19.2))
'@sveltejs/kit@2.50.2(@sveltejs/vite-plugin-svelte@6.2.4(svelte@5.49.2)(vite@7.3.1(@types/node@22.8.6)(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass@1.80.6)(terser@5.36.0)(tsx@4.21.0)))(svelte@5.49.2)(typescript@5.9.3)(vite@7.3.1(@types/node@22.8.6)(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass@1.80.6)(terser@5.36.0)(tsx@4.21.0))':
'@sveltejs/kit@2.50.2(@sveltejs/vite-plugin-svelte@6.2.4(svelte@5.49.2)(vite@7.3.1(@types/node@22.8.6)(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass@1.80.6)(terser@5.36.0)(tsx@4.19.2)))(svelte@5.49.2)(typescript@5.9.3)(vite@7.3.1(@types/node@22.8.6)(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass@1.80.6)(terser@5.36.0)(tsx@4.19.2))':
dependencies:
'@standard-schema/spec': 1.1.0
'@sveltejs/acorn-typescript': 1.0.8(acorn@8.15.0)
'@sveltejs/vite-plugin-svelte': 6.2.4(svelte@5.49.2)(vite@7.3.1(@types/node@22.8.6)(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass@1.80.6)(terser@5.36.0)(tsx@4.21.0))
'@sveltejs/vite-plugin-svelte': 6.2.4(svelte@5.49.2)(vite@7.3.1(@types/node@22.8.6)(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass@1.80.6)(terser@5.36.0)(tsx@4.19.2))
'@types/cookie': 0.6.0
acorn: 8.15.0
cookie: 0.6.0
@@ -3274,7 +3492,7 @@ snapshots:
set-cookie-parser: 3.0.1
sirv: 3.0.2
svelte: 5.49.2
vite: 7.3.1(@types/node@22.8.6)(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass@1.80.6)(terser@5.36.0)(tsx@4.21.0)
vite: 7.3.1(@types/node@22.8.6)(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass@1.80.6)(terser@5.36.0)(tsx@4.19.2)
optionalDependencies:
typescript: 5.9.3
@@ -3289,22 +3507,22 @@ snapshots:
transitivePeerDependencies:
- typescript
'@sveltejs/vite-plugin-svelte-inspector@5.0.2(@sveltejs/vite-plugin-svelte@6.2.4(svelte@5.49.2)(vite@7.3.1(@types/node@22.8.6)(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass@1.80.6)(terser@5.36.0)(tsx@4.21.0)))(svelte@5.49.2)(vite@7.3.1(@types/node@22.8.6)(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass@1.80.6)(terser@5.36.0)(tsx@4.21.0))':
'@sveltejs/vite-plugin-svelte-inspector@5.0.2(@sveltejs/vite-plugin-svelte@6.2.4(svelte@5.49.2)(vite@7.3.1(@types/node@22.8.6)(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass@1.80.6)(terser@5.36.0)(tsx@4.19.2)))(svelte@5.49.2)(vite@7.3.1(@types/node@22.8.6)(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass@1.80.6)(terser@5.36.0)(tsx@4.19.2))':
dependencies:
'@sveltejs/vite-plugin-svelte': 6.2.4(svelte@5.49.2)(vite@7.3.1(@types/node@22.8.6)(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass@1.80.6)(terser@5.36.0)(tsx@4.21.0))
'@sveltejs/vite-plugin-svelte': 6.2.4(svelte@5.49.2)(vite@7.3.1(@types/node@22.8.6)(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass@1.80.6)(terser@5.36.0)(tsx@4.19.2))
obug: 2.1.1
svelte: 5.49.2
vite: 7.3.1(@types/node@22.8.6)(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass@1.80.6)(terser@5.36.0)(tsx@4.21.0)
vite: 7.3.1(@types/node@22.8.6)(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass@1.80.6)(terser@5.36.0)(tsx@4.19.2)
'@sveltejs/vite-plugin-svelte@6.2.4(svelte@5.49.2)(vite@7.3.1(@types/node@22.8.6)(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass@1.80.6)(terser@5.36.0)(tsx@4.21.0))':
'@sveltejs/vite-plugin-svelte@6.2.4(svelte@5.49.2)(vite@7.3.1(@types/node@22.8.6)(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass@1.80.6)(terser@5.36.0)(tsx@4.19.2))':
dependencies:
'@sveltejs/vite-plugin-svelte-inspector': 5.0.2(@sveltejs/vite-plugin-svelte@6.2.4(svelte@5.49.2)(vite@7.3.1(@types/node@22.8.6)(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass@1.80.6)(terser@5.36.0)(tsx@4.21.0)))(svelte@5.49.2)(vite@7.3.1(@types/node@22.8.6)(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass@1.80.6)(terser@5.36.0)(tsx@4.21.0))
'@sveltejs/vite-plugin-svelte-inspector': 5.0.2(@sveltejs/vite-plugin-svelte@6.2.4(svelte@5.49.2)(vite@7.3.1(@types/node@22.8.6)(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass@1.80.6)(terser@5.36.0)(tsx@4.19.2)))(svelte@5.49.2)(vite@7.3.1(@types/node@22.8.6)(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass@1.80.6)(terser@5.36.0)(tsx@4.19.2))
deepmerge: 4.3.1
magic-string: 0.30.21
obug: 2.1.1
svelte: 5.49.2
vite: 7.3.1(@types/node@22.8.6)(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass@1.80.6)(terser@5.36.0)(tsx@4.21.0)
vitefu: 1.1.1(vite@7.3.1(@types/node@22.8.6)(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass@1.80.6)(terser@5.36.0)(tsx@4.21.0))
vite: 7.3.1(@types/node@22.8.6)(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass@1.80.6)(terser@5.36.0)(tsx@4.19.2)
vitefu: 1.1.1(vite@7.3.1(@types/node@22.8.6)(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass@1.80.6)(terser@5.36.0)(tsx@4.19.2))
'@tailwindcss/node@4.1.18':
dependencies:
@@ -3367,12 +3585,12 @@ snapshots:
'@tailwindcss/oxide-win32-arm64-msvc': 4.1.18
'@tailwindcss/oxide-win32-x64-msvc': 4.1.18
'@tailwindcss/vite@4.1.18(vite@7.3.1(@types/node@22.8.6)(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass@1.80.6)(terser@5.36.0)(tsx@4.21.0))':
'@tailwindcss/vite@4.1.18(vite@7.3.1(@types/node@22.8.6)(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass@1.80.6)(terser@5.36.0)(tsx@4.19.2))':
dependencies:
'@tailwindcss/node': 4.1.18
'@tailwindcss/oxide': 4.1.18
tailwindcss: 4.1.18
vite: 7.3.1(@types/node@22.8.6)(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass@1.80.6)(terser@5.36.0)(tsx@4.21.0)
vite: 7.3.1(@types/node@22.8.6)(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass@1.80.6)(terser@5.36.0)(tsx@4.19.2)
'@testing-library/dom@10.4.1':
dependencies:
@@ -3389,14 +3607,14 @@ snapshots:
dependencies:
svelte: 5.49.2
'@testing-library/svelte@5.3.1(svelte@5.49.2)(vite@7.3.1(@types/node@22.8.6)(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass@1.80.6)(terser@5.36.0)(tsx@4.21.0))(vitest@4.0.18)':
'@testing-library/svelte@5.3.1(svelte@5.49.2)(vite@7.3.1(@types/node@22.8.6)(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass@1.80.6)(terser@5.36.0)(tsx@4.19.2))(vitest@4.0.18)':
dependencies:
'@testing-library/dom': 10.4.1
'@testing-library/svelte-core': 1.0.0(svelte@5.49.2)
svelte: 5.49.2
optionalDependencies:
vite: 7.3.1(@types/node@22.8.6)(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass@1.80.6)(terser@5.36.0)(tsx@4.21.0)
vitest: 4.0.18(@types/node@22.8.6)(@vitest/browser-playwright@4.0.18)(jiti@2.6.1)(jsdom@25.0.1)(less@4.2.0)(lightningcss@1.30.2)(sass@1.80.6)(terser@5.36.0)(tsx@4.21.0)
vite: 7.3.1(@types/node@22.8.6)(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass@1.80.6)(terser@5.36.0)(tsx@4.19.2)
vitest: 4.0.18(@types/node@22.8.6)(@vitest/browser-playwright@4.0.18)(jiti@2.6.1)(jsdom@25.0.1)(less@4.2.0)(lightningcss@1.30.2)(sass@1.80.6)(terser@5.36.0)(tsx@4.19.2)
'@threejs-kit/instanced-sprite-mesh@2.5.1(@types/three@0.182.0)(three@0.182.0)':
dependencies:
@@ -3582,26 +3800,26 @@ snapshots:
'@typescript-eslint/types': 8.54.0
eslint-visitor-keys: 4.2.1
'@vitest/browser-playwright@4.0.18(playwright@1.58.1)(vite@7.3.1(@types/node@22.8.6)(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass@1.80.6)(terser@5.36.0)(tsx@4.21.0))(vitest@4.0.18)':
'@vitest/browser-playwright@4.0.18(playwright@1.58.1)(vite@7.3.1(@types/node@22.8.6)(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass@1.80.6)(terser@5.36.0)(tsx@4.19.2))(vitest@4.0.18)':
dependencies:
'@vitest/browser': 4.0.18(vite@7.3.1(@types/node@22.8.6)(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass@1.80.6)(terser@5.36.0)(tsx@4.21.0))(vitest@4.0.18)
'@vitest/mocker': 4.0.18(vite@7.3.1(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass@1.80.6)(terser@5.36.0)(tsx@4.21.0))
'@vitest/browser': 4.0.18(vite@7.3.1(@types/node@22.8.6)(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass@1.80.6)(terser@5.36.0)(tsx@4.19.2))(vitest@4.0.18)
'@vitest/mocker': 4.0.18(vite@7.3.1(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass@1.80.6)(terser@5.36.0)(tsx@4.19.2))
playwright: 1.58.1
tinyrainbow: 3.0.3
vitest: 4.0.18(@types/node@22.8.6)(@vitest/browser-playwright@4.0.18)(jiti@2.6.1)(jsdom@25.0.1)(less@4.2.0)(lightningcss@1.30.2)(sass@1.80.6)(terser@5.36.0)(tsx@4.21.0)
vitest: 4.0.18(@types/node@22.8.6)(@vitest/browser-playwright@4.0.18)(jiti@2.6.1)(jsdom@25.0.1)(less@4.2.0)(lightningcss@1.30.2)(sass@1.80.6)(terser@5.36.0)(tsx@4.19.2)
transitivePeerDependencies:
- bufferutil
- msw
- utf-8-validate
- vite
'@vitest/browser-playwright@4.0.18(playwright@1.58.1)(vite@7.3.1(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass@1.80.6)(terser@5.36.0)(tsx@4.21.0))(vitest@4.0.18)':
'@vitest/browser-playwright@4.0.18(playwright@1.58.1)(vite@7.3.1(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass@1.80.6)(terser@5.36.0)(tsx@4.19.2))(vitest@4.0.18)':
dependencies:
'@vitest/browser': 4.0.18(vite@7.3.1(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass@1.80.6)(terser@5.36.0)(tsx@4.21.0))(vitest@4.0.18)
'@vitest/mocker': 4.0.18(vite@7.3.1(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass@1.80.6)(terser@5.36.0)(tsx@4.21.0))
'@vitest/browser': 4.0.18(vite@7.3.1(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass@1.80.6)(terser@5.36.0)(tsx@4.19.2))(vitest@4.0.18)
'@vitest/mocker': 4.0.18(vite@7.3.1(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass@1.80.6)(terser@5.36.0)(tsx@4.19.2))
playwright: 1.58.1
tinyrainbow: 3.0.3
vitest: 4.0.18(@vitest/browser-playwright@4.0.18)(jiti@2.6.1)(jsdom@25.0.1)(less@4.2.0)(lightningcss@1.30.2)(sass@1.80.6)(terser@5.36.0)(tsx@4.21.0)
vitest: 4.0.18(@vitest/browser-playwright@4.0.18)(jiti@2.6.1)(jsdom@25.0.1)(less@4.2.0)(lightningcss@1.30.2)(sass@1.80.6)(terser@5.36.0)(tsx@4.19.2)
transitivePeerDependencies:
- bufferutil
- msw
@@ -3609,16 +3827,16 @@ snapshots:
- vite
optional: true
'@vitest/browser@4.0.18(vite@7.3.1(@types/node@22.8.6)(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass@1.80.6)(terser@5.36.0)(tsx@4.21.0))(vitest@4.0.18)':
'@vitest/browser@4.0.18(vite@7.3.1(@types/node@22.8.6)(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass@1.80.6)(terser@5.36.0)(tsx@4.19.2))(vitest@4.0.18)':
dependencies:
'@vitest/mocker': 4.0.18(vite@7.3.1(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass@1.80.6)(terser@5.36.0)(tsx@4.21.0))
'@vitest/mocker': 4.0.18(vite@7.3.1(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass@1.80.6)(terser@5.36.0)(tsx@4.19.2))
'@vitest/utils': 4.0.18
magic-string: 0.30.21
pixelmatch: 7.1.0
pngjs: 7.0.0
sirv: 3.0.2
tinyrainbow: 3.0.3
vitest: 4.0.18(@types/node@22.8.6)(@vitest/browser-playwright@4.0.18)(jiti@2.6.1)(jsdom@25.0.1)(less@4.2.0)(lightningcss@1.30.2)(sass@1.80.6)(terser@5.36.0)(tsx@4.21.0)
vitest: 4.0.18(@types/node@22.8.6)(@vitest/browser-playwright@4.0.18)(jiti@2.6.1)(jsdom@25.0.1)(less@4.2.0)(lightningcss@1.30.2)(sass@1.80.6)(terser@5.36.0)(tsx@4.19.2)
ws: 8.19.0
transitivePeerDependencies:
- bufferutil
@@ -3626,16 +3844,16 @@ snapshots:
- utf-8-validate
- vite
'@vitest/browser@4.0.18(vite@7.3.1(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass@1.80.6)(terser@5.36.0)(tsx@4.21.0))(vitest@4.0.18)':
'@vitest/browser@4.0.18(vite@7.3.1(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass@1.80.6)(terser@5.36.0)(tsx@4.19.2))(vitest@4.0.18)':
dependencies:
'@vitest/mocker': 4.0.18(vite@7.3.1(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass@1.80.6)(terser@5.36.0)(tsx@4.21.0))
'@vitest/mocker': 4.0.18(vite@7.3.1(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass@1.80.6)(terser@5.36.0)(tsx@4.19.2))
'@vitest/utils': 4.0.18
magic-string: 0.30.21
pixelmatch: 7.1.0
pngjs: 7.0.0
sirv: 3.0.2
tinyrainbow: 3.0.3
vitest: 4.0.18(@vitest/browser-playwright@4.0.18)(jiti@2.6.1)(jsdom@25.0.1)(less@4.2.0)(lightningcss@1.30.2)(sass@1.80.6)(terser@5.36.0)(tsx@4.21.0)
vitest: 4.0.18(@vitest/browser-playwright@4.0.18)(jiti@2.6.1)(jsdom@25.0.1)(less@4.2.0)(lightningcss@1.30.2)(sass@1.80.6)(terser@5.36.0)(tsx@4.19.2)
ws: 8.19.0
transitivePeerDependencies:
- bufferutil
@@ -3653,13 +3871,13 @@ snapshots:
chai: 6.2.2
tinyrainbow: 3.0.3
'@vitest/mocker@4.0.18(vite@7.3.1(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass@1.80.6)(terser@5.36.0)(tsx@4.21.0))':
'@vitest/mocker@4.0.18(vite@7.3.1(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass@1.80.6)(terser@5.36.0)(tsx@4.19.2))':
dependencies:
'@vitest/spy': 4.0.18
estree-walker: 3.0.3
magic-string: 0.30.21
optionalDependencies:
vite: 7.3.1(@types/node@22.8.6)(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass@1.80.6)(terser@5.36.0)(tsx@4.21.0)
vite: 7.3.1(@types/node@22.8.6)(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass@1.80.6)(terser@5.36.0)(tsx@4.19.2)
'@vitest/pretty-format@4.0.18':
dependencies:
@@ -4015,6 +4233,34 @@ snapshots:
hasown: 2.0.2
optional: true
esbuild@0.23.1:
optionalDependencies:
'@esbuild/aix-ppc64': 0.23.1
'@esbuild/android-arm': 0.23.1
'@esbuild/android-arm64': 0.23.1
'@esbuild/android-x64': 0.23.1
'@esbuild/darwin-arm64': 0.23.1
'@esbuild/darwin-x64': 0.23.1
'@esbuild/freebsd-arm64': 0.23.1
'@esbuild/freebsd-x64': 0.23.1
'@esbuild/linux-arm': 0.23.1
'@esbuild/linux-arm64': 0.23.1
'@esbuild/linux-ia32': 0.23.1
'@esbuild/linux-loong64': 0.23.1
'@esbuild/linux-mips64el': 0.23.1
'@esbuild/linux-ppc64': 0.23.1
'@esbuild/linux-riscv64': 0.23.1
'@esbuild/linux-s390x': 0.23.1
'@esbuild/linux-x64': 0.23.1
'@esbuild/netbsd-x64': 0.23.1
'@esbuild/openbsd-arm64': 0.23.1
'@esbuild/openbsd-x64': 0.23.1
'@esbuild/sunos-x64': 0.23.1
'@esbuild/win32-arm64': 0.23.1
'@esbuild/win32-ia32': 0.23.1
'@esbuild/win32-x64': 0.23.1
optional: true
esbuild@0.27.3:
optionalDependencies:
'@esbuild/aix-ppc64': 0.27.3
@@ -4228,6 +4474,7 @@ snapshots:
get-tsconfig@4.13.6:
dependencies:
resolve-pkg-maps: 1.0.0
optional: true
glob-parent@5.1.2:
dependencies:
@@ -4821,7 +5068,8 @@ snapshots:
resolve-from@4.0.0: {}
resolve-pkg-maps@1.0.0: {}
resolve-pkg-maps@1.0.0:
optional: true
rollup@4.57.1:
dependencies:
@@ -5107,12 +5355,13 @@ snapshots:
tslib@2.8.1: {}
tsx@4.21.0:
tsx@4.19.2:
dependencies:
esbuild: 0.27.3
esbuild: 0.23.1
get-tsconfig: 4.13.6
optionalDependencies:
fsevents: 2.3.3
optional: true
tweakpane@3.1.10: {}
@@ -5147,26 +5396,26 @@ snapshots:
v8-compile-cache-lib@3.0.1:
optional: true
vite-plugin-comlink@5.3.0(comlink@4.4.2)(vite@7.3.1(@types/node@22.8.6)(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass@1.80.6)(terser@5.36.0)(tsx@4.21.0)):
vite-plugin-comlink@5.3.0(comlink@4.4.2)(vite@7.3.1(@types/node@22.8.6)(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass@1.80.6)(terser@5.36.0)(tsx@4.19.2)):
dependencies:
comlink: 4.4.2
json5: 2.2.3
magic-string: 0.30.17
source-map: 0.7.6
vite: 7.3.1(@types/node@22.8.6)(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass@1.80.6)(terser@5.36.0)(tsx@4.21.0)
vite: 7.3.1(@types/node@22.8.6)(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass@1.80.6)(terser@5.36.0)(tsx@4.19.2)
vite-plugin-glsl@1.5.5(@rollup/pluginutils@5.1.4(rollup@4.57.1))(esbuild@0.27.3)(vite@7.3.1(@types/node@22.8.6)(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass@1.80.6)(terser@5.36.0)(tsx@4.21.0)):
vite-plugin-glsl@1.5.5(@rollup/pluginutils@5.1.4(rollup@4.57.1))(esbuild@0.27.3)(vite@7.3.1(@types/node@22.8.6)(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass@1.80.6)(terser@5.36.0)(tsx@4.19.2)):
dependencies:
vite: 7.3.1(@types/node@22.8.6)(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass@1.80.6)(terser@5.36.0)(tsx@4.21.0)
vite: 7.3.1(@types/node@22.8.6)(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass@1.80.6)(terser@5.36.0)(tsx@4.19.2)
optionalDependencies:
'@rollup/pluginutils': 5.1.4(rollup@4.57.1)
esbuild: 0.27.3
vite-plugin-wasm@3.5.0(vite@7.3.1(@types/node@22.8.6)(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass@1.80.6)(terser@5.36.0)(tsx@4.21.0)):
vite-plugin-wasm@3.5.0(vite@7.3.1(@types/node@22.8.6)(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass@1.80.6)(terser@5.36.0)(tsx@4.19.2)):
dependencies:
vite: 7.3.1(@types/node@22.8.6)(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass@1.80.6)(terser@5.36.0)(tsx@4.21.0)
vite: 7.3.1(@types/node@22.8.6)(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass@1.80.6)(terser@5.36.0)(tsx@4.19.2)
vite@7.3.1(@types/node@22.8.6)(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass@1.80.6)(terser@5.36.0)(tsx@4.21.0):
vite@7.3.1(@types/node@22.8.6)(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass@1.80.6)(terser@5.36.0)(tsx@4.19.2):
dependencies:
esbuild: 0.27.3
fdir: 6.5.0(picomatch@4.0.3)
@@ -5182,22 +5431,22 @@ snapshots:
lightningcss: 1.30.2
sass: 1.80.6
terser: 5.36.0
tsx: 4.21.0
tsx: 4.19.2
vitefu@1.1.1(vite@7.3.1(@types/node@22.8.6)(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass@1.80.6)(terser@5.36.0)(tsx@4.21.0)):
vitefu@1.1.1(vite@7.3.1(@types/node@22.8.6)(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass@1.80.6)(terser@5.36.0)(tsx@4.19.2)):
optionalDependencies:
vite: 7.3.1(@types/node@22.8.6)(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass@1.80.6)(terser@5.36.0)(tsx@4.21.0)
vite: 7.3.1(@types/node@22.8.6)(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass@1.80.6)(terser@5.36.0)(tsx@4.19.2)
vitest-browser-svelte@2.0.2(svelte@5.49.2)(vitest@4.0.18):
dependencies:
'@testing-library/svelte-core': 1.0.0(svelte@5.49.2)
svelte: 5.49.2
vitest: 4.0.18(@types/node@22.8.6)(@vitest/browser-playwright@4.0.18)(jiti@2.6.1)(jsdom@25.0.1)(less@4.2.0)(lightningcss@1.30.2)(sass@1.80.6)(terser@5.36.0)(tsx@4.21.0)
vitest: 4.0.18(@types/node@22.8.6)(@vitest/browser-playwright@4.0.18)(jiti@2.6.1)(jsdom@25.0.1)(less@4.2.0)(lightningcss@1.30.2)(sass@1.80.6)(terser@5.36.0)(tsx@4.19.2)
vitest@4.0.18(@types/node@22.8.6)(@vitest/browser-playwright@4.0.18)(jiti@2.6.1)(jsdom@25.0.1)(less@4.2.0)(lightningcss@1.30.2)(sass@1.80.6)(terser@5.36.0)(tsx@4.21.0):
vitest@4.0.18(@types/node@22.8.6)(@vitest/browser-playwright@4.0.18)(jiti@2.6.1)(jsdom@25.0.1)(less@4.2.0)(lightningcss@1.30.2)(sass@1.80.6)(terser@5.36.0)(tsx@4.19.2):
dependencies:
'@vitest/expect': 4.0.18
'@vitest/mocker': 4.0.18(vite@7.3.1(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass@1.80.6)(terser@5.36.0)(tsx@4.21.0))
'@vitest/mocker': 4.0.18(vite@7.3.1(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass@1.80.6)(terser@5.36.0)(tsx@4.19.2))
'@vitest/pretty-format': 4.0.18
'@vitest/runner': 4.0.18
'@vitest/snapshot': 4.0.18
@@ -5214,11 +5463,11 @@ snapshots:
tinyexec: 1.0.2
tinyglobby: 0.2.15
tinyrainbow: 3.0.3
vite: 7.3.1(@types/node@22.8.6)(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass@1.80.6)(terser@5.36.0)(tsx@4.21.0)
vite: 7.3.1(@types/node@22.8.6)(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass@1.80.6)(terser@5.36.0)(tsx@4.19.2)
why-is-node-running: 2.3.0
optionalDependencies:
'@types/node': 22.8.6
'@vitest/browser-playwright': 4.0.18(playwright@1.58.1)(vite@7.3.1(@types/node@22.8.6)(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass@1.80.6)(terser@5.36.0)(tsx@4.21.0))(vitest@4.0.18)
'@vitest/browser-playwright': 4.0.18(playwright@1.58.1)(vite@7.3.1(@types/node@22.8.6)(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass@1.80.6)(terser@5.36.0)(tsx@4.19.2))(vitest@4.0.18)
jsdom: 25.0.1
transitivePeerDependencies:
- jiti
@@ -5233,10 +5482,10 @@ snapshots:
- tsx
- yaml
vitest@4.0.18(@vitest/browser-playwright@4.0.18)(jiti@2.6.1)(jsdom@25.0.1)(less@4.2.0)(lightningcss@1.30.2)(sass@1.80.6)(terser@5.36.0)(tsx@4.21.0):
vitest@4.0.18(@vitest/browser-playwright@4.0.18)(jiti@2.6.1)(jsdom@25.0.1)(less@4.2.0)(lightningcss@1.30.2)(sass@1.80.6)(terser@5.36.0)(tsx@4.19.2):
dependencies:
'@vitest/expect': 4.0.18
'@vitest/mocker': 4.0.18(vite@7.3.1(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass@1.80.6)(terser@5.36.0)(tsx@4.21.0))
'@vitest/mocker': 4.0.18(vite@7.3.1(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass@1.80.6)(terser@5.36.0)(tsx@4.19.2))
'@vitest/pretty-format': 4.0.18
'@vitest/runner': 4.0.18
'@vitest/snapshot': 4.0.18
@@ -5253,10 +5502,10 @@ snapshots:
tinyexec: 1.0.2
tinyglobby: 0.2.15
tinyrainbow: 3.0.3
vite: 7.3.1(@types/node@22.8.6)(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass@1.80.6)(terser@5.36.0)(tsx@4.21.0)
vite: 7.3.1(@types/node@22.8.6)(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass@1.80.6)(terser@5.36.0)(tsx@4.19.2)
why-is-node-running: 2.3.0
optionalDependencies:
'@vitest/browser-playwright': 4.0.18(playwright@1.58.1)(vite@7.3.1(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass@1.80.6)(terser@5.36.0)(tsx@4.21.0))(vitest@4.0.18)
'@vitest/browser-playwright': 4.0.18(playwright@1.58.1)(vite@7.3.1(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass@1.80.6)(terser@5.36.0)(tsx@4.19.2))(vitest@4.0.18)
jsdom: 25.0.1
transitivePeerDependencies:
- jiti