blanchon commited on
Commit
31d3580
·
0 Parent(s):

Initial CS2 render dataset viewer

Browse files
This view is limited to 50 files because it contains too many changes.   See raw diff
Files changed (50) hide show
  1. .agents/skills/hf-cli/.hf-skill-manifest.json +4 -0
  2. .agents/skills/hf-cli/SKILL.md +195 -0
  3. .claude/skills/hf-cli +1 -0
  4. .claude/skills/huggingface-doc/SKILL.md +6 -0
  5. .gitattributes +36 -0
  6. .gitignore +25 -0
  7. .npmrc +1 -0
  8. .vscode/extensions.json +6 -0
  9. .vscode/settings.json +5 -0
  10. README.md +41 -0
  11. components.json +20 -0
  12. package.json +48 -0
  13. pnpm-lock.yaml +2444 -0
  14. pnpm-workspace.yaml +3 -0
  15. src/app.d.ts +13 -0
  16. src/app.html +12 -0
  17. src/lib/api/hf.ts +136 -0
  18. src/lib/api/hub.ts +21 -0
  19. src/lib/api/parquet.ts +55 -0
  20. src/lib/api/world.ts +232 -0
  21. src/lib/assets/favicon.svg +1 -0
  22. src/lib/components/grid-tile.svelte +187 -0
  23. src/lib/components/header.svelte +80 -0
  24. src/lib/components/hf-logo.svelte +28 -0
  25. src/lib/components/map-preview.svelte +179 -0
  26. src/lib/components/match-card.svelte +87 -0
  27. src/lib/components/match-info.svelte +103 -0
  28. src/lib/components/match-map.svelte +74 -0
  29. src/lib/components/perspective-grid.svelte +190 -0
  30. src/lib/components/player-grid.svelte +158 -0
  31. src/lib/components/round-list.svelte +66 -0
  32. src/lib/components/timeline-bar.svelte +86 -0
  33. src/lib/components/ui/accordion/accordion-content.svelte +27 -0
  34. src/lib/components/ui/accordion/accordion-item.svelte +17 -0
  35. src/lib/components/ui/accordion/accordion-trigger.svelte +32 -0
  36. src/lib/components/ui/accordion/accordion.svelte +19 -0
  37. src/lib/components/ui/accordion/index.ts +16 -0
  38. src/lib/components/ui/alert-dialog/alert-dialog-action.svelte +27 -0
  39. src/lib/components/ui/alert-dialog/alert-dialog-cancel.svelte +27 -0
  40. src/lib/components/ui/alert-dialog/alert-dialog-content.svelte +32 -0
  41. src/lib/components/ui/alert-dialog/alert-dialog-description.svelte +17 -0
  42. src/lib/components/ui/alert-dialog/alert-dialog-footer.svelte +23 -0
  43. src/lib/components/ui/alert-dialog/alert-dialog-header.svelte +20 -0
  44. src/lib/components/ui/alert-dialog/alert-dialog-media.svelte +20 -0
  45. src/lib/components/ui/alert-dialog/alert-dialog-overlay.svelte +17 -0
  46. src/lib/components/ui/alert-dialog/alert-dialog-portal.svelte +7 -0
  47. src/lib/components/ui/alert-dialog/alert-dialog-title.svelte +17 -0
  48. src/lib/components/ui/alert-dialog/alert-dialog-trigger.svelte +7 -0
  49. src/lib/components/ui/alert-dialog/alert-dialog.svelte +7 -0
  50. src/lib/components/ui/alert-dialog/index.ts +40 -0
.agents/skills/hf-cli/.hf-skill-manifest.json ADDED
@@ -0,0 +1,4 @@
 
 
 
 
 
1
+ {
2
+ "installed_revision": "377a0d3f596ece474d3c5082dd4057219cc726dc",
3
+ "schema_version": 1
4
+ }
.agents/skills/hf-cli/SKILL.md ADDED
@@ -0,0 +1,195 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ name: hf-cli
3
+ description: "Hugging Face Hub CLI (`hf`) for downloading, uploading, and managing models, datasets, spaces, buckets, repos, papers, jobs, and more on the Hugging Face Hub. Use when: handling authentication; managing local cache; managing Hugging Face Buckets; running or scheduling jobs on Hugging Face infrastructure; managing Hugging Face repos; discussions and pull requests; browsing models, datasets and spaces; reading, searching, or browsing academic papers; managing collections; querying datasets; configuring spaces; setting up webhooks; or deploying and managing HF Inference Endpoints. Make sure to use this skill whenever the user mentions 'hf', 'huggingface', 'Hugging Face', 'huggingface-cli', or 'hugging face cli', or wants to do anything related to the Hugging Face ecosystem and to AI and ML in general. Also use for cloud storage needs like training checkpoints, data pipelines, or agent traces. Use even if the user doesn't explicitly ask for a CLI command. Replaces the deprecated `huggingface-cli`."
4
+ ---
5
+
6
+ Install: `curl -LsSf https://hf.co/cli/install.sh | bash -s`.
7
+
8
+ The Hugging Face Hub CLI tool `hf` is available. IMPORTANT: The `hf` command replaces the deprecated `huggingface-cli` command.
9
+
10
+ Use `hf --help` to view available functions. Note that auth commands are now all under `hf auth` e.g. `hf auth whoami`.
11
+
12
+ Generated with `huggingface_hub v1.12.0`. Run `hf skills add --force` to regenerate.
13
+
14
+ ## Commands
15
+
16
+ - `hf download REPO_ID` — Download files from the Hub. `[--type CHOICE --revision TEXT --include TEXT --exclude TEXT --cache-dir TEXT --local-dir TEXT --force-download --dry-run --max-workers INTEGER --format CHOICE]`
17
+ - `hf env` — Print information about the environment.
18
+ - `hf sync` — Sync files between local directory and a bucket. `[--delete --ignore-times --ignore-sizes --plan TEXT --apply TEXT --dry-run --include TEXT --exclude TEXT --filter-from TEXT --existing --ignore-existing --verbose --quiet]`
19
+ - `hf upload REPO_ID` — Upload a file or a folder to the Hub. Recommended for single-commit uploads. `[--type CHOICE --revision TEXT --private --include TEXT --exclude TEXT --delete TEXT --commit-message TEXT --commit-description TEXT --create-pr --every FLOAT --format CHOICE]`
20
+ - `hf upload-large-folder REPO_ID LOCAL_PATH` — Upload a large folder to the Hub. Recommended for resumable uploads. `[--type CHOICE --revision TEXT --private --include TEXT --exclude TEXT --num-workers INTEGER --no-report --no-bars --format CHOICE]`
21
+ - `hf version` — Print information about the hf version.
22
+
23
+ ### `hf auth` — Manage authentication (login, logout, etc.).
24
+
25
+ - `hf auth list` — List all stored access tokens.
26
+ - `hf auth login` — Login using a token from huggingface.co/settings/tokens. `[--add-to-git-credential --force]`
27
+ - `hf auth logout` — Logout from a specific token. `[--token-name TEXT]`
28
+ - `hf auth switch` — Switch between access tokens. `[--token-name TEXT --add-to-git-credential]`
29
+ - `hf auth token` — Print the current access token to stdout.
30
+ - `hf auth whoami` — Find out which huggingface.co account you are logged in as. `[--format CHOICE]`
31
+
32
+ ### `hf buckets` — Commands to interact with buckets.
33
+
34
+ - `hf buckets cp SRC` — Copy files to or from buckets. `[--format CHOICE]`
35
+ - `hf buckets create BUCKET_ID` — Create a new bucket. `[--private --exist-ok --format CHOICE]`
36
+ - `hf buckets delete BUCKET_ID` — Delete a bucket. `[--yes --missing-ok --format CHOICE]`
37
+ - `hf buckets info BUCKET_ID` — Get info about a bucket. `[--format CHOICE]`
38
+ - `hf buckets list` — List buckets or files in a bucket. `[--human-readable --tree --recursive --search TEXT --format CHOICE]`
39
+ - `hf buckets move FROM_ID TO_ID` — Move (rename) a bucket to a new name or namespace. `[--format CHOICE]`
40
+ - `hf buckets remove ARGUMENT` — Remove files from a bucket. `[--recursive --yes --dry-run --include TEXT --exclude TEXT --format CHOICE]`
41
+ - `hf buckets sync` — Sync files between local directory and a bucket. `[--delete --ignore-times --ignore-sizes --plan TEXT --apply TEXT --dry-run --include TEXT --exclude TEXT --filter-from TEXT --existing --ignore-existing --verbose --quiet]`
42
+
43
+ ### `hf cache` — Manage local cache directory.
44
+
45
+ - `hf cache list` — List cached repositories or revisions. `[--cache-dir TEXT --revisions --filter TEXT --format CHOICE --sort CHOICE --limit INTEGER]`
46
+ - `hf cache prune` — Remove detached revisions from the cache. `[--cache-dir TEXT --yes --dry-run --format CHOICE]`
47
+ - `hf cache rm TARGETS` — Remove cached repositories or revisions. `[--cache-dir TEXT --yes --dry-run --format CHOICE]`
48
+ - `hf cache verify REPO_ID` — Verify checksums for a single repo revision from cache or a local directory. `[--type CHOICE --revision TEXT --cache-dir TEXT --local-dir TEXT --fail-on-missing-files --fail-on-extra-files --format CHOICE]`
49
+
50
+ ### `hf collections` — Interact with collections on the Hub.
51
+
52
+ - `hf collections add-item COLLECTION_SLUG ITEM_ID ITEM_TYPE` — Add an item to a collection. `[--note TEXT --exists-ok --format CHOICE]`
53
+ - `hf collections create TITLE` — Create a new collection on the Hub. `[--namespace TEXT --description TEXT --private --exists-ok --format CHOICE]`
54
+ - `hf collections delete COLLECTION_SLUG` — Delete a collection from the Hub. `[--missing-ok --format CHOICE]`
55
+ - `hf collections delete-item COLLECTION_SLUG ITEM_OBJECT_ID` — Delete an item from a collection. `[--missing-ok --format CHOICE]`
56
+ - `hf collections info COLLECTION_SLUG` — Get info about a collection on the Hub. `[--format CHOICE]`
57
+ - `hf collections list` — List collections on the Hub. `[--owner TEXT --item TEXT --sort CHOICE --limit INTEGER --format CHOICE]`
58
+ - `hf collections update COLLECTION_SLUG` — Update a collection's metadata on the Hub. `[--title TEXT --description TEXT --position INTEGER --private --theme TEXT --format CHOICE]`
59
+ - `hf collections update-item COLLECTION_SLUG ITEM_OBJECT_ID` — Update an item in a collection. `[--note TEXT --position INTEGER --format CHOICE]`
60
+
61
+ ### `hf datasets` — Interact with datasets on the Hub.
62
+
63
+ - `hf datasets info DATASET_ID` — Get info about a dataset on the Hub. `[--revision TEXT --expand TEXT --format CHOICE]`
64
+ - `hf datasets list` — List datasets on the Hub. `[--search TEXT --author TEXT --filter TEXT --sort CHOICE --limit INTEGER --expand TEXT --format CHOICE]`
65
+ - `hf datasets parquet DATASET_ID` — List parquet file URLs available for a dataset. `[--subset TEXT --split TEXT --format CHOICE]`
66
+ - `hf datasets sql SQL` — Execute a raw SQL query with DuckDB against dataset parquet URLs. `[--format CHOICE]`
67
+
68
+ ### `hf discussions` — Manage discussions and pull requests on the Hub.
69
+
70
+ - `hf discussions close REPO_ID NUM` — Close a discussion or pull request. `[--comment TEXT --yes --type CHOICE --format CHOICE]`
71
+ - `hf discussions comment REPO_ID NUM` — Comment on a discussion or pull request. `[--body TEXT --body-file PATH --type CHOICE --format CHOICE]`
72
+ - `hf discussions create REPO_ID --title TEXT` — Create a new discussion or pull request on a repo. `[--body TEXT --body-file PATH --pull-request --type CHOICE --format CHOICE]`
73
+ - `hf discussions diff REPO_ID NUM` — Show the diff of a pull request. `[--type CHOICE --format CHOICE]`
74
+ - `hf discussions info REPO_ID NUM` — Get info about a discussion or pull request. `[--type CHOICE --format CHOICE]`
75
+ - `hf discussions list REPO_ID` — List discussions and pull requests on a repo. `[--status CHOICE --kind CHOICE --author TEXT --limit INTEGER --type CHOICE --format CHOICE]`
76
+ - `hf discussions merge REPO_ID NUM` — Merge a pull request. `[--comment TEXT --yes --type CHOICE --format CHOICE]`
77
+ - `hf discussions rename REPO_ID NUM NEW_TITLE` — Rename a discussion or pull request. `[--type CHOICE --format CHOICE]`
78
+ - `hf discussions reopen REPO_ID NUM` — Reopen a closed discussion or pull request. `[--comment TEXT --yes --type CHOICE --format CHOICE]`
79
+
80
+ ### `hf endpoints` — Manage Hugging Face Inference Endpoints.
81
+
82
+ - `hf endpoints catalog deploy --repo TEXT` — Deploy an Inference Endpoint from the Model Catalog. `[--name TEXT --accelerator TEXT --namespace TEXT --format CHOICE]`
83
+ - `hf endpoints catalog list` — List available Catalog models. `[--format CHOICE]`
84
+ - `hf endpoints delete NAME` — Delete an Inference Endpoint permanently. `[--namespace TEXT --yes --format CHOICE]`
85
+ - `hf endpoints deploy NAME --repo TEXT --framework TEXT --accelerator TEXT --instance-size TEXT --instance-type TEXT --region TEXT --vendor TEXT` — Deploy an Inference Endpoint from a Hub repository. `[--namespace TEXT --task TEXT --format CHOICE --min-replica INTEGER --max-replica INTEGER --scale-to-zero-timeout INTEGER --scaling-metric CHOICE --scaling-threshold FLOAT]`
86
+ - `hf endpoints describe NAME` — Get information about an existing endpoint. `[--namespace TEXT --format CHOICE]`
87
+ - `hf endpoints list` — Lists all Inference Endpoints for the given namespace. `[--namespace TEXT --format CHOICE]`
88
+ - `hf endpoints pause NAME` — Pause an Inference Endpoint. `[--namespace TEXT --format CHOICE]`
89
+ - `hf endpoints resume NAME` — Resume an Inference Endpoint. `[--namespace TEXT --fail-if-already-running --format CHOICE]`
90
+ - `hf endpoints scale-to-zero NAME` — Scale an Inference Endpoint to zero. `[--namespace TEXT --format CHOICE]`
91
+ - `hf endpoints update NAME` — Update an existing endpoint. `[--namespace TEXT --repo TEXT --accelerator TEXT --instance-size TEXT --instance-type TEXT --framework TEXT --revision TEXT --task TEXT --min-replica INTEGER --max-replica INTEGER --scale-to-zero-timeout INTEGER --scaling-metric CHOICE --scaling-threshold FLOAT --format CHOICE]`
92
+
93
+ ### `hf extensions` — Manage hf CLI extensions.
94
+
95
+ - `hf extensions exec NAME` — Execute an installed extension.
96
+ - `hf extensions install REPO_ID` — Install an extension from a public GitHub repository. `[--force]`
97
+ - `hf extensions list` — List installed extension commands. `[--format CHOICE]`
98
+ - `hf extensions remove NAME` — Remove an installed extension.
99
+ - `hf extensions search` — Search extensions available on GitHub (tagged with 'hf-extension' topic). `[--format CHOICE]`
100
+
101
+ ### `hf jobs` — Run and manage Jobs on the Hub.
102
+
103
+ - `hf jobs cancel JOB_ID` — Cancel a Job `[--namespace TEXT]`
104
+ - `hf jobs hardware` — List available hardware options for Jobs
105
+ - `hf jobs inspect JOB_IDS` — Display detailed information on one or more Jobs `[--namespace TEXT]`
106
+ - `hf jobs logs JOB_ID` — Fetch the logs of a Job. `[--follow --tail INTEGER --namespace TEXT]`
107
+ - `hf jobs ps` — List Jobs. `[--all --namespace TEXT --filter TEXT --format TEXT --quiet]`
108
+ - `hf jobs run IMAGE COMMAND` — Run a Job. `[--env TEXT --secrets TEXT --label TEXT --volume TEXT --env-file TEXT --secrets-file TEXT --flavor CHOICE --timeout TEXT --detach --namespace TEXT]`
109
+ - `hf jobs scheduled delete SCHEDULED_JOB_ID` — Delete a scheduled Job. `[--namespace TEXT]`
110
+ - `hf jobs scheduled inspect SCHEDULED_JOB_IDS` — Display detailed information on one or more scheduled Jobs `[--namespace TEXT]`
111
+ - `hf jobs scheduled ps` — List scheduled Jobs `[--all --namespace TEXT --filter TEXT --format TEXT --quiet]`
112
+ - `hf jobs scheduled resume SCHEDULED_JOB_ID` — Resume (unpause) a scheduled Job. `[--namespace TEXT]`
113
+ - `hf jobs scheduled run SCHEDULE IMAGE COMMAND` — Schedule a Job. `[--suspend --concurrency --env TEXT --secrets TEXT --label TEXT --volume TEXT --env-file TEXT --secrets-file TEXT --flavor CHOICE --timeout TEXT --namespace TEXT]`
114
+ - `hf jobs scheduled suspend SCHEDULED_JOB_ID` — Suspend (pause) a scheduled Job. `[--namespace TEXT]`
115
+ - `hf jobs scheduled uv run SCHEDULE SCRIPT` — Run a UV script (local file or URL) on HF infrastructure `[--suspend --concurrency --image TEXT --flavor CHOICE --env TEXT --secrets TEXT --label TEXT --volume TEXT --env-file TEXT --secrets-file TEXT --timeout TEXT --namespace TEXT --with TEXT --python TEXT]`
116
+ - `hf jobs stats` — Fetch the resource usage statistics and metrics of Jobs `[--namespace TEXT]`
117
+ - `hf jobs uv run SCRIPT` — Run a UV script (local file or URL) on HF infrastructure `[--image TEXT --flavor CHOICE --env TEXT --secrets TEXT --label TEXT --volume TEXT --env-file TEXT --secrets-file TEXT --timeout TEXT --detach --namespace TEXT --with TEXT --python TEXT]`
118
+
119
+ ### `hf models` — Interact with models on the Hub.
120
+
121
+ - `hf models info MODEL_ID` — Get info about a model on the Hub. `[--revision TEXT --expand TEXT --format CHOICE]`
122
+ - `hf models list` — List models on the Hub. `[--search TEXT --author TEXT --filter TEXT --num-parameters TEXT --sort CHOICE --limit INTEGER --expand TEXT --format CHOICE]`
123
+
124
+ ### `hf papers` — Interact with papers on the Hub.
125
+
126
+ - `hf papers info PAPER_ID` — Get info about a paper on the Hub. `[--format CHOICE]`
127
+ - `hf papers list` — List daily papers on the Hub. `[--date TEXT --week TEXT --month TEXT --submitter TEXT --sort CHOICE --limit INTEGER --format CHOICE]`
128
+ - `hf papers read PAPER_ID` — Read a paper as markdown.
129
+ - `hf papers search QUERY` — Search papers on the Hub. `[--limit INTEGER --format CHOICE]`
130
+
131
+ ### `hf repos` — Manage repos on the Hub.
132
+
133
+ - `hf repos branch create REPO_ID BRANCH` — Create a new branch for a repo on the Hub. `[--revision TEXT --type CHOICE --exist-ok --format CHOICE]`
134
+ - `hf repos branch delete REPO_ID BRANCH` — Delete a branch from a repo on the Hub. `[--type CHOICE --format CHOICE]`
135
+ - `hf repos create REPO_ID` — Create a new repo on the Hub. `[--type CHOICE --space-sdk TEXT --private --public --protected --exist-ok --resource-group-id TEXT --flavor CHOICE --storage CHOICE --sleep-time INTEGER --secrets TEXT --secrets-file TEXT --env TEXT --env-file TEXT --volume TEXT --format CHOICE]`
136
+ - `hf repos delete REPO_ID` — Delete a repo from the Hub. This is an irreversible operation. `[--type CHOICE --missing-ok --yes --format CHOICE]`
137
+ - `hf repos delete-files REPO_ID PATTERNS` — Delete files from a repo on the Hub. `[--type CHOICE --revision TEXT --commit-message TEXT --commit-description TEXT --create-pr --format CHOICE]`
138
+ - `hf repos duplicate FROM_ID` — Duplicate a repo on the Hub (model, dataset, or Space). `[--type CHOICE --private --public --protected --exist-ok --flavor CHOICE --storage CHOICE --sleep-time INTEGER --secrets TEXT --secrets-file TEXT --env TEXT --env-file TEXT --volume TEXT --format CHOICE]`
139
+ - `hf repos move FROM_ID TO_ID` — Move a repository from a namespace to another namespace. `[--type CHOICE --format CHOICE]`
140
+ - `hf repos settings REPO_ID` — Update the settings of a repository. `[--gated CHOICE --private --public --protected --type CHOICE --format CHOICE]`
141
+ - `hf repos tag create REPO_ID TAG` — Create a tag for a repo. `[--message TEXT --revision TEXT --type CHOICE --format CHOICE]`
142
+ - `hf repos tag delete REPO_ID TAG` — Delete a tag for a repo. `[--yes --type CHOICE --format CHOICE]`
143
+ - `hf repos tag list REPO_ID` — List tags for a repo. `[--type CHOICE --format CHOICE]`
144
+
145
+ ### `hf skills` — Manage skills for AI assistants.
146
+
147
+ - `hf skills add` — Download a Hugging Face skill and install it for an AI assistant. `[--claude --global --dest PATH --force]`
148
+ - `hf skills preview` — Print the generated `hf-cli` SKILL.md to stdout.
149
+ - `hf skills upgrade` — Upgrade installed Hugging Face marketplace skills. `[--claude --global --dest PATH]`
150
+
151
+ ### `hf spaces` — Interact with spaces on the Hub.
152
+
153
+ - `hf spaces dev-mode SPACE_ID` — Enable or disable dev mode on a Space. `[--stop]`
154
+ - `hf spaces hot-reload SPACE_ID` — Hot-reload any Python file of a Space without a full rebuild + restart. `[--local-file PATH --skip-checks --skip-summary]`
155
+ - `hf spaces info SPACE_ID` — Get info about a space on the Hub. `[--revision TEXT --expand TEXT --format CHOICE]`
156
+ - `hf spaces list` — List spaces on the Hub. `[--search TEXT --author TEXT --filter TEXT --sort CHOICE --limit INTEGER --expand TEXT --format CHOICE]`
157
+ - `hf spaces logs SPACE_ID` — Fetch the run or build logs of a Space. `[--build --follow --tail INTEGER]`
158
+ - `hf spaces search QUERY` — Search spaces on the Hub using semantic search. `[--filter TEXT --sdk TEXT --include-non-running --description --limit INTEGER --format CHOICE]`
159
+ - `hf spaces volumes delete SPACE_ID` — Remove all volumes from a Space. `[--yes --format CHOICE]`
160
+ - `hf spaces volumes list SPACE_ID` — List volumes mounted in a Space. `[--format CHOICE]`
161
+ - `hf spaces volumes set SPACE_ID` — Set (replace) volumes for a Space. `[--volume TEXT --format CHOICE]`
162
+
163
+ ### `hf webhooks` — Manage webhooks on the Hub.
164
+
165
+ - `hf webhooks create --watch TEXT` — Create a new webhook. `[--url TEXT --job-id TEXT --domain CHOICE --secret TEXT --format CHOICE]`
166
+ - `hf webhooks delete WEBHOOK_ID` — Delete a webhook permanently. `[--yes --format CHOICE]`
167
+ - `hf webhooks disable WEBHOOK_ID` — Disable an active webhook. `[--format CHOICE]`
168
+ - `hf webhooks enable WEBHOOK_ID` — Enable a disabled webhook. `[--format CHOICE]`
169
+ - `hf webhooks info WEBHOOK_ID` — Show full details for a single webhook. `[--format CHOICE]`
170
+ - `hf webhooks list` — List all webhooks for the current user. `[--format CHOICE]`
171
+ - `hf webhooks update WEBHOOK_ID` — Update an existing webhook. Only provided options are changed. `[--url TEXT --watch TEXT --domain CHOICE --secret TEXT --format CHOICE]`
172
+
173
+ ## Common options
174
+
175
+ - `--format` — Output format: `--format json` (or `--json`) or `--format table` (default).
176
+ - `-q / --quiet` — Minimal output.
177
+ - `--revision` — Git revision id which can be a branch name, a tag, or a commit hash.
178
+ - `--token` — Use a User Access Token. Prefer setting `HF_TOKEN` env var instead of passing `--token`.
179
+ - `--type` — The type of repository (model, dataset, or space).
180
+
181
+ ## Mounting repos as local filesystems
182
+
183
+ To mount Hub repositories or buckets as local filesystems — no download, no copy, no waiting — use `hf-mount`. Files are fetched on demand. GitHub: https://github.com/huggingface/hf-mount
184
+
185
+ Install: `curl -fsSL https://raw.githubusercontent.com/huggingface/hf-mount/main/install.sh | sh`
186
+
187
+ Some command examples:
188
+ - `hf-mount start repo openai-community/gpt2 /tmp/gpt2` — mount a repo (read-only)
189
+ - `hf-mount start --hf-token $HF_TOKEN bucket myuser/my-bucket /tmp/data` — mount a bucket (read-write)
190
+ - `hf-mount status` / `hf-mount stop /tmp/data` — list or unmount
191
+
192
+ ## Tips
193
+
194
+ - Use `hf <command> --help` for full options, descriptions, usage, and real-world examples
195
+ - Authenticate with `HF_TOKEN` env var (recommended) or with `--token`
.claude/skills/hf-cli ADDED
@@ -0,0 +1 @@
 
 
1
+ ../../.agents/skills/hf-cli
.claude/skills/huggingface-doc/SKILL.md ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
 
1
+ ---
2
+ name: Hugging Face Doc
3
+ description: Use Hugging Face Docs API to efficiently search for huggingface related information
4
+ ---
5
+
6
+ ⁠Use api https://huggingface.co/api/docs/search?q={query} to find huggingface related information
.gitattributes ADDED
@@ -0,0 +1,36 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ *.7z filter=lfs diff=lfs merge=lfs -text
2
+ *.arrow filter=lfs diff=lfs merge=lfs -text
3
+ *.bin filter=lfs diff=lfs merge=lfs -text
4
+ *.bz2 filter=lfs diff=lfs merge=lfs -text
5
+ *.ckpt filter=lfs diff=lfs merge=lfs -text
6
+ *.ftz filter=lfs diff=lfs merge=lfs -text
7
+ *.gz filter=lfs diff=lfs merge=lfs -text
8
+ *.h5 filter=lfs diff=lfs merge=lfs -text
9
+ *.joblib filter=lfs diff=lfs merge=lfs -text
10
+ *.lfs.* filter=lfs diff=lfs merge=lfs -text
11
+ *.mlmodel filter=lfs diff=lfs merge=lfs -text
12
+ *.model filter=lfs diff=lfs merge=lfs -text
13
+ *.msgpack filter=lfs diff=lfs merge=lfs -text
14
+ *.npy filter=lfs diff=lfs merge=lfs -text
15
+ *.npz filter=lfs diff=lfs merge=lfs -text
16
+ *.onnx filter=lfs diff=lfs merge=lfs -text
17
+ *.ot filter=lfs diff=lfs merge=lfs -text
18
+ *.parquet filter=lfs diff=lfs merge=lfs -text
19
+ *.pb filter=lfs diff=lfs merge=lfs -text
20
+ *.pickle filter=lfs diff=lfs merge=lfs -text
21
+ *.pkl filter=lfs diff=lfs merge=lfs -text
22
+ *.pt filter=lfs diff=lfs merge=lfs -text
23
+ *.pth filter=lfs diff=lfs merge=lfs -text
24
+ *.rar filter=lfs diff=lfs merge=lfs -text
25
+ *.safetensors filter=lfs diff=lfs merge=lfs -text
26
+ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
27
+ *.tar.* filter=lfs diff=lfs merge=lfs -text
28
+ *.tar filter=lfs diff=lfs merge=lfs -text
29
+ *.tflite filter=lfs diff=lfs merge=lfs -text
30
+ *.tgz filter=lfs diff=lfs merge=lfs -text
31
+ *.wasm filter=lfs diff=lfs merge=lfs -text
32
+ *.xz filter=lfs diff=lfs merge=lfs -text
33
+ *.zip filter=lfs diff=lfs merge=lfs -text
34
+ *.zst filter=lfs diff=lfs merge=lfs -text
35
+ *tfevents* filter=lfs diff=lfs merge=lfs -text
36
+ *.png filter=lfs diff=lfs merge=lfs -text
.gitignore ADDED
@@ -0,0 +1,25 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ node_modules
2
+
3
+ # Output
4
+ .output
5
+ .vercel
6
+ .netlify
7
+ .wrangler
8
+ /.svelte-kit
9
+ /build
10
+ /dist
11
+
12
+ # OS
13
+ .DS_Store
14
+ Thumbs.db
15
+
16
+ # Env
17
+ .env
18
+ .env.*
19
+ !.env.example
20
+ !.env.test
21
+
22
+ # Vite
23
+ vite.config.js.timestamp-*
24
+ vite.config.ts.timestamp-*
25
+
.npmrc ADDED
@@ -0,0 +1 @@
 
 
1
+ engine-strict=true
.vscode/extensions.json ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
 
1
+ {
2
+ "recommendations": [
3
+ "svelte.svelte-vscode",
4
+ "bradlc.vscode-tailwindcss"
5
+ ]
6
+ }
.vscode/settings.json ADDED
@@ -0,0 +1,5 @@
 
 
 
 
 
 
1
+ {
2
+ "files.associations": {
3
+ "*.css": "tailwindcss"
4
+ }
5
+ }
README.md ADDED
@@ -0,0 +1,41 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ title: Counter Strike 2 Dataset
3
+ emoji: 🔥
4
+ colorFrom: pink
5
+ colorTo: gray
6
+ sdk: static
7
+ pinned: false
8
+ app_build_command: npm run build
9
+ app_file: dist/index.html
10
+ license: mit
11
+ short_description: Counter Strike 2 Dataset
12
+ ---
13
+
14
+ # CS2 Render Dataset Viewer
15
+
16
+ Browse Counter-Strike 2 esports matches with synchronized 10-perspective POV
17
+ videos, sourced from the [`blanchon/cs2_dataset_render`](https://huggingface.co/datasets/blanchon/cs2_dataset_render)
18
+ Hugging Face dataset.
19
+
20
+ Built with SvelteKit (`@sveltejs/adapter-static`, SPA mode) — all data is
21
+ fetched client-side from the dataset's parquet files via `parquet-wasm`.
22
+
23
+ ## Develop
24
+
25
+ ```sh
26
+ pnpm install
27
+ pnpm dev
28
+ ```
29
+
30
+ ## Build
31
+
32
+ ```sh
33
+ pnpm build # → dist/
34
+ pnpm preview # serve dist/ locally
35
+ ```
36
+
37
+ The Space's build command (`npm run build`, configured in the frontmatter)
38
+ runs the same Vite build. Output is `dist/index.html` plus an `_app` chunk
39
+ directory and the `static/maps/` radar assets.
40
+
41
+ Configuration reference: <https://huggingface.co/docs/hub/spaces-config-reference>
components.json ADDED
@@ -0,0 +1,20 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "$schema": "https://shadcn-svelte.com/schema.json",
3
+ "tailwind": {
4
+ "css": "src/routes/layout.css",
5
+ "baseColor": "taupe"
6
+ },
7
+ "aliases": {
8
+ "components": "$lib/components",
9
+ "utils": "$lib/utils",
10
+ "ui": "$lib/components/ui",
11
+ "hooks": "$lib/hooks",
12
+ "lib": "$lib"
13
+ },
14
+ "typescript": true,
15
+ "registry": "https://shadcn-svelte.com/registry",
16
+ "style": "mira",
17
+ "iconLibrary": "phosphor",
18
+ "menuColor": "default",
19
+ "menuAccent": "subtle"
20
+ }
package.json ADDED
@@ -0,0 +1,48 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "name": "app",
3
+ "private": true,
4
+ "version": "0.0.1",
5
+ "type": "module",
6
+ "scripts": {
7
+ "dev": "vite dev",
8
+ "build": "vite build",
9
+ "preview": "vite preview",
10
+ "prepare": "svelte-kit sync || echo ''",
11
+ "check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json",
12
+ "check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch"
13
+ },
14
+ "devDependencies": {
15
+ "@fontsource-variable/oxanium": "^5.2.8",
16
+ "@fontsource-variable/roboto-slab": "^5.2.8",
17
+ "@internationalized/date": "^3.12.1",
18
+ "@sveltejs/adapter-static": "latest",
19
+ "@sveltejs/kit": "latest",
20
+ "@sveltejs/vite-plugin-svelte": "^7.0.0",
21
+ "@tailwindcss/vite": "^4.2.2",
22
+ "@tanstack/table-core": "^8.21.3",
23
+ "bits-ui": "^2.18.0",
24
+ "clsx": "^2.1.1",
25
+ "formsnap": "^2.0.1",
26
+ "layerchart": "2.0.0-next.48",
27
+ "mode-watcher": "^1.1.0",
28
+ "paneforge": "^1.0.2",
29
+ "phosphor-svelte": "^3.1.0",
30
+ "shadcn-svelte": "^1.2.7",
31
+ "svelte": "^5.55.2",
32
+ "svelte-check": "^4.4.6",
33
+ "svelte-sonner": "^1.1.1",
34
+ "sveltekit-superforms": "^2.30.1",
35
+ "tailwind-merge": "^3.5.0",
36
+ "tailwind-variants": "^3.2.2",
37
+ "tailwindcss": "^4.2.2",
38
+ "tw-animate-css": "^1.4.0",
39
+ "typescript": "^6.0.2",
40
+ "vaul-svelte": "1.0.0-next.7",
41
+ "vite": "^8.0.7"
42
+ },
43
+ "dependencies": {
44
+ "apache-arrow": "^21.1.0",
45
+ "mediabunny": "^1.42.0",
46
+ "parquet-wasm": "^0.7.1"
47
+ }
48
+ }
pnpm-lock.yaml ADDED
@@ -0,0 +1,2444 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ lockfileVersion: '9.0'
2
+
3
+ settings:
4
+ autoInstallPeers: true
5
+ excludeLinksFromLockfile: false
6
+
7
+ importers:
8
+
9
+ .:
10
+ dependencies:
11
+ apache-arrow:
12
+ specifier: ^21.1.0
13
+ version: 21.1.0
14
+ mediabunny:
15
+ specifier: ^1.42.0
16
+ version: 1.42.0
17
+ parquet-wasm:
18
+ specifier: ^0.7.1
19
+ version: 0.7.1
20
+ devDependencies:
21
+ '@fontsource-variable/oxanium':
22
+ specifier: ^5.2.8
23
+ version: 5.2.8
24
+ '@fontsource-variable/roboto-slab':
25
+ specifier: ^5.2.8
26
+ version: 5.2.8
27
+ '@internationalized/date':
28
+ specifier: ^3.12.1
29
+ version: 3.12.1
30
+ '@sveltejs/adapter-static':
31
+ specifier: latest
32
+ version: 3.0.10(@sveltejs/kit@2.58.0(@sveltejs/vite-plugin-svelte@7.0.0(svelte@5.55.5)(vite@8.0.10(@types/node@24.12.2)(jiti@2.6.1)))(svelte@5.55.5)(typescript@6.0.3)(vite@8.0.10(@types/node@24.12.2)(jiti@2.6.1)))
33
+ '@sveltejs/kit':
34
+ specifier: latest
35
+ version: 2.58.0(@sveltejs/vite-plugin-svelte@7.0.0(svelte@5.55.5)(vite@8.0.10(@types/node@24.12.2)(jiti@2.6.1)))(svelte@5.55.5)(typescript@6.0.3)(vite@8.0.10(@types/node@24.12.2)(jiti@2.6.1))
36
+ '@sveltejs/vite-plugin-svelte':
37
+ specifier: ^7.0.0
38
+ version: 7.0.0(svelte@5.55.5)(vite@8.0.10(@types/node@24.12.2)(jiti@2.6.1))
39
+ '@tailwindcss/vite':
40
+ specifier: ^4.2.2
41
+ version: 4.2.4(vite@8.0.10(@types/node@24.12.2)(jiti@2.6.1))
42
+ '@tanstack/table-core':
43
+ specifier: ^8.21.3
44
+ version: 8.21.3
45
+ bits-ui:
46
+ specifier: ^2.18.0
47
+ version: 2.18.0(@internationalized/date@3.12.1)(@sveltejs/kit@2.58.0(@sveltejs/vite-plugin-svelte@7.0.0(svelte@5.55.5)(vite@8.0.10(@types/node@24.12.2)(jiti@2.6.1)))(svelte@5.55.5)(typescript@6.0.3)(vite@8.0.10(@types/node@24.12.2)(jiti@2.6.1)))(svelte@5.55.5)
48
+ clsx:
49
+ specifier: ^2.1.1
50
+ version: 2.1.1
51
+ formsnap:
52
+ specifier: ^2.0.1
53
+ version: 2.0.1(svelte@5.55.5)(sveltekit-superforms@2.30.1(@sveltejs/kit@2.58.0(@sveltejs/vite-plugin-svelte@7.0.0(svelte@5.55.5)(vite@8.0.10(@types/node@24.12.2)(jiti@2.6.1)))(svelte@5.55.5)(typescript@6.0.3)(vite@8.0.10(@types/node@24.12.2)(jiti@2.6.1)))(svelte@5.55.5)(typescript@6.0.3))
54
+ layerchart:
55
+ specifier: 2.0.0-next.48
56
+ version: 2.0.0-next.48(@sveltejs/kit@2.58.0(@sveltejs/vite-plugin-svelte@7.0.0(svelte@5.55.5)(vite@8.0.10(@types/node@24.12.2)(jiti@2.6.1)))(svelte@5.55.5)(typescript@6.0.3)(vite@8.0.10(@types/node@24.12.2)(jiti@2.6.1)))(svelte@5.55.5)(zod@4.3.6)
57
+ mode-watcher:
58
+ specifier: ^1.1.0
59
+ version: 1.1.0(svelte@5.55.5)
60
+ paneforge:
61
+ specifier: ^1.0.2
62
+ version: 1.0.2(svelte@5.55.5)
63
+ phosphor-svelte:
64
+ specifier: ^3.1.0
65
+ version: 3.1.0(svelte@5.55.5)(vite@8.0.10(@types/node@24.12.2)(jiti@2.6.1))
66
+ shadcn-svelte:
67
+ specifier: ^1.2.7
68
+ version: 1.2.7(svelte@5.55.5)
69
+ svelte:
70
+ specifier: ^5.55.2
71
+ version: 5.55.5
72
+ svelte-check:
73
+ specifier: ^4.4.6
74
+ version: 4.4.6(picomatch@4.0.4)(svelte@5.55.5)(typescript@6.0.3)
75
+ svelte-sonner:
76
+ specifier: ^1.1.1
77
+ version: 1.1.1(svelte@5.55.5)
78
+ sveltekit-superforms:
79
+ specifier: ^2.30.1
80
+ version: 2.30.1(@sveltejs/kit@2.58.0(@sveltejs/vite-plugin-svelte@7.0.0(svelte@5.55.5)(vite@8.0.10(@types/node@24.12.2)(jiti@2.6.1)))(svelte@5.55.5)(typescript@6.0.3)(vite@8.0.10(@types/node@24.12.2)(jiti@2.6.1)))(svelte@5.55.5)(typescript@6.0.3)
81
+ tailwind-merge:
82
+ specifier: ^3.5.0
83
+ version: 3.5.0
84
+ tailwind-variants:
85
+ specifier: ^3.2.2
86
+ version: 3.2.2(tailwind-merge@3.5.0)(tailwindcss@4.2.4)
87
+ tailwindcss:
88
+ specifier: ^4.2.2
89
+ version: 4.2.4
90
+ tw-animate-css:
91
+ specifier: ^1.4.0
92
+ version: 1.4.0
93
+ typescript:
94
+ specifier: ^6.0.2
95
+ version: 6.0.3
96
+ vaul-svelte:
97
+ specifier: 1.0.0-next.7
98
+ version: 1.0.0-next.7(svelte@5.55.5)
99
+ vite:
100
+ specifier: ^8.0.7
101
+ version: 8.0.10(@types/node@24.12.2)(jiti@2.6.1)
102
+
103
+ packages:
104
+
105
+ '@ark/schema@0.56.0':
106
+ resolution: {integrity: sha512-ECg3hox/6Z/nLajxXqNhgPtNdHWC9zNsDyskwO28WinoFEnWow4IsERNz9AnXRhTZJnYIlAJ4uGn3nlLk65vZA==}
107
+
108
+ '@ark/util@0.56.0':
109
+ resolution: {integrity: sha512-BghfRC8b9pNs3vBoDJhcta0/c1J1rsoS1+HgVUreMFPdhz/CRAKReAu57YEllNaSy98rWAdY1gE+gFup7OXpgA==}
110
+
111
+ '@babel/runtime@7.29.2':
112
+ resolution: {integrity: sha512-JiDShH45zKHWyGe4ZNVRrCjBz8Nh9TMmZG1kh4QTK8hCBTWBi8Da+i7s1fJw7/lYpM4ccepSNfqzZ/QvABBi5g==}
113
+ engines: {node: '>=6.9.0'}
114
+
115
+ '@dagrejs/dagre@2.0.4':
116
+ resolution: {integrity: sha512-J6vCWTNpicHF4zFlZG1cS5DkGzMr9941gddYkakjrg3ZNev4bbqEgLHFTWiFrcJm7UCRu7olO3K6IRDd9gSGhA==}
117
+
118
+ '@dagrejs/graphlib@3.0.4':
119
+ resolution: {integrity: sha512-HxZ7fCvAwTLCWCO0WjDkzAFQze8LdC6iOpKbetDKHIuDfIgMlIzYzqZ4nxwLlclQX+3ZVeZ1K2OuaOE2WWcyOg==}
120
+
121
+ '@emnapi/core@1.10.0':
122
+ resolution: {integrity: sha512-yq6OkJ4p82CAfPl0u9mQebQHKPJkY7WrIuk205cTYnYe+k2Z8YBh11FrbRG/H6ihirqcacOgl2BIO8oyMQLeXw==}
123
+
124
+ '@emnapi/runtime@1.10.0':
125
+ resolution: {integrity: sha512-ewvYlk86xUoGI0zQRNq/mC+16R1QeDlKQy21Ki3oSYXNgLb45GV1P6A0M+/s6nyCuNDqe5VpaY84BzXGwVbwFA==}
126
+
127
+ '@emnapi/wasi-threads@1.2.1':
128
+ resolution: {integrity: sha512-uTII7OYF+/Mes/MrcIOYp5yOtSMLBWSIoLPpcgwipoiKbli6k322tcoFsxoIIxPDqW01SQGAgko4EzZi2BNv2w==}
129
+
130
+ '@exodus/schemasafe@1.3.0':
131
+ resolution: {integrity: sha512-5Aap/GaRupgNx/feGBwLLTVv8OQFfv3pq2lPRzPg9R+IOBnDgghTGW7l7EuVXOvg5cc/xSAlRW8rBrjIC3Nvqw==}
132
+
133
+ '@floating-ui/core@1.7.5':
134
+ resolution: {integrity: sha512-1Ih4WTWyw0+lKyFMcBHGbb5U5FtuHJuujoyyr5zTaWS5EYMeT6Jb2AuDeftsCsEuchO+mM2ij5+q9crhydzLhQ==}
135
+
136
+ '@floating-ui/dom@1.7.6':
137
+ resolution: {integrity: sha512-9gZSAI5XM36880PPMm//9dfiEngYoC6Am2izES1FF406YFsjvyBMmeJ2g4SAju3xWwtuynNRFL2s9hgxpLI5SQ==}
138
+
139
+ '@floating-ui/utils@0.2.11':
140
+ resolution: {integrity: sha512-RiB/yIh78pcIxl6lLMG0CgBXAZ2Y0eVHqMPYugu+9U0AeT6YBeiJpf7lbdJNIugFP5SIjwNRgo4DhR1Qxi26Gg==}
141
+
142
+ '@fontsource-variable/oxanium@5.2.8':
143
+ resolution: {integrity: sha512-W3HWxRLXVB6yox3dgm1DIGOp98pz8KglwiM6/2BsMopvZrg98mXI9citFWz2pUX0FOOLwf8fmHxX+KrIn+6BoA==}
144
+
145
+ '@fontsource-variable/roboto-slab@5.2.8':
146
+ resolution: {integrity: sha512-cdvOSwocP50xS01gXqnGxw7uFcCZQgn1IDlqiAmNuZP4uEVScYAKMDC+aWsbP1grn9QdMJ2frhcuVBNXniBVGA==}
147
+
148
+ '@hapi/hoek@9.3.0':
149
+ resolution: {integrity: sha512-/c6rf4UJlmHlC9b5BaNvzAcFv7HZ2QHaV0D4/HNlBdvFnvQq8RI4kYdhyPCl7Xj+oWvTWQ8ujhqS53LIgAe6KQ==}
150
+
151
+ '@hapi/topo@5.1.0':
152
+ resolution: {integrity: sha512-foQZKJig7Ob0BMAYBfcJk8d77QtOe7Wo4ox7ff1lQYoNNAb6jwcY1ncdoy2e9wQZzvNy7ODZCYJkK8kzmcAnAg==}
153
+
154
+ '@internationalized/date@3.12.1':
155
+ resolution: {integrity: sha512-6IedsVWXyq4P9Tj+TxuU8WGWM70hYLl12nbYU8jkikVpa6WXapFazPUcHUMDMoWftIDE2ILDkFFte6W2nFCkRQ==}
156
+
157
+ '@jridgewell/gen-mapping@0.3.13':
158
+ resolution: {integrity: sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==}
159
+
160
+ '@jridgewell/remapping@2.3.5':
161
+ resolution: {integrity: sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==}
162
+
163
+ '@jridgewell/resolve-uri@3.1.2':
164
+ resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==}
165
+ engines: {node: '>=6.0.0'}
166
+
167
+ '@jridgewell/sourcemap-codec@1.5.5':
168
+ resolution: {integrity: sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==}
169
+
170
+ '@jridgewell/trace-mapping@0.3.31':
171
+ resolution: {integrity: sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==}
172
+
173
+ '@layerstack/svelte-actions@1.0.1-next.18':
174
+ resolution: {integrity: sha512-gxPzCnJ1c9LTfWtRqLUzefCx+k59ZpxDUQ2XB+LokveZQPe7IDSOwHaBOEMlaGoGrtwc3Ft8dSZq+2WT2o9u/g==}
175
+
176
+ '@layerstack/svelte-state@0.1.0-next.23':
177
+ resolution: {integrity: sha512-7O4umv+gXwFfs3/vjzFWYHNXGwYnnjBapWJ5Y+9u99F4eVk6rh4ocNwqkqQNkpMZ5tUJBlRTWjPE1So6+hEzIg==}
178
+
179
+ '@layerstack/tailwind@2.0.0-next.21':
180
+ resolution: {integrity: sha512-Qgp2EpmEHmjtura8MQzWicR6ztBRSsRvddakFtx9ShrLMz6jWzd6bCMVVRu44Q3ZOrtXmSu4QxjCZWu1ytvuPg==}
181
+
182
+ '@layerstack/utils@2.0.0-next.18':
183
+ resolution: {integrity: sha512-EYILHpfBRYMMEahajInu9C2AXQom5IcAEdtCeucD3QIl/fdDgRbtzn6/8QW9ewumfyNZetdUvitOksmI1+gZYQ==}
184
+
185
+ '@napi-rs/wasm-runtime@1.1.4':
186
+ resolution: {integrity: sha512-3NQNNgA1YSlJb/kMH1ildASP9HW7/7kYnRI2szWJaofaS1hWmbGI4H+d3+22aGzXXN9IJ+n+GiFVcGipJP18ow==}
187
+ peerDependencies:
188
+ '@emnapi/core': ^1.7.1
189
+ '@emnapi/runtime': ^1.7.1
190
+
191
+ '@oxc-project/types@0.127.0':
192
+ resolution: {integrity: sha512-aIYXQBo4lCbO4z0R3FHeucQHpF46l2LbMdxRvqvuRuW2OxdnSkcng5B8+K12spgLDj93rtN3+J2Vac/TIO+ciQ==}
193
+
194
+ '@polka/url@1.0.0-next.29':
195
+ resolution: {integrity: sha512-wwQAWhWSuHaag8c4q/KN/vCoeOJYshAIvMQwD4GpSb3OiZklFfvAgmj0VCBBImRpuF/aFgIRzllXlVX93Jevww==}
196
+
197
+ '@poppinss/macroable@1.1.2':
198
+ resolution: {integrity: sha512-FAVBRzzWhYP5mA3lCwLH1A0fKBqq5anyjGet90Z81aRK5c/+LTGUE1zJhZrErjaenBSOOI9BVUs3WVmotneFQA==}
199
+
200
+ '@rolldown/binding-android-arm64@1.0.0-rc.17':
201
+ resolution: {integrity: sha512-s70pVGhw4zqGeFnXWvAzJDlvxhlRollagdCCKRgOsgUOH3N1l0LIxf83AtGzmb5SiVM4Hjl5HyarMRfdfj3DaQ==}
202
+ engines: {node: ^20.19.0 || >=22.12.0}
203
+ cpu: [arm64]
204
+ os: [android]
205
+
206
+ '@rolldown/binding-darwin-arm64@1.0.0-rc.17':
207
+ resolution: {integrity: sha512-4ksWc9n0mhlZpZ9PMZgTGjeOPRu8MB1Z3Tz0Mo02eWfWCHMW1zN82Qz/pL/rC+yQa+8ZnutMF0JjJe7PjwasYw==}
208
+ engines: {node: ^20.19.0 || >=22.12.0}
209
+ cpu: [arm64]
210
+ os: [darwin]
211
+
212
+ '@rolldown/binding-darwin-x64@1.0.0-rc.17':
213
+ resolution: {integrity: sha512-SUSDOI6WwUVNcWxd02QEBjLdY1VPHvlEkw6T/8nYG322iYWCTxRb1vzk4E+mWWYehTp7ERibq54LSJGjmouOsw==}
214
+ engines: {node: ^20.19.0 || >=22.12.0}
215
+ cpu: [x64]
216
+ os: [darwin]
217
+
218
+ '@rolldown/binding-freebsd-x64@1.0.0-rc.17':
219
+ resolution: {integrity: sha512-hwnz3nw9dbJ05EDO/PvcjaaewqqDy7Y1rn1UO81l8iIK1GjenME75dl16ajbvSSMfv66WXSRCYKIqfgq2KCfxw==}
220
+ engines: {node: ^20.19.0 || >=22.12.0}
221
+ cpu: [x64]
222
+ os: [freebsd]
223
+
224
+ '@rolldown/binding-linux-arm-gnueabihf@1.0.0-rc.17':
225
+ resolution: {integrity: sha512-IS+W7epTcwANmFSQFrS1SivEXHtl1JtuQA9wlxrZTcNi6mx+FDOYrakGevvvTwgj2JvWiK8B29/qD9BELZPyXQ==}
226
+ engines: {node: ^20.19.0 || >=22.12.0}
227
+ cpu: [arm]
228
+ os: [linux]
229
+
230
+ '@rolldown/binding-linux-arm64-gnu@1.0.0-rc.17':
231
+ resolution: {integrity: sha512-e6usGaHKW5BMNZOymS1UcEYGowQMWcgZ71Z17Sl/h2+ZziNJ1a9n3Zvcz6LdRyIW5572wBCTH/Z+bKuZouGk9Q==}
232
+ engines: {node: ^20.19.0 || >=22.12.0}
233
+ cpu: [arm64]
234
+ os: [linux]
235
+ libc: [glibc]
236
+
237
+ '@rolldown/binding-linux-arm64-musl@1.0.0-rc.17':
238
+ resolution: {integrity: sha512-b/CgbwAJpmrRLp02RPfhbudf5tZnN9nsPWK82znefso832etkem8H7FSZwxrOI9djcdTP7U6YfNhbRnh7djErg==}
239
+ engines: {node: ^20.19.0 || >=22.12.0}
240
+ cpu: [arm64]
241
+ os: [linux]
242
+ libc: [musl]
243
+
244
+ '@rolldown/binding-linux-ppc64-gnu@1.0.0-rc.17':
245
+ resolution: {integrity: sha512-4EII1iNGRUN5WwGbF/kOh/EIkoDN9HsupgLQoXfY+D1oyJm7/F4t5PYU5n8SWZgG0FEwakyM8pGgwcBYruGTlA==}
246
+ engines: {node: ^20.19.0 || >=22.12.0}
247
+ cpu: [ppc64]
248
+ os: [linux]
249
+ libc: [glibc]
250
+
251
+ '@rolldown/binding-linux-s390x-gnu@1.0.0-rc.17':
252
+ resolution: {integrity: sha512-AH8oq3XqQo4IibpVXvPeLDI5pzkpYn0WiZAfT05kFzoJ6tQNzwRdDYQ45M8I/gslbodRZwW8uxLhbSBbkv96rA==}
253
+ engines: {node: ^20.19.0 || >=22.12.0}
254
+ cpu: [s390x]
255
+ os: [linux]
256
+ libc: [glibc]
257
+
258
+ '@rolldown/binding-linux-x64-gnu@1.0.0-rc.17':
259
+ resolution: {integrity: sha512-cLnjV3xfo7KslbU41Z7z8BH/E1y5mzUYzAqih1d1MDaIGZRCMqTijqLv76/P7fyHuvUcfGsIpqCdddbxLLK9rA==}
260
+ engines: {node: ^20.19.0 || >=22.12.0}
261
+ cpu: [x64]
262
+ os: [linux]
263
+ libc: [glibc]
264
+
265
+ '@rolldown/binding-linux-x64-musl@1.0.0-rc.17':
266
+ resolution: {integrity: sha512-0phclDw1spsL7dUB37sIARuis2tAgomCJXAHZlpt8PXZ4Ba0dRP1e+66lsRqrfhISeN9bEGNjQs+T/Fbd7oYGw==}
267
+ engines: {node: ^20.19.0 || >=22.12.0}
268
+ cpu: [x64]
269
+ os: [linux]
270
+ libc: [musl]
271
+
272
+ '@rolldown/binding-openharmony-arm64@1.0.0-rc.17':
273
+ resolution: {integrity: sha512-0ag/hEgXOwgw4t8QyQvUCxvEg+V0KBcA6YuOx9g0r02MprutRF5dyljgm3EmR02O292UX7UeS6HzWHAl6KgyhA==}
274
+ engines: {node: ^20.19.0 || >=22.12.0}
275
+ cpu: [arm64]
276
+ os: [openharmony]
277
+
278
+ '@rolldown/binding-wasm32-wasi@1.0.0-rc.17':
279
+ resolution: {integrity: sha512-LEXei6vo0E5wTGwpkJ4KoT3OZJRnglwldt5ziLzOlc6qqb55z4tWNq2A+PFqCJuvWWdP53CVhG1Z9NtToDPJrA==}
280
+ engines: {node: ^20.19.0 || >=22.12.0}
281
+ cpu: [wasm32]
282
+
283
+ '@rolldown/binding-win32-arm64-msvc@1.0.0-rc.17':
284
+ resolution: {integrity: sha512-gUmyzBl3SPMa6hrqFUth9sVfcLBlYsbMzBx5PlexMroZStgzGqlZ26pYG89rBb45Mnia+oil6YAIFeEWGWhoZA==}
285
+ engines: {node: ^20.19.0 || >=22.12.0}
286
+ cpu: [arm64]
287
+ os: [win32]
288
+
289
+ '@rolldown/binding-win32-x64-msvc@1.0.0-rc.17':
290
+ resolution: {integrity: sha512-3hkiolcUAvPB9FLb3UZdfjVVNWherN1f/skkGWJP/fgSQhYUZpSIRr0/I8ZK9TkF3F7kxvJAk0+IcKvPHk9qQg==}
291
+ engines: {node: ^20.19.0 || >=22.12.0}
292
+ cpu: [x64]
293
+ os: [win32]
294
+
295
+ '@rolldown/pluginutils@1.0.0-rc.17':
296
+ resolution: {integrity: sha512-n8iosDOt6Ig1UhJ2AYqoIhHWh/isz0xpicHTzpKBeotdVsTEcxsSA/i3EVM7gQAj0rU27OLAxCjzlj15IWY7bg==}
297
+
298
+ '@sideway/address@4.1.5':
299
+ resolution: {integrity: sha512-IqO/DUQHUkPeixNQ8n0JA6102hT9CmaljNTPmQ1u8MEhBo/R4Q8eKLN/vGZxuebwOroDB4cbpjheD4+/sKFK4Q==}
300
+
301
+ '@sideway/formula@3.0.1':
302
+ resolution: {integrity: sha512-/poHZJJVjx3L+zVD6g9KgHfYnb443oi7wLu/XKojDviHy6HOEOA6z1Trk5aR1dGcmPenJEgb2sK2I80LeS3MIg==}
303
+
304
+ '@sideway/pinpoint@2.0.0':
305
+ resolution: {integrity: sha512-RNiOoTPkptFtSVzQevY/yWtZwf/RxyVnPy/OcA9HBM3MlGDnBEYL5B41H0MTn0Uec8Hi+2qUtTfG2WWZBmMejQ==}
306
+
307
+ '@standard-schema/spec@1.1.0':
308
+ resolution: {integrity: sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==}
309
+
310
+ '@sveltejs/acorn-typescript@1.0.9':
311
+ resolution: {integrity: sha512-lVJX6qEgs/4DOcRTpo56tmKzVPtoWAaVbL4hfO7t7NVwl9AAXzQR6cihesW1BmNMPl+bK6dreu2sOKBP2Q9CIA==}
312
+ peerDependencies:
313
+ acorn: ^8.9.0
314
+
315
+ '@sveltejs/adapter-static@3.0.10':
316
+ resolution: {integrity: sha512-7D9lYFWJmB7zxZyTE/qxjksvMqzMuYrrsyh1f4AlZqeZeACPRySjbC3aFiY55wb1tWUaKOQG9PVbm74JcN2Iew==}
317
+ peerDependencies:
318
+ '@sveltejs/kit': ^2.0.0
319
+
320
+ '@sveltejs/kit@2.58.0':
321
+ resolution: {integrity: sha512-kT9GCN8yJTkCK1W+Gi/bvGooWAM7y7WXP+yd+rf6QOIjyoK1ERPrMwSufXJUNu2pMWIqruhFvmz+LbOqsEmKmA==}
322
+ engines: {node: '>=18.13'}
323
+ hasBin: true
324
+ peerDependencies:
325
+ '@opentelemetry/api': ^1.0.0
326
+ '@sveltejs/vite-plugin-svelte': ^3.0.0 || ^4.0.0-next.1 || ^5.0.0 || ^6.0.0-next.0 || ^7.0.0
327
+ svelte: ^4.0.0 || ^5.0.0-next.0
328
+ typescript: ^5.3.3 || ^6.0.0
329
+ vite: ^5.0.3 || ^6.0.0 || ^7.0.0-beta.0 || ^8.0.0
330
+ peerDependenciesMeta:
331
+ '@opentelemetry/api':
332
+ optional: true
333
+ typescript:
334
+ optional: true
335
+
336
+ '@sveltejs/vite-plugin-svelte@7.0.0':
337
+ resolution: {integrity: sha512-ILXmxC7HAsnkK2eslgPetrqqW1BKSL7LktsFgqzNj83MaivMGZzluWq32m25j2mDOjmSKX7GGWahePhuEs7P/g==}
338
+ engines: {node: ^20.19 || ^22.12 || >=24}
339
+ peerDependencies:
340
+ svelte: ^5.46.4
341
+ vite: ^8.0.0-beta.7 || ^8.0.0
342
+
343
+ '@swc/helpers@0.5.21':
344
+ resolution: {integrity: sha512-jI/VAmtdjB/RnI8GTnokyX7Ug8c+g+ffD6QRLa6XQewtnGyukKkKSk3wLTM3b5cjt1jNh9x0jfVlagdN2gDKQg==}
345
+
346
+ '@tailwindcss/node@4.2.4':
347
+ resolution: {integrity: sha512-Ai7+yQPxz3ddrDQzFfBKdHEVBg0w3Zl83jnjuwxnZOsnH9pGn93QHQtpU0p/8rYWxvbFZHneni6p1BSLK4DkGA==}
348
+
349
+ '@tailwindcss/oxide-android-arm64@4.2.4':
350
+ resolution: {integrity: sha512-e7MOr1SAn9U8KlZzPi1ZXGZHeC5anY36qjNwmZv9pOJ8E4Q6jmD1vyEHkQFmNOIN7twGPEMXRHmitN4zCMN03g==}
351
+ engines: {node: '>= 20'}
352
+ cpu: [arm64]
353
+ os: [android]
354
+
355
+ '@tailwindcss/oxide-darwin-arm64@4.2.4':
356
+ resolution: {integrity: sha512-tSC/Kbqpz/5/o/C2sG7QvOxAKqyd10bq+ypZNf+9Fi2TvbVbv1zNpcEptcsU7DPROaSbVgUXmrzKhurFvo5eDg==}
357
+ engines: {node: '>= 20'}
358
+ cpu: [arm64]
359
+ os: [darwin]
360
+
361
+ '@tailwindcss/oxide-darwin-x64@4.2.4':
362
+ resolution: {integrity: sha512-yPyUXn3yO/ufR6+Kzv0t4fCg2qNr90jxXc5QqBpjlPNd0NqyDXcmQb/6weunH/MEDXW5dhyEi+agTDiqa3WsGg==}
363
+ engines: {node: '>= 20'}
364
+ cpu: [x64]
365
+ os: [darwin]
366
+
367
+ '@tailwindcss/oxide-freebsd-x64@4.2.4':
368
+ resolution: {integrity: sha512-BoMIB4vMQtZsXdGLVc2z+P9DbETkiopogfWZKbWwM8b/1Vinbs4YcUwo+kM/KeLkX3Ygrf4/PsRndKaYhS8Eiw==}
369
+ engines: {node: '>= 20'}
370
+ cpu: [x64]
371
+ os: [freebsd]
372
+
373
+ '@tailwindcss/oxide-linux-arm-gnueabihf@4.2.4':
374
+ resolution: {integrity: sha512-7pIHBLTHYRAlS7V22JNuTh33yLH4VElwKtB3bwchK/UaKUPpQ0lPQiOWcbm4V3WP2I6fNIJ23vABIvoy2izdwA==}
375
+ engines: {node: '>= 20'}
376
+ cpu: [arm]
377
+ os: [linux]
378
+
379
+ '@tailwindcss/oxide-linux-arm64-gnu@4.2.4':
380
+ resolution: {integrity: sha512-+E4wxJ0ZGOzSH325reXTWB48l42i93kQqMvDyz5gqfRzRZ7faNhnmvlV4EPGJU3QJM/3Ab5jhJ5pCRUsKn6OQw==}
381
+ engines: {node: '>= 20'}
382
+ cpu: [arm64]
383
+ os: [linux]
384
+ libc: [glibc]
385
+
386
+ '@tailwindcss/oxide-linux-arm64-musl@4.2.4':
387
+ resolution: {integrity: sha512-bBADEGAbo4ASnppIziaQJelekCxdMaxisrk+fB7Thit72IBnALp9K6ffA2G4ruj90G9XRS2VQ6q2bCKbfFV82g==}
388
+ engines: {node: '>= 20'}
389
+ cpu: [arm64]
390
+ os: [linux]
391
+ libc: [musl]
392
+
393
+ '@tailwindcss/oxide-linux-x64-gnu@4.2.4':
394
+ resolution: {integrity: sha512-7Mx25E4WTfnht0TVRTyC00j3i0M+EeFe7wguMDTlX4mRxafznw0CA8WJkFjWYH5BlgELd1kSjuU2JiPnNZbJDA==}
395
+ engines: {node: '>= 20'}
396
+ cpu: [x64]
397
+ os: [linux]
398
+ libc: [glibc]
399
+
400
+ '@tailwindcss/oxide-linux-x64-musl@4.2.4':
401
+ resolution: {integrity: sha512-2wwJRF7nyhOR0hhHoChc04xngV3iS+akccHTGtz965FwF0up4b2lOdo6kI1EbDaEXKgvcrFBYcYQQ/rrnWFVfA==}
402
+ engines: {node: '>= 20'}
403
+ cpu: [x64]
404
+ os: [linux]
405
+ libc: [musl]
406
+
407
+ '@tailwindcss/oxide-wasm32-wasi@4.2.4':
408
+ resolution: {integrity: sha512-FQsqApeor8Fo6gUEklzmaa9994orJZZDBAlQpK2Mq+DslRKFJeD6AjHpBQ0kZFQohVr8o85PPh8eOy86VlSCmw==}
409
+ engines: {node: '>=14.0.0'}
410
+ cpu: [wasm32]
411
+ bundledDependencies:
412
+ - '@napi-rs/wasm-runtime'
413
+ - '@emnapi/core'
414
+ - '@emnapi/runtime'
415
+ - '@tybys/wasm-util'
416
+ - '@emnapi/wasi-threads'
417
+ - tslib
418
+
419
+ '@tailwindcss/oxide-win32-arm64-msvc@4.2.4':
420
+ resolution: {integrity: sha512-L9BXqxC4ToVgwMFqj3pmZRqyHEztulpUJzCxUtLjobMCzTPsGt1Fa9enKbOpY2iIyVtaHNeNvAK8ERP/64sqGQ==}
421
+ engines: {node: '>= 20'}
422
+ cpu: [arm64]
423
+ os: [win32]
424
+
425
+ '@tailwindcss/oxide-win32-x64-msvc@4.2.4':
426
+ resolution: {integrity: sha512-ESlKG0EpVJQwRjXDDa9rLvhEAh0mhP1sF7sap9dNZT0yyl9SAG6T7gdP09EH0vIv0UNTlo6jPWyujD6559fZvw==}
427
+ engines: {node: '>= 20'}
428
+ cpu: [x64]
429
+ os: [win32]
430
+
431
+ '@tailwindcss/oxide@4.2.4':
432
+ resolution: {integrity: sha512-9El/iI069DKDSXwTvB9J4BwdO5JhRrOweGaK25taBAvBXyXqJAX+Jqdvs8r8gKpsI/1m0LeJLyQYTf/WLrBT1Q==}
433
+ engines: {node: '>= 20'}
434
+
435
+ '@tailwindcss/vite@4.2.4':
436
+ resolution: {integrity: sha512-pCvohwOCspk3ZFn6eJzrrX3g4n2JY73H6MmYC87XfGPyTty4YsCjYTMArRZm/zOI8dIt3+EcrLHAFPe5A4bgtw==}
437
+ peerDependencies:
438
+ vite: ^5.2.0 || ^6 || ^7 || ^8
439
+
440
+ '@tanstack/table-core@8.21.3':
441
+ resolution: {integrity: sha512-ldZXEhOBb8Is7xLs01fR3YEc3DERiz5silj8tnGkFZytt1abEvl/GhUmCE0PMLaMPTa3Jk4HbKmRlHmu+gCftg==}
442
+ engines: {node: '>=12'}
443
+
444
+ '@tybys/wasm-util@0.10.1':
445
+ resolution: {integrity: sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg==}
446
+
447
+ '@types/command-line-args@5.2.3':
448
+ resolution: {integrity: sha512-uv0aG6R0Y8WHZLTamZwtfsDLVRnOa+n+n5rEvFWL5Na5gZ8V2Teab/duDPFzIIIhs9qizDpcavCusCLJZu62Kw==}
449
+
450
+ '@types/command-line-usage@5.0.4':
451
+ resolution: {integrity: sha512-BwR5KP3Es/CSht0xqBcUXS3qCAUVXwpRKsV2+arxeb65atasuXG9LykC9Ab10Cw3s2raH92ZqOeILaQbsB2ACg==}
452
+
453
+ '@types/cookie@0.6.0':
454
+ resolution: {integrity: sha512-4Kh9a6B2bQciAhf7FSuMRRkUWecJgJu9nPnx3yzpsfXX/c50REIqpHY4C82bXP90qrLtXtkDxTZosYO3UpOwlA==}
455
+
456
+ '@types/d3-array@3.2.2':
457
+ resolution: {integrity: sha512-hOLWVbm7uRza0BYXpIIW5pxfrKe0W+D5lrFiAEYR+pb6w3N2SwSMaJbXdUfSEv+dT4MfHBLtn5js0LAWaO6otw==}
458
+
459
+ '@types/d3-contour@3.0.6':
460
+ resolution: {integrity: sha512-BjzLgXGnCWjUSYGfH1cpdo41/hgdWETu4YxpezoztawmqsvCeep+8QGfiY6YbDvfgHz/DkjeIkkZVJavB4a3rg==}
461
+
462
+ '@types/dom-mediacapture-transform@0.1.11':
463
+ resolution: {integrity: sha512-Y2p+nGf1bF2XMttBnsVPHUWzRRZzqUoJAKmiP10b5umnO6DDrWI0BrGDJy1pOHoOULVmGSfFNkQrAlC5dcj6nQ==}
464
+
465
+ '@types/dom-webcodecs@0.1.13':
466
+ resolution: {integrity: sha512-O5hkiFIcjjszPIYyUSyvScyvrBoV3NOEEZx/pMlsu44TKzWNkLVBBxnxJz42in5n3QIolYOcBYFCPZZ0h8SkwQ==}
467
+
468
+ '@types/estree@1.0.8':
469
+ resolution: {integrity: sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==}
470
+
471
+ '@types/geojson@7946.0.16':
472
+ resolution: {integrity: sha512-6C8nqWur3j98U6+lXDfTUWIfgvZU+EumvpHKcYjujKH7woYyLj2sUmff0tRhrqM7BohUw7Pz3ZB1jj2gW9Fvmg==}
473
+
474
+ '@types/node@24.12.2':
475
+ resolution: {integrity: sha512-A1sre26ke7HDIuY/M23nd9gfB+nrmhtYyMINbjI1zHJxYteKR6qSMX56FsmjMcDb3SMcjJg5BiRRgOCC/yBD0g==}
476
+
477
+ '@types/trusted-types@2.0.7':
478
+ resolution: {integrity: sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==}
479
+
480
+ '@types/validator@13.15.10':
481
+ resolution: {integrity: sha512-T8L6i7wCuyoK8A/ZeLYt1+q0ty3Zb9+qbSSvrIVitzT3YjZqkTZ40IbRsPanlB4h1QB3JVL1SYCdR6ngtFYcuA==}
482
+
483
+ '@typeschema/class-validator@0.3.0':
484
+ resolution: {integrity: sha512-OJSFeZDIQ8EK1HTljKLT5CItM2wsbgczLN8tMEfz3I1Lmhc5TBfkZ0eikFzUC16tI3d1Nag7um6TfCgp2I2Bww==}
485
+ peerDependencies:
486
+ class-validator: ^0.14.1
487
+ peerDependenciesMeta:
488
+ class-validator:
489
+ optional: true
490
+
491
+ '@typeschema/core@0.14.0':
492
+ resolution: {integrity: sha512-Ia6PtZHcL3KqsAWXjMi5xIyZ7XMH4aSnOQes8mfMLx+wGFGtGRNlwe6Y7cYvX+WfNK67OL0/HSe9t8QDygV0/w==}
493
+ peerDependencies:
494
+ '@types/json-schema': ^7.0.15
495
+ peerDependenciesMeta:
496
+ '@types/json-schema':
497
+ optional: true
498
+
499
+ '@valibot/to-json-schema@1.6.0':
500
+ resolution: {integrity: sha512-d6rYyK5KVa2XdqamWgZ4/Nr+cXhxjy7lmpe6Iajw15J/jmU+gyxl2IEd1Otg1d7Rl3gOQL5reulnSypzBtYy1A==}
501
+ peerDependencies:
502
+ valibot: ^1.3.0
503
+
504
+ '@vinejs/compiler@3.0.0':
505
+ resolution: {integrity: sha512-v9Lsv59nR56+bmy2p0+czjZxsLHwaibJ+SV5iK9JJfehlJMa501jUJQqqz4X/OqKXrxtE3uTQmSqjUqzF3B2mw==}
506
+ engines: {node: '>=18.0.0'}
507
+
508
+ '@vinejs/vine@3.0.1':
509
+ resolution: {integrity: sha512-ZtvYkYpZOYdvbws3uaOAvTFuvFXoQGAtmzeiXu+XSMGxi5GVsODpoI9Xu9TplEMuD/5fmAtBbKb9cQHkWkLXDQ==}
510
+ engines: {node: '>=18.16.0'}
511
+
512
+ acorn@8.16.0:
513
+ resolution: {integrity: sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==}
514
+ engines: {node: '>=0.4.0'}
515
+ hasBin: true
516
+
517
+ ansi-styles@4.3.0:
518
+ resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==}
519
+ engines: {node: '>=8'}
520
+
521
+ apache-arrow@21.1.0:
522
+ resolution: {integrity: sha512-kQrYLxhC+NTVVZ4CCzGF6L/uPVOzJmD1T3XgbiUnP7oTeVFOFgEUu6IKNwCDkpFoBVqDKQivlX4RUFqqnWFlEA==}
523
+ hasBin: true
524
+
525
+ aria-query@5.3.1:
526
+ resolution: {integrity: sha512-Z/ZeOgVl7bcSYZ/u/rh0fOpvEpq//LZmdbkXyc7syVzjPAhfOa9ebsdTSjEBDU4vs5nC98Kfduj1uFo0qyET3g==}
527
+ engines: {node: '>= 0.4'}
528
+
529
+ arkregex@0.0.5:
530
+ resolution: {integrity: sha512-ncYjBdLlh5/QnVsAA8De16Tc9EqmYM7y/WU9j+236KcyYNUXogpz3sC4ATIZYzzLxwI+0sEOaQLEmLmRleaEXw==}
531
+
532
+ arktype@2.2.0:
533
+ resolution: {integrity: sha512-t54MZ7ti5BhOEvzEkgKnWvqj+UbDfWig+DHr5I34xatymPusKLS0lQpNJd8M6DzmIto2QGszHfNKoFIT8tMCZQ==}
534
+
535
+ array-back@6.2.3:
536
+ resolution: {integrity: sha512-SGDvmg6QTYiTxCBkYVmThcoa67uLl35pyzRHdpCGBOcqFy6BtwnphoFPk7LhJshD+Yk1Kt35WGWeZPTgwR4Fhw==}
537
+ engines: {node: '>=12.17'}
538
+
539
+ axobject-query@4.1.0:
540
+ resolution: {integrity: sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ==}
541
+ engines: {node: '>= 0.4'}
542
+
543
+ bits-ui@2.18.0:
544
+ resolution: {integrity: sha512-GLOBZRVy3hxNHIQ2MpD/+5aK9KcBFZRhUJtZ1UDABXdlVR4K6zFpgt4T+Rwuhf2sQzlc6yK1q/DprHPjwT4Pjw==}
545
+ engines: {node: '>=20'}
546
+ peerDependencies:
547
+ '@internationalized/date': ^3.8.1
548
+ svelte: ^5.33.0
549
+
550
+ camelcase@8.0.0:
551
+ resolution: {integrity: sha512-8WB3Jcas3swSvjIeA2yvCJ+Miyz5l1ZmB6HFb9R1317dt9LCQoswg/BGrmAmkWVEszSrrg4RwmO46qIm2OEnSA==}
552
+ engines: {node: '>=16'}
553
+
554
+ chalk-template@0.4.0:
555
+ resolution: {integrity: sha512-/ghrgmhfY8RaSdeo43hNXxpoHAtxdbskUHjPpfqUWGttFgycUhYPGx3YZBCnUCvOa7Doivn1IZec3DEGFoMgLg==}
556
+ engines: {node: '>=12'}
557
+
558
+ chalk@4.1.2:
559
+ resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==}
560
+ engines: {node: '>=10'}
561
+
562
+ chokidar@4.0.3:
563
+ resolution: {integrity: sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==}
564
+ engines: {node: '>= 14.16.0'}
565
+
566
+ class-validator@0.14.4:
567
+ resolution: {integrity: sha512-AwNusCCam51q703dW82x95tOqQp6oC9HNUl724KxJJOfnKscI8dOloXFgyez7LbTTKWuRBA37FScqVbJEoq8Yw==}
568
+
569
+ clsx@2.1.1:
570
+ resolution: {integrity: sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==}
571
+ engines: {node: '>=6'}
572
+
573
+ color-convert@2.0.1:
574
+ resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==}
575
+ engines: {node: '>=7.0.0'}
576
+
577
+ color-name@1.1.4:
578
+ resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==}
579
+
580
+ command-line-args@6.0.2:
581
+ resolution: {integrity: sha512-AIjYVxrV9X752LmPDLbVYv8aMCuHPSLZJXEo2qo/xJfv+NYhaZ4sMSF01rM+gHPaMgvPM0l5D/F+Qx+i2WfSmQ==}
582
+ engines: {node: '>=12.20'}
583
+ peerDependencies:
584
+ '@75lb/nature': latest
585
+ peerDependenciesMeta:
586
+ '@75lb/nature':
587
+ optional: true
588
+
589
+ command-line-usage@7.0.4:
590
+ resolution: {integrity: sha512-85UdvzTNx/+s5CkSgBm/0hzP80RFHAa7PsfeADE5ezZF3uHz3/Tqj9gIKGT9PTtpycc3Ua64T0oVulGfKxzfqg==}
591
+ engines: {node: '>=12.20.0'}
592
+
593
+ commander@14.0.3:
594
+ resolution: {integrity: sha512-H+y0Jo/T1RZ9qPP4Eh1pkcQcLRglraJaSLoyOtHxu6AapkjWVCy2Sit1QQ4x3Dng8qDlSsZEet7g5Pq06MvTgw==}
595
+ engines: {node: '>=20'}
596
+
597
+ commander@7.2.0:
598
+ resolution: {integrity: sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==}
599
+ engines: {node: '>= 10'}
600
+
601
+ cookie@0.6.0:
602
+ resolution: {integrity: sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==}
603
+ engines: {node: '>= 0.6'}
604
+
605
+ d3-array@2.12.1:
606
+ resolution: {integrity: sha512-B0ErZK/66mHtEsR1TkPEEkwdy+WDesimkM5gpZr5Dsg54BiTA5RXtYW5qTLIAcekaS9xfZrzBLF/OAkB3Qn1YQ==}
607
+
608
+ d3-array@3.2.4:
609
+ resolution: {integrity: sha512-tdQAmyA18i4J7wprpYq8ClcxZy3SC31QMeByyCFyRt7BVHdREQZ5lpzoe5mFEYZUWe+oq8HBvk9JjpibyEV4Jg==}
610
+ engines: {node: '>=12'}
611
+
612
+ d3-chord@3.0.1:
613
+ resolution: {integrity: sha512-VE5S6TNa+j8msksl7HwjxMHDM2yNK3XCkusIlpX5kwauBfXuyLAtNg9jCp/iHH61tgI4sb6R/EIMWCqEIdjT/g==}
614
+ engines: {node: '>=12'}
615
+
616
+ d3-color@3.1.0:
617
+ resolution: {integrity: sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA==}
618
+ engines: {node: '>=12'}
619
+
620
+ d3-contour@4.0.2:
621
+ resolution: {integrity: sha512-4EzFTRIikzs47RGmdxbeUvLWtGedDUNkTcmzoeyg4sP/dvCexO47AaQL7VKy/gul85TOxw+IBgA8US2xwbToNA==}
622
+ engines: {node: '>=12'}
623
+
624
+ d3-delaunay@6.0.4:
625
+ resolution: {integrity: sha512-mdjtIZ1XLAM8bm/hx3WwjfHt6Sggek7qH043O8KEjDXN40xi3vx/6pYSVTwLjEgiXQTbvaouWKynLBiUZ6SK6A==}
626
+ engines: {node: '>=12'}
627
+
628
+ d3-dispatch@3.0.1:
629
+ resolution: {integrity: sha512-rzUyPU/S7rwUflMyLc1ETDeBj0NRuHKKAcvukozwhshr6g6c5d8zh4c2gQjY2bZ0dXeGLWc1PF174P2tVvKhfg==}
630
+ engines: {node: '>=12'}
631
+
632
+ d3-dsv@3.0.1:
633
+ resolution: {integrity: sha512-UG6OvdI5afDIFP9w4G0mNq50dSOsXHJaRE8arAS5o9ApWnIElp8GZw1Dun8vP8OyHOZ/QJUKUJwxiiCCnUwm+Q==}
634
+ engines: {node: '>=12'}
635
+ hasBin: true
636
+
637
+ d3-force@3.0.0:
638
+ resolution: {integrity: sha512-zxV/SsA+U4yte8051P4ECydjD/S+qeYtnaIyAs9tgHCqfguma/aAQDjo85A9Z6EKhBirHRJHXIgJUlffT4wdLg==}
639
+ engines: {node: '>=12'}
640
+
641
+ d3-format@3.1.2:
642
+ resolution: {integrity: sha512-AJDdYOdnyRDV5b6ArilzCPPwc1ejkHcoyFarqlPqT7zRYjhavcT3uSrqcMvsgh2CgoPbK3RCwyHaVyxYcP2Arg==}
643
+ engines: {node: '>=12'}
644
+
645
+ d3-geo-voronoi@2.1.0:
646
+ resolution: {integrity: sha512-kqE4yYuOjPbKdBXG0xztCacPwkVSK2REF1opSNrnqqtXJmNcM++UbwQ8SxvwP6IQTj9RvIjjK4qeiVsEfj0Z2Q==}
647
+ engines: {node: '>=12'}
648
+
649
+ d3-geo@3.1.1:
650
+ resolution: {integrity: sha512-637ln3gXKXOwhalDzinUgY83KzNWZRKbYubaG+fGVuc/dxO64RRljtCTnf5ecMyE1RIdtqpkVcq0IbtU2S8j2Q==}
651
+ engines: {node: '>=12'}
652
+
653
+ d3-hierarchy@3.1.2:
654
+ resolution: {integrity: sha512-FX/9frcub54beBdugHjDCdikxThEqjnR93Qt7PvQTOHxyiNCAlvMrHhclk3cD5VeAaq9fxmfRp+CnWw9rEMBuA==}
655
+ engines: {node: '>=12'}
656
+
657
+ d3-interpolate-path@2.3.0:
658
+ resolution: {integrity: sha512-tZYtGXxBmbgHsIc9Wms6LS5u4w6KbP8C09a4/ZYc4KLMYYqub57rRBUgpUr2CIarIrJEpdAWWxWQvofgaMpbKQ==}
659
+
660
+ d3-interpolate@3.0.1:
661
+ resolution: {integrity: sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g==}
662
+ engines: {node: '>=12'}
663
+
664
+ d3-path@1.0.9:
665
+ resolution: {integrity: sha512-VLaYcn81dtHVTjEHd8B+pbe9yHWpXKZUC87PzoFmsFrJqgFwDe/qxfp5MlfsfM1V5E/iVt0MmEbWQ7FVIXh/bg==}
666
+
667
+ d3-path@3.1.0:
668
+ resolution: {integrity: sha512-p3KP5HCf/bvjBSSKuXid6Zqijx7wIfNW+J/maPs+iwR35at5JCbLUT0LzF1cnjbCHWhqzQTIN2Jpe8pRebIEFQ==}
669
+ engines: {node: '>=12'}
670
+
671
+ d3-quadtree@3.0.1:
672
+ resolution: {integrity: sha512-04xDrxQTDTCFwP5H6hRhsRcb9xxv2RzkcsygFzmkSIOJy3PeRJP7sNk3VRIbKXcog561P9oU0/rVH6vDROAgUw==}
673
+ engines: {node: '>=12'}
674
+
675
+ d3-random@3.0.1:
676
+ resolution: {integrity: sha512-FXMe9GfxTxqd5D6jFsQ+DJ8BJS4E/fT5mqqdjovykEB2oFbTMDVdg1MGFxfQW+FBOGoB++k8swBrgwSHT1cUXQ==}
677
+ engines: {node: '>=12'}
678
+
679
+ d3-sankey@0.12.3:
680
+ resolution: {integrity: sha512-nQhsBRmM19Ax5xEIPLMY9ZmJ/cDvd1BG3UVvt5h3WRxKg5zGRbvnteTyWAbzeSvlh3tW7ZEmq4VwR5mB3tutmQ==}
681
+
682
+ d3-scale-chromatic@3.1.0:
683
+ resolution: {integrity: sha512-A3s5PWiZ9YCXFye1o246KoscMWqf8BsD9eRiJ3He7C9OBaxKhAd5TFCdEx/7VbKtxxTsu//1mMJFrEt572cEyQ==}
684
+ engines: {node: '>=12'}
685
+
686
+ d3-scale@4.0.2:
687
+ resolution: {integrity: sha512-GZW464g1SH7ag3Y7hXjf8RoUuAFIqklOAq3MRl4OaWabTFJY9PN/E1YklhXLh+OQ3fM9yS2nOkCoS+WLZ6kvxQ==}
688
+ engines: {node: '>=12'}
689
+
690
+ d3-shape@1.3.7:
691
+ resolution: {integrity: sha512-EUkvKjqPFUAZyOlhY5gzCxCeI0Aep04LwIRpsZ/mLFelJiUfnK56jo5JMDSE7yyP2kLSb6LtF+S5chMk7uqPqw==}
692
+
693
+ d3-shape@3.2.0:
694
+ resolution: {integrity: sha512-SaLBuwGm3MOViRq2ABk3eLoxwZELpH6zhl3FbAoJ7Vm1gofKx6El1Ib5z23NUEhF9AsGl7y+dzLe5Cw2AArGTA==}
695
+ engines: {node: '>=12'}
696
+
697
+ d3-tile@1.0.0:
698
+ resolution: {integrity: sha512-79fnTKpPMPDS5xQ0xuS9ir0165NEwwkFpe/DSOmc2Gl9ldYzKKRDWogmTTE8wAJ8NA7PMapNfEcyKhI9Lxdu5Q==}
699
+
700
+ d3-time-format@4.1.0:
701
+ resolution: {integrity: sha512-dJxPBlzC7NugB2PDLwo9Q8JiTR3M3e4/XANkreKSUxF8vvXKqm1Yfq4Q5dl8budlunRVlUUaDUgFt7eA8D6NLg==}
702
+ engines: {node: '>=12'}
703
+
704
+ d3-time@3.1.0:
705
+ resolution: {integrity: sha512-VqKjzBLejbSMT4IgbmVgDjpkYrNWUYJnbCGo874u7MMKIWsILRX+OpX/gTk8MqjpT1A/c6HY2dCA77ZN0lkQ2Q==}
706
+ engines: {node: '>=12'}
707
+
708
+ d3-timer@3.0.1:
709
+ resolution: {integrity: sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA==}
710
+ engines: {node: '>=12'}
711
+
712
+ d3-tricontour@1.1.0:
713
+ resolution: {integrity: sha512-G7gHKj89n2owmkGb6WX6ixcnQ0Kf/0wpa9VIh9DGdbHu8wdrlaHU4ir3/bFNERl8N8nn4G7e7qbtBG8N9caihQ==}
714
+ engines: {node: '>=12'}
715
+
716
+ dayjs@1.11.20:
717
+ resolution: {integrity: sha512-YbwwqR/uYpeoP4pu043q+LTDLFBLApUP6VxRihdfNTqu4ubqMlGDLd6ErXhEgsyvY0K6nCs7nggYumAN+9uEuQ==}
718
+
719
+ deepmerge@4.3.1:
720
+ resolution: {integrity: sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==}
721
+ engines: {node: '>=0.10.0'}
722
+
723
+ delaunator@5.1.0:
724
+ resolution: {integrity: sha512-AGrQ4QSgssa1NGmWmLPqN5NY2KajF5MqxetNEO+o0n3ZwZZeTmt7bBnvzHWrmkZFxGgr4HdyFgelzgi06otLuQ==}
725
+
726
+ dequal@2.0.3:
727
+ resolution: {integrity: sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==}
728
+ engines: {node: '>=6'}
729
+
730
+ detect-libc@2.1.2:
731
+ resolution: {integrity: sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==}
732
+ engines: {node: '>=8'}
733
+
734
+ devalue@5.7.1:
735
+ resolution: {integrity: sha512-MUbZ586EgQqdRnC4yDrlod3BEdyvE4TapGYHMW2CiaW+KkkFmWEFqBUaLltEZCGi0iFXCEjRF0OjF0DV2QHjOA==}
736
+
737
+ dlv@1.1.3:
738
+ resolution: {integrity: sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==}
739
+
740
+ effect@3.21.2:
741
+ resolution: {integrity: sha512-rXd2FGDM8KdjSIrc+mqEELo7ScW7xTVxEf1iInmPSpIde9/nyGuFM710cjTo7/EreGXiUX2MOonPpprbz2XHCg==}
742
+
743
+ enhanced-resolve@5.21.0:
744
+ resolution: {integrity: sha512-otxSQPw4lkOZWkHpB3zaEQs6gWYEsmX4xQF68ElXC/TWvGxGMSGOvoNbaLXm6/cS/fSfHtsEdw90y20PCd+sCA==}
745
+ engines: {node: '>=10.13.0'}
746
+
747
+ esm-env@1.2.2:
748
+ resolution: {integrity: sha512-Epxrv+Nr/CaL4ZcFGPJIYLWFom+YeV1DqMLHJoEd9SYRxNbaFruBwfEX/kkHUJf55j2+TUbmDcmuilbP1TmXHA==}
749
+
750
+ esrap@2.2.5:
751
+ resolution: {integrity: sha512-/yLB1538mag+dn0wsePTe8C0rDIjUOaJpMs2McodSzmM2msWcZsBSdRtg6HOBt0A/r82BN+Md3pgwSc/uWt2Ig==}
752
+ peerDependencies:
753
+ '@typescript-eslint/types': ^8.2.0
754
+ peerDependenciesMeta:
755
+ '@typescript-eslint/types':
756
+ optional: true
757
+
758
+ estree-walker@3.0.3:
759
+ resolution: {integrity: sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==}
760
+
761
+ fast-check@3.23.2:
762
+ resolution: {integrity: sha512-h5+1OzzfCC3Ef7VbtKdcv7zsstUQwUDlYpUTvjeUsJAssPgLn7QzbboPtL5ro04Mq0rPOsMzl7q5hIbRs2wD1A==}
763
+ engines: {node: '>=8.0.0'}
764
+
765
+ fdir@6.5.0:
766
+ resolution: {integrity: sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==}
767
+ engines: {node: '>=12.0.0'}
768
+ peerDependencies:
769
+ picomatch: ^3 || ^4
770
+ peerDependenciesMeta:
771
+ picomatch:
772
+ optional: true
773
+
774
+ find-replace@5.0.2:
775
+ resolution: {integrity: sha512-Y45BAiE3mz2QsrN2fb5QEtO4qb44NcS7en/0y9PEVsg351HsLeVclP8QPMH79Le9sH3rs5RSwJu99W0WPZO43Q==}
776
+ engines: {node: '>=14'}
777
+ peerDependencies:
778
+ '@75lb/nature': latest
779
+ peerDependenciesMeta:
780
+ '@75lb/nature':
781
+ optional: true
782
+
783
+ flatbuffers@25.9.23:
784
+ resolution: {integrity: sha512-MI1qs7Lo4Syw0EOzUl0xjs2lsoeqFku44KpngfIduHBYvzm8h2+7K8YMQh1JtVVVrUvhLpNwqVi4DERegUJhPQ==}
785
+
786
+ formsnap@2.0.1:
787
+ resolution: {integrity: sha512-iJSe4YKd/W6WhLwKDVJU9FQeaJRpEFuolhju7ZXlRpUVyDdqFdMP8AUBICgnVvQPyP41IPAlBa/v0Eo35iE6wQ==}
788
+ engines: {node: '>=18', pnpm: '>=8.7.0'}
789
+ peerDependencies:
790
+ svelte: ^5.0.0
791
+ sveltekit-superforms: ^2.19.0
792
+
793
+ fsevents@2.3.3:
794
+ resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==}
795
+ engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0}
796
+ os: [darwin]
797
+
798
+ graceful-fs@4.2.11:
799
+ resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==}
800
+
801
+ has-flag@4.0.0:
802
+ resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==}
803
+ engines: {node: '>=8'}
804
+
805
+ iconv-lite@0.6.3:
806
+ resolution: {integrity: sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==}
807
+ engines: {node: '>=0.10.0'}
808
+
809
+ inline-style-parser@0.2.7:
810
+ resolution: {integrity: sha512-Nb2ctOyNR8DqQoR0OwRG95uNWIC0C1lCgf5Naz5H6Ji72KZ8OcFZLz2P5sNgwlyoJ8Yif11oMuYs5pBQa86csA==}
811
+
812
+ internmap@1.0.1:
813
+ resolution: {integrity: sha512-lDB5YccMydFBtasVtxnZ3MRBHuaoE8GKsppq+EchKL2U4nK/DmEpPHNH8MZe5HkMtpSiTSOZwfN0tzYjO/lJEw==}
814
+
815
+ internmap@2.0.3:
816
+ resolution: {integrity: sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg==}
817
+ engines: {node: '>=12'}
818
+
819
+ is-reference@3.0.3:
820
+ resolution: {integrity: sha512-ixkJoqQvAP88E6wLydLGGqCJsrFUnqoH6HnaczB8XmDH1oaWU+xxdptvikTgaEhtZ53Ky6YXiBuUI2WXLMCwjw==}
821
+
822
+ jiti@2.6.1:
823
+ resolution: {integrity: sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ==}
824
+ hasBin: true
825
+
826
+ joi@17.13.3:
827
+ resolution: {integrity: sha512-otDA4ldcIx+ZXsKHWmp0YizCweVRZG96J10b0FevjfuncLO1oX59THoAmHkNubYJ+9gWsYsp5k8v4ib6oDv1fA==}
828
+
829
+ json-bignum@0.0.3:
830
+ resolution: {integrity: sha512-2WHyXj3OfHSgNyuzDbSxI1w2jgw5gkWSWhS7Qg4bWXx1nLk3jnbwfUeS0PSba3IzpTUWdHxBieELUzXRjQB2zg==}
831
+ engines: {node: '>=0.8'}
832
+
833
+ json-schema-to-ts@3.1.1:
834
+ resolution: {integrity: sha512-+DWg8jCJG2TEnpy7kOm/7/AxaYoaRbjVB4LFZLySZlWn8exGs3A4OLJR966cVvU26N7X9TWxl+Jsw7dzAqKT6g==}
835
+ engines: {node: '>=16'}
836
+
837
+ kleur@4.1.5:
838
+ resolution: {integrity: sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==}
839
+ engines: {node: '>=6'}
840
+
841
+ layerchart@2.0.0-next.48:
842
+ resolution: {integrity: sha512-XoEYBztamA8lMxtF/Jz3aDX0HMk8dI+o4fK9fSl8ecT2Tdx3DQUjtKGtlQAOFdwC/AWifeLmKq5cMTQt9COZPQ==}
843
+ peerDependencies:
844
+ svelte: ^5.0.0
845
+
846
+ libphonenumber-js@1.12.42:
847
+ resolution: {integrity: sha512-oKQFPTibqQwZZkChCDVMFVJXMZdyJNqDWZWYNn8BgyAaK/6yFJEowxCY0RVFirRyWP63hMRuKlkSEd9qlvbWXg==}
848
+
849
+ lightningcss-android-arm64@1.32.0:
850
+ resolution: {integrity: sha512-YK7/ClTt4kAK0vo6w3X+Pnm0D2cf2vPHbhOXdoNti1Ga0al1P4TBZhwjATvjNwLEBCnKvjJc2jQgHXH0NEwlAg==}
851
+ engines: {node: '>= 12.0.0'}
852
+ cpu: [arm64]
853
+ os: [android]
854
+
855
+ lightningcss-darwin-arm64@1.32.0:
856
+ resolution: {integrity: sha512-RzeG9Ju5bag2Bv1/lwlVJvBE3q6TtXskdZLLCyfg5pt+HLz9BqlICO7LZM7VHNTTn/5PRhHFBSjk5lc4cmscPQ==}
857
+ engines: {node: '>= 12.0.0'}
858
+ cpu: [arm64]
859
+ os: [darwin]
860
+
861
+ lightningcss-darwin-x64@1.32.0:
862
+ resolution: {integrity: sha512-U+QsBp2m/s2wqpUYT/6wnlagdZbtZdndSmut/NJqlCcMLTWp5muCrID+K5UJ6jqD2BFshejCYXniPDbNh73V8w==}
863
+ engines: {node: '>= 12.0.0'}
864
+ cpu: [x64]
865
+ os: [darwin]
866
+
867
+ lightningcss-freebsd-x64@1.32.0:
868
+ resolution: {integrity: sha512-JCTigedEksZk3tHTTthnMdVfGf61Fky8Ji2E4YjUTEQX14xiy/lTzXnu1vwiZe3bYe0q+SpsSH/CTeDXK6WHig==}
869
+ engines: {node: '>= 12.0.0'}
870
+ cpu: [x64]
871
+ os: [freebsd]
872
+
873
+ lightningcss-linux-arm-gnueabihf@1.32.0:
874
+ resolution: {integrity: sha512-x6rnnpRa2GL0zQOkt6rts3YDPzduLpWvwAF6EMhXFVZXD4tPrBkEFqzGowzCsIWsPjqSK+tyNEODUBXeeVHSkw==}
875
+ engines: {node: '>= 12.0.0'}
876
+ cpu: [arm]
877
+ os: [linux]
878
+
879
+ lightningcss-linux-arm64-gnu@1.32.0:
880
+ resolution: {integrity: sha512-0nnMyoyOLRJXfbMOilaSRcLH3Jw5z9HDNGfT/gwCPgaDjnx0i8w7vBzFLFR1f6CMLKF8gVbebmkUN3fa/kQJpQ==}
881
+ engines: {node: '>= 12.0.0'}
882
+ cpu: [arm64]
883
+ os: [linux]
884
+ libc: [glibc]
885
+
886
+ lightningcss-linux-arm64-musl@1.32.0:
887
+ resolution: {integrity: sha512-UpQkoenr4UJEzgVIYpI80lDFvRmPVg6oqboNHfoH4CQIfNA+HOrZ7Mo7KZP02dC6LjghPQJeBsvXhJod/wnIBg==}
888
+ engines: {node: '>= 12.0.0'}
889
+ cpu: [arm64]
890
+ os: [linux]
891
+ libc: [musl]
892
+
893
+ lightningcss-linux-x64-gnu@1.32.0:
894
+ resolution: {integrity: sha512-V7Qr52IhZmdKPVr+Vtw8o+WLsQJYCTd8loIfpDaMRWGUZfBOYEJeyJIkqGIDMZPwPx24pUMfwSxxI8phr/MbOA==}
895
+ engines: {node: '>= 12.0.0'}
896
+ cpu: [x64]
897
+ os: [linux]
898
+ libc: [glibc]
899
+
900
+ lightningcss-linux-x64-musl@1.32.0:
901
+ resolution: {integrity: sha512-bYcLp+Vb0awsiXg/80uCRezCYHNg1/l3mt0gzHnWV9XP1W5sKa5/TCdGWaR/zBM2PeF/HbsQv/j2URNOiVuxWg==}
902
+ engines: {node: '>= 12.0.0'}
903
+ cpu: [x64]
904
+ os: [linux]
905
+ libc: [musl]
906
+
907
+ lightningcss-win32-arm64-msvc@1.32.0:
908
+ resolution: {integrity: sha512-8SbC8BR40pS6baCM8sbtYDSwEVQd4JlFTOlaD3gWGHfThTcABnNDBda6eTZeqbofalIJhFx0qKzgHJmcPTnGdw==}
909
+ engines: {node: '>= 12.0.0'}
910
+ cpu: [arm64]
911
+ os: [win32]
912
+
913
+ lightningcss-win32-x64-msvc@1.32.0:
914
+ resolution: {integrity: sha512-Amq9B/SoZYdDi1kFrojnoqPLxYhQ4Wo5XiL8EVJrVsB8ARoC1PWW6VGtT0WKCemjy8aC+louJnjS7U18x3b06Q==}
915
+ engines: {node: '>= 12.0.0'}
916
+ cpu: [x64]
917
+ os: [win32]
918
+
919
+ lightningcss@1.32.0:
920
+ resolution: {integrity: sha512-NXYBzinNrblfraPGyrbPoD19C1h9lfI/1mzgWYvXUTe414Gz/X1FD2XBZSZM7rRTrMA8JL3OtAaGifrIKhQ5yQ==}
921
+ engines: {node: '>= 12.0.0'}
922
+
923
+ locate-character@3.0.0:
924
+ resolution: {integrity: sha512-SW13ws7BjaeJ6p7Q6CO2nchbYEc3X3J6WrmTTDto7yMPqVSZTUyY5Tjbid+Ab8gLnATtygYtiDIJGQRRn2ZOiA==}
925
+
926
+ lodash.camelcase@4.3.0:
927
+ resolution: {integrity: sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA==}
928
+
929
+ lz-string@1.5.0:
930
+ resolution: {integrity: sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ==}
931
+ hasBin: true
932
+
933
+ magic-string@0.30.21:
934
+ resolution: {integrity: sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==}
935
+
936
+ mediabunny@1.42.0:
937
+ resolution: {integrity: sha512-s9ypTqLi6kbh95gC+YaJlG0PkLvMxu37Q/wO/pFZx0fUCA5Ym5mp+2dWoa83mKQ3Uo18aNlgev5iJ5ESZqWwgQ==}
938
+
939
+ memoize-weak@1.0.2:
940
+ resolution: {integrity: sha512-gj39xkrjEw7nCn4nJ1M5ms6+MyMlyiGmttzsqAUsAKn6bYKwuTHh/AO3cKPF8IBrTIYTxb0wWXFs3E//Y8VoWQ==}
941
+
942
+ memoize@10.2.0:
943
+ resolution: {integrity: sha512-DeC6b7QBrZsRs3Y02A6A7lQyzFbsQbqgjI6UW0GigGWV+u1s25TycMr0XHZE4cJce7rY/vyw2ctMQqfDkIhUEA==}
944
+ engines: {node: '>=18'}
945
+
946
+ mimic-function@5.0.1:
947
+ resolution: {integrity: sha512-VP79XUPxV2CigYP3jWwAUFSku2aKqBH7uTAapFWCBqutsbmDo96KY5o8uh6U+/YSIn5OxJnXp73beVkpqMIGhA==}
948
+ engines: {node: '>=18'}
949
+
950
+ mode-watcher@1.1.0:
951
+ resolution: {integrity: sha512-mUT9RRGPDYenk59qJauN1rhsIMKBmWA3xMF+uRwE8MW/tjhaDSCCARqkSuDTq8vr4/2KcAxIGVjACxTjdk5C3g==}
952
+ peerDependencies:
953
+ svelte: ^5.27.0
954
+
955
+ mri@1.2.0:
956
+ resolution: {integrity: sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==}
957
+ engines: {node: '>=4'}
958
+
959
+ mrmime@2.0.1:
960
+ resolution: {integrity: sha512-Y3wQdFg2Va6etvQ5I82yUhGdsKrcYox6p7FfL1LbK2J4V01F9TGlepTIhnK24t7koZibmg82KGglhA1XK5IsLQ==}
961
+ engines: {node: '>=10'}
962
+
963
+ nanoid@3.3.11:
964
+ resolution: {integrity: sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==}
965
+ engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1}
966
+ hasBin: true
967
+
968
+ node-fetch-native@1.6.7:
969
+ resolution: {integrity: sha512-g9yhqoedzIUm0nTnTqAQvueMPVOuIY16bqgAJJC8XOOubYFNwz6IER9qs0Gq2Xd0+CecCKFjtdDTMA4u4xG06Q==}
970
+
971
+ normalize-url@8.1.1:
972
+ resolution: {integrity: sha512-JYc0DPlpGWB40kH5g07gGTrYuMqV653k3uBKY6uITPWds3M0ov3GaWGp9lbE3Bzngx8+XkfzgvASb9vk9JDFXQ==}
973
+ engines: {node: '>=14.16'}
974
+
975
+ obug@2.1.1:
976
+ resolution: {integrity: sha512-uTqF9MuPraAQ+IsnPf366RG4cP9RtUi7MLO1N3KEc+wb0a6yKpeL0lmk2IB1jY5KHPAlTc6T/JRdC/YqxHNwkQ==}
977
+
978
+ paneforge@1.0.2:
979
+ resolution: {integrity: sha512-KzmIXQH1wCfwZ4RsMohD/IUtEjVhteR+c+ulb/CHYJHX8SuDXoJmChtsc/Xs5Wl8NHS4L5Q7cxL8MG40gSU1bA==}
980
+ peerDependencies:
981
+ svelte: ^5.29.0
982
+
983
+ parquet-wasm@0.7.1:
984
+ resolution: {integrity: sha512-fjEGpMApzt3mpI2pUxdRgQGu5G+s4nr0vm5xn43JO7jxdYzzu2fHrVrTHtfeEhtB6vfvTzJBz0WydDYzLWvszQ==}
985
+
986
+ phosphor-svelte@3.1.0:
987
+ resolution: {integrity: sha512-nldtxx+XCgNREvrb7O5xgDsefytXpSkPTx8Rnu3f2qQCUZLDV1rLxYSd2Jcwckuo9lZB1qKMqGR17P4UDC0PrA==}
988
+ peerDependencies:
989
+ svelte: ^5.0.0 || ^5.0.0-next.96
990
+ vite: '>=5'
991
+ peerDependenciesMeta:
992
+ vite:
993
+ optional: true
994
+
995
+ picocolors@1.1.1:
996
+ resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==}
997
+
998
+ picomatch@4.0.4:
999
+ resolution: {integrity: sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==}
1000
+ engines: {node: '>=12'}
1001
+
1002
+ postcss@8.5.12:
1003
+ resolution: {integrity: sha512-W62t/Se6rA0Az3DfCL0AqJwXuKwBeYg6nOaIgzP+xZ7N5BFCI7DYi1qs6ygUYT6rvfi6t9k65UMLJC+PHZpDAA==}
1004
+ engines: {node: ^10 || ^12 || >=14}
1005
+
1006
+ property-expr@2.0.6:
1007
+ resolution: {integrity: sha512-SVtmxhRE/CGkn3eZY1T6pC8Nln6Fr/lu1mKSgRud0eC73whjGfoAogbn78LkD8aFL0zz3bAFerKSnOl7NlErBA==}
1008
+
1009
+ pure-rand@6.1.0:
1010
+ resolution: {integrity: sha512-bVWawvoZoBYpp6yIoQtQXHZjmz35RSVHnUOTefl8Vcjr8snTPY1wnpSPMWekcFwbxI6gtmT7rSYPFvz71ldiOA==}
1011
+
1012
+ readdirp@4.1.2:
1013
+ resolution: {integrity: sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==}
1014
+ engines: {node: '>= 14.18.0'}
1015
+
1016
+ robust-predicates@3.0.3:
1017
+ resolution: {integrity: sha512-NS3levdsRIUOmiJ8FZWCP7LG3QpJyrs/TE0Zpf1yvZu8cAJJ6QMW92H1c7kWpdIHo8RvmLxN/o2JXTKHp74lUA==}
1018
+
1019
+ rolldown@1.0.0-rc.17:
1020
+ resolution: {integrity: sha512-ZrT53oAKrtA4+YtBWPQbtPOxIbVDbxT0orcYERKd63VJTF13zPcgXTvD4843L8pcsI7M6MErt8QtON6lrB9tyA==}
1021
+ engines: {node: ^20.19.0 || >=22.12.0}
1022
+ hasBin: true
1023
+
1024
+ runed@0.23.4:
1025
+ resolution: {integrity: sha512-9q8oUiBYeXIDLWNK5DfCWlkL0EW3oGbk845VdKlPeia28l751VpfesaB/+7pI6rnbx1I6rqoZ2fZxptOJLxILA==}
1026
+ peerDependencies:
1027
+ svelte: ^5.7.0
1028
+
1029
+ runed@0.25.0:
1030
+ resolution: {integrity: sha512-7+ma4AG9FT2sWQEA0Egf6mb7PBT2vHyuHail1ie8ropfSjvZGtEAx8YTmUjv/APCsdRRxEVvArNjALk9zFSOrg==}
1031
+ peerDependencies:
1032
+ svelte: ^5.7.0
1033
+
1034
+ runed@0.28.0:
1035
+ resolution: {integrity: sha512-k2xx7RuO9hWcdd9f+8JoBeqWtYrm5CALfgpkg2YDB80ds/QE4w0qqu34A7fqiAwiBBSBQOid7TLxwxVC27ymWQ==}
1036
+ peerDependencies:
1037
+ svelte: ^5.7.0
1038
+
1039
+ runed@0.29.2:
1040
+ resolution: {integrity: sha512-0cq6cA6sYGZwl/FvVqjx9YN+1xEBu9sDDyuWdDW1yWX7JF2wmvmVKfH+hVCZs+csW+P3ARH92MjI3H9QTagOQA==}
1041
+ peerDependencies:
1042
+ svelte: ^5.7.0
1043
+
1044
+ runed@0.35.1:
1045
+ resolution: {integrity: sha512-2F4Q/FZzbeJTFdIS/PuOoPRSm92sA2LhzTnv6FXhCoENb3huf5+fDuNOg1LNvGOouy3u/225qxmuJvcV3IZK5Q==}
1046
+ peerDependencies:
1047
+ '@sveltejs/kit': ^2.21.0
1048
+ svelte: ^5.7.0
1049
+ peerDependenciesMeta:
1050
+ '@sveltejs/kit':
1051
+ optional: true
1052
+
1053
+ runed@0.37.1:
1054
+ resolution: {integrity: sha512-MeFY73xBW8IueWBm012nNFIGy19WUGPLtknavyUPMpnyt350M47PhGSGrGoSLbidwn+Zlt/O0cp8/OZE3LASWA==}
1055
+ peerDependencies:
1056
+ '@sveltejs/kit': ^2.21.0
1057
+ svelte: ^5.7.0
1058
+ zod: ^4.1.0
1059
+ peerDependenciesMeta:
1060
+ '@sveltejs/kit':
1061
+ optional: true
1062
+ zod:
1063
+ optional: true
1064
+
1065
+ rw@1.3.3:
1066
+ resolution: {integrity: sha512-PdhdWy89SiZogBLaw42zdeqtRJ//zFd2PgQavcICDUgJT5oW10QCRKbJ6bg4r0/UY2M6BWd5tkxuGFRvCkgfHQ==}
1067
+
1068
+ sade@1.8.1:
1069
+ resolution: {integrity: sha512-xal3CZX1Xlo/k4ApwCFrHVACi9fBqJ7V+mwhBsuf/1IOKbBy098Fex+Wa/5QMubw09pSZ/u8EY8PWgevJsXp1A==}
1070
+ engines: {node: '>=6'}
1071
+
1072
+ safer-buffer@2.1.2:
1073
+ resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==}
1074
+
1075
+ set-cookie-parser@3.1.0:
1076
+ resolution: {integrity: sha512-kjnC1DXBHcxaOaOXBHBeRtltsDG2nUiUni+jP92M9gYdW12rsmx92UsfpH7o5tDRs7I1ZZPSQJQGv3UaRfCiuw==}
1077
+
1078
+ shadcn-svelte@1.2.7:
1079
+ resolution: {integrity: sha512-mWuQk4H4gtV+J2wJQ7nEPKNnB/v86AALFryZU0SSM7ChHmJJMZ1kH+qIuxYKrXm9vOOOcSWHRsWzPDB71DnjYA==}
1080
+ hasBin: true
1081
+ peerDependencies:
1082
+ svelte: ^5.0.0
1083
+
1084
+ sirv@3.0.2:
1085
+ resolution: {integrity: sha512-2wcC/oGxHis/BoHkkPwldgiPSYcpZK3JU28WoMVv55yHJgcZ8rlXvuG9iZggz+sU1d4bRgIGASwyWqjxu3FM0g==}
1086
+ engines: {node: '>=18'}
1087
+
1088
+ source-map-js@1.2.1:
1089
+ resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==}
1090
+ engines: {node: '>=0.10.0'}
1091
+
1092
+ style-to-object@1.0.14:
1093
+ resolution: {integrity: sha512-LIN7rULI0jBscWQYaSswptyderlarFkjQ+t79nzty8tcIAceVomEVlLzH5VP4Cmsv6MtKhs7qaAiwlcp+Mgaxw==}
1094
+
1095
+ superstruct@2.0.2:
1096
+ resolution: {integrity: sha512-uV+TFRZdXsqXTL2pRvujROjdZQ4RAlBUS5BTh9IGm+jTqQntYThciG/qu57Gs69yjnVUSqdxF9YLmSnpupBW9A==}
1097
+ engines: {node: '>=14.0.0'}
1098
+
1099
+ supports-color@7.2.0:
1100
+ resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==}
1101
+ engines: {node: '>=8'}
1102
+
1103
+ svelte-check@4.4.6:
1104
+ resolution: {integrity: sha512-kP1zG81EWaFe9ZyTv4ZXv44Csi6Pkdpb7S3oj6m+K2ec/IcDg/a8LsFsnVLqm2nxtkSwsd5xPj/qFkTBgXHXjg==}
1105
+ engines: {node: '>= 18.0.0'}
1106
+ hasBin: true
1107
+ peerDependencies:
1108
+ svelte: ^4.0.0 || ^5.0.0-next.0
1109
+ typescript: '>=5.0.0'
1110
+
1111
+ svelte-sonner@1.1.1:
1112
+ resolution: {integrity: sha512-5cd3p7wa4cq0NsqslMwdlPb7x1JglEZ/GKrLePWNr5bCxR1nagAVrY01FRFrXfUGs41miLt3C327+8XJo5BzZw==}
1113
+ peerDependencies:
1114
+ svelte: ^5.0.0
1115
+
1116
+ svelte-toolbelt@0.10.6:
1117
+ resolution: {integrity: sha512-YWuX+RE+CnWYx09yseAe4ZVMM7e7GRFZM6OYWpBKOb++s+SQ8RBIMMe+Bs/CznBMc0QPLjr+vDBxTAkozXsFXQ==}
1118
+ engines: {node: '>=18', pnpm: '>=8.7.0'}
1119
+ peerDependencies:
1120
+ svelte: ^5.30.2
1121
+
1122
+ svelte-toolbelt@0.5.0:
1123
+ resolution: {integrity: sha512-t3tenZcnfQoIeRuQf/jBU7bvTeT3TGkcEE+1EUr5orp0lR7NEpprflpuie3x9Dn0W9nOKqs3HwKGJeeN5Ok1sQ==}
1124
+ engines: {node: '>=18', pnpm: '>=8.7.0'}
1125
+ peerDependencies:
1126
+ svelte: ^5.0.0-next.126
1127
+
1128
+ svelte-toolbelt@0.7.1:
1129
+ resolution: {integrity: sha512-HcBOcR17Vx9bjaOceUvxkY3nGmbBmCBBbuWLLEWO6jtmWH8f/QoWmbyUfQZrpDINH39en1b8mptfPQT9VKQ1xQ==}
1130
+ engines: {node: '>=18', pnpm: '>=8.7.0'}
1131
+ peerDependencies:
1132
+ svelte: ^5.0.0
1133
+
1134
+ svelte-toolbelt@0.9.3:
1135
+ resolution: {integrity: sha512-HCSWxCtVmv+c6g1ACb8LTwHVbDqLKJvHpo6J8TaqwUme2hj9ATJCpjCPNISR1OCq2Q4U1KT41if9ON0isINQZw==}
1136
+ engines: {node: '>=18', pnpm: '>=8.7.0'}
1137
+ peerDependencies:
1138
+ svelte: ^5.30.2
1139
+
1140
+ svelte@5.55.5:
1141
+ resolution: {integrity: sha512-2uCs/LZ9us+AktdzYJM8OcxQ8qnPS1kpaO7syGT/MgO+6Qr1Ybl+TqPq+97u7PHqmmMlye5ZkoyXONy5mjjAbw==}
1142
+ engines: {node: '>=18'}
1143
+
1144
+ sveltekit-superforms@2.30.1:
1145
+ resolution: {integrity: sha512-wBzyqsE0idvEJWuNJ+HCiAtdxa7Z55GZ8jmtlVHJfonrk9bRYC49MoPaloYyFoYuU3QPy6Omna/Qzn1kaIkgew==}
1146
+ peerDependencies:
1147
+ '@sveltejs/kit': 1.x || 2.x
1148
+ svelte: 3.x || 4.x || >=5.0.0-next.51
1149
+
1150
+ tabbable@6.4.0:
1151
+ resolution: {integrity: sha512-05PUHKSNE8ou2dwIxTngl4EzcnsCDZGJ/iCLtDflR/SHB/ny14rXc+qU5P4mG9JkusiV7EivzY9Mhm55AzAvCg==}
1152
+
1153
+ table-layout@4.1.1:
1154
+ resolution: {integrity: sha512-iK5/YhZxq5GO5z8wb0bY1317uDF3Zjpha0QFFLA8/trAoiLbQD0HUbMesEaxyzUgDxi2QlcbM8IvqOlEjgoXBA==}
1155
+ engines: {node: '>=12.17'}
1156
+
1157
+ tailwind-merge@3.5.0:
1158
+ resolution: {integrity: sha512-I8K9wewnVDkL1NTGoqWmVEIlUcB9gFriAEkXkfCjX5ib8ezGxtR3xD7iZIxrfArjEsH7F1CHD4RFUtxefdqV/A==}
1159
+
1160
+ tailwind-variants@3.2.2:
1161
+ resolution: {integrity: sha512-Mi4kHeMTLvKlM98XPnK+7HoBPmf4gygdFmqQPaDivc3DpYS6aIY6KiG/PgThrGvii5YZJqRsPz0aPyhoFzmZgg==}
1162
+ engines: {node: '>=16.x', pnpm: '>=7.x'}
1163
+ peerDependencies:
1164
+ tailwind-merge: '>=3.0.0'
1165
+ tailwindcss: '*'
1166
+ peerDependenciesMeta:
1167
+ tailwind-merge:
1168
+ optional: true
1169
+
1170
+ tailwindcss@4.2.4:
1171
+ resolution: {integrity: sha512-HhKppgO81FQof5m6TEnuBWCZGgfRAWbaeOaGT00KOy/Pf/j6oUihdvBpA7ltCeAvZpFhW3j0PTclkxsd4IXYDA==}
1172
+
1173
+ tapable@2.3.3:
1174
+ resolution: {integrity: sha512-uxc/zpqFg6x7C8vOE7lh6Lbda8eEL9zmVm/PLeTPBRhh1xCgdWaQ+J1CUieGpIfm2HdtsUpRv+HshiasBMcc6A==}
1175
+ engines: {node: '>=6'}
1176
+
1177
+ tiny-case@1.0.3:
1178
+ resolution: {integrity: sha512-Eet/eeMhkO6TX8mnUteS9zgPbUMQa4I6Kkp5ORiBD5476/m+PIRiumP5tmh5ioJpH7k51Kehawy2UDfsnxxY8Q==}
1179
+
1180
+ tinyglobby@0.2.16:
1181
+ resolution: {integrity: sha512-pn99VhoACYR8nFHhxqix+uvsbXineAasWm5ojXoN8xEwK5Kd3/TrhNn1wByuD52UxWRLy8pu+kRMniEi6Eq9Zg==}
1182
+ engines: {node: '>=12.0.0'}
1183
+
1184
+ toposort@2.0.2:
1185
+ resolution: {integrity: sha512-0a5EOkAUp8D4moMi2W8ZF8jcga7BgZd91O/yabJCFY8az+XSzeGyTKs0Aoo897iV1Nj6guFq8orWDS96z91oGg==}
1186
+
1187
+ totalist@3.0.1:
1188
+ resolution: {integrity: sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ==}
1189
+ engines: {node: '>=6'}
1190
+
1191
+ ts-algebra@2.0.0:
1192
+ resolution: {integrity: sha512-FPAhNPFMrkwz76P7cdjdmiShwMynZYN6SgOujD1urY4oNm80Ou9oMdmbR45LotcKOXoy7wSmHkRFE6Mxbrhefw==}
1193
+
1194
+ ts-deepmerge@7.0.3:
1195
+ resolution: {integrity: sha512-Du/ZW2RfwV/D4cmA5rXafYjBQVuvu4qGiEEla4EmEHVHgRdx68Gftx7i66jn2bzHPwSVZY36Ae6OuDn9el4ZKA==}
1196
+ engines: {node: '>=14.13.1'}
1197
+
1198
+ tslib@2.8.1:
1199
+ resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==}
1200
+
1201
+ tw-animate-css@1.4.0:
1202
+ resolution: {integrity: sha512-7bziOlRqH0hJx80h/3mbicLW7o8qLsH5+RaLR2t+OHM3D0JlWGODQKQ4cxbK7WlvmUxpcj6Kgu6EKqjrGFe3QQ==}
1203
+
1204
+ type-fest@2.19.0:
1205
+ resolution: {integrity: sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA==}
1206
+ engines: {node: '>=12.20'}
1207
+
1208
+ typebox@1.1.34:
1209
+ resolution: {integrity: sha512-V0fM5W5DTXlEMDxqtX1dQ25HR1RQ11DPUVrIup4sJi1yQtIyI30SHfxBy/HjXKL1CtUqc5or2igA/wa/v4hMKQ==}
1210
+
1211
+ typescript@6.0.3:
1212
+ resolution: {integrity: sha512-y2TvuxSZPDyQakkFRPZHKFm+KKVqIisdg9/CZwm9ftvKXLP8NRWj38/ODjNbr43SsoXqNuAisEf1GdCxqWcdBw==}
1213
+ engines: {node: '>=14.17'}
1214
+ hasBin: true
1215
+
1216
+ typical@7.3.0:
1217
+ resolution: {integrity: sha512-ya4mg/30vm+DOWfBg4YK3j2WD6TWtRkCbasOJr40CseYENzCUby/7rIvXA99JGsQHeNxLbnXdyLLxKSv3tauFw==}
1218
+ engines: {node: '>=12.17'}
1219
+
1220
+ undici-types@7.16.0:
1221
+ resolution: {integrity: sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==}
1222
+
1223
+ valibot@1.3.1:
1224
+ resolution: {integrity: sha512-sfdRir/QFM0JaF22hqTroPc5xy4DimuGQVKFrzF1YfGwaS1nJot3Y8VqMdLO2Lg27fMzat2yD3pY5PbAYO39Gg==}
1225
+ peerDependencies:
1226
+ typescript: '>=5'
1227
+ peerDependenciesMeta:
1228
+ typescript:
1229
+ optional: true
1230
+
1231
+ validator@13.15.35:
1232
+ resolution: {integrity: sha512-TQ5pAGhd5whStmqWvYF4OjQROlmv9SMFVt37qoCBdqRffuuklWYQlCNnEs2ZaIBD1kZRNnikiZOS1eqgkar0iw==}
1233
+ engines: {node: '>= 0.10'}
1234
+
1235
+ vaul-svelte@1.0.0-next.7:
1236
+ resolution: {integrity: sha512-7zN7Bi3dFQixvvbUJY9uGDe7Ws/dGZeBQR2pXdXmzQiakjrxBvWo0QrmsX3HK+VH+SZOltz378cmgmCS9f9rSg==}
1237
+ engines: {node: '>=18', pnpm: '>=8.7.0'}
1238
+ peerDependencies:
1239
+ svelte: ^5.0.0
1240
+
1241
+ vite@8.0.10:
1242
+ resolution: {integrity: sha512-rZuUu9j6J5uotLDs+cAA4O5H4K1SfPliUlQwqa6YEwSrWDZzP4rhm00oJR5snMewjxF5V/K3D4kctsUTsIU9Mw==}
1243
+ engines: {node: ^20.19.0 || >=22.12.0}
1244
+ hasBin: true
1245
+ peerDependencies:
1246
+ '@types/node': ^20.19.0 || >=22.12.0
1247
+ '@vitejs/devtools': ^0.1.0
1248
+ esbuild: ^0.27.0 || ^0.28.0
1249
+ jiti: '>=1.21.0'
1250
+ less: ^4.0.0
1251
+ sass: ^1.70.0
1252
+ sass-embedded: ^1.70.0
1253
+ stylus: '>=0.54.8'
1254
+ sugarss: ^5.0.0
1255
+ terser: ^5.16.0
1256
+ tsx: ^4.8.1
1257
+ yaml: ^2.4.2
1258
+ peerDependenciesMeta:
1259
+ '@types/node':
1260
+ optional: true
1261
+ '@vitejs/devtools':
1262
+ optional: true
1263
+ esbuild:
1264
+ optional: true
1265
+ jiti:
1266
+ optional: true
1267
+ less:
1268
+ optional: true
1269
+ sass:
1270
+ optional: true
1271
+ sass-embedded:
1272
+ optional: true
1273
+ stylus:
1274
+ optional: true
1275
+ sugarss:
1276
+ optional: true
1277
+ terser:
1278
+ optional: true
1279
+ tsx:
1280
+ optional: true
1281
+ yaml:
1282
+ optional: true
1283
+
1284
+ vitefu@1.1.3:
1285
+ resolution: {integrity: sha512-ub4okH7Z5KLjb6hDyjqrGXqWtWvoYdU3IGm/NorpgHncKoLTCfRIbvlhBm7r0YstIaQRYlp4yEbFqDcKSzXSSg==}
1286
+ peerDependencies:
1287
+ vite: ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0
1288
+ peerDependenciesMeta:
1289
+ vite:
1290
+ optional: true
1291
+
1292
+ wordwrapjs@5.1.1:
1293
+ resolution: {integrity: sha512-0yweIbkINJodk27gX9LBGMzyQdBDan3s/dEAiwBOj+Mf0PPyWL6/rikalkv8EeD0E8jm4o5RXEOrFTP3NXbhJg==}
1294
+ engines: {node: '>=12.17'}
1295
+
1296
+ yup@1.7.1:
1297
+ resolution: {integrity: sha512-GKHFX2nXul2/4Dtfxhozv701jLQHdf6J34YDh2cEkpqoo8le5Mg6/LrdseVLrFarmFygZTlfIhHx/QKfb/QWXw==}
1298
+
1299
+ zimmerframe@1.1.4:
1300
+ resolution: {integrity: sha512-B58NGBEoc8Y9MWWCQGl/gq9xBCe4IiKM0a2x7GZdQKOW5Exr8S1W24J6OgM1njK8xCRGvAJIL/MxXHf6SkmQKQ==}
1301
+
1302
+ zod-v3-to-json-schema@4.0.0:
1303
+ resolution: {integrity: sha512-KixLrhX/uPmRFnDgsZrzrk4x5SSJA+PmaE5adbfID9+3KPJcdxqRobaHU397EfWBqfQircrjKqvEqZ/mW5QH6w==}
1304
+ peerDependencies:
1305
+ zod: ^3.25 || ^4.0.14
1306
+
1307
+ zod@4.3.6:
1308
+ resolution: {integrity: sha512-rftlrkhHZOcjDwkGlnUtZZkvaPHCsDATp4pGpuOOMDaTdDDXF91wuVDJoWoPsKX/3YPQ5fHuF3STjcYyKr+Qhg==}
1309
+
1310
+ snapshots:
1311
+
1312
+ '@ark/schema@0.56.0':
1313
+ dependencies:
1314
+ '@ark/util': 0.56.0
1315
+ optional: true
1316
+
1317
+ '@ark/util@0.56.0':
1318
+ optional: true
1319
+
1320
+ '@babel/runtime@7.29.2':
1321
+ optional: true
1322
+
1323
+ '@dagrejs/dagre@2.0.4':
1324
+ dependencies:
1325
+ '@dagrejs/graphlib': 3.0.4
1326
+
1327
+ '@dagrejs/graphlib@3.0.4': {}
1328
+
1329
+ '@emnapi/core@1.10.0':
1330
+ dependencies:
1331
+ '@emnapi/wasi-threads': 1.2.1
1332
+ tslib: 2.8.1
1333
+ optional: true
1334
+
1335
+ '@emnapi/runtime@1.10.0':
1336
+ dependencies:
1337
+ tslib: 2.8.1
1338
+ optional: true
1339
+
1340
+ '@emnapi/wasi-threads@1.2.1':
1341
+ dependencies:
1342
+ tslib: 2.8.1
1343
+ optional: true
1344
+
1345
+ '@exodus/schemasafe@1.3.0':
1346
+ optional: true
1347
+
1348
+ '@floating-ui/core@1.7.5':
1349
+ dependencies:
1350
+ '@floating-ui/utils': 0.2.11
1351
+
1352
+ '@floating-ui/dom@1.7.6':
1353
+ dependencies:
1354
+ '@floating-ui/core': 1.7.5
1355
+ '@floating-ui/utils': 0.2.11
1356
+
1357
+ '@floating-ui/utils@0.2.11': {}
1358
+
1359
+ '@fontsource-variable/oxanium@5.2.8': {}
1360
+
1361
+ '@fontsource-variable/roboto-slab@5.2.8': {}
1362
+
1363
+ '@hapi/hoek@9.3.0':
1364
+ optional: true
1365
+
1366
+ '@hapi/topo@5.1.0':
1367
+ dependencies:
1368
+ '@hapi/hoek': 9.3.0
1369
+ optional: true
1370
+
1371
+ '@internationalized/date@3.12.1':
1372
+ dependencies:
1373
+ '@swc/helpers': 0.5.21
1374
+
1375
+ '@jridgewell/gen-mapping@0.3.13':
1376
+ dependencies:
1377
+ '@jridgewell/sourcemap-codec': 1.5.5
1378
+ '@jridgewell/trace-mapping': 0.3.31
1379
+
1380
+ '@jridgewell/remapping@2.3.5':
1381
+ dependencies:
1382
+ '@jridgewell/gen-mapping': 0.3.13
1383
+ '@jridgewell/trace-mapping': 0.3.31
1384
+
1385
+ '@jridgewell/resolve-uri@3.1.2': {}
1386
+
1387
+ '@jridgewell/sourcemap-codec@1.5.5': {}
1388
+
1389
+ '@jridgewell/trace-mapping@0.3.31':
1390
+ dependencies:
1391
+ '@jridgewell/resolve-uri': 3.1.2
1392
+ '@jridgewell/sourcemap-codec': 1.5.5
1393
+
1394
+ '@layerstack/svelte-actions@1.0.1-next.18':
1395
+ dependencies:
1396
+ '@floating-ui/dom': 1.7.6
1397
+ '@layerstack/utils': 2.0.0-next.18
1398
+ d3-scale: 4.0.2
1399
+
1400
+ '@layerstack/svelte-state@0.1.0-next.23':
1401
+ dependencies:
1402
+ '@layerstack/utils': 2.0.0-next.18
1403
+
1404
+ '@layerstack/tailwind@2.0.0-next.21':
1405
+ dependencies:
1406
+ '@layerstack/utils': 2.0.0-next.18
1407
+ clsx: 2.1.1
1408
+ d3-array: 3.2.4
1409
+ tailwind-merge: 3.5.0
1410
+
1411
+ '@layerstack/utils@2.0.0-next.18':
1412
+ dependencies:
1413
+ d3-array: 3.2.4
1414
+ d3-time: 3.1.0
1415
+ d3-time-format: 4.1.0
1416
+
1417
+ '@napi-rs/wasm-runtime@1.1.4(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)':
1418
+ dependencies:
1419
+ '@emnapi/core': 1.10.0
1420
+ '@emnapi/runtime': 1.10.0
1421
+ '@tybys/wasm-util': 0.10.1
1422
+ optional: true
1423
+
1424
+ '@oxc-project/types@0.127.0': {}
1425
+
1426
+ '@polka/url@1.0.0-next.29': {}
1427
+
1428
+ '@poppinss/macroable@1.1.2':
1429
+ optional: true
1430
+
1431
+ '@rolldown/binding-android-arm64@1.0.0-rc.17':
1432
+ optional: true
1433
+
1434
+ '@rolldown/binding-darwin-arm64@1.0.0-rc.17':
1435
+ optional: true
1436
+
1437
+ '@rolldown/binding-darwin-x64@1.0.0-rc.17':
1438
+ optional: true
1439
+
1440
+ '@rolldown/binding-freebsd-x64@1.0.0-rc.17':
1441
+ optional: true
1442
+
1443
+ '@rolldown/binding-linux-arm-gnueabihf@1.0.0-rc.17':
1444
+ optional: true
1445
+
1446
+ '@rolldown/binding-linux-arm64-gnu@1.0.0-rc.17':
1447
+ optional: true
1448
+
1449
+ '@rolldown/binding-linux-arm64-musl@1.0.0-rc.17':
1450
+ optional: true
1451
+
1452
+ '@rolldown/binding-linux-ppc64-gnu@1.0.0-rc.17':
1453
+ optional: true
1454
+
1455
+ '@rolldown/binding-linux-s390x-gnu@1.0.0-rc.17':
1456
+ optional: true
1457
+
1458
+ '@rolldown/binding-linux-x64-gnu@1.0.0-rc.17':
1459
+ optional: true
1460
+
1461
+ '@rolldown/binding-linux-x64-musl@1.0.0-rc.17':
1462
+ optional: true
1463
+
1464
+ '@rolldown/binding-openharmony-arm64@1.0.0-rc.17':
1465
+ optional: true
1466
+
1467
+ '@rolldown/binding-wasm32-wasi@1.0.0-rc.17':
1468
+ dependencies:
1469
+ '@emnapi/core': 1.10.0
1470
+ '@emnapi/runtime': 1.10.0
1471
+ '@napi-rs/wasm-runtime': 1.1.4(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)
1472
+ optional: true
1473
+
1474
+ '@rolldown/binding-win32-arm64-msvc@1.0.0-rc.17':
1475
+ optional: true
1476
+
1477
+ '@rolldown/binding-win32-x64-msvc@1.0.0-rc.17':
1478
+ optional: true
1479
+
1480
+ '@rolldown/pluginutils@1.0.0-rc.17': {}
1481
+
1482
+ '@sideway/address@4.1.5':
1483
+ dependencies:
1484
+ '@hapi/hoek': 9.3.0
1485
+ optional: true
1486
+
1487
+ '@sideway/formula@3.0.1':
1488
+ optional: true
1489
+
1490
+ '@sideway/pinpoint@2.0.0':
1491
+ optional: true
1492
+
1493
+ '@standard-schema/spec@1.1.0': {}
1494
+
1495
+ '@sveltejs/acorn-typescript@1.0.9(acorn@8.16.0)':
1496
+ dependencies:
1497
+ acorn: 8.16.0
1498
+
1499
+ '@sveltejs/adapter-static@3.0.10(@sveltejs/kit@2.58.0(@sveltejs/vite-plugin-svelte@7.0.0(svelte@5.55.5)(vite@8.0.10(@types/node@24.12.2)(jiti@2.6.1)))(svelte@5.55.5)(typescript@6.0.3)(vite@8.0.10(@types/node@24.12.2)(jiti@2.6.1)))':
1500
+ dependencies:
1501
+ '@sveltejs/kit': 2.58.0(@sveltejs/vite-plugin-svelte@7.0.0(svelte@5.55.5)(vite@8.0.10(@types/node@24.12.2)(jiti@2.6.1)))(svelte@5.55.5)(typescript@6.0.3)(vite@8.0.10(@types/node@24.12.2)(jiti@2.6.1))
1502
+
1503
+ '@sveltejs/kit@2.58.0(@sveltejs/vite-plugin-svelte@7.0.0(svelte@5.55.5)(vite@8.0.10(@types/node@24.12.2)(jiti@2.6.1)))(svelte@5.55.5)(typescript@6.0.3)(vite@8.0.10(@types/node@24.12.2)(jiti@2.6.1))':
1504
+ dependencies:
1505
+ '@standard-schema/spec': 1.1.0
1506
+ '@sveltejs/acorn-typescript': 1.0.9(acorn@8.16.0)
1507
+ '@sveltejs/vite-plugin-svelte': 7.0.0(svelte@5.55.5)(vite@8.0.10(@types/node@24.12.2)(jiti@2.6.1))
1508
+ '@types/cookie': 0.6.0
1509
+ acorn: 8.16.0
1510
+ cookie: 0.6.0
1511
+ devalue: 5.7.1
1512
+ esm-env: 1.2.2
1513
+ kleur: 4.1.5
1514
+ magic-string: 0.30.21
1515
+ mrmime: 2.0.1
1516
+ set-cookie-parser: 3.1.0
1517
+ sirv: 3.0.2
1518
+ svelte: 5.55.5
1519
+ vite: 8.0.10(@types/node@24.12.2)(jiti@2.6.1)
1520
+ optionalDependencies:
1521
+ typescript: 6.0.3
1522
+
1523
+ '@sveltejs/vite-plugin-svelte@7.0.0(svelte@5.55.5)(vite@8.0.10(@types/node@24.12.2)(jiti@2.6.1))':
1524
+ dependencies:
1525
+ deepmerge: 4.3.1
1526
+ magic-string: 0.30.21
1527
+ obug: 2.1.1
1528
+ svelte: 5.55.5
1529
+ vite: 8.0.10(@types/node@24.12.2)(jiti@2.6.1)
1530
+ vitefu: 1.1.3(vite@8.0.10(@types/node@24.12.2)(jiti@2.6.1))
1531
+
1532
+ '@swc/helpers@0.5.21':
1533
+ dependencies:
1534
+ tslib: 2.8.1
1535
+
1536
+ '@tailwindcss/node@4.2.4':
1537
+ dependencies:
1538
+ '@jridgewell/remapping': 2.3.5
1539
+ enhanced-resolve: 5.21.0
1540
+ jiti: 2.6.1
1541
+ lightningcss: 1.32.0
1542
+ magic-string: 0.30.21
1543
+ source-map-js: 1.2.1
1544
+ tailwindcss: 4.2.4
1545
+
1546
+ '@tailwindcss/oxide-android-arm64@4.2.4':
1547
+ optional: true
1548
+
1549
+ '@tailwindcss/oxide-darwin-arm64@4.2.4':
1550
+ optional: true
1551
+
1552
+ '@tailwindcss/oxide-darwin-x64@4.2.4':
1553
+ optional: true
1554
+
1555
+ '@tailwindcss/oxide-freebsd-x64@4.2.4':
1556
+ optional: true
1557
+
1558
+ '@tailwindcss/oxide-linux-arm-gnueabihf@4.2.4':
1559
+ optional: true
1560
+
1561
+ '@tailwindcss/oxide-linux-arm64-gnu@4.2.4':
1562
+ optional: true
1563
+
1564
+ '@tailwindcss/oxide-linux-arm64-musl@4.2.4':
1565
+ optional: true
1566
+
1567
+ '@tailwindcss/oxide-linux-x64-gnu@4.2.4':
1568
+ optional: true
1569
+
1570
+ '@tailwindcss/oxide-linux-x64-musl@4.2.4':
1571
+ optional: true
1572
+
1573
+ '@tailwindcss/oxide-wasm32-wasi@4.2.4':
1574
+ optional: true
1575
+
1576
+ '@tailwindcss/oxide-win32-arm64-msvc@4.2.4':
1577
+ optional: true
1578
+
1579
+ '@tailwindcss/oxide-win32-x64-msvc@4.2.4':
1580
+ optional: true
1581
+
1582
+ '@tailwindcss/oxide@4.2.4':
1583
+ optionalDependencies:
1584
+ '@tailwindcss/oxide-android-arm64': 4.2.4
1585
+ '@tailwindcss/oxide-darwin-arm64': 4.2.4
1586
+ '@tailwindcss/oxide-darwin-x64': 4.2.4
1587
+ '@tailwindcss/oxide-freebsd-x64': 4.2.4
1588
+ '@tailwindcss/oxide-linux-arm-gnueabihf': 4.2.4
1589
+ '@tailwindcss/oxide-linux-arm64-gnu': 4.2.4
1590
+ '@tailwindcss/oxide-linux-arm64-musl': 4.2.4
1591
+ '@tailwindcss/oxide-linux-x64-gnu': 4.2.4
1592
+ '@tailwindcss/oxide-linux-x64-musl': 4.2.4
1593
+ '@tailwindcss/oxide-wasm32-wasi': 4.2.4
1594
+ '@tailwindcss/oxide-win32-arm64-msvc': 4.2.4
1595
+ '@tailwindcss/oxide-win32-x64-msvc': 4.2.4
1596
+
1597
+ '@tailwindcss/vite@4.2.4(vite@8.0.10(@types/node@24.12.2)(jiti@2.6.1))':
1598
+ dependencies:
1599
+ '@tailwindcss/node': 4.2.4
1600
+ '@tailwindcss/oxide': 4.2.4
1601
+ tailwindcss: 4.2.4
1602
+ vite: 8.0.10(@types/node@24.12.2)(jiti@2.6.1)
1603
+
1604
+ '@tanstack/table-core@8.21.3': {}
1605
+
1606
+ '@tybys/wasm-util@0.10.1':
1607
+ dependencies:
1608
+ tslib: 2.8.1
1609
+ optional: true
1610
+
1611
+ '@types/command-line-args@5.2.3': {}
1612
+
1613
+ '@types/command-line-usage@5.0.4': {}
1614
+
1615
+ '@types/cookie@0.6.0': {}
1616
+
1617
+ '@types/d3-array@3.2.2': {}
1618
+
1619
+ '@types/d3-contour@3.0.6':
1620
+ dependencies:
1621
+ '@types/d3-array': 3.2.2
1622
+ '@types/geojson': 7946.0.16
1623
+
1624
+ '@types/dom-mediacapture-transform@0.1.11':
1625
+ dependencies:
1626
+ '@types/dom-webcodecs': 0.1.13
1627
+
1628
+ '@types/dom-webcodecs@0.1.13': {}
1629
+
1630
+ '@types/estree@1.0.8': {}
1631
+
1632
+ '@types/geojson@7946.0.16': {}
1633
+
1634
+ '@types/node@24.12.2':
1635
+ dependencies:
1636
+ undici-types: 7.16.0
1637
+
1638
+ '@types/trusted-types@2.0.7': {}
1639
+
1640
+ '@types/validator@13.15.10':
1641
+ optional: true
1642
+
1643
+ '@typeschema/class-validator@0.3.0(class-validator@0.14.4)':
1644
+ dependencies:
1645
+ '@typeschema/core': 0.14.0
1646
+ optionalDependencies:
1647
+ class-validator: 0.14.4
1648
+ transitivePeerDependencies:
1649
+ - '@types/json-schema'
1650
+ optional: true
1651
+
1652
+ '@typeschema/core@0.14.0':
1653
+ optional: true
1654
+
1655
+ '@valibot/to-json-schema@1.6.0(valibot@1.3.1(typescript@6.0.3))':
1656
+ dependencies:
1657
+ valibot: 1.3.1(typescript@6.0.3)
1658
+ optional: true
1659
+
1660
+ '@vinejs/compiler@3.0.0':
1661
+ optional: true
1662
+
1663
+ '@vinejs/vine@3.0.1':
1664
+ dependencies:
1665
+ '@poppinss/macroable': 1.1.2
1666
+ '@types/validator': 13.15.10
1667
+ '@vinejs/compiler': 3.0.0
1668
+ camelcase: 8.0.0
1669
+ dayjs: 1.11.20
1670
+ dlv: 1.1.3
1671
+ normalize-url: 8.1.1
1672
+ validator: 13.15.35
1673
+ optional: true
1674
+
1675
+ acorn@8.16.0: {}
1676
+
1677
+ ansi-styles@4.3.0:
1678
+ dependencies:
1679
+ color-convert: 2.0.1
1680
+
1681
+ apache-arrow@21.1.0:
1682
+ dependencies:
1683
+ '@swc/helpers': 0.5.21
1684
+ '@types/command-line-args': 5.2.3
1685
+ '@types/command-line-usage': 5.0.4
1686
+ '@types/node': 24.12.2
1687
+ command-line-args: 6.0.2
1688
+ command-line-usage: 7.0.4
1689
+ flatbuffers: 25.9.23
1690
+ json-bignum: 0.0.3
1691
+ tslib: 2.8.1
1692
+ transitivePeerDependencies:
1693
+ - '@75lb/nature'
1694
+
1695
+ aria-query@5.3.1: {}
1696
+
1697
+ arkregex@0.0.5:
1698
+ dependencies:
1699
+ '@ark/util': 0.56.0
1700
+ optional: true
1701
+
1702
+ arktype@2.2.0:
1703
+ dependencies:
1704
+ '@ark/schema': 0.56.0
1705
+ '@ark/util': 0.56.0
1706
+ arkregex: 0.0.5
1707
+ optional: true
1708
+
1709
+ array-back@6.2.3: {}
1710
+
1711
+ axobject-query@4.1.0: {}
1712
+
1713
+ bits-ui@2.18.0(@internationalized/date@3.12.1)(@sveltejs/kit@2.58.0(@sveltejs/vite-plugin-svelte@7.0.0(svelte@5.55.5)(vite@8.0.10(@types/node@24.12.2)(jiti@2.6.1)))(svelte@5.55.5)(typescript@6.0.3)(vite@8.0.10(@types/node@24.12.2)(jiti@2.6.1)))(svelte@5.55.5):
1714
+ dependencies:
1715
+ '@floating-ui/core': 1.7.5
1716
+ '@floating-ui/dom': 1.7.6
1717
+ '@internationalized/date': 3.12.1
1718
+ esm-env: 1.2.2
1719
+ runed: 0.35.1(@sveltejs/kit@2.58.0(@sveltejs/vite-plugin-svelte@7.0.0(svelte@5.55.5)(vite@8.0.10(@types/node@24.12.2)(jiti@2.6.1)))(svelte@5.55.5)(typescript@6.0.3)(vite@8.0.10(@types/node@24.12.2)(jiti@2.6.1)))(svelte@5.55.5)
1720
+ svelte: 5.55.5
1721
+ svelte-toolbelt: 0.10.6(@sveltejs/kit@2.58.0(@sveltejs/vite-plugin-svelte@7.0.0(svelte@5.55.5)(vite@8.0.10(@types/node@24.12.2)(jiti@2.6.1)))(svelte@5.55.5)(typescript@6.0.3)(vite@8.0.10(@types/node@24.12.2)(jiti@2.6.1)))(svelte@5.55.5)
1722
+ tabbable: 6.4.0
1723
+ transitivePeerDependencies:
1724
+ - '@sveltejs/kit'
1725
+
1726
+ camelcase@8.0.0:
1727
+ optional: true
1728
+
1729
+ chalk-template@0.4.0:
1730
+ dependencies:
1731
+ chalk: 4.1.2
1732
+
1733
+ chalk@4.1.2:
1734
+ dependencies:
1735
+ ansi-styles: 4.3.0
1736
+ supports-color: 7.2.0
1737
+
1738
+ chokidar@4.0.3:
1739
+ dependencies:
1740
+ readdirp: 4.1.2
1741
+
1742
+ class-validator@0.14.4:
1743
+ dependencies:
1744
+ '@types/validator': 13.15.10
1745
+ libphonenumber-js: 1.12.42
1746
+ validator: 13.15.35
1747
+ optional: true
1748
+
1749
+ clsx@2.1.1: {}
1750
+
1751
+ color-convert@2.0.1:
1752
+ dependencies:
1753
+ color-name: 1.1.4
1754
+
1755
+ color-name@1.1.4: {}
1756
+
1757
+ command-line-args@6.0.2:
1758
+ dependencies:
1759
+ array-back: 6.2.3
1760
+ find-replace: 5.0.2
1761
+ lodash.camelcase: 4.3.0
1762
+ typical: 7.3.0
1763
+
1764
+ command-line-usage@7.0.4:
1765
+ dependencies:
1766
+ array-back: 6.2.3
1767
+ chalk-template: 0.4.0
1768
+ table-layout: 4.1.1
1769
+ typical: 7.3.0
1770
+
1771
+ commander@14.0.3: {}
1772
+
1773
+ commander@7.2.0: {}
1774
+
1775
+ cookie@0.6.0: {}
1776
+
1777
+ d3-array@2.12.1:
1778
+ dependencies:
1779
+ internmap: 1.0.1
1780
+
1781
+ d3-array@3.2.4:
1782
+ dependencies:
1783
+ internmap: 2.0.3
1784
+
1785
+ d3-chord@3.0.1:
1786
+ dependencies:
1787
+ d3-path: 3.1.0
1788
+
1789
+ d3-color@3.1.0: {}
1790
+
1791
+ d3-contour@4.0.2:
1792
+ dependencies:
1793
+ d3-array: 3.2.4
1794
+
1795
+ d3-delaunay@6.0.4:
1796
+ dependencies:
1797
+ delaunator: 5.1.0
1798
+
1799
+ d3-dispatch@3.0.1: {}
1800
+
1801
+ d3-dsv@3.0.1:
1802
+ dependencies:
1803
+ commander: 7.2.0
1804
+ iconv-lite: 0.6.3
1805
+ rw: 1.3.3
1806
+
1807
+ d3-force@3.0.0:
1808
+ dependencies:
1809
+ d3-dispatch: 3.0.1
1810
+ d3-quadtree: 3.0.1
1811
+ d3-timer: 3.0.1
1812
+
1813
+ d3-format@3.1.2: {}
1814
+
1815
+ d3-geo-voronoi@2.1.0:
1816
+ dependencies:
1817
+ d3-array: 3.2.4
1818
+ d3-delaunay: 6.0.4
1819
+ d3-geo: 3.1.1
1820
+ d3-tricontour: 1.1.0
1821
+
1822
+ d3-geo@3.1.1:
1823
+ dependencies:
1824
+ d3-array: 3.2.4
1825
+
1826
+ d3-hierarchy@3.1.2: {}
1827
+
1828
+ d3-interpolate-path@2.3.0: {}
1829
+
1830
+ d3-interpolate@3.0.1:
1831
+ dependencies:
1832
+ d3-color: 3.1.0
1833
+
1834
+ d3-path@1.0.9: {}
1835
+
1836
+ d3-path@3.1.0: {}
1837
+
1838
+ d3-quadtree@3.0.1: {}
1839
+
1840
+ d3-random@3.0.1: {}
1841
+
1842
+ d3-sankey@0.12.3:
1843
+ dependencies:
1844
+ d3-array: 2.12.1
1845
+ d3-shape: 1.3.7
1846
+
1847
+ d3-scale-chromatic@3.1.0:
1848
+ dependencies:
1849
+ d3-color: 3.1.0
1850
+ d3-interpolate: 3.0.1
1851
+
1852
+ d3-scale@4.0.2:
1853
+ dependencies:
1854
+ d3-array: 3.2.4
1855
+ d3-format: 3.1.2
1856
+ d3-interpolate: 3.0.1
1857
+ d3-time: 3.1.0
1858
+ d3-time-format: 4.1.0
1859
+
1860
+ d3-shape@1.3.7:
1861
+ dependencies:
1862
+ d3-path: 1.0.9
1863
+
1864
+ d3-shape@3.2.0:
1865
+ dependencies:
1866
+ d3-path: 3.1.0
1867
+
1868
+ d3-tile@1.0.0: {}
1869
+
1870
+ d3-time-format@4.1.0:
1871
+ dependencies:
1872
+ d3-time: 3.1.0
1873
+
1874
+ d3-time@3.1.0:
1875
+ dependencies:
1876
+ d3-array: 3.2.4
1877
+
1878
+ d3-timer@3.0.1: {}
1879
+
1880
+ d3-tricontour@1.1.0:
1881
+ dependencies:
1882
+ d3-delaunay: 6.0.4
1883
+ d3-scale: 4.0.2
1884
+
1885
+ dayjs@1.11.20:
1886
+ optional: true
1887
+
1888
+ deepmerge@4.3.1: {}
1889
+
1890
+ delaunator@5.1.0:
1891
+ dependencies:
1892
+ robust-predicates: 3.0.3
1893
+
1894
+ dequal@2.0.3: {}
1895
+
1896
+ detect-libc@2.1.2: {}
1897
+
1898
+ devalue@5.7.1: {}
1899
+
1900
+ dlv@1.1.3:
1901
+ optional: true
1902
+
1903
+ effect@3.21.2:
1904
+ dependencies:
1905
+ '@standard-schema/spec': 1.1.0
1906
+ fast-check: 3.23.2
1907
+ optional: true
1908
+
1909
+ enhanced-resolve@5.21.0:
1910
+ dependencies:
1911
+ graceful-fs: 4.2.11
1912
+ tapable: 2.3.3
1913
+
1914
+ esm-env@1.2.2: {}
1915
+
1916
+ esrap@2.2.5:
1917
+ dependencies:
1918
+ '@jridgewell/sourcemap-codec': 1.5.5
1919
+
1920
+ estree-walker@3.0.3:
1921
+ dependencies:
1922
+ '@types/estree': 1.0.8
1923
+
1924
+ fast-check@3.23.2:
1925
+ dependencies:
1926
+ pure-rand: 6.1.0
1927
+ optional: true
1928
+
1929
+ fdir@6.5.0(picomatch@4.0.4):
1930
+ optionalDependencies:
1931
+ picomatch: 4.0.4
1932
+
1933
+ find-replace@5.0.2: {}
1934
+
1935
+ flatbuffers@25.9.23: {}
1936
+
1937
+ formsnap@2.0.1(svelte@5.55.5)(sveltekit-superforms@2.30.1(@sveltejs/kit@2.58.0(@sveltejs/vite-plugin-svelte@7.0.0(svelte@5.55.5)(vite@8.0.10(@types/node@24.12.2)(jiti@2.6.1)))(svelte@5.55.5)(typescript@6.0.3)(vite@8.0.10(@types/node@24.12.2)(jiti@2.6.1)))(svelte@5.55.5)(typescript@6.0.3)):
1938
+ dependencies:
1939
+ svelte: 5.55.5
1940
+ svelte-toolbelt: 0.5.0(svelte@5.55.5)
1941
+ sveltekit-superforms: 2.30.1(@sveltejs/kit@2.58.0(@sveltejs/vite-plugin-svelte@7.0.0(svelte@5.55.5)(vite@8.0.10(@types/node@24.12.2)(jiti@2.6.1)))(svelte@5.55.5)(typescript@6.0.3)(vite@8.0.10(@types/node@24.12.2)(jiti@2.6.1)))(svelte@5.55.5)(typescript@6.0.3)
1942
+
1943
+ fsevents@2.3.3:
1944
+ optional: true
1945
+
1946
+ graceful-fs@4.2.11: {}
1947
+
1948
+ has-flag@4.0.0: {}
1949
+
1950
+ iconv-lite@0.6.3:
1951
+ dependencies:
1952
+ safer-buffer: 2.1.2
1953
+
1954
+ inline-style-parser@0.2.7: {}
1955
+
1956
+ internmap@1.0.1: {}
1957
+
1958
+ internmap@2.0.3: {}
1959
+
1960
+ is-reference@3.0.3:
1961
+ dependencies:
1962
+ '@types/estree': 1.0.8
1963
+
1964
+ jiti@2.6.1: {}
1965
+
1966
+ joi@17.13.3:
1967
+ dependencies:
1968
+ '@hapi/hoek': 9.3.0
1969
+ '@hapi/topo': 5.1.0
1970
+ '@sideway/address': 4.1.5
1971
+ '@sideway/formula': 3.0.1
1972
+ '@sideway/pinpoint': 2.0.0
1973
+ optional: true
1974
+
1975
+ json-bignum@0.0.3: {}
1976
+
1977
+ json-schema-to-ts@3.1.1:
1978
+ dependencies:
1979
+ '@babel/runtime': 7.29.2
1980
+ ts-algebra: 2.0.0
1981
+ optional: true
1982
+
1983
+ kleur@4.1.5: {}
1984
+
1985
+ layerchart@2.0.0-next.48(@sveltejs/kit@2.58.0(@sveltejs/vite-plugin-svelte@7.0.0(svelte@5.55.5)(vite@8.0.10(@types/node@24.12.2)(jiti@2.6.1)))(svelte@5.55.5)(typescript@6.0.3)(vite@8.0.10(@types/node@24.12.2)(jiti@2.6.1)))(svelte@5.55.5)(zod@4.3.6):
1986
+ dependencies:
1987
+ '@dagrejs/dagre': 2.0.4
1988
+ '@layerstack/svelte-actions': 1.0.1-next.18
1989
+ '@layerstack/svelte-state': 0.1.0-next.23
1990
+ '@layerstack/tailwind': 2.0.0-next.21
1991
+ '@layerstack/utils': 2.0.0-next.18
1992
+ '@types/d3-contour': 3.0.6
1993
+ d3-array: 3.2.4
1994
+ d3-chord: 3.0.1
1995
+ d3-color: 3.1.0
1996
+ d3-contour: 4.0.2
1997
+ d3-delaunay: 6.0.4
1998
+ d3-dsv: 3.0.1
1999
+ d3-force: 3.0.0
2000
+ d3-geo: 3.1.1
2001
+ d3-geo-voronoi: 2.1.0
2002
+ d3-hierarchy: 3.1.2
2003
+ d3-interpolate: 3.0.1
2004
+ d3-interpolate-path: 2.3.0
2005
+ d3-path: 3.1.0
2006
+ d3-quadtree: 3.0.1
2007
+ d3-random: 3.0.1
2008
+ d3-sankey: 0.12.3
2009
+ d3-scale: 4.0.2
2010
+ d3-scale-chromatic: 3.1.0
2011
+ d3-shape: 3.2.0
2012
+ d3-tile: 1.0.0
2013
+ d3-time: 3.1.0
2014
+ memoize: 10.2.0
2015
+ runed: 0.37.1(@sveltejs/kit@2.58.0(@sveltejs/vite-plugin-svelte@7.0.0(svelte@5.55.5)(vite@8.0.10(@types/node@24.12.2)(jiti@2.6.1)))(svelte@5.55.5)(typescript@6.0.3)(vite@8.0.10(@types/node@24.12.2)(jiti@2.6.1)))(svelte@5.55.5)(zod@4.3.6)
2016
+ svelte: 5.55.5
2017
+ transitivePeerDependencies:
2018
+ - '@sveltejs/kit'
2019
+ - zod
2020
+
2021
+ libphonenumber-js@1.12.42:
2022
+ optional: true
2023
+
2024
+ lightningcss-android-arm64@1.32.0:
2025
+ optional: true
2026
+
2027
+ lightningcss-darwin-arm64@1.32.0:
2028
+ optional: true
2029
+
2030
+ lightningcss-darwin-x64@1.32.0:
2031
+ optional: true
2032
+
2033
+ lightningcss-freebsd-x64@1.32.0:
2034
+ optional: true
2035
+
2036
+ lightningcss-linux-arm-gnueabihf@1.32.0:
2037
+ optional: true
2038
+
2039
+ lightningcss-linux-arm64-gnu@1.32.0:
2040
+ optional: true
2041
+
2042
+ lightningcss-linux-arm64-musl@1.32.0:
2043
+ optional: true
2044
+
2045
+ lightningcss-linux-x64-gnu@1.32.0:
2046
+ optional: true
2047
+
2048
+ lightningcss-linux-x64-musl@1.32.0:
2049
+ optional: true
2050
+
2051
+ lightningcss-win32-arm64-msvc@1.32.0:
2052
+ optional: true
2053
+
2054
+ lightningcss-win32-x64-msvc@1.32.0:
2055
+ optional: true
2056
+
2057
+ lightningcss@1.32.0:
2058
+ dependencies:
2059
+ detect-libc: 2.1.2
2060
+ optionalDependencies:
2061
+ lightningcss-android-arm64: 1.32.0
2062
+ lightningcss-darwin-arm64: 1.32.0
2063
+ lightningcss-darwin-x64: 1.32.0
2064
+ lightningcss-freebsd-x64: 1.32.0
2065
+ lightningcss-linux-arm-gnueabihf: 1.32.0
2066
+ lightningcss-linux-arm64-gnu: 1.32.0
2067
+ lightningcss-linux-arm64-musl: 1.32.0
2068
+ lightningcss-linux-x64-gnu: 1.32.0
2069
+ lightningcss-linux-x64-musl: 1.32.0
2070
+ lightningcss-win32-arm64-msvc: 1.32.0
2071
+ lightningcss-win32-x64-msvc: 1.32.0
2072
+
2073
+ locate-character@3.0.0: {}
2074
+
2075
+ lodash.camelcase@4.3.0: {}
2076
+
2077
+ lz-string@1.5.0: {}
2078
+
2079
+ magic-string@0.30.21:
2080
+ dependencies:
2081
+ '@jridgewell/sourcemap-codec': 1.5.5
2082
+
2083
+ mediabunny@1.42.0:
2084
+ dependencies:
2085
+ '@types/dom-mediacapture-transform': 0.1.11
2086
+ '@types/dom-webcodecs': 0.1.13
2087
+
2088
+ memoize-weak@1.0.2: {}
2089
+
2090
+ memoize@10.2.0:
2091
+ dependencies:
2092
+ mimic-function: 5.0.1
2093
+
2094
+ mimic-function@5.0.1: {}
2095
+
2096
+ mode-watcher@1.1.0(svelte@5.55.5):
2097
+ dependencies:
2098
+ runed: 0.25.0(svelte@5.55.5)
2099
+ svelte: 5.55.5
2100
+ svelte-toolbelt: 0.7.1(svelte@5.55.5)
2101
+
2102
+ mri@1.2.0: {}
2103
+
2104
+ mrmime@2.0.1: {}
2105
+
2106
+ nanoid@3.3.11: {}
2107
+
2108
+ node-fetch-native@1.6.7: {}
2109
+
2110
+ normalize-url@8.1.1:
2111
+ optional: true
2112
+
2113
+ obug@2.1.1: {}
2114
+
2115
+ paneforge@1.0.2(svelte@5.55.5):
2116
+ dependencies:
2117
+ runed: 0.23.4(svelte@5.55.5)
2118
+ svelte: 5.55.5
2119
+ svelte-toolbelt: 0.9.3(svelte@5.55.5)
2120
+
2121
+ parquet-wasm@0.7.1: {}
2122
+
2123
+ phosphor-svelte@3.1.0(svelte@5.55.5)(vite@8.0.10(@types/node@24.12.2)(jiti@2.6.1)):
2124
+ dependencies:
2125
+ estree-walker: 3.0.3
2126
+ magic-string: 0.30.21
2127
+ svelte: 5.55.5
2128
+ optionalDependencies:
2129
+ vite: 8.0.10(@types/node@24.12.2)(jiti@2.6.1)
2130
+
2131
+ picocolors@1.1.1: {}
2132
+
2133
+ picomatch@4.0.4: {}
2134
+
2135
+ postcss@8.5.12:
2136
+ dependencies:
2137
+ nanoid: 3.3.11
2138
+ picocolors: 1.1.1
2139
+ source-map-js: 1.2.1
2140
+
2141
+ property-expr@2.0.6:
2142
+ optional: true
2143
+
2144
+ pure-rand@6.1.0:
2145
+ optional: true
2146
+
2147
+ readdirp@4.1.2: {}
2148
+
2149
+ robust-predicates@3.0.3: {}
2150
+
2151
+ rolldown@1.0.0-rc.17:
2152
+ dependencies:
2153
+ '@oxc-project/types': 0.127.0
2154
+ '@rolldown/pluginutils': 1.0.0-rc.17
2155
+ optionalDependencies:
2156
+ '@rolldown/binding-android-arm64': 1.0.0-rc.17
2157
+ '@rolldown/binding-darwin-arm64': 1.0.0-rc.17
2158
+ '@rolldown/binding-darwin-x64': 1.0.0-rc.17
2159
+ '@rolldown/binding-freebsd-x64': 1.0.0-rc.17
2160
+ '@rolldown/binding-linux-arm-gnueabihf': 1.0.0-rc.17
2161
+ '@rolldown/binding-linux-arm64-gnu': 1.0.0-rc.17
2162
+ '@rolldown/binding-linux-arm64-musl': 1.0.0-rc.17
2163
+ '@rolldown/binding-linux-ppc64-gnu': 1.0.0-rc.17
2164
+ '@rolldown/binding-linux-s390x-gnu': 1.0.0-rc.17
2165
+ '@rolldown/binding-linux-x64-gnu': 1.0.0-rc.17
2166
+ '@rolldown/binding-linux-x64-musl': 1.0.0-rc.17
2167
+ '@rolldown/binding-openharmony-arm64': 1.0.0-rc.17
2168
+ '@rolldown/binding-wasm32-wasi': 1.0.0-rc.17
2169
+ '@rolldown/binding-win32-arm64-msvc': 1.0.0-rc.17
2170
+ '@rolldown/binding-win32-x64-msvc': 1.0.0-rc.17
2171
+
2172
+ runed@0.23.4(svelte@5.55.5):
2173
+ dependencies:
2174
+ esm-env: 1.2.2
2175
+ svelte: 5.55.5
2176
+
2177
+ runed@0.25.0(svelte@5.55.5):
2178
+ dependencies:
2179
+ esm-env: 1.2.2
2180
+ svelte: 5.55.5
2181
+
2182
+ runed@0.28.0(svelte@5.55.5):
2183
+ dependencies:
2184
+ esm-env: 1.2.2
2185
+ svelte: 5.55.5
2186
+
2187
+ runed@0.29.2(svelte@5.55.5):
2188
+ dependencies:
2189
+ esm-env: 1.2.2
2190
+ svelte: 5.55.5
2191
+
2192
+ runed@0.35.1(@sveltejs/kit@2.58.0(@sveltejs/vite-plugin-svelte@7.0.0(svelte@5.55.5)(vite@8.0.10(@types/node@24.12.2)(jiti@2.6.1)))(svelte@5.55.5)(typescript@6.0.3)(vite@8.0.10(@types/node@24.12.2)(jiti@2.6.1)))(svelte@5.55.5):
2193
+ dependencies:
2194
+ dequal: 2.0.3
2195
+ esm-env: 1.2.2
2196
+ lz-string: 1.5.0
2197
+ svelte: 5.55.5
2198
+ optionalDependencies:
2199
+ '@sveltejs/kit': 2.58.0(@sveltejs/vite-plugin-svelte@7.0.0(svelte@5.55.5)(vite@8.0.10(@types/node@24.12.2)(jiti@2.6.1)))(svelte@5.55.5)(typescript@6.0.3)(vite@8.0.10(@types/node@24.12.2)(jiti@2.6.1))
2200
+
2201
+ runed@0.37.1(@sveltejs/kit@2.58.0(@sveltejs/vite-plugin-svelte@7.0.0(svelte@5.55.5)(vite@8.0.10(@types/node@24.12.2)(jiti@2.6.1)))(svelte@5.55.5)(typescript@6.0.3)(vite@8.0.10(@types/node@24.12.2)(jiti@2.6.1)))(svelte@5.55.5)(zod@4.3.6):
2202
+ dependencies:
2203
+ dequal: 2.0.3
2204
+ esm-env: 1.2.2
2205
+ lz-string: 1.5.0
2206
+ svelte: 5.55.5
2207
+ optionalDependencies:
2208
+ '@sveltejs/kit': 2.58.0(@sveltejs/vite-plugin-svelte@7.0.0(svelte@5.55.5)(vite@8.0.10(@types/node@24.12.2)(jiti@2.6.1)))(svelte@5.55.5)(typescript@6.0.3)(vite@8.0.10(@types/node@24.12.2)(jiti@2.6.1))
2209
+ zod: 4.3.6
2210
+
2211
+ rw@1.3.3: {}
2212
+
2213
+ sade@1.8.1:
2214
+ dependencies:
2215
+ mri: 1.2.0
2216
+
2217
+ safer-buffer@2.1.2: {}
2218
+
2219
+ set-cookie-parser@3.1.0: {}
2220
+
2221
+ shadcn-svelte@1.2.7(svelte@5.55.5):
2222
+ dependencies:
2223
+ commander: 14.0.3
2224
+ node-fetch-native: 1.6.7
2225
+ postcss: 8.5.12
2226
+ svelte: 5.55.5
2227
+ tailwind-merge: 3.5.0
2228
+
2229
+ sirv@3.0.2:
2230
+ dependencies:
2231
+ '@polka/url': 1.0.0-next.29
2232
+ mrmime: 2.0.1
2233
+ totalist: 3.0.1
2234
+
2235
+ source-map-js@1.2.1: {}
2236
+
2237
+ style-to-object@1.0.14:
2238
+ dependencies:
2239
+ inline-style-parser: 0.2.7
2240
+
2241
+ superstruct@2.0.2:
2242
+ optional: true
2243
+
2244
+ supports-color@7.2.0:
2245
+ dependencies:
2246
+ has-flag: 4.0.0
2247
+
2248
+ svelte-check@4.4.6(picomatch@4.0.4)(svelte@5.55.5)(typescript@6.0.3):
2249
+ dependencies:
2250
+ '@jridgewell/trace-mapping': 0.3.31
2251
+ chokidar: 4.0.3
2252
+ fdir: 6.5.0(picomatch@4.0.4)
2253
+ picocolors: 1.1.1
2254
+ sade: 1.8.1
2255
+ svelte: 5.55.5
2256
+ typescript: 6.0.3
2257
+ transitivePeerDependencies:
2258
+ - picomatch
2259
+
2260
+ svelte-sonner@1.1.1(svelte@5.55.5):
2261
+ dependencies:
2262
+ runed: 0.28.0(svelte@5.55.5)
2263
+ svelte: 5.55.5
2264
+
2265
+ svelte-toolbelt@0.10.6(@sveltejs/kit@2.58.0(@sveltejs/vite-plugin-svelte@7.0.0(svelte@5.55.5)(vite@8.0.10(@types/node@24.12.2)(jiti@2.6.1)))(svelte@5.55.5)(typescript@6.0.3)(vite@8.0.10(@types/node@24.12.2)(jiti@2.6.1)))(svelte@5.55.5):
2266
+ dependencies:
2267
+ clsx: 2.1.1
2268
+ runed: 0.35.1(@sveltejs/kit@2.58.0(@sveltejs/vite-plugin-svelte@7.0.0(svelte@5.55.5)(vite@8.0.10(@types/node@24.12.2)(jiti@2.6.1)))(svelte@5.55.5)(typescript@6.0.3)(vite@8.0.10(@types/node@24.12.2)(jiti@2.6.1)))(svelte@5.55.5)
2269
+ style-to-object: 1.0.14
2270
+ svelte: 5.55.5
2271
+ transitivePeerDependencies:
2272
+ - '@sveltejs/kit'
2273
+
2274
+ svelte-toolbelt@0.5.0(svelte@5.55.5):
2275
+ dependencies:
2276
+ clsx: 2.1.1
2277
+ style-to-object: 1.0.14
2278
+ svelte: 5.55.5
2279
+
2280
+ svelte-toolbelt@0.7.1(svelte@5.55.5):
2281
+ dependencies:
2282
+ clsx: 2.1.1
2283
+ runed: 0.23.4(svelte@5.55.5)
2284
+ style-to-object: 1.0.14
2285
+ svelte: 5.55.5
2286
+
2287
+ svelte-toolbelt@0.9.3(svelte@5.55.5):
2288
+ dependencies:
2289
+ clsx: 2.1.1
2290
+ runed: 0.29.2(svelte@5.55.5)
2291
+ style-to-object: 1.0.14
2292
+ svelte: 5.55.5
2293
+
2294
+ svelte@5.55.5:
2295
+ dependencies:
2296
+ '@jridgewell/remapping': 2.3.5
2297
+ '@jridgewell/sourcemap-codec': 1.5.5
2298
+ '@sveltejs/acorn-typescript': 1.0.9(acorn@8.16.0)
2299
+ '@types/estree': 1.0.8
2300
+ '@types/trusted-types': 2.0.7
2301
+ acorn: 8.16.0
2302
+ aria-query: 5.3.1
2303
+ axobject-query: 4.1.0
2304
+ clsx: 2.1.1
2305
+ devalue: 5.7.1
2306
+ esm-env: 1.2.2
2307
+ esrap: 2.2.5
2308
+ is-reference: 3.0.3
2309
+ locate-character: 3.0.0
2310
+ magic-string: 0.30.21
2311
+ zimmerframe: 1.1.4
2312
+ transitivePeerDependencies:
2313
+ - '@typescript-eslint/types'
2314
+
2315
+ sveltekit-superforms@2.30.1(@sveltejs/kit@2.58.0(@sveltejs/vite-plugin-svelte@7.0.0(svelte@5.55.5)(vite@8.0.10(@types/node@24.12.2)(jiti@2.6.1)))(svelte@5.55.5)(typescript@6.0.3)(vite@8.0.10(@types/node@24.12.2)(jiti@2.6.1)))(svelte@5.55.5)(typescript@6.0.3):
2316
+ dependencies:
2317
+ '@sveltejs/kit': 2.58.0(@sveltejs/vite-plugin-svelte@7.0.0(svelte@5.55.5)(vite@8.0.10(@types/node@24.12.2)(jiti@2.6.1)))(svelte@5.55.5)(typescript@6.0.3)(vite@8.0.10(@types/node@24.12.2)(jiti@2.6.1))
2318
+ devalue: 5.7.1
2319
+ memoize-weak: 1.0.2
2320
+ svelte: 5.55.5
2321
+ ts-deepmerge: 7.0.3
2322
+ optionalDependencies:
2323
+ '@exodus/schemasafe': 1.3.0
2324
+ '@standard-schema/spec': 1.1.0
2325
+ '@typeschema/class-validator': 0.3.0(class-validator@0.14.4)
2326
+ '@valibot/to-json-schema': 1.6.0(valibot@1.3.1(typescript@6.0.3))
2327
+ '@vinejs/vine': 3.0.1
2328
+ arktype: 2.2.0
2329
+ class-validator: 0.14.4
2330
+ effect: 3.21.2
2331
+ joi: 17.13.3
2332
+ json-schema-to-ts: 3.1.1
2333
+ superstruct: 2.0.2
2334
+ typebox: 1.1.34
2335
+ valibot: 1.3.1(typescript@6.0.3)
2336
+ yup: 1.7.1
2337
+ zod: 4.3.6
2338
+ zod-v3-to-json-schema: 4.0.0(zod@4.3.6)
2339
+ transitivePeerDependencies:
2340
+ - '@types/json-schema'
2341
+ - typescript
2342
+
2343
+ tabbable@6.4.0: {}
2344
+
2345
+ table-layout@4.1.1:
2346
+ dependencies:
2347
+ array-back: 6.2.3
2348
+ wordwrapjs: 5.1.1
2349
+
2350
+ tailwind-merge@3.5.0: {}
2351
+
2352
+ tailwind-variants@3.2.2(tailwind-merge@3.5.0)(tailwindcss@4.2.4):
2353
+ dependencies:
2354
+ tailwindcss: 4.2.4
2355
+ optionalDependencies:
2356
+ tailwind-merge: 3.5.0
2357
+
2358
+ tailwindcss@4.2.4: {}
2359
+
2360
+ tapable@2.3.3: {}
2361
+
2362
+ tiny-case@1.0.3:
2363
+ optional: true
2364
+
2365
+ tinyglobby@0.2.16:
2366
+ dependencies:
2367
+ fdir: 6.5.0(picomatch@4.0.4)
2368
+ picomatch: 4.0.4
2369
+
2370
+ toposort@2.0.2:
2371
+ optional: true
2372
+
2373
+ totalist@3.0.1: {}
2374
+
2375
+ ts-algebra@2.0.0:
2376
+ optional: true
2377
+
2378
+ ts-deepmerge@7.0.3: {}
2379
+
2380
+ tslib@2.8.1: {}
2381
+
2382
+ tw-animate-css@1.4.0: {}
2383
+
2384
+ type-fest@2.19.0:
2385
+ optional: true
2386
+
2387
+ typebox@1.1.34:
2388
+ optional: true
2389
+
2390
+ typescript@6.0.3: {}
2391
+
2392
+ typical@7.3.0: {}
2393
+
2394
+ undici-types@7.16.0: {}
2395
+
2396
+ valibot@1.3.1(typescript@6.0.3):
2397
+ optionalDependencies:
2398
+ typescript: 6.0.3
2399
+ optional: true
2400
+
2401
+ validator@13.15.35:
2402
+ optional: true
2403
+
2404
+ vaul-svelte@1.0.0-next.7(svelte@5.55.5):
2405
+ dependencies:
2406
+ runed: 0.23.4(svelte@5.55.5)
2407
+ svelte: 5.55.5
2408
+ svelte-toolbelt: 0.7.1(svelte@5.55.5)
2409
+
2410
+ vite@8.0.10(@types/node@24.12.2)(jiti@2.6.1):
2411
+ dependencies:
2412
+ lightningcss: 1.32.0
2413
+ picomatch: 4.0.4
2414
+ postcss: 8.5.12
2415
+ rolldown: 1.0.0-rc.17
2416
+ tinyglobby: 0.2.16
2417
+ optionalDependencies:
2418
+ '@types/node': 24.12.2
2419
+ fsevents: 2.3.3
2420
+ jiti: 2.6.1
2421
+
2422
+ vitefu@1.1.3(vite@8.0.10(@types/node@24.12.2)(jiti@2.6.1)):
2423
+ optionalDependencies:
2424
+ vite: 8.0.10(@types/node@24.12.2)(jiti@2.6.1)
2425
+
2426
+ wordwrapjs@5.1.1: {}
2427
+
2428
+ yup@1.7.1:
2429
+ dependencies:
2430
+ property-expr: 2.0.6
2431
+ tiny-case: 1.0.3
2432
+ toposort: 2.0.2
2433
+ type-fest: 2.19.0
2434
+ optional: true
2435
+
2436
+ zimmerframe@1.1.4: {}
2437
+
2438
+ zod-v3-to-json-schema@4.0.0(zod@4.3.6):
2439
+ dependencies:
2440
+ zod: 4.3.6
2441
+ optional: true
2442
+
2443
+ zod@4.3.6:
2444
+ optional: true
pnpm-workspace.yaml ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ onlyBuiltDependencies:
2
+ - '@tailwindcss/oxide'
3
+ - esbuild
src/app.d.ts ADDED
@@ -0,0 +1,13 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // See https://svelte.dev/docs/kit/types#app.d.ts
2
+ // for information about these interfaces
3
+ declare global {
4
+ namespace App {
5
+ // interface Error {}
6
+ // interface Locals {}
7
+ // interface PageData {}
8
+ // interface PageState {}
9
+ // interface Platform {}
10
+ }
11
+ }
12
+
13
+ export {};
src/app.html ADDED
@@ -0,0 +1,12 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!doctype html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="utf-8" />
5
+ <meta name="viewport" content="width=device-width, initial-scale=1" />
6
+ <meta name="text-scale" content="scale" />
7
+ %sveltekit.head%
8
+ </head>
9
+ <body data-sveltekit-preload-data="hover">
10
+ <div style="display: contents">%sveltekit.body%</div>
11
+ </body>
12
+ </html>
src/lib/api/hf.ts ADDED
@@ -0,0 +1,136 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import type { Match, PreviewChunk, Round } from '../types';
2
+ import { fetchParquetRows } from './parquet';
3
+ import { listTree, resolveUrl, type FetchOpts } from './hub';
4
+
5
+ export type FetchOptions = FetchOpts;
6
+
7
+ const PLAYER_COUNT = 10;
8
+
9
+ let matchesPromise: Promise<Match[]> | null = null;
10
+ let roundsPromise: Promise<Round[]> | null = null;
11
+ const matchPreviewsCache = new Map<string, Promise<PreviewChunk[]>>();
12
+
13
+ // The dataset is sharded by upload batch. Index files are named like
14
+ // `index/manifest-<shard_id>.parquet` / `index/rounds-<shard_id>.parquet`.
15
+ // Discover them at runtime so new shards don't require a code change.
16
+ async function listIndexShards(
17
+ prefix: 'manifest' | 'rounds',
18
+ opts: FetchOptions
19
+ ): Promise<string[]> {
20
+ const entries = await listTree('index', opts);
21
+ return entries
22
+ .filter((e) => e.type === 'file')
23
+ .map((e) => e.path)
24
+ .filter((p) => {
25
+ const name = p.split('/').pop() ?? '';
26
+ return name.startsWith(`${prefix}-`) && name.endsWith('.parquet');
27
+ });
28
+ }
29
+
30
+ async function loadShardedIndex<T>(
31
+ prefix: 'manifest' | 'rounds',
32
+ opts: FetchOptions
33
+ ): Promise<T[]> {
34
+ const paths = await listIndexShards(prefix, opts);
35
+ if (!paths.length) return [];
36
+ const shards = await Promise.all(
37
+ paths.map((p) => fetchParquetRows<T>(resolveUrl(p), opts))
38
+ );
39
+ return shards.flat();
40
+ }
41
+
42
+ export function listMatches(opts: FetchOptions = {}): Promise<Match[]> {
43
+ if (matchesPromise) return matchesPromise;
44
+ matchesPromise = loadShardedIndex<Match>('manifest', opts)
45
+ .then((rows) => {
46
+ rows.sort(
47
+ (a, b) =>
48
+ new Date(b.match_date).getTime() - new Date(a.match_date).getTime() ||
49
+ (a.map_index ?? 0) - (b.map_index ?? 0)
50
+ );
51
+ return rows;
52
+ })
53
+ .catch((err) => {
54
+ matchesPromise = null;
55
+ throw err;
56
+ });
57
+ return matchesPromise;
58
+ }
59
+
60
+ export async function listAllRounds(opts: FetchOptions = {}): Promise<Round[]> {
61
+ if (!roundsPromise) {
62
+ roundsPromise = loadShardedIndex<Round>('rounds', opts).catch((err) => {
63
+ roundsPromise = null;
64
+ throw err;
65
+ });
66
+ }
67
+ return roundsPromise;
68
+ }
69
+
70
+ export async function listRounds(
71
+ matchId: number,
72
+ mapName: string,
73
+ opts: FetchOptions = {}
74
+ ): Promise<Round[]> {
75
+ const all = await listAllRounds(opts);
76
+ return all
77
+ .filter((r) => r.match_id === matchId && r.map_name === mapName)
78
+ .sort((a, b) => a.round - b.round);
79
+ }
80
+
81
+ /**
82
+ * Fetch all preview rows for every player on this (match, map) in parallel.
83
+ * The shard_id from the match's manifest row is enough to construct each
84
+ * player's parquet URL — no tree-API discovery needed.
85
+ */
86
+ async function loadMatchPreviews(
87
+ matchId: number,
88
+ mapName: string,
89
+ opts: FetchOptions
90
+ ): Promise<PreviewChunk[]> {
91
+ const key = `${matchId}/${mapName}`;
92
+ const cached = matchPreviewsCache.get(key);
93
+ if (cached) return cached;
94
+
95
+ const promise = (async () => {
96
+ const matches = await listMatches(opts);
97
+ const match = matches.find((m) => m.match_id === matchId && m.map_name === mapName);
98
+ if (!match) return [];
99
+
100
+ const players = Array.from({ length: PLAYER_COUNT }, (_, i) => i);
101
+ const results = await Promise.all(
102
+ players.map(async (player) => {
103
+ const dir = `data/match_id=${matchId}/map_name=${mapName}/player=${player}`;
104
+ try {
105
+ const rows = await fetchParquetRows<PreviewChunk>(
106
+ resolveUrl(`${dir}/chunks-preview-${match.shard_id}.parquet`),
107
+ opts
108
+ );
109
+ for (const r of rows) r.preview_video = { src: resolveUrl(`${dir}/${r.preview_path}`) };
110
+ return rows;
111
+ } catch {
112
+ return [] as PreviewChunk[];
113
+ }
114
+ })
115
+ );
116
+ return results.flat();
117
+ })().catch((err) => {
118
+ matchPreviewsCache.delete(key);
119
+ throw err;
120
+ });
121
+
122
+ matchPreviewsCache.set(key, promise);
123
+ return promise;
124
+ }
125
+
126
+ export async function listRoundPreviews(
127
+ matchId: number,
128
+ mapName: string,
129
+ round: number,
130
+ opts: FetchOptions = {}
131
+ ): Promise<PreviewChunk[]> {
132
+ const all = await loadMatchPreviews(matchId, mapName, opts);
133
+ return all
134
+ .filter((p) => p.round === round)
135
+ .sort((a, b) => a.player - b.player || a.chunk_index - b.chunk_index);
136
+ }
src/lib/api/hub.ts ADDED
@@ -0,0 +1,21 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import { DATASET } from '../types';
2
+
3
+ const REF = 'main';
4
+
5
+ export type FetchOpts = { fetch?: typeof fetch; signal?: AbortSignal };
6
+
7
+ /** Build a `huggingface.co/datasets/<repo>/resolve/main/<path>` URL. */
8
+ export function resolveUrl(repoPath: string): string {
9
+ return `https://huggingface.co/datasets/${DATASET}/resolve/${REF}/${repoPath}`;
10
+ }
11
+
12
+ export type TreeEntry = { type: 'file' | 'directory'; path: string; size?: number };
13
+
14
+ /** List entries under `<dataset>/<dirPath>` via the HF tree API. */
15
+ export async function listTree(dirPath: string, opts: FetchOpts = {}): Promise<TreeEntry[]> {
16
+ const fetchFn = opts.fetch ?? fetch;
17
+ const url = `https://huggingface.co/api/datasets/${DATASET}/tree/${REF}/${dirPath}`;
18
+ const r = await fetchFn(url, { signal: opts.signal });
19
+ if (!r.ok) throw new Error(`tree ${dirPath}: ${r.status}`);
20
+ return (await r.json()) as TreeEntry[];
21
+ }
src/lib/api/parquet.ts ADDED
@@ -0,0 +1,55 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import * as arrow from 'apache-arrow';
2
+
3
+ let wasmReady: Promise<void> | null = null;
4
+ let readParquetFn: ((bytes: Uint8Array) => { intoIPCStream: () => Uint8Array }) | null = null;
5
+
6
+ async function ensureWasm(): Promise<void> {
7
+ if (wasmReady) return wasmReady;
8
+ wasmReady = (async () => {
9
+ const mod = await import('parquet-wasm');
10
+ const init = (mod as unknown as { default?: () => Promise<unknown> }).default;
11
+ if (typeof init === 'function') await init();
12
+ readParquetFn = (mod as unknown as { readParquet: typeof readParquetFn }).readParquet!;
13
+ })().catch((err) => {
14
+ wasmReady = null;
15
+ throw err;
16
+ });
17
+ return wasmReady;
18
+ }
19
+
20
+ export type ParquetFetchOptions = {
21
+ fetch?: typeof fetch;
22
+ signal?: AbortSignal;
23
+ };
24
+
25
+ /**
26
+ * Fetch a parquet file over HTTP and return its rows as plain JS objects.
27
+ * Timestamp columns are converted to ISO strings; BigInts become numbers.
28
+ * Nested struct/list columns are returned as Arrow proxies (we don't read any).
29
+ */
30
+ export async function fetchParquetRows<T = Record<string, unknown>>(
31
+ url: string,
32
+ opts: ParquetFetchOptions = {}
33
+ ): Promise<T[]> {
34
+ await ensureWasm();
35
+ const f = opts.fetch ?? fetch;
36
+ const res = await f(url, { signal: opts.signal });
37
+ if (!res.ok) throw new Error(`parquet fetch ${url}: ${res.status} ${res.statusText}`);
38
+ const bytes = new Uint8Array(await res.arrayBuffer());
39
+ const table = arrow.tableFromIPC(readParquetFn!(bytes).intoIPCStream());
40
+
41
+ const timestamps = new Set(
42
+ table.schema.fields.filter((f) => arrow.DataType.isTimestamp(f.type)).map((f) => f.name)
43
+ );
44
+
45
+ return table.toArray().map((row) => {
46
+ const out: Record<string, unknown> = {};
47
+ for (const [k, v] of Object.entries(row as Record<string, unknown>)) {
48
+ if (v == null) out[k] = v;
49
+ else if (timestamps.has(k)) out[k] = new Date(Number(v)).toISOString();
50
+ else if (typeof v === 'bigint') out[k] = Number(v);
51
+ else out[k] = v;
52
+ }
53
+ return out;
54
+ }) as T[];
55
+ }
src/lib/api/world.ts ADDED
@@ -0,0 +1,232 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import type { PreviewChunk } from '../types';
2
+ import type { FetchOpts } from './hub';
3
+
4
+ // One player's pose at one sampled tick. Round-relative `t` (seconds).
5
+ export type WorldFrame = {
6
+ t: number;
7
+ player: number; // dataset slot 0..9
8
+ steamid: string;
9
+ name: string;
10
+ team_num: number;
11
+ is_alive: boolean;
12
+ health: number;
13
+ armor_value: number;
14
+ X: number;
15
+ Y: number;
16
+ Z: number;
17
+ yaw?: number;
18
+ };
19
+
20
+ export type PlayerSeries = {
21
+ player: number;
22
+ frames: WorldFrame[];
23
+ };
24
+
25
+ export type RoundWorld = {
26
+ players: PlayerSeries[];
27
+ duration: number;
28
+ };
29
+
30
+ const cache = new Map<string, Promise<RoundWorld>>();
31
+
32
+ // preview_video.src is ".../player=N/previews/chunk_NNN/preview.mp4" — strip
33
+ // the filename to get the chunk dir we'll resolve sibling assets against.
34
+ function chunkBaseUrl(chunk: PreviewChunk): string {
35
+ return chunk.preview_video.src.replace(/\/[^/]+$/, '');
36
+ }
37
+
38
+ type WorldColumns = {
39
+ t: number[];
40
+ steamid: (number | string)[];
41
+ name: string[];
42
+ team_num: number[];
43
+ is_alive: boolean[];
44
+ health: number[];
45
+ armor_value: number[];
46
+ X: number[];
47
+ Y: number[];
48
+ Z: number[];
49
+ };
50
+
51
+ type InputsJson = {
52
+ t: number[];
53
+ view?: { yaw?: number[] };
54
+ };
55
+
56
+ async function loadChunkFrames(
57
+ chunk: PreviewChunk,
58
+ chunkStartT: number,
59
+ player: number,
60
+ opts: FetchOpts
61
+ ): Promise<WorldFrame[]> {
62
+ const base = chunkBaseUrl(chunk);
63
+ const fetchFn = opts.fetch ?? fetch;
64
+ const [worldR, inputsR] = await Promise.all([
65
+ fetchFn(`${base}/world.preview.jsonl`, { signal: opts.signal }),
66
+ fetchFn(`${base}/inputs.preview.json`, { signal: opts.signal })
67
+ ]);
68
+ if (!worldR.ok) return [];
69
+ const worldText = await worldR.text();
70
+ // JSONL with one columnar object on the first line.
71
+ const firstLine = worldText.split('\n').find((l) => l.trim().length > 0);
72
+ if (!firstLine) return [];
73
+ const world = JSON.parse(firstLine) as WorldColumns;
74
+ const inputs: InputsJson | null = inputsR.ok ? await inputsR.json() : null;
75
+ const yawArr = inputs?.view?.yaw;
76
+
77
+ const n = world.t.length;
78
+ const frames: WorldFrame[] = new Array(n);
79
+ for (let i = 0; i < n; i++) {
80
+ frames[i] = {
81
+ t: chunkStartT + world.t[i],
82
+ player,
83
+ steamid: String(world.steamid[i]),
84
+ name: world.name[i],
85
+ team_num: world.team_num[i],
86
+ is_alive: world.is_alive[i],
87
+ health: world.health[i],
88
+ armor_value: world.armor_value[i],
89
+ X: world.X[i],
90
+ Y: world.Y[i],
91
+ Z: world.Z[i],
92
+ yaw: yawArr?.[i]
93
+ };
94
+ }
95
+ return frames;
96
+ }
97
+
98
+ export async function loadRoundWorld(
99
+ matchId: number,
100
+ mapName: string,
101
+ round: number,
102
+ chunks: PreviewChunk[],
103
+ opts: FetchOpts = {}
104
+ ): Promise<RoundWorld> {
105
+ const key = `${matchId}/${mapName}/${round}`;
106
+ const cached = cache.get(key);
107
+ if (cached) return cached;
108
+
109
+ const promise = (async () => {
110
+ const byPlayer = new Map<number, PreviewChunk[]>();
111
+ for (const c of chunks) {
112
+ if (c.round !== round) continue;
113
+ if (!byPlayer.has(c.player)) byPlayer.set(c.player, []);
114
+ byPlayer.get(c.player)!.push(c);
115
+ }
116
+
117
+ // If we were asked to load a round whose chunks haven't arrived yet,
118
+ // don't poison the cache with an empty result — let the next call
119
+ // (with chunks) actually fetch.
120
+ if (byPlayer.size === 0) {
121
+ cache.delete(key);
122
+ return { players: [], duration: 0 } as RoundWorld;
123
+ }
124
+
125
+ const players: PlayerSeries[] = await Promise.all(
126
+ Array.from(byPlayer.entries()).map(async ([player, list]) => {
127
+ list.sort((a, b) => a.chunk_index - b.chunk_index);
128
+ let startT = 0;
129
+ const frames: WorldFrame[] = [];
130
+ for (const c of list) {
131
+ const f = await loadChunkFrames(c, startT, player, opts);
132
+ frames.push(...f);
133
+ startT += c.duration_s || 0;
134
+ }
135
+ return { player, frames };
136
+ })
137
+ );
138
+
139
+ const duration = players.reduce(
140
+ (m, p) => Math.max(m, p.frames[p.frames.length - 1]?.t ?? 0),
141
+ 0
142
+ );
143
+ return { players, duration };
144
+ })().catch((err) => {
145
+ cache.delete(key);
146
+ throw err;
147
+ });
148
+
149
+ cache.set(key, promise);
150
+ return promise;
151
+ }
152
+
153
+ function nearestLeq(frames: WorldFrame[], t: number): number {
154
+ let lo = 0;
155
+ let hi = frames.length - 1;
156
+ let best = -1;
157
+ while (lo <= hi) {
158
+ const mid = (lo + hi) >> 1;
159
+ if (frames[mid].t <= t) {
160
+ best = mid;
161
+ lo = mid + 1;
162
+ } else {
163
+ hi = mid - 1;
164
+ }
165
+ }
166
+ return best;
167
+ }
168
+
169
+ // Shortest-arc lerp so a player turning across the ±180° boundary doesn't
170
+ // spin the long way around between sampled ticks.
171
+ function lerpAngle(a: number, b: number, alpha: number): number {
172
+ const d = (((b - a + 540) % 360) - 180) || 0;
173
+ return a + d * alpha;
174
+ }
175
+
176
+ export type Snapshot = {
177
+ player: number;
178
+ steamid: string;
179
+ name: string;
180
+ team_num: number;
181
+ is_alive: boolean;
182
+ health: number;
183
+ X: number;
184
+ Y: number;
185
+ Z: number;
186
+ yaw?: number;
187
+ };
188
+
189
+ export function snapshotAt(world: RoundWorld, t: number): Snapshot[] {
190
+ const out: Snapshot[] = [];
191
+ for (const series of world.players) {
192
+ const frames = series.frames;
193
+ if (!frames.length) continue;
194
+ const i = nearestLeq(frames, t);
195
+ const cur = i < 0 ? frames[0] : frames[i];
196
+ const next = i >= 0 && i + 1 < frames.length ? frames[i + 1] : null;
197
+
198
+ // If we've run off the end of this player's series (typically: died
199
+ // mid-round and their chunks stop), drop them after a small grace
200
+ // window so the last-known position doesn't linger forever.
201
+ const last = frames[frames.length - 1];
202
+ if (!next && t > last.t + 2) continue;
203
+
204
+ let X = cur.X;
205
+ let Y = cur.Y;
206
+ let Z = cur.Z;
207
+ let yaw = cur.yaw;
208
+ if (next && next.t > cur.t) {
209
+ const alpha = Math.max(0, Math.min(1, (t - cur.t) / (next.t - cur.t)));
210
+ X = cur.X + (next.X - cur.X) * alpha;
211
+ Y = cur.Y + (next.Y - cur.Y) * alpha;
212
+ Z = cur.Z + (next.Z - cur.Z) * alpha;
213
+ if (cur.yaw !== undefined && next.yaw !== undefined) {
214
+ yaw = lerpAngle(cur.yaw, next.yaw, alpha);
215
+ }
216
+ }
217
+
218
+ out.push({
219
+ player: cur.player,
220
+ steamid: cur.steamid,
221
+ name: cur.name,
222
+ team_num: cur.team_num,
223
+ is_alive: cur.is_alive,
224
+ health: cur.health,
225
+ X,
226
+ Y,
227
+ Z,
228
+ yaw
229
+ });
230
+ }
231
+ return out;
232
+ }
src/lib/assets/favicon.svg ADDED
src/lib/components/grid-tile.svelte ADDED
@@ -0,0 +1,187 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <script lang="ts">
2
+ import { onDestroy } from 'svelte';
3
+ import { ChunkedMediaSource, type Chunk } from '$lib/components/video-player';
4
+ import { Skull, SpeakerHigh } from 'phosphor-svelte';
5
+ import { playerColor } from '$lib/utils/player-colors';
6
+
7
+ interface Props {
8
+ chunks: Chunk[];
9
+ masterTime: number;
10
+ masterPaused: boolean;
11
+ isLeader: boolean;
12
+ isCurrent: boolean;
13
+ isMuted: boolean;
14
+ available: boolean;
15
+ duration: number;
16
+ player: number;
17
+ side: 'CT' | 'T' | string;
18
+ onSelect: () => void;
19
+ onLeaderTime?: (t: number) => void;
20
+ onLeaderEnded?: () => void;
21
+ onBufferedChange?: (player: number, ranges: { start: number; end: number }[]) => void;
22
+ }
23
+
24
+ let {
25
+ chunks,
26
+ masterTime,
27
+ masterPaused,
28
+ isLeader,
29
+ isCurrent,
30
+ isMuted,
31
+ available,
32
+ duration,
33
+ player,
34
+ side,
35
+ onSelect,
36
+ onLeaderTime,
37
+ onLeaderEnded,
38
+ onBufferedChange
39
+ }: Props = $props();
40
+
41
+ let videoEl = $state<HTMLVideoElement | undefined>();
42
+ let mse: ChunkedMediaSource | null = null;
43
+ let videoSrc = $state<string | undefined>(undefined);
44
+
45
+ function chunksSig(cs: Chunk[]): string {
46
+ return cs.length ? `${cs.length}|${cs[0].src}|${cs[cs.length - 1].src}` : '';
47
+ }
48
+ let prevSig = '';
49
+
50
+ $effect(() => {
51
+ const sig = chunksSig(chunks);
52
+ if (sig === prevSig) return;
53
+ prevSig = sig;
54
+ if (mse) {
55
+ mse.destroy();
56
+ mse = null;
57
+ }
58
+ if (videoSrc) {
59
+ URL.revokeObjectURL(videoSrc);
60
+ videoSrc = undefined;
61
+ }
62
+ if (!chunks.length) return;
63
+ const m = new ChunkedMediaSource(chunks, {
64
+ codecOverride: ChunkedMediaSource.getCachedCodec() ?? undefined,
65
+ priorityTime: masterTime
66
+ });
67
+ mse = m;
68
+ videoSrc = m.url;
69
+ m.start().catch(() => {});
70
+ });
71
+
72
+ // Drift correction: pull our currentTime back toward the master if we
73
+ // fall out of step (network jitter, decoder hiccups, etc.).
74
+ $effect(() => {
75
+ if (!videoEl) return;
76
+ const t = masterTime;
77
+ if (!Number.isFinite(t)) return;
78
+ if (Math.abs(videoEl.currentTime - t) > 0.35) {
79
+ try {
80
+ videoEl.currentTime = t;
81
+ } catch {
82
+ /* not seekable yet */
83
+ }
84
+ }
85
+ });
86
+
87
+ // Mirror the master play/pause state.
88
+ $effect(() => {
89
+ if (!videoEl) return;
90
+ if (masterPaused) videoEl.pause();
91
+ else videoEl.play()?.catch(() => {});
92
+ });
93
+
94
+ $effect(() => {
95
+ if (videoEl) videoEl.muted = isMuted;
96
+ });
97
+
98
+ function onTimeUpdate() {
99
+ if (videoEl && isLeader) {
100
+ onLeaderTime?.(videoEl.currentTime);
101
+ }
102
+ }
103
+
104
+ function onEnded() {
105
+ if (isLeader) onLeaderEnded?.();
106
+ }
107
+
108
+ function onProgress() {
109
+ if (!videoEl || !onBufferedChange) return;
110
+ const ranges = videoEl.buffered;
111
+ const out: { start: number; end: number }[] = [];
112
+ for (let i = 0; i < ranges.length; i++) {
113
+ out.push({ start: ranges.start(i), end: ranges.end(i) });
114
+ }
115
+ onBufferedChange(player, out);
116
+ }
117
+
118
+ onDestroy(() => {
119
+ mse?.destroy();
120
+ if (videoSrc) URL.revokeObjectURL(videoSrc);
121
+ });
122
+
123
+ const ct = $derived(side === 'CT');
124
+ const color = $derived(playerColor(player));
125
+ </script>
126
+
127
+ <!-- svelte-ignore a11y_click_events_have_key_events -->
128
+ <!-- svelte-ignore a11y_no_static_element_interactions -->
129
+ <div
130
+ class="group relative aspect-video overflow-hidden rounded-md border bg-black transition cursor-pointer
131
+ {isCurrent
132
+ ? ct
133
+ ? 'border-sky-500 ring-2 ring-sky-500/40'
134
+ : 'border-amber-500 ring-2 ring-amber-500/40'
135
+ : 'border-border hover:border-foreground/40'}
136
+ {!available ? 'opacity-60' : ''}"
137
+ onclick={() => available && onSelect()}
138
+ role="button"
139
+ tabindex={available ? 0 : -1}
140
+ aria-label="Switch to player {player}"
141
+ >
142
+ <!-- svelte-ignore a11y_media_has_caption -->
143
+ <video
144
+ bind:this={videoEl}
145
+ src={videoSrc}
146
+ muted={isMuted}
147
+ playsinline
148
+ autoplay={!masterPaused}
149
+ preload="auto"
150
+ disablepictureinpicture
151
+ disableremoteplayback
152
+ controlslist="nodownload nofullscreen noplaybackrate noremoteplayback"
153
+ oncontextmenu={(e) => e.preventDefault()}
154
+ ontimeupdate={onTimeUpdate}
155
+ onended={onEnded}
156
+ onprogress={onProgress}
157
+ class="h-full w-full object-cover"
158
+ ></video>
159
+
160
+ <!-- top-left: player number, colored per slot -->
161
+ <div
162
+ class="absolute left-1.5 top-1.5 flex h-6 w-6 items-center justify-center rounded-sm font-mono text-[11px] font-bold text-white/95 shadow-sm ring-1 ring-black/20"
163
+ style="background-color: {color};"
164
+ >
165
+ {player}
166
+ </div>
167
+
168
+ {#if isLeader}
169
+ <div
170
+ class="absolute right-1.5 top-1.5 grid h-5 w-5 place-items-center rounded bg-emerald-500/85 text-white shadow ring-1 ring-black/20"
171
+ aria-label="Audio source"
172
+ title="Audio source"
173
+ >
174
+ <SpeakerHigh size={11} weight="fill" />
175
+ </div>
176
+ {/if}
177
+
178
+ {#if !available}
179
+ <div
180
+ class="absolute right-1.5 bottom-1.5 grid h-5 w-5 place-items-center rounded bg-rose-500/85 text-white shadow ring-1 ring-black/20"
181
+ aria-label="Player is dead"
182
+ title="Player is dead"
183
+ >
184
+ <Skull size={11} weight="duotone" />
185
+ </div>
186
+ {/if}
187
+ </div>
src/lib/components/header.svelte ADDED
@@ -0,0 +1,80 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <script lang="ts">
2
+ import { Button } from '$lib/components/ui/button';
3
+ import * as Breadcrumb from '$lib/components/ui/breadcrumb';
4
+ import * as Tooltip from '$lib/components/ui/tooltip';
5
+ import { Sun, Moon, Crosshair } from 'phosphor-svelte';
6
+ import { mode, toggleMode } from 'mode-watcher';
7
+ import HfLogo from '$lib/components/hf-logo.svelte';
8
+
9
+ interface Props {
10
+ breadcrumb?: { label: string; href?: string }[];
11
+ }
12
+ let { breadcrumb = [] }: Props = $props();
13
+ </script>
14
+
15
+ <header
16
+ class="bg-background/80 supports-backdrop-filter:bg-background/60 sticky top-0 z-30 border-b backdrop-blur"
17
+ >
18
+ <div class="mx-auto flex h-14 w-full max-w-[1600px] items-center gap-4 px-4">
19
+ <a href="/" class="font-heading flex items-center gap-2 text-base font-semibold tracking-tight">
20
+ <Crosshair size={20} weight="duotone" class="text-primary" />
21
+ <span>CS2 Render Dataset</span>
22
+ </a>
23
+
24
+ {#if breadcrumb.length}
25
+ <Breadcrumb.Root class="hidden sm:flex">
26
+ <Breadcrumb.List>
27
+ {#each breadcrumb as crumb, i (i)}
28
+ <Breadcrumb.Item>
29
+ {#if crumb.href}
30
+ <Breadcrumb.Link href={crumb.href}>{crumb.label}</Breadcrumb.Link>
31
+ {:else}
32
+ <Breadcrumb.Page>{crumb.label}</Breadcrumb.Page>
33
+ {/if}
34
+ </Breadcrumb.Item>
35
+ {#if i < breadcrumb.length - 1}
36
+ <Breadcrumb.Separator />
37
+ {/if}
38
+ {/each}
39
+ </Breadcrumb.List>
40
+ </Breadcrumb.Root>
41
+ {/if}
42
+
43
+ <div class="ml-auto flex items-center gap-1">
44
+ <Tooltip.Root>
45
+ <Tooltip.Trigger>
46
+ {#snippet child({ props })}
47
+ <Button
48
+ {...props}
49
+ href="https://huggingface.co/datasets/blanchon/cs2_dataset_render"
50
+ target="_blank"
51
+ rel="noreferrer noopener"
52
+ variant="ghost"
53
+ size="icon"
54
+ aria-label="Dataset on Hugging Face"
55
+ >
56
+ <HfLogo class="size-5" />
57
+ </Button>
58
+ {/snippet}
59
+ </Tooltip.Trigger>
60
+ <Tooltip.Content side="bottom">View dataset on Hugging Face</Tooltip.Content>
61
+ </Tooltip.Root>
62
+ <Tooltip.Root>
63
+ <Tooltip.Trigger>
64
+ {#snippet child({ props })}
65
+ <Button {...props} variant="ghost" size="icon" onclick={toggleMode} aria-label="Toggle theme">
66
+ {#if mode.current === 'dark'}
67
+ <Sun size={18} weight="duotone" />
68
+ {:else}
69
+ <Moon size={18} weight="duotone" />
70
+ {/if}
71
+ </Button>
72
+ {/snippet}
73
+ </Tooltip.Trigger>
74
+ <Tooltip.Content side="bottom">
75
+ Switch to {mode.current === 'dark' ? 'light' : 'dark'} mode
76
+ </Tooltip.Content>
77
+ </Tooltip.Root>
78
+ </div>
79
+ </div>
80
+ </header>
src/lib/components/hf-logo.svelte ADDED
@@ -0,0 +1,28 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <script lang="ts">
2
+ interface Props {
3
+ class?: string;
4
+ }
5
+ let { class: className = '' }: Props = $props();
6
+ </script>
7
+
8
+ <svg
9
+ viewBox="0 0 100 100"
10
+ fill="none"
11
+ xmlns="http://www.w3.org/2000/svg"
12
+ role="img"
13
+ aria-label="Hugging Face"
14
+ class={className}
15
+ >
16
+ <circle cx="50" cy="48" r="34" fill="#FFD21E" />
17
+ <ellipse cx="38" cy="44" rx="4.5" ry="6" fill="#1F2937" />
18
+ <ellipse cx="62" cy="44" rx="4.5" ry="6" fill="#1F2937" />
19
+ <path
20
+ d="M32 58 Q50 73 68 58"
21
+ stroke="#1F2937"
22
+ stroke-width="4"
23
+ fill="none"
24
+ stroke-linecap="round"
25
+ />
26
+ <ellipse cx="14" cy="60" rx="9" ry="11" transform="rotate(-15 14 60)" fill="#FF9D0B" />
27
+ <ellipse cx="86" cy="60" rx="9" ry="11" transform="rotate(15 86 60)" fill="#FF9D0B" />
28
+ </svg>
src/lib/components/map-preview.svelte ADDED
@@ -0,0 +1,179 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <script lang="ts">
2
+ import { Skeleton } from '$lib/components/ui/skeleton';
3
+ import * as ToggleGroup from '$lib/components/ui/toggle-group';
4
+ import {
5
+ loadMapData,
6
+ radarUrl,
7
+ hasLowerFloor,
8
+ floorForZ,
9
+ worldToImage,
10
+ yawToScreenDeg,
11
+ RADAR_PX,
12
+ type MapData,
13
+ type Floor
14
+ } from '$lib/utils/map';
15
+
16
+ type Player = {
17
+ steamid: string;
18
+ name: string;
19
+ team_num: number;
20
+ is_alive: boolean;
21
+ health: number;
22
+ X: number;
23
+ Y: number;
24
+ Z: number;
25
+ yaw?: number;
26
+ color: string;
27
+ slot?: number;
28
+ };
29
+
30
+ type Props = {
31
+ mapName: string;
32
+ players: Player[];
33
+ size?: number;
34
+ floor?: 'upper' | 'lower' | 'auto';
35
+ class?: string;
36
+ };
37
+
38
+ let { mapName, players, size, floor = 'auto', class: className = '' }: Props = $props();
39
+
40
+ let allMaps = $state<Record<string, MapData> | null>(null);
41
+ let userFloor = $state<Floor | null>(null);
42
+
43
+ $effect(() => {
44
+ let cancelled = false;
45
+ loadMapData()
46
+ .then((d) => {
47
+ if (!cancelled) allMaps = d;
48
+ })
49
+ .catch(() => {});
50
+ return () => {
51
+ cancelled = true;
52
+ };
53
+ });
54
+
55
+ const map = $derived(allMaps?.[mapName] ?? null);
56
+ const lowerAvailable = $derived(map ? hasLowerFloor(map) : false);
57
+
58
+ const autoFloor = $derived.by<Floor>(() => {
59
+ if (!map || !lowerAvailable) return 'upper';
60
+ let upper = 0;
61
+ let lower = 0;
62
+ for (const p of players) {
63
+ if (!p.is_alive) continue;
64
+ if (floorForZ(map, p.Z) === 'lower') lower++;
65
+ else upper++;
66
+ }
67
+ return lower > upper ? 'lower' : 'upper';
68
+ });
69
+
70
+ const displayedFloor = $derived<Floor>(
71
+ userFloor ?? (floor === 'auto' ? autoFloor : (floor as Floor))
72
+ );
73
+
74
+ const toggleValue = $derived<Floor>(displayedFloor);
75
+ </script>
76
+
77
+ <div
78
+ class="relative {size === undefined ? 'aspect-square w-full' : ''} {className}"
79
+ style={size === undefined ? undefined : `width: ${size}px; height: ${size}px;`}
80
+ >
81
+ {#if !map}
82
+ <Skeleton class="h-full w-full rounded-md" />
83
+ {:else}
84
+ <img
85
+ src={radarUrl(mapName, displayedFloor)}
86
+ alt="{mapName} radar"
87
+ class="absolute inset-0 h-full w-full select-none rounded-md"
88
+ draggable="false"
89
+ />
90
+ <svg
91
+ viewBox="0 0 {RADAR_PX} {RADAR_PX}"
92
+ class="absolute inset-0 h-full w-full"
93
+ aria-label="Player positions on {mapName}"
94
+ >
95
+ {#each players as p (p.steamid)}
96
+ {@const { px, py } = worldToImage(map, p.X, p.Y)}
97
+ {@const playerFloor = floorForZ(map, p.Z)}
98
+ {@const onDisplayed = !lowerAvailable || playerFloor === displayedFloor}
99
+ {@const baseOpacity = onDisplayed ? 1 : 0.3}
100
+ <g opacity={baseOpacity}>
101
+ <title>{p.name}{p.slot !== undefined ? ` (#${p.slot})` : ''}</title>
102
+ {#if p.is_alive}
103
+ {#if p.yaw !== undefined}
104
+ <polygon
105
+ points="0,-7 26,0 0,7"
106
+ fill={p.color}
107
+ fill-opacity="0.45"
108
+ stroke={p.color}
109
+ stroke-width="1.5"
110
+ transform="translate({px} {py}) rotate({yawToScreenDeg(p.yaw)})"
111
+ />
112
+ {/if}
113
+ <circle
114
+ cx={px}
115
+ cy={py}
116
+ r="14"
117
+ fill={p.color}
118
+ stroke="#0b0f14"
119
+ stroke-width="2.5"
120
+ />
121
+ {#if p.slot !== undefined}
122
+ <text
123
+ x={px}
124
+ y={py}
125
+ text-anchor="middle"
126
+ dominant-baseline="central"
127
+ font-size="16"
128
+ font-weight="700"
129
+ fill="#fff"
130
+ stroke="#0b0f14"
131
+ stroke-width="0.5"
132
+ paint-order="stroke"
133
+ style="pointer-events: none; user-select: none;"
134
+ >
135
+ {p.slot}
136
+ </text>
137
+ {/if}
138
+ {:else}
139
+ <g
140
+ opacity={baseOpacity * 0.55}
141
+ transform="translate({px} {py})"
142
+ stroke={p.color}
143
+ stroke-width="2.5"
144
+ fill="none"
145
+ >
146
+ <circle r="11" />
147
+ <line x1="-6" y1="-6" x2="6" y2="6" />
148
+ <line x1="-6" y1="6" x2="6" y2="-6" />
149
+ </g>
150
+ {/if}
151
+ </g>
152
+ {/each}
153
+ </svg>
154
+
155
+ {#if lowerAvailable}
156
+ <div class="absolute right-2 top-2">
157
+ <ToggleGroup.Root
158
+ type="single"
159
+ value={toggleValue}
160
+ onValueChange={(v) => {
161
+ if (v === 'upper' || v === 'lower') userFloor = v;
162
+ }}
163
+ variant="outline"
164
+ size="sm"
165
+ spacing={1}
166
+ aria-label="Floor"
167
+ class="bg-background/80 backdrop-blur-sm"
168
+ >
169
+ <ToggleGroup.Item value="upper" aria-label="Upper floor" class="text-xs">
170
+ Upper
171
+ </ToggleGroup.Item>
172
+ <ToggleGroup.Item value="lower" aria-label="Lower floor" class="text-xs">
173
+ Lower
174
+ </ToggleGroup.Item>
175
+ </ToggleGroup.Root>
176
+ </div>
177
+ {/if}
178
+ {/if}
179
+ </div>
src/lib/components/match-card.svelte ADDED
@@ -0,0 +1,87 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <script lang="ts">
2
+ import type { Match } from '$lib/types';
3
+ import * as Card from '$lib/components/ui/card';
4
+ import { Badge } from '$lib/components/ui/badge';
5
+ import { Calendar, MapPin, FilmSlate, Shield, Sword } from 'phosphor-svelte';
6
+ import { formatDate, prettyMap } from '$lib/utils/format';
7
+ import { mapColorClasses } from '$lib/utils/map-colors';
8
+
9
+ interface Props {
10
+ match: Match;
11
+ }
12
+ let { match }: Props = $props();
13
+
14
+ const team1Wins = $derived(match.winner === 'team1');
15
+ const team2Wins = $derived(match.winner === 'team2');
16
+ const href = $derived(
17
+ `/match/${encodeURIComponent(match.match_id)}/${encodeURIComponent(match.map_name)}`
18
+ );
19
+ const winnerSide = $derived((match.winner_side ?? '').toLowerCase());
20
+ </script>
21
+
22
+ <a {href} class="group block focus:outline-none">
23
+ <Card.Root
24
+ class="hover:border-primary/40 hover:shadow-md group-focus-visible:ring-ring h-full transition-all group-focus-visible:ring-2"
25
+ >
26
+ <Card.Header class="gap-1 pb-3">
27
+ <div class="text-muted-foreground flex items-center justify-between text-xs">
28
+ <span class="inline-flex items-center gap-1">
29
+ <Calendar size={12} weight="duotone" />
30
+ {formatDate(match.match_date)}
31
+ </span>
32
+ <span class="inline-flex items-center gap-1 uppercase tracking-wide">
33
+ {match.format}
34
+ </span>
35
+ </div>
36
+ <Card.Title class="font-heading mt-1 truncate text-base font-semibold tracking-tight">
37
+ {match.event}
38
+ </Card.Title>
39
+ </Card.Header>
40
+
41
+ <Card.Content class="space-y-3">
42
+ <div class="grid grid-cols-[1fr_auto_1fr] items-center gap-2">
43
+ <div
44
+ class="truncate text-right text-sm font-medium {team1Wins
45
+ ? 'text-foreground'
46
+ : 'text-muted-foreground'}"
47
+ >
48
+ {match.team1}
49
+ </div>
50
+ <div class="flex items-center gap-1 text-base font-bold tabular-nums">
51
+ <span class={team1Wins ? 'text-primary' : 'text-muted-foreground'}>{match.score1}</span>
52
+ <span class="text-muted-foreground/50 text-xs">:</span>
53
+ <span class={team2Wins ? 'text-primary' : 'text-muted-foreground'}>{match.score2}</span>
54
+ </div>
55
+ <div
56
+ class="truncate text-left text-sm font-medium {team2Wins
57
+ ? 'text-foreground'
58
+ : 'text-muted-foreground'}"
59
+ >
60
+ {match.team2}
61
+ </div>
62
+ </div>
63
+
64
+ <div class="flex flex-wrap items-center gap-1.5">
65
+ <Badge class="gap-1 border capitalize {mapColorClasses(match.map_name)}">
66
+ <MapPin size={11} weight="duotone" />{prettyMap(match.map_name)}
67
+ </Badge>
68
+ <Badge variant="outline" class="gap-1">
69
+ <FilmSlate size={11} weight="duotone" />{match.rounds_played} rounds
70
+ </Badge>
71
+ {#if winnerSide === 'ct'}
72
+ <Badge
73
+ class="gap-1 border border-sky-500/40 bg-sky-500/15 text-sky-700 dark:text-sky-300"
74
+ >
75
+ <Shield size={11} weight="duotone" /> CT won
76
+ </Badge>
77
+ {:else if winnerSide === 't'}
78
+ <Badge
79
+ class="gap-1 border border-amber-500/40 bg-amber-500/15 text-amber-700 dark:text-amber-300"
80
+ >
81
+ <Sword size={11} weight="duotone" /> T won
82
+ </Badge>
83
+ {/if}
84
+ </div>
85
+ </Card.Content>
86
+ </Card.Root>
87
+ </a>
src/lib/components/match-info.svelte ADDED
@@ -0,0 +1,103 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <script lang="ts">
2
+ import type { Match } from '$lib/types';
3
+ import { Badge } from '$lib/components/ui/badge';
4
+ import { Calendar, MapPin, Shield, Sword, FilmSlate, ArrowSquareOut, Hash } from 'phosphor-svelte';
5
+ import { formatDateTime, prettyMap } from '$lib/utils/format';
6
+ import { mapColorClasses } from '$lib/utils/map-colors';
7
+
8
+ interface Props {
9
+ match: Match;
10
+ }
11
+ let { match }: Props = $props();
12
+
13
+ const team1Wins = $derived(match.winner === 'team1');
14
+ const winnerSide = $derived((match.winner_side ?? '').toLowerCase());
15
+ </script>
16
+
17
+ <div class="space-y-3">
18
+ <div>
19
+ <div class="text-muted-foreground text-xs uppercase tracking-wide">Event</div>
20
+ <div class="font-heading mt-0.5 text-sm font-semibold">{match.event}</div>
21
+ </div>
22
+
23
+ <div class="border-y py-3">
24
+ <div class="grid grid-cols-[1fr_auto_1fr] items-center gap-3">
25
+ <div
26
+ class="text-right text-sm font-medium {team1Wins ? 'text-foreground' : 'text-muted-foreground'}"
27
+ >
28
+ {match.team1}
29
+ </div>
30
+ <div class="font-heading flex items-center gap-1 text-xl font-bold tabular-nums">
31
+ <span class={team1Wins ? 'text-primary' : ''}>{match.score1}</span>
32
+ <span class="text-muted-foreground/40">:</span>
33
+ <span class={!team1Wins ? 'text-primary' : ''}>{match.score2}</span>
34
+ </div>
35
+ <div
36
+ class="text-left text-sm font-medium {!team1Wins ? 'text-foreground' : 'text-muted-foreground'}"
37
+ >
38
+ {match.team2}
39
+ </div>
40
+ </div>
41
+ </div>
42
+
43
+ <dl class="grid grid-cols-2 gap-x-3 gap-y-2 text-xs">
44
+ <dt class="text-muted-foreground inline-flex items-center gap-1">
45
+ <MapPin size={12} weight="duotone" /> Map
46
+ </dt>
47
+ <dd class="text-right">
48
+ <Badge class="gap-1 border capitalize {mapColorClasses(match.map_name)}">
49
+ {prettyMap(match.map_name)}
50
+ </Badge>
51
+ </dd>
52
+
53
+ <dt class="text-muted-foreground inline-flex items-center gap-1">
54
+ <FilmSlate size={12} weight="duotone" /> Format
55
+ </dt>
56
+ <dd class="text-right font-medium uppercase">{match.format}</dd>
57
+
58
+ <dt class="text-muted-foreground inline-flex items-center gap-1">
59
+ <Calendar size={12} weight="duotone" /> Played
60
+ </dt>
61
+ <dd class="text-right font-medium">{formatDateTime(match.match_date)}</dd>
62
+
63
+ {#if winnerSide === 'ct' || winnerSide === 't'}
64
+ <dt class="text-muted-foreground inline-flex items-center gap-1">
65
+ {#if winnerSide === 'ct'}
66
+ <Shield size={12} weight="duotone" />
67
+ {:else}
68
+ <Sword size={12} weight="duotone" />
69
+ {/if}
70
+ Winner
71
+ </dt>
72
+ <dd class="text-right">
73
+ {#if winnerSide === 'ct'}
74
+ <Badge class="gap-1 border border-sky-500/40 bg-sky-500/15 text-sky-700 dark:text-sky-300">
75
+ <Shield size={11} weight="duotone" /> CT won
76
+ </Badge>
77
+ {:else}
78
+ <Badge
79
+ class="gap-1 border border-amber-500/40 bg-amber-500/15 text-amber-700 dark:text-amber-300"
80
+ >
81
+ <Sword size={11} weight="duotone" /> T won
82
+ </Badge>
83
+ {/if}
84
+ </dd>
85
+ {/if}
86
+
87
+ <dt class="text-muted-foreground inline-flex items-center gap-1">
88
+ <Hash size={12} weight="duotone" /> Rounds
89
+ </dt>
90
+ <dd class="text-right font-medium tabular-nums">{match.rounds_played}</dd>
91
+ </dl>
92
+
93
+ {#if match.match_url}
94
+ <a
95
+ class="text-muted-foreground hover:text-foreground inline-flex items-center gap-1 text-xs underline-offset-2 hover:underline"
96
+ href={match.match_url}
97
+ target="_blank"
98
+ rel="noreferrer noopener"
99
+ >
100
+ <ArrowSquareOut size={12} weight="duotone" /> View on HLTV
101
+ </a>
102
+ {/if}
103
+ </div>
src/lib/components/match-map.svelte ADDED
@@ -0,0 +1,74 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <script lang="ts">
2
+ import MapPreview from '$lib/components/map-preview.svelte';
3
+ import { Skeleton } from '$lib/components/ui/skeleton';
4
+ import { loadRoundWorld, snapshotAt, type RoundWorld } from '$lib/api/world';
5
+ import { playerColor } from '$lib/utils/player-colors';
6
+ import type { PreviewChunk } from '$lib/types';
7
+
8
+ type Props = {
9
+ matchId: number;
10
+ mapName: string;
11
+ round: number;
12
+ chunks: PreviewChunk[];
13
+ virtualTime: number;
14
+ };
15
+
16
+ let { matchId, mapName, round, chunks, virtualTime }: Props = $props();
17
+
18
+ let world = $state<RoundWorld | null>(null);
19
+ let error = $state<string | null>(null);
20
+
21
+ // On round change, `round` updates a render before `chunks` (the parent's
22
+ // `previews` state is replaced after an async fetch). Filter here so we
23
+ // only kick off the world load once chunks for the *new* round have
24
+ // arrived — otherwise we'd cache an empty result under the new key.
25
+ const roundChunks = $derived(chunks.filter((c) => c.round === round));
26
+
27
+ $effect(() => {
28
+ const _matchId = matchId;
29
+ const _mapName = mapName;
30
+ const _round = round;
31
+ const _chunks = roundChunks;
32
+ if (!_chunks.length) {
33
+ world = null;
34
+ error = null;
35
+ return;
36
+ }
37
+ let cancelled = false;
38
+ const ctrl = new AbortController();
39
+ world = null;
40
+ error = null;
41
+ loadRoundWorld(_matchId, _mapName, _round, _chunks, { signal: ctrl.signal })
42
+ .then((w) => {
43
+ if (!cancelled) world = w;
44
+ })
45
+ .catch((e) => {
46
+ if (cancelled || (e as Error)?.name === 'AbortError') return;
47
+ error = (e as Error).message ?? 'Failed to load world data';
48
+ });
49
+ return () => {
50
+ cancelled = true;
51
+ ctrl.abort();
52
+ };
53
+ });
54
+
55
+ const players = $derived(
56
+ world
57
+ ? snapshotAt(world, virtualTime).map((s) => ({
58
+ ...s,
59
+ color: playerColor(s.player),
60
+ slot: s.player
61
+ }))
62
+ : []
63
+ );
64
+ </script>
65
+
66
+ {#if error}
67
+ <div class="text-muted-foreground bg-muted/30 rounded-md border p-3 text-xs">
68
+ Map data unavailable: {error}
69
+ </div>
70
+ {:else if !world}
71
+ <Skeleton class="aspect-square w-full rounded-md" />
72
+ {:else}
73
+ <MapPreview {mapName} {players} />
74
+ {/if}
src/lib/components/perspective-grid.svelte ADDED
@@ -0,0 +1,190 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <script lang="ts">
2
+ import type { PreviewChunk } from "$lib/types";
3
+ import GridTile from "./grid-tile.svelte";
4
+ import { Shield, Sword } from "phosphor-svelte";
5
+ import { playerColor } from "$lib/utils/player-colors";
6
+
7
+ interface Props {
8
+ previews: PreviewChunk[];
9
+ currentPlayer: number;
10
+ availablePlayers: Set<number>;
11
+ playerDurations: Map<number, number>;
12
+ virtualTime: number;
13
+ paused?: boolean;
14
+ muted?: boolean;
15
+ onPausedChange?: (paused: boolean) => void;
16
+ onSelect: (player: number) => void;
17
+ onTimeUpdate?: (t: number) => void;
18
+ onLeaderEnded?: () => void;
19
+ onBufferedChange?: (ranges: { start: number; end: number }[]) => void;
20
+ }
21
+
22
+ let {
23
+ previews,
24
+ currentPlayer,
25
+ availablePlayers,
26
+ playerDurations,
27
+ virtualTime,
28
+ paused = false,
29
+ muted = false,
30
+ onSelect,
31
+ onTimeUpdate,
32
+ onLeaderEnded,
33
+ onBufferedChange,
34
+ }: Props = $props();
35
+
36
+ type PerPlayer = {
37
+ player: number;
38
+ side: "CT" | "T" | string;
39
+ weapon: string;
40
+ chunks: { src: string; duration: number }[];
41
+ duration: number;
42
+ };
43
+
44
+ const perPlayer = $derived.by<PerPlayer[]>(() => {
45
+ const map = new Map<number, PreviewChunk[]>();
46
+ for (const p of previews) {
47
+ if (!map.has(p.player)) map.set(p.player, []);
48
+ map.get(p.player)!.push(p);
49
+ }
50
+ const out: PerPlayer[] = [];
51
+ for (const [player, chunks] of map.entries()) {
52
+ chunks.sort((a, b) => a.chunk_index - b.chunk_index);
53
+ const last = chunks[chunks.length - 1];
54
+ out.push({
55
+ player,
56
+ side: last.player_side,
57
+ weapon: last.primary_weapon,
58
+ chunks: chunks.map((c) => ({
59
+ src: c.preview_video.src,
60
+ duration: c.duration_s,
61
+ })),
62
+ duration: playerDurations.get(player) ?? 0,
63
+ });
64
+ }
65
+ out.sort((a, b) => a.player - b.player);
66
+ return out;
67
+ });
68
+
69
+ const ctPlayers = $derived(perPlayer.filter((p) => p.side === "CT"));
70
+ const tPlayers = $derived(perPlayer.filter((p) => p.side === "T"));
71
+
72
+ function onLeaderTime(t: number) {
73
+ onTimeUpdate?.(t);
74
+ }
75
+
76
+ // Intersect every tile's buffered ranges: the timeline span that's safe
77
+ // to play across *all* perspectives at once. Emit imperatively from the
78
+ // tile callback (not via $effect) — wiring this through reactivity would
79
+ // trip Svelte's effect-cycle detection because every emit produces fresh
80
+ // array references that propagate back through prop changes.
81
+ const tileBuffers = new Map<number, { start: number; end: number }[]>();
82
+
83
+ function intersectAll() {
84
+ const lists = Array.from(tileBuffers.values()).filter((r) => r.length > 0);
85
+ if (!lists.length) return [] as { start: number; end: number }[];
86
+ let acc = lists[0];
87
+ for (let i = 1; i < lists.length; i++) {
88
+ const next: { start: number; end: number }[] = [];
89
+ for (const a of acc) {
90
+ for (const b of lists[i]) {
91
+ const start = Math.max(a.start, b.start);
92
+ const end = Math.min(a.end, b.end);
93
+ if (end > start) next.push({ start, end });
94
+ }
95
+ }
96
+ if (!next.length) return [];
97
+ acc = next;
98
+ }
99
+ return acc;
100
+ }
101
+
102
+ function handleTileBuffered(
103
+ player: number,
104
+ ranges: { start: number; end: number }[],
105
+ ) {
106
+ tileBuffers.set(player, ranges);
107
+ onBufferedChange?.(intersectAll());
108
+ }
109
+ </script>
110
+
111
+ <div class="bg-card max-h-[80vh] overflow-y-auto rounded-lg border shadow-sm">
112
+ <div class="space-y-4 p-3">
113
+ {#if ctPlayers.length}
114
+ <div>
115
+ <div
116
+ class="mb-2 flex items-center gap-1.5 text-[11px] font-semibold uppercase tracking-wide text-sky-700 dark:text-sky-400"
117
+ >
118
+ <Shield size={12} weight="duotone" /> Counter-Terrorists
119
+ </div>
120
+ <div class="grid gap-2 grid-cols-[repeat(auto-fit,minmax(180px,1fr))]">
121
+ {#each ctPlayers as p (p.player)}
122
+ <div class="flex min-w-0 flex-col gap-1">
123
+ <GridTile
124
+ chunks={p.chunks}
125
+ masterTime={virtualTime}
126
+ masterPaused={paused}
127
+ isLeader={p.player === currentPlayer}
128
+ isCurrent={p.player === currentPlayer}
129
+ isMuted={muted || p.player !== currentPlayer}
130
+ available={availablePlayers.has(p.player)}
131
+ duration={p.duration}
132
+ player={p.player}
133
+ side={p.side}
134
+ onSelect={() => onSelect(p.player)}
135
+ {onLeaderTime}
136
+ onLeaderEnded={() => onLeaderEnded?.()}
137
+ onBufferedChange={handleTileBuffered}
138
+ />
139
+ <div class="flex items-center gap-1.5 px-0.5 text-xs">
140
+ <span
141
+ class="inline-block h-2 w-2 shrink-0 rounded-full"
142
+ style="background: {playerColor(p.player)};"
143
+ ></span>
144
+ <span class="truncate font-medium">Player {p.player}</span>
145
+ </div>
146
+ </div>
147
+ {/each}
148
+ </div>
149
+ </div>
150
+ {/if}
151
+ {#if tPlayers.length}
152
+ <div>
153
+ <div
154
+ class="mb-2 flex items-center gap-1.5 text-[11px] font-semibold uppercase tracking-wide text-amber-700 dark:text-amber-400"
155
+ >
156
+ <Sword size={12} weight="duotone" /> Terrorists
157
+ </div>
158
+ <div class="grid gap-2 grid-cols-[repeat(auto-fit,minmax(180px,1fr))]">
159
+ {#each tPlayers as p (p.player)}
160
+ <div class="flex min-w-0 flex-col gap-1">
161
+ <GridTile
162
+ chunks={p.chunks}
163
+ masterTime={virtualTime}
164
+ masterPaused={paused}
165
+ isLeader={p.player === currentPlayer}
166
+ isCurrent={p.player === currentPlayer}
167
+ isMuted={muted || p.player !== currentPlayer}
168
+ available={availablePlayers.has(p.player)}
169
+ duration={p.duration}
170
+ player={p.player}
171
+ side={p.side}
172
+ onSelect={() => onSelect(p.player)}
173
+ {onLeaderTime}
174
+ onLeaderEnded={() => onLeaderEnded?.()}
175
+ onBufferedChange={handleTileBuffered}
176
+ />
177
+ <div class="flex items-center gap-1.5 px-0.5 text-xs">
178
+ <span
179
+ class="inline-block h-2 w-2 shrink-0 rounded-full"
180
+ style="background: {playerColor(p.player)};"
181
+ ></span>
182
+ <span class="truncate font-medium">Player {p.player}</span>
183
+ </div>
184
+ </div>
185
+ {/each}
186
+ </div>
187
+ </div>
188
+ {/if}
189
+ </div>
190
+ </div>
src/lib/components/player-grid.svelte ADDED
@@ -0,0 +1,158 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <script lang="ts">
2
+ import type { PreviewChunk } from '$lib/types';
3
+ import * as ToggleGroup from '$lib/components/ui/toggle-group';
4
+ import { Switch } from '$lib/components/ui/switch';
5
+ import { Label } from '$lib/components/ui/label';
6
+ import { Skull, Shield, Sword } from 'phosphor-svelte';
7
+ import { formatDuration } from '$lib/utils/format';
8
+ import { playerColor } from '$lib/utils/player-colors';
9
+
10
+ interface Props {
11
+ previews: PreviewChunk[];
12
+ currentPlayer: number;
13
+ preloadedPlayers: Set<number>;
14
+ availablePlayers: Set<number>;
15
+ playerDurations: Map<number, number>;
16
+ preloadAll: boolean;
17
+ onSelect: (player: number) => void;
18
+ onPreloadAllChange: (enabled: boolean) => void;
19
+ }
20
+ let {
21
+ previews,
22
+ currentPlayer,
23
+ preloadedPlayers,
24
+ availablePlayers,
25
+ playerDurations,
26
+ preloadAll,
27
+ onSelect,
28
+ onPreloadAllChange
29
+ }: Props = $props();
30
+
31
+ type PlayerSummary = {
32
+ player: number;
33
+ side: 'CT' | 'T' | string;
34
+ weapon: string;
35
+ survived: boolean;
36
+ duration: number;
37
+ };
38
+
39
+ const players = $derived.by<PlayerSummary[]>(() => {
40
+ const map = new Map<number, PreviewChunk[]>();
41
+ for (const p of previews) {
42
+ if (!map.has(p.player)) map.set(p.player, []);
43
+ map.get(p.player)!.push(p);
44
+ }
45
+ const out: PlayerSummary[] = [];
46
+ for (const [player, chunks] of map.entries()) {
47
+ chunks.sort((a, b) => a.chunk_index - b.chunk_index);
48
+ const last = chunks[chunks.length - 1];
49
+ out.push({
50
+ player,
51
+ side: last.player_side,
52
+ weapon: last.primary_weapon,
53
+ survived: last.survived_chunk,
54
+ duration: playerDurations.get(player) ?? 0
55
+ });
56
+ }
57
+ out.sort((a, b) => a.player - b.player);
58
+ return out;
59
+ });
60
+
61
+ const ctPlayers = $derived(players.filter((p) => p.side === 'CT'));
62
+ const tPlayers = $derived(players.filter((p) => p.side === 'T'));
63
+ </script>
64
+
65
+ {#snippet playerItem(p: PlayerSummary)}
66
+ {@const ct = p.side === 'CT'}
67
+ {@const ready = preloadedPlayers.has(p.player)}
68
+ {@const available = availablePlayers.has(p.player)}
69
+ <ToggleGroup.Item
70
+ value={String(p.player)}
71
+ aria-label="Player {p.player} ({p.weapon || 'no weapon'})"
72
+ title={available
73
+ ? `Player ${p.player} — ${p.weapon || 'no weapon'}`
74
+ : `Player ${p.player} died at ${formatDuration(p.duration)} — not available at current time`}
75
+ disabled={!available}
76
+ class="data-[state=on]:bg-accent data-[state=on]:text-accent-foreground group flex h-auto min-w-0 flex-1 basis-0 items-center justify-start gap-2 rounded-md border px-2 py-1.5 text-left text-sm transition disabled:cursor-not-allowed disabled:opacity-40 data-[state=on]:border-current
77
+ {ct
78
+ ? 'data-[state=on]:border-sky-500 data-[state=on]:bg-sky-500/10 data-[state=on]:text-foreground'
79
+ : 'data-[state=on]:border-amber-500 data-[state=on]:bg-amber-500/10 data-[state=on]:text-foreground'}
80
+ {available && ready ? 'ring-2 ring-emerald-500/60 ring-offset-1 ring-offset-background' : ''}"
81
+ >
82
+ <span
83
+ class="flex h-7 w-7 shrink-0 items-center justify-center rounded-sm font-mono text-xs font-bold text-white/95 shadow-sm ring-1 ring-black/20"
84
+ style="background-color: {playerColor(p.player)};"
85
+ >
86
+ {p.player}
87
+ </span>
88
+ <div class="min-w-0 flex-1">
89
+ <div class="truncate font-medium">Player {p.player}</div>
90
+ {#if !available}
91
+ <div class="text-muted-foreground text-[10px] tabular-nums">
92
+ died · {formatDuration(p.duration)}
93
+ </div>
94
+ {/if}
95
+ </div>
96
+ {#if p.survived}
97
+ <Shield size={14} weight="duotone" class="text-emerald-500" />
98
+ {:else}
99
+ <Skull size={14} weight="duotone" class="text-rose-500" />
100
+ {/if}
101
+ </ToggleGroup.Item>
102
+ {/snippet}
103
+
104
+ <div class="space-y-2">
105
+ <div class="flex items-center justify-between gap-3">
106
+ <div class="text-muted-foreground text-xs uppercase tracking-wide">Player perspectives</div>
107
+ <div class="flex items-center gap-2">
108
+ <Label
109
+ for="preload-all-players"
110
+ class="text-muted-foreground text-[11px] uppercase tracking-wide"
111
+ >
112
+ Preload all
113
+ </Label>
114
+ <Switch
115
+ id="preload-all-players"
116
+ size="sm"
117
+ checked={preloadAll}
118
+ onCheckedChange={(v) => onPreloadAllChange(!!v)}
119
+ />
120
+ </div>
121
+ </div>
122
+
123
+ <ToggleGroup.Root
124
+ type="single"
125
+ value={String(currentPlayer)}
126
+ onValueChange={(v) => v && onSelect(Number(v))}
127
+ variant="outline"
128
+ spacing={1}
129
+ aria-label="Player perspective"
130
+ class="w-full! flex-col gap-2"
131
+ >
132
+ <div class="w-full">
133
+ <div
134
+ class="mb-1 flex items-center gap-1.5 text-[10px] font-semibold uppercase tracking-wide text-sky-700 dark:text-sky-400"
135
+ >
136
+ <Shield size={11} weight="duotone" /> Counter-Terrorists
137
+ </div>
138
+ <div class="flex w-full items-stretch gap-1.5">
139
+ {#each ctPlayers as p (p.player)}
140
+ {@render playerItem(p)}
141
+ {/each}
142
+ </div>
143
+ </div>
144
+
145
+ <div class="w-full">
146
+ <div
147
+ class="mb-1 flex items-center gap-1.5 text-[10px] font-semibold uppercase tracking-wide text-amber-700 dark:text-amber-400"
148
+ >
149
+ <Sword size={11} weight="duotone" /> Terrorists
150
+ </div>
151
+ <div class="flex w-full items-stretch gap-1.5">
152
+ {#each tPlayers as p (p.player)}
153
+ {@render playerItem(p)}
154
+ {/each}
155
+ </div>
156
+ </div>
157
+ </ToggleGroup.Root>
158
+ </div>
src/lib/components/round-list.svelte ADDED
@@ -0,0 +1,66 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <script lang="ts">
2
+ import type { Round } from '$lib/types';
3
+ import { ScrollArea } from '$lib/components/ui/scroll-area';
4
+ import * as ToggleGroup from '$lib/components/ui/toggle-group';
5
+
6
+ interface Props {
7
+ rounds: Round[];
8
+ current: number;
9
+ onSelect: (round: number) => void;
10
+ }
11
+ let { rounds, current, onSelect }: Props = $props();
12
+
13
+ // CS2 modern format (MR12): regulation = 24 rounds, sides flip at the
14
+ // half (round 13). Overtime is MR3, so sides flip every 3 rounds starting
15
+ // at round 25 (28, 31, 34, ...).
16
+ function isSideSwitchBefore(round: number): boolean {
17
+ if (round <= 1) return false;
18
+ if (round === 13) return true;
19
+ if (round < 25) return false;
20
+ return (round - 25) % 3 === 0;
21
+ }
22
+
23
+ function switchLabel(round: number): string {
24
+ if (round === 13) return 'Half';
25
+ if (round === 25) return 'OT';
26
+ return 'Switch';
27
+ }
28
+ </script>
29
+
30
+ <div class="flex h-full min-h-0 flex-col">
31
+ <div class="text-muted-foreground border-b px-2 py-2 text-[10px] font-semibold uppercase tracking-wide">
32
+ Rounds <span class="text-muted-foreground/50 ml-1">({rounds.length})</span>
33
+ </div>
34
+ <ScrollArea class="flex-1">
35
+ <ToggleGroup.Root
36
+ type="single"
37
+ value={String(current)}
38
+ onValueChange={(v) => v && onSelect(Number(v))}
39
+ variant="outline"
40
+ size="sm"
41
+ spacing={1}
42
+ aria-label="Round"
43
+ class="grid w-full! grid-cols-1 gap-1 p-1.5"
44
+ >
45
+ {#each rounds as r, i (r.round)}
46
+ {#if i > 0 && isSideSwitchBefore(r.round)}
47
+ <div
48
+ class="text-muted-foreground/70 my-0.5 flex items-center gap-1.5 px-1 text-[9px] font-semibold uppercase tracking-wider"
49
+ aria-hidden="true"
50
+ >
51
+ <span class="bg-border h-px flex-1"></span>
52
+ <span>{switchLabel(r.round)}</span>
53
+ <span class="bg-border h-px flex-1"></span>
54
+ </div>
55
+ {/if}
56
+ <ToggleGroup.Item
57
+ value={String(r.round)}
58
+ aria-label="Round {r.round}"
59
+ class="font-mono tabular-nums"
60
+ >
61
+ {r.round}
62
+ </ToggleGroup.Item>
63
+ {/each}
64
+ </ToggleGroup.Root>
65
+ </ScrollArea>
66
+ </div>
src/lib/components/timeline-bar.svelte ADDED
@@ -0,0 +1,86 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <script lang="ts">
2
+ import { Button } from '$lib/components/ui/button';
3
+ import { Play, Pause, SpeakerHigh, SpeakerSlash } from 'phosphor-svelte';
4
+ import { formatDuration } from '$lib/utils/format';
5
+ import Playbar from './video-player/playbar.svelte';
6
+
7
+ interface Props {
8
+ currentTime: number;
9
+ duration: number;
10
+ paused: boolean;
11
+ muted: boolean;
12
+ bufferedRanges?: { start: number; end: number }[];
13
+ disabled?: boolean;
14
+ onTogglePlay: () => void;
15
+ onToggleMute: () => void;
16
+ onSeek: (t: number) => void;
17
+ onScrubStart?: () => void;
18
+ onScrubEnd?: () => void;
19
+ }
20
+
21
+ let {
22
+ currentTime,
23
+ duration,
24
+ paused,
25
+ muted,
26
+ bufferedRanges = [],
27
+ disabled = false,
28
+ onTogglePlay,
29
+ onToggleMute,
30
+ onSeek,
31
+ onScrubStart,
32
+ onScrubEnd
33
+ }: Props = $props();
34
+ </script>
35
+
36
+ <div
37
+ class="bg-card flex items-center gap-3 rounded-lg border px-3 py-2 shadow-sm"
38
+ class:opacity-60={disabled}
39
+ class:pointer-events-none={disabled}
40
+ aria-disabled={disabled}
41
+ >
42
+ <Button
43
+ variant="ghost"
44
+ size="icon-sm"
45
+ onclick={onTogglePlay}
46
+ aria-label={paused ? 'Play' : 'Pause'}
47
+ >
48
+ {#if paused}
49
+ <Play weight="fill" />
50
+ {:else}
51
+ <Pause weight="fill" />
52
+ {/if}
53
+ </Button>
54
+
55
+ <span class="text-foreground w-12 text-right font-mono text-[11px] tabular-nums">
56
+ {formatDuration(currentTime)}
57
+ </span>
58
+
59
+ <div class="flex-1">
60
+ <Playbar
61
+ {currentTime}
62
+ {duration}
63
+ {bufferedRanges}
64
+ {onSeek}
65
+ {onScrubStart}
66
+ {onScrubEnd}
67
+ />
68
+ </div>
69
+
70
+ <span class="text-muted-foreground w-12 font-mono text-[11px] tabular-nums">
71
+ {formatDuration(duration)}
72
+ </span>
73
+
74
+ <Button
75
+ variant="ghost"
76
+ size="icon-sm"
77
+ onclick={onToggleMute}
78
+ aria-label={muted ? 'Unmute' : 'Mute'}
79
+ >
80
+ {#if muted}
81
+ <SpeakerSlash weight="duotone" />
82
+ {:else}
83
+ <SpeakerHigh weight="duotone" />
84
+ {/if}
85
+ </Button>
86
+ </div>
src/lib/components/ui/accordion/accordion-content.svelte ADDED
@@ -0,0 +1,27 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <script lang="ts">
2
+ import { Accordion as AccordionPrimitive } from "bits-ui";
3
+ import { cn, type WithoutChild } from "$lib/utils.js";
4
+
5
+ let {
6
+ ref = $bindable(null),
7
+ class: className,
8
+ children,
9
+ ...restProps
10
+ }: WithoutChild<AccordionPrimitive.ContentProps> = $props();
11
+ </script>
12
+
13
+ <AccordionPrimitive.Content
14
+ bind:ref
15
+ data-slot="accordion-content"
16
+ class="data-open:animate-accordion-down data-closed:animate-accordion-up px-2 text-xs/relaxed overflow-hidden"
17
+ {...restProps}
18
+ >
19
+ <div
20
+ class={cn(
21
+ "pt-0 pb-4 [&_a]:hover:text-foreground [&_a]:underline [&_a]:underline-offset-3 [&_p:not(:last-child)]:mb-4",
22
+ className
23
+ )}
24
+ >
25
+ {@render children?.()}
26
+ </div>
27
+ </AccordionPrimitive.Content>
src/lib/components/ui/accordion/accordion-item.svelte ADDED
@@ -0,0 +1,17 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <script lang="ts">
2
+ import { Accordion as AccordionPrimitive } from "bits-ui";
3
+ import { cn } from "$lib/utils.js";
4
+
5
+ let {
6
+ ref = $bindable(null),
7
+ class: className,
8
+ ...restProps
9
+ }: AccordionPrimitive.ItemProps = $props();
10
+ </script>
11
+
12
+ <AccordionPrimitive.Item
13
+ bind:ref
14
+ data-slot="accordion-item"
15
+ class={cn("data-open:bg-muted/50 not-last:border-b", className)}
16
+ {...restProps}
17
+ />
src/lib/components/ui/accordion/accordion-trigger.svelte ADDED
@@ -0,0 +1,32 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <script lang="ts">
2
+ import { Accordion as AccordionPrimitive } from "bits-ui";
3
+ import { cn, type WithoutChild } from "$lib/utils.js";
4
+ import CaretDownIcon from 'phosphor-svelte/lib/CaretDown';
5
+ import CaretUpIcon from 'phosphor-svelte/lib/CaretUp';
6
+
7
+ let {
8
+ ref = $bindable(null),
9
+ class: className,
10
+ level = 3,
11
+ children,
12
+ ...restProps
13
+ }: WithoutChild<AccordionPrimitive.TriggerProps> & {
14
+ level?: AccordionPrimitive.HeaderProps["level"];
15
+ } = $props();
16
+ </script>
17
+
18
+ <AccordionPrimitive.Header {level} class="flex">
19
+ <AccordionPrimitive.Trigger
20
+ data-slot="accordion-trigger"
21
+ bind:ref
22
+ class={cn(
23
+ "**:data-[slot=accordion-trigger-icon]:text-muted-foreground gap-6 p-2 text-left text-xs/relaxed font-medium hover:underline **:data-[slot=accordion-trigger-icon]:ml-auto **:data-[slot=accordion-trigger-icon]:size-4 group/accordion-trigger relative flex flex-1 items-start justify-between border border-transparent transition-all outline-none disabled:pointer-events-none disabled:opacity-50",
24
+ className
25
+ )}
26
+ {...restProps}
27
+ >
28
+ {@render children?.()}
29
+ <CaretDownIcon data-slot="accordion-trigger-icon" class="cn-accordion-trigger-icon pointer-events-none shrink-0 group-aria-expanded/accordion-trigger:hidden" />
30
+ <CaretUpIcon data-slot="accordion-trigger-icon" class="cn-accordion-trigger-icon pointer-events-none hidden shrink-0 group-aria-expanded/accordion-trigger:inline" />
31
+ </AccordionPrimitive.Trigger>
32
+ </AccordionPrimitive.Header>
src/lib/components/ui/accordion/accordion.svelte ADDED
@@ -0,0 +1,19 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <script lang="ts">
2
+ import { Accordion as AccordionPrimitive } from "bits-ui";
3
+ import { cn } from "$lib/utils.js";
4
+
5
+ let {
6
+ ref = $bindable(null),
7
+ value = $bindable(),
8
+ class: className,
9
+ ...restProps
10
+ }: AccordionPrimitive.RootProps = $props();
11
+ </script>
12
+
13
+ <AccordionPrimitive.Root
14
+ bind:ref
15
+ bind:value={value as never}
16
+ data-slot="accordion"
17
+ class={cn("overflow-hidden rounded-md border flex w-full flex-col", className)}
18
+ {...restProps}
19
+ />
src/lib/components/ui/accordion/index.ts ADDED
@@ -0,0 +1,16 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import Root from "./accordion.svelte";
2
+ import Content from "./accordion-content.svelte";
3
+ import Item from "./accordion-item.svelte";
4
+ import Trigger from "./accordion-trigger.svelte";
5
+
6
+ export {
7
+ Root,
8
+ Content,
9
+ Item,
10
+ Trigger,
11
+ //
12
+ Root as Accordion,
13
+ Content as AccordionContent,
14
+ Item as AccordionItem,
15
+ Trigger as AccordionTrigger,
16
+ };
src/lib/components/ui/alert-dialog/alert-dialog-action.svelte ADDED
@@ -0,0 +1,27 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <script lang="ts">
2
+ import { AlertDialog as AlertDialogPrimitive } from "bits-ui";
3
+ import {
4
+ buttonVariants,
5
+ type ButtonVariant,
6
+ type ButtonSize,
7
+ } from "$lib/components/ui/button/index.js";
8
+ import { cn } from "$lib/utils.js";
9
+
10
+ let {
11
+ ref = $bindable(null),
12
+ class: className,
13
+ variant = "default",
14
+ size = "default",
15
+ ...restProps
16
+ }: AlertDialogPrimitive.ActionProps & {
17
+ variant?: ButtonVariant;
18
+ size?: ButtonSize;
19
+ } = $props();
20
+ </script>
21
+
22
+ <AlertDialogPrimitive.Action
23
+ bind:ref
24
+ data-slot="alert-dialog-action"
25
+ class={cn(buttonVariants({ variant, size }), "cn-alert-dialog-action", className)}
26
+ {...restProps}
27
+ />
src/lib/components/ui/alert-dialog/alert-dialog-cancel.svelte ADDED
@@ -0,0 +1,27 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <script lang="ts">
2
+ import { AlertDialog as AlertDialogPrimitive } from "bits-ui";
3
+ import {
4
+ buttonVariants,
5
+ type ButtonVariant,
6
+ type ButtonSize,
7
+ } from "$lib/components/ui/button/index.js";
8
+ import { cn } from "$lib/utils.js";
9
+
10
+ let {
11
+ ref = $bindable(null),
12
+ class: className,
13
+ variant = "outline",
14
+ size = "default",
15
+ ...restProps
16
+ }: AlertDialogPrimitive.CancelProps & {
17
+ variant?: ButtonVariant;
18
+ size?: ButtonSize;
19
+ } = $props();
20
+ </script>
21
+
22
+ <AlertDialogPrimitive.Cancel
23
+ bind:ref
24
+ data-slot="alert-dialog-cancel"
25
+ class={cn(buttonVariants({ variant, size }), "cn-alert-dialog-cancel", className)}
26
+ {...restProps}
27
+ />
src/lib/components/ui/alert-dialog/alert-dialog-content.svelte ADDED
@@ -0,0 +1,32 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <script lang="ts">
2
+ import { AlertDialog as AlertDialogPrimitive } from "bits-ui";
3
+ import AlertDialogPortal from "./alert-dialog-portal.svelte";
4
+ import AlertDialogOverlay from "./alert-dialog-overlay.svelte";
5
+ import { cn, type WithoutChild, type WithoutChildrenOrChild } from "$lib/utils.js";
6
+ import type { ComponentProps } from "svelte";
7
+
8
+ let {
9
+ ref = $bindable(null),
10
+ class: className,
11
+ size = "default",
12
+ portalProps,
13
+ ...restProps
14
+ }: WithoutChild<AlertDialogPrimitive.ContentProps> & {
15
+ size?: "default" | "sm";
16
+ portalProps?: WithoutChildrenOrChild<ComponentProps<typeof AlertDialogPortal>>;
17
+ } = $props();
18
+ </script>
19
+
20
+ <AlertDialogPortal {...portalProps}>
21
+ <AlertDialogOverlay />
22
+ <AlertDialogPrimitive.Content
23
+ bind:ref
24
+ data-slot="alert-dialog-content"
25
+ data-size={size}
26
+ class={cn(
27
+ "data-open:animate-in data-closed:animate-out data-closed:fade-out-0 data-open:fade-in-0 data-closed:zoom-out-95 data-open:zoom-in-95 bg-popover text-popover-foreground ring-foreground/10 gap-3 rounded-xl p-4 ring-1 duration-100 data-[size=default]:max-w-xs data-[size=sm]:max-w-64 data-[size=default]:sm:max-w-sm group/alert-dialog-content fixed top-1/2 left-1/2 z-50 grid w-full -translate-x-1/2 -translate-y-1/2 outline-none",
28
+ className
29
+ )}
30
+ {...restProps}
31
+ />
32
+ </AlertDialogPortal>
src/lib/components/ui/alert-dialog/alert-dialog-description.svelte ADDED
@@ -0,0 +1,17 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <script lang="ts">
2
+ import { AlertDialog as AlertDialogPrimitive } from "bits-ui";
3
+ import { cn } from "$lib/utils.js";
4
+
5
+ let {
6
+ ref = $bindable(null),
7
+ class: className,
8
+ ...restProps
9
+ }: AlertDialogPrimitive.DescriptionProps = $props();
10
+ </script>
11
+
12
+ <AlertDialogPrimitive.Description
13
+ bind:ref
14
+ data-slot="alert-dialog-description"
15
+ class={cn("text-muted-foreground *:[a]:hover:text-foreground text-xs/relaxed text-balance md:text-pretty *:[a]:underline *:[a]:underline-offset-3", className)}
16
+ {...restProps}
17
+ />
src/lib/components/ui/alert-dialog/alert-dialog-footer.svelte ADDED
@@ -0,0 +1,23 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <script lang="ts">
2
+ import { cn, type WithElementRef } from "$lib/utils.js";
3
+ import type { HTMLAttributes } from "svelte/elements";
4
+
5
+ let {
6
+ ref = $bindable(null),
7
+ class: className,
8
+ children,
9
+ ...restProps
10
+ }: WithElementRef<HTMLAttributes<HTMLDivElement>> = $props();
11
+ </script>
12
+
13
+ <div
14
+ bind:this={ref}
15
+ data-slot="alert-dialog-footer"
16
+ class={cn(
17
+ "cn-alert-dialog-footer flex flex-col-reverse gap-2 group-data-[size=sm]/alert-dialog-content:grid group-data-[size=sm]/alert-dialog-content:grid-cols-2 sm:flex-row sm:justify-end",
18
+ className
19
+ )}
20
+ {...restProps}
21
+ >
22
+ {@render children?.()}
23
+ </div>
src/lib/components/ui/alert-dialog/alert-dialog-header.svelte ADDED
@@ -0,0 +1,20 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <script lang="ts">
2
+ import type { HTMLAttributes } from "svelte/elements";
3
+ import { cn, type WithElementRef } from "$lib/utils.js";
4
+
5
+ let {
6
+ ref = $bindable(null),
7
+ class: className,
8
+ children,
9
+ ...restProps
10
+ }: WithElementRef<HTMLAttributes<HTMLDivElement>> = $props();
11
+ </script>
12
+
13
+ <div
14
+ bind:this={ref}
15
+ data-slot="alert-dialog-header"
16
+ class={cn("grid grid-rows-[auto_1fr] place-items-center gap-1 text-center has-data-[slot=alert-dialog-media]:grid-rows-[auto_auto_1fr] has-data-[slot=alert-dialog-media]:gap-x-4 sm:group-data-[size=default]/alert-dialog-content:place-items-start sm:group-data-[size=default]/alert-dialog-content:text-left sm:group-data-[size=default]/alert-dialog-content:has-data-[slot=alert-dialog-media]:grid-rows-[auto_1fr]", className)}
17
+ {...restProps}
18
+ >
19
+ {@render children?.()}
20
+ </div>
src/lib/components/ui/alert-dialog/alert-dialog-media.svelte ADDED
@@ -0,0 +1,20 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <script lang="ts">
2
+ import type { HTMLAttributes } from "svelte/elements";
3
+ import { cn, type WithElementRef } from "$lib/utils.js";
4
+
5
+ let {
6
+ ref = $bindable(null),
7
+ class: className,
8
+ children,
9
+ ...restProps
10
+ }: WithElementRef<HTMLAttributes<HTMLDivElement>> = $props();
11
+ </script>
12
+
13
+ <div
14
+ bind:this={ref}
15
+ data-slot="alert-dialog-media"
16
+ class={cn("bg-muted mb-2 inline-flex size-8 items-center justify-center rounded-md sm:group-data-[size=default]/alert-dialog-content:row-span-2 *:[svg:not([class*='size-'])]:size-4", className)}
17
+ {...restProps}
18
+ >
19
+ {@render children?.()}
20
+ </div>
src/lib/components/ui/alert-dialog/alert-dialog-overlay.svelte ADDED
@@ -0,0 +1,17 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <script lang="ts">
2
+ import { AlertDialog as AlertDialogPrimitive } from "bits-ui";
3
+ import { cn } from "$lib/utils.js";
4
+
5
+ let {
6
+ ref = $bindable(null),
7
+ class: className,
8
+ ...restProps
9
+ }: AlertDialogPrimitive.OverlayProps = $props();
10
+ </script>
11
+
12
+ <AlertDialogPrimitive.Overlay
13
+ bind:ref
14
+ data-slot="alert-dialog-overlay"
15
+ class={cn("data-open:animate-in data-closed:animate-out data-closed:fade-out-0 data-open:fade-in-0 bg-black/80 duration-100 supports-backdrop-filter:backdrop-blur-xs fixed inset-0 z-50", className)}
16
+ {...restProps}
17
+ />
src/lib/components/ui/alert-dialog/alert-dialog-portal.svelte ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
 
1
+ <script lang="ts">
2
+ import { AlertDialog as AlertDialogPrimitive } from "bits-ui";
3
+
4
+ let { ...restProps }: AlertDialogPrimitive.PortalProps = $props();
5
+ </script>
6
+
7
+ <AlertDialogPrimitive.Portal {...restProps} />
src/lib/components/ui/alert-dialog/alert-dialog-title.svelte ADDED
@@ -0,0 +1,17 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <script lang="ts">
2
+ import { AlertDialog as AlertDialogPrimitive } from "bits-ui";
3
+ import { cn } from "$lib/utils.js";
4
+
5
+ let {
6
+ ref = $bindable(null),
7
+ class: className,
8
+ ...restProps
9
+ }: AlertDialogPrimitive.TitleProps = $props();
10
+ </script>
11
+
12
+ <AlertDialogPrimitive.Title
13
+ bind:ref
14
+ data-slot="alert-dialog-title"
15
+ class={cn("font-heading text-sm font-medium sm:group-data-[size=default]/alert-dialog-content:group-has-data-[slot=alert-dialog-media]/alert-dialog-content:col-start-2", className)}
16
+ {...restProps}
17
+ />
src/lib/components/ui/alert-dialog/alert-dialog-trigger.svelte ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
 
1
+ <script lang="ts">
2
+ import { AlertDialog as AlertDialogPrimitive } from "bits-ui";
3
+
4
+ let { ref = $bindable(null), ...restProps }: AlertDialogPrimitive.TriggerProps = $props();
5
+ </script>
6
+
7
+ <AlertDialogPrimitive.Trigger bind:ref data-slot="alert-dialog-trigger" {...restProps} />
src/lib/components/ui/alert-dialog/alert-dialog.svelte ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
 
1
+ <script lang="ts">
2
+ import { AlertDialog as AlertDialogPrimitive } from "bits-ui";
3
+
4
+ let { open = $bindable(false), ...restProps }: AlertDialogPrimitive.RootProps = $props();
5
+ </script>
6
+
7
+ <AlertDialogPrimitive.Root bind:open {...restProps} />
src/lib/components/ui/alert-dialog/index.ts ADDED
@@ -0,0 +1,40 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import Root from "./alert-dialog.svelte";
2
+ import Portal from "./alert-dialog-portal.svelte";
3
+ import Trigger from "./alert-dialog-trigger.svelte";
4
+ import Title from "./alert-dialog-title.svelte";
5
+ import Action from "./alert-dialog-action.svelte";
6
+ import Cancel from "./alert-dialog-cancel.svelte";
7
+ import Footer from "./alert-dialog-footer.svelte";
8
+ import Header from "./alert-dialog-header.svelte";
9
+ import Overlay from "./alert-dialog-overlay.svelte";
10
+ import Content from "./alert-dialog-content.svelte";
11
+ import Description from "./alert-dialog-description.svelte";
12
+ import Media from "./alert-dialog-media.svelte";
13
+
14
+ export {
15
+ Root,
16
+ Title,
17
+ Action,
18
+ Cancel,
19
+ Portal,
20
+ Footer,
21
+ Header,
22
+ Trigger,
23
+ Overlay,
24
+ Content,
25
+ Description,
26
+ Media,
27
+ //
28
+ Root as AlertDialog,
29
+ Title as AlertDialogTitle,
30
+ Action as AlertDialogAction,
31
+ Cancel as AlertDialogCancel,
32
+ Portal as AlertDialogPortal,
33
+ Footer as AlertDialogFooter,
34
+ Header as AlertDialogHeader,
35
+ Trigger as AlertDialogTrigger,
36
+ Overlay as AlertDialogOverlay,
37
+ Content as AlertDialogContent,
38
+ Description as AlertDialogDescription,
39
+ Media as AlertDialogMedia,
40
+ };