diff --git a/.DS_Store b/.DS_Store deleted file mode 100644 index 66d7dba..0000000 Binary files a/.DS_Store and /dev/null differ diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml new file mode 100644 index 0000000..e0feb65 --- /dev/null +++ b/.github/workflows/deploy.yml @@ -0,0 +1,54 @@ +name: Deploy to GitHub Pages + +on: + push: + branches: + - main + workflow_dispatch: + +permissions: + contents: read + pages: write + id-token: write + +concurrency: + group: pages + cancel-in-progress: true + +jobs: + build: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Setup Node + uses: actions/setup-node@v4 + with: + node-version: 24 + cache: npm + + - name: Configure GitHub Pages + uses: actions/configure-pages@v5 + + - name: Install dependencies + run: npm ci + + - name: Build site + run: npm run build + + - name: Upload artifact + uses: actions/upload-pages-artifact@v3 + with: + path: build + + deploy: + needs: build + runs-on: ubuntu-latest + environment: + name: github-pages + url: ${{ steps.deployment.outputs.page_url }} + steps: + - name: Deploy to GitHub Pages + id: deployment + uses: actions/deploy-pages@v4 diff --git a/.gitignore b/.gitignore index 4794b48..7418603 100644 --- a/.gitignore +++ b/.gitignore @@ -1,7 +1,5 @@ +node_modules +.svelte-kit +build _site -.sass-cache -.jekyll-cache -.jekyll-metadata -vendor - -Gemfile.lock \ No newline at end of file +.DS_Store diff --git a/.prettierignore b/.prettierignore new file mode 100644 index 0000000..25d24d6 --- /dev/null +++ b/.prettierignore @@ -0,0 +1,7 @@ +# Generated output +.svelte-kit +build +_site + +# Package managers +package-lock.json diff --git a/.prettierrc b/.prettierrc new file mode 100644 index 0000000..05dafbf --- /dev/null +++ b/.prettierrc @@ -0,0 +1,11 @@ +{ + "plugins": ["prettier-plugin-svelte"], + "overrides": [ + { + "files": "*.svelte", + "options": { + "parser": "svelte" + } + } + ] +} diff --git a/404.html b/404.html deleted file mode 100644 index 45ef7e4..0000000 --- a/404.html +++ /dev/null @@ -1,37 +0,0 @@ ---- -permalink: /404.html -layout: page ---- - - - - - -
-

404

- -

Page not found :(

-

The requested page could not be found.

-
diff --git a/Gemfile b/Gemfile deleted file mode 100644 index fec23cb..0000000 --- a/Gemfile +++ /dev/null @@ -1,33 +0,0 @@ -source "https://rubygems.org" -# Hello! This is where you manage which Jekyll version is used to run. -# When you want to use a different version, change it below, save the -# file and run `bundle install`. Run Jekyll with `bundle exec`, like so: -# -# bundle exec jekyll serve -# -# This will help ensure the proper Jekyll version is running. -# Happy Jekylling! -#gem "jekyll", "~> 4.4.1" -# This is the default theme for new Jekyll sites. You may change this to anything you like. -gem "minima", "~> 2.5" -# If you want to use GitHub Pages, remove the "gem "jekyll"" above and -# uncomment the line below. To upgrade, run `bundle update github-pages`. -gem "github-pages", "~> 232", group: :jekyll_plugins -# If you have any plugins, put them here! -group :jekyll_plugins do - gem "jekyll-feed", "~> 0.12" -end - -# Windows and JRuby does not include zoneinfo files, so bundle the tzinfo-data gem -# and associated library. -platforms :mingw, :x64_mingw, :mswin, :jruby do - gem "tzinfo", ">= 1", "< 3" - gem "tzinfo-data" -end - -# Performance-booster for watching directories on Windows -gem "wdm", "~> 0.1", :platforms => [:mingw, :x64_mingw, :mswin] - -# Lock `http_parser.rb` gem to `v0.6.x` on JRuby builds since newer versions of the gem -# do not have a Java counterpart. -gem "http_parser.rb", "~> 0.6.0", :platforms => [:jruby] diff --git a/README.md b/README.md index fe19d06..442c5a1 100644 --- a/README.md +++ b/README.md @@ -1,23 +1,55 @@ -# 5of12 Github Pages site -For blogs and content relating to our projects and open source repositories. +# 5of12 Site -## Setup instructions +This repository builds the 5of12 site as a static SvelteKit app and deploys it to GitHub Pages. -The site is built with Jekyll, setup instructions here: [Jekyll Installation](https://jekyllrb.com/docs/installation/) -That will take you through making sure Homebrew, Ruby and Jekyl are installed. +The previous Jekyll/Ruby build has been removed. GitHub CodeQL default setup was also disabled because it was still trying to analyze Ruby even though the site no longer contains Ruby source. -Once that's all setup install the github pages gem `gem install github-pages` +## Development -### Local testing +```bash +npm install +npm run dev +``` -You can build and serve the files locally with Jekyll using `bundle exec jekyll serve` optionally with `--livereload` +The dev server defaults to Vite's local URL, usually `http://localhost:5173/`. -### Remote builds +## Quality checks -Merges to main will trigger a github action to build the site using the same Jekyll config. +```bash +npm run check +npm run build +``` -# New Content +`npm run build` writes the static site to `build/`, which is the directory uploaded by the GitHub Pages workflow. -New pages are created as Markdown files that get converted to html following the rules of the Theme. +## Content -New blogs can be added by placing them in the `_posts` directory with a name formatted as `YYYY-MM-DD-title-of-blog` +- Home and about pages live in `src/routes/`. +- Shared site data lives in `src/lib/content/site.ts`. +- Journal posts remain in `_posts/` and are parsed at build time. +- Static images and media are served from `static/assets/`. + +## Markdown Rendering + +Journal posts are currently parsed from the old Jekyll-style `_posts/` directory by `src/lib/server/posts.ts`. This preserves the existing content during the Svelte transition, but it is not as capable as the previous Jekyll Markdown pipeline. + +For future Markdown work, consider adding mdsvex so posts can be rendered as first-class Svelte content with component support, layouts and better authoring ergonomics: + +- Svelte CLI mdsvex docs: https://svelte.dev/docs/cli/mdsvex + +Likely migration path: + +1. Add mdsvex to the Svelte config. +2. Move posts from `_posts/` into a Svelte-friendly content route or content directory. +3. Keep existing front matter fields: `title`, `author`, `date`, `coverImage`. +4. Replace the custom Markdown parsing in `src/lib/server/posts.ts` once mdsvex owns rendering. + +## Deployment + +GitHub Pages deploys from `.github/workflows/deploy.yml` on pushes to `main`. + +The workflow: + +1. Installs Node dependencies with `npm ci`. +2. Builds the static SvelteKit site with `npm run build`. +3. Uploads the `build/` directory to GitHub Pages. diff --git a/_config.yml b/_config.yml deleted file mode 100644 index 28e7ef4..0000000 --- a/_config.yml +++ /dev/null @@ -1,54 +0,0 @@ -# Welcome to Jekyll! -# -# This config file is meant for settings that affect your whole blog, values -# which you are expected to set up once and rarely edit after that. If you find -# yourself editing this file very often, consider using Jekyll's data files -# feature for the data you need to update frequently. -# -# For technical reasons, this file is *NOT* reloaded automatically when you use -# 'bundle exec jekyll serve'. If you change this file, please restart the server process. -# -# If you need help with YAML syntax, here are some quick references for you: -# https://learn-the-web.algonquindesign.ca/topics/markdown-yaml-cheat-sheet/#yaml -# https://learnxinyminutes.com/docs/yaml/ -# -# Site settings -# These are used to personalize your new site. If you look in the HTML files, -# you will see them accessed via {{ site.title }}, {{ site.email }}, and so on. -# You can create any custom variable you would like, and they will be accessible -# in the templates via {{ site.myvariable }}. - -title: We are 5of12 -email: info@5of12.co.uk -description: >- # this means to ignore newlines until "baseurl:" - We are 5of12. We love spatial computing, building immersive experiences - and designing apps that encourage play, experimentation & fun. -baseurl: "" # the subpath of your site, e.g. /blog -url: "https://5of12.github.io" # the base hostname & protocol for your site, e.g. http://example.com -github_username: 5of12 - -# Build settings -theme: minima -plugins: - - jekyll-feed - - jekyll-seo-tag - -# Exclude from processing. -# The following items will not be processed, by default. -# Any item listed under the `exclude:` key here will be automatically added to -# the internal "default list". -# -# Excluded items can be processed by explicitly listing the directories or -# their entries' file path in the `include:` list. -# -# exclude: -# - .sass-cache/ -# - .jekyll-cache/ -# - gemfiles/ -# - Gemfile -# - Gemfile.lock -# - node_modules/ -# - vendor/bundle/ -# - vendor/cache/ -# - vendor/gems/ -# - vendor/ruby/ diff --git a/_posts/2025-04-07-a-cacophony-of-gestures.markdown b/_posts/2025-04-07-a-cacophony-of-gestures.markdown index 47a93cb..a21ed23 100644 --- a/_posts/2025-04-07-a-cacophony-of-gestures.markdown +++ b/_posts/2025-04-07-a-cacophony-of-gestures.markdown @@ -4,11 +4,13 @@ author: Pete Nancollis --- # TL;DR -We built a gesture control library for Unity. One that isn’t tied to a particular source of input data and works outside XR. It is modelled on an Anticipation, Action, Reaction cycle to help development run smoothly. It’s called [Cacophony](https://github.com/5of12/cacophony) as a nod to the complexity that arises from the interactions between gestures when building applications with multiple controls. + +We built a gesture control library for Unity. One that isn’t tied to a particular source of input data and works outside XR. It is modelled on an Anticipation, Action, Reaction cycle to help development run smoothly. It’s called Cacophony as a nod to the complexity that arises from the interactions between gestures when building applications with multiple controls. ![Hands in a range of poses. forming confusing gestures](/assets/CacophonyOfGestures.png "Cacophony of gesturing hands") -# Intro +# Intro + Spatial computing applications give us the possibility of using our hands to interact with content without additional controllers. XR headsets such as those from Apple, Meta and Microsoft have built fantastic spatial interaction systems and they provide robust tooling to help developers work with their respective platforms. But what are you to do if you want to apply these techniques outside the XR space? In the world of flat screens, spatial computing often starts with something that sounds simple. Using hand gestures to trigger behaviour in an application. Despite it being a common entry point to this world, there aren’t a lot of tools available to help you implement it. So we built one! @@ -20,26 +22,28 @@ In the world of flat screens, spatial computing often starts with something that Developing a gesture control application is a journey of discovery. It’s very easy to fall into some common design traps that make building a reliable solution difficult and expensive. This is why we named our library Cacophony, it’s a friendly warning about what’s to come so that you can be prepared! ## What is a gesture? -A gesture can be pretty much anything you do with your hand that a sensor can detect. With optical hand tracking solutions that can detect the positions of your fingers, that means any hand pose you can think of and any kind of motion you might associate with it. + +A gesture can be pretty much anything you do with your hand that a sensor can detect. With optical hand tracking solutions that can detect the positions of your fingers, that means any hand pose you can think of and any kind of motion you might associate with it. ![Video of showing a virtual hand grabbing and releasing, then confetti is release](/assets/Grab-Release.gif "Grab Release gesture") This is a lot of freedom for designing your system. But, like a kid let loose with a new set of paints, there’s suddenly colours everywhere and it’s all merging into brown. Gestures can be thought of as discrete, but the boundaries between them are fluid. To successfully design with gestures we need constraints. -## Turning Gestures Into Action +## Turning Gestures Into Action + Cacophony doesn’t prevent you from defining as many gestures as you like in your application. It does however try to make things easier to manage and control. -Cacophony breaks down gestures into a set of components which combine to form an Anticipation, Action, Reaction cycle. +Cacophony breaks down gestures into a set of components which combine to form an Anticipation, Action, Reaction cycle. First we detect the shape of the hand and determine if that shape matches a given Gesture Definition. A Gesture Definition is a collection of pose descriptions that allow us to specify what is and isn’t the hand shape we are looking for. This forms the anticipation part of the cycle. > Given a hand in an OK pose 👌 -Now we have detected a gesture is occurring, we are ready for action. You’ve put your thumb up, but what are we going to do with it? Gestures are coupled with Actions, which observe the gesture over time and determine if there is intent behind it. +Now we have detected a gesture is occurring, we are ready for action. You’ve put your thumb up, but what are we going to do with it? Gestures are coupled with Actions, which observe the gesture over time and determine if there is intent behind it. > When moved down ⬇️ -The reaction from the application is how users perceive the effect of their actions. Reactions are important at every stage of a gesture from initiation to successful detection completes. Clear feedback helps people learn the system and gives them confidence that their inputs are being processed as they expect. +The reaction from the application is how users perceive the effect of their actions. Reactions are important at every stage of a gesture from initiation to successful detection completes. Clear feedback helps people learn the system and gives them confidence that their inputs are being processed as they expect. Cacophony actions provide a series of events for your application to react to, representing each stage of detection. This makes it a simple process to create rich audio, visual and haptic feedback in response to the gestures detection. @@ -47,18 +51,18 @@ Cacophony actions provide a series of events for your application to react to, r ![Animation of a hand pinching and moving down, turning on a light bulb](/assets/Lightbulb.gif "Lightbulb animation") -When designing applications for gestures it’s important to consider all the stages of the process and not just think of it as a static symbol. Using tools that are structured around this process a designer and developer can quickly iterate on designs and ensure their interactions are clearly defined. +When designing applications for gestures it’s important to consider all the stages of the process and not just think of it as a static symbol. Using tools that are structured around this process a designer and developer can quickly iterate on designs and ensure their interactions are clearly defined. ## About that friendly warning… + With all this freedom to create new gestures comes a temptation to use them. Even with a robust detection system though, the reality of gesture systems is that the complexity grows unmanageable very quickly. -Overlap between different gestures is common, and you have to remember them all while avoiding accidentally performing them when you don’t want to. If you attach a sound effect to each gesture then you quickly create a cacophony of intentional and unintentional sound. +Overlap between different gestures is common, and you have to remember them all while avoiding accidentally performing them when you don’t want to. If you attach a sound effect to each gesture then you quickly create a cacophony of intentional and unintentional sound. ![Animation of a hand pinching and moving down, turning on a light bulb](/assets/Cacophonous.gif "Cacophonous animation") With restraint and careful design however you can build some fun and engaging applications that bring the spatial computing world into the real world. - ## Try it yourself -If you’ve read this far you are probably interested in trying the system out for yourself. The good news is you can! Check out the [Cacophony](https://github.com/5of12/cacophony) project on github and take a look at the example projects in our [Cacophony Playground](https://github.com/5of12/Cacophony-Playground) for some inspiration. +If you’ve read this far you are probably interested in trying the system out for yourself. The good news is you can! Check out the Cacophony project on github and take a look at the example projects in our Cacophony Playground for some inspiration. diff --git a/_posts/2025-09-04-playtonik-looping.md b/_posts/2025-09-04-playtonik-looping.md index bf3f2cc..a894fdc 100644 --- a/_posts/2025-09-04-playtonik-looping.md +++ b/_posts/2025-09-04-playtonik-looping.md @@ -5,7 +5,7 @@ author: Tom Cartwright -Get Playtonik on the [App Store](https://apple.co/4oTOgyW) +Get Playtonik on the App Store --- @@ -44,7 +44,7 @@ Now we're getting notes out, but they're not as we performed them - which for a To get around this, I thought of using the playback thread as a lookahead process instead of triggering the notes directly. Each fixed update frame, the thread will run and gather all the notes that should be played in the following frame. These notes are then collected into a buffer which can be read from the main thread, meaning that each frame only plays notes that should be played in that window of time. - + Success! The notes being played back now feel much more in time with how they were originally performed and the feature feels much more useful. diff --git a/_posts/2025-09-05-musical-physics-poster.markdown b/_posts/2025-09-05-musical-physics-poster.markdown index 17aacfd..78a1697 100644 --- a/_posts/2025-09-05-musical-physics-poster.markdown +++ b/_posts/2025-09-05-musical-physics-poster.markdown @@ -25,8 +25,8 @@ Unity is a great choice for this, due to its highly performant and flexible 2D & -**Get Started:** link audio sources to collisions and make the engine your playground. +**Get Started:** link audio sources to collisions and make the engine your playground. ### Hear the space @@ -80,7 +80,7 @@ For example, swiping a finger over the shape in Playtonik will alter its angular It's super simple to target multiple platforms, with support for most common platforms built into the engine. Any area that the built-in tooling doesn't cover likely has a plugin, tailor-made by the vast Unity developer community. -We've used plugins to handle [MIDI connectivity](https://assetstore.unity.com/packages/tools/audio/midi-plugin-for-mobile-and-desktop-198917) and [musical scale theory](https://melanchall.github.io/drywetmidi/). +We've used plugins to handle MIDI connectivity and musical scale theory. ### Going native @@ -106,7 +106,6 @@ There are a number of pitfalls when working with audio in Unity. Here are some t - Also related - watch out for performance! Unity will use all the resources it can - cap the framerate! ### Plug-in elsewhere? diff --git a/_posts/2025-09-29-how-to-connect-ios-to-midi.md b/_posts/2025-09-29-how-to-connect-ios-to-midi.md index ac7e46f..e5d35e3 100644 --- a/_posts/2025-09-29-how-to-connect-ios-to-midi.md +++ b/_posts/2025-09-29-how-to-connect-ios-to-midi.md @@ -23,11 +23,11 @@ We've not found a similar setup for connecting to Windows or Linux systems. If y -If your iPhone or iPad has a USB-C connector, then you can also connect directly to many USB audio/MIDI interfaces, keyboards and instruments. This can limit onward connectivity with a DAW but it is great if you just want to hook up Playtonik and a synth for a quick jam. +If your iPhone or iPad has a USB-C connector, then you can also connect directly to many USB audio/MIDI interfaces, keyboards and instruments. This can limit onward connectivity with a DAW but it is great if you just want to hook up Playtonik and a synth for a quick jam. # Network MIDI -iOS supports MIDI connections across a local network. This works over WiFi and can allow you to connect to a Mac on the same network. This is an easy solution to setup but latency will depend on the quality of the connection. MacOS has a built in solution for Network MIDI but on Windows or other plaatforms you will need to find a thirdparty solution. +iOS supports MIDI connections across a local network. This works over WiFi and can allow you to connect to a Mac on the same network. This is an easy solution to setup but latency will depend on the quality of the connection. MacOS has a built in solution for Network MIDI but on Windows or other plaatforms you will need to find a thirdparty solution. - In Playtonik, tap the settings cog in the top right, then select the "Session 1" device in the MIDI Input/Ouput dropdown. This is the network MIDI session - Open Audio Midi Settings on the Mac @@ -38,11 +38,11 @@ iOS supports MIDI connections across a local network. This works over WiFi and c -Ableton have a nice guide for [Setting up a virtual MIDI network](https://help.ableton.com/hc/en-us/articles/209071169-Setting-up-a-virtual-MIDI-network) which has some details of how it works on different platforms +Ableton have a nice guide for Setting up a virtual MIDI network which has some details of how it works on different platforms # Bluetooth MIDI -Bluetooth MIDI is best for connecting direct to other instruments, but can also be used to connect to a computer. It runs on Bluetooth LE so has a small amount of latency, but is one of the easiest options to set up. +Bluetooth MIDI is best for connecting direct to other instruments, but can also be used to connect to a computer. It runs on Bluetooth LE so has a small amount of latency, but is one of the easiest options to set up. - Open Audio Midi Settings on the Mac - Open the Midi Studio Window, then tap the Bluetooth icon in the top right to get the Bluetooth setup window @@ -63,6 +63,7 @@ If you want to try out MIDI, but don't have any external gear, all is not lost! Options on iPhone are more limited as you can only run one foreground app at a time. Playtonik doesn't run in the background (to save on battery life) but some audio apps like the awesome Fugue Machine and Korg Gadget will. You can set them playing, then switch to Playtonik and send/receive MIDI with the background app. On iPad you can run two apps in the foreground with Stage Manager. With the extra screen space you can set up a side by side view of Playtonik with another MIDI enabled app and control both at once. Fugue machine example: + - Open Fugue Machine and tap the ... icon in the top right - Enable MIDI Out via Settings screen using the "Fugue Machine MIDI Out" option - Pick a pattern and press play @@ -76,5 +77,5 @@ Note: As of Playtonik 1.5 the app doesn't show up as a virtual MIDI port. Playto # Find out more -To find out more about Playtonik check out our website [5of12.co.uk](https://www.5of12.co.uk/#Playtonik)
-For examples of how we integrate Playtonik into our music check out our [Playtonik Playlist on YouTube](https://www.youtube.com/playlist?list=PL4zuBsU0ueMlLnphaBhRjQ5iLQO9R2qMJ) \ No newline at end of file +To find out more about Playtonik, visit the Playtonik product page.
+For examples of how we integrate Playtonik into our music check out our Playtonik Playlist on YouTube diff --git a/about.markdown b/about.markdown deleted file mode 100644 index f1cc284..0000000 --- a/about.markdown +++ /dev/null @@ -1,14 +0,0 @@ ---- -layout: page -title: About -permalink: /about/ ---- - -5of12 are a Spatial Computing Studio based in the UK. A partnership formed out of ex-Ultraleap coleagues, with 15+ years combined experience in software product development. - -5of12 specialise in spatial interaction design and solutions for XR, digital out of home, screen-based experiences and mixed media, immersive arts. - -We are the creators of Playtonik, a musical fidget toy app for iOS and winner of a 2025 [Midi Association Innovation Award](https://midi.org/innovation-awards) for Software Prototypes! Check it out on the [App Store](https://apps.apple.com/gb/app/playtonik/id6738356927) - - -Learn more and get in touch at [5of12.co.uk](https://5of12.co.uk) \ No newline at end of file diff --git a/index.markdown b/index.markdown deleted file mode 100644 index 169d3d9..0000000 --- a/index.markdown +++ /dev/null @@ -1,38 +0,0 @@ ---- -# Feel free to add content and custom Front Matter to this file. -# To modify the layout, see https://jekyllrb.com/docs/themes/#overriding-theme-defaults - -layout: home - ---- - -The 5of12 Logo, a notched circle with 5 coloured pill shapes arrayed like a paw - -## Welcome - -5of12 gets to do some pretty innovative work in the world of spatial computing. Where possible we like to share what we're learning, rather than keep all this knowledge trapped in our heads. - -If you find something interesting, or have a project you'd like to talk about, get in touch. - -## Check out some examples of our work - -### Playtonik - -Playtonik is a musical fidget toy app for iOS. It combines playful physics interactions with immersive sound and expressive haptics for a relaxing and inspiring musical experience. It also has great connectivity with MIDI, with the ability to control or be controlled by external gear. This little app brings together everything we enjoy about building software! - -Playtonik is also a winner of a 2025 [MIDI Association Innovation Award](https://midi.org/innovation-awards) for Software Prototypes! -Find out more at [5of12.co.uk/playtonik](https://5of12.co.uk/#playtonik) - -### MediaPipe Playground - -Gesture control running in your browser. Interaction from across the room using comfortable motions centred around you. No headset, no specialised cameras, just you and a webcam! - -[5of12.github.io/MediaPipe-Playground](https://5of12.github.io/MediaPipe-Playground) - -- 🦈 Give 3D objects a spin, with a single hand! - - [Spin The Shark](https://5of12.github.io/MediaPipe-Playground/examples/SpinTheShark.html) -- 🌌 Head to the stars with pose detections. Engage warp speed! - - [Warp Fingers](https://5of12.github.io/MediaPipe-Playground/examples/WarpFingers.html) -- 🗺️ Explore mapping data with two handed gestures. Pinch and zoom! - - [World in your Hands](https://5of12.github.io/MediaPipe-Playground/examples/WorldInYourHands.html) \ No newline at end of file diff --git a/midiweb-hub/index.html b/midiweb-hub/index.html index 4686e5e..37d78b5 100644 --- a/midiweb-hub/index.html +++ b/midiweb-hub/index.html @@ -7,7 +7,9 @@ diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..cd4686d --- /dev/null +++ b/package-lock.json @@ -0,0 +1,1823 @@ +{ + "name": "5of12-site", + "version": "0.0.1", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "5of12-site", + "version": "0.0.1", + "dependencies": { + "@fortawesome/free-brands-svg-icons": "^7.2.0", + "@fortawesome/svelte-fontawesome": "^0.2.4", + "@lucide/svelte": "^1.17.0", + "gray-matter": "^4.0.3", + "marked": "^17.0.4" + }, + "devDependencies": { + "@sveltejs/adapter-static": "^3.0.10", + "@sveltejs/kit": "^2.50.2", + "@sveltejs/vite-plugin-svelte": "^6.2.4", + "prettier": "^3.8.1", + "prettier-plugin-svelte": "^3.5.1", + "svelte": "^5.51.0", + "svelte-check": "^4.4.2", + "typescript": "^5.9.3", + "vite": "^7.3.1" + } + }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.27.4", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.27.4.tgz", + "integrity": "sha512-cQPwL2mp2nSmHHJlCyoXgHGhbEPMrEEU5xhkcy3Hs/O7nGZqEpZ2sUtLaL9MORLtDfRvVl2/3PAuEkYZH0Ty8Q==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.27.4", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.27.4.tgz", + "integrity": "sha512-X9bUgvxiC8CHAGKYufLIHGXPJWnr0OCdR0anD2e21vdvgCI8lIfqFbnoeOz7lBjdrAGUhqLZLcQo6MLhTO2DKQ==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.27.4", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.27.4.tgz", + "integrity": "sha512-gdLscB7v75wRfu7QSm/zg6Rx29VLdy9eTr2t44sfTW7CxwAtQghZ4ZnqHk3/ogz7xao0QAgrkradbBzcqFPasw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.27.4", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.27.4.tgz", + "integrity": "sha512-PzPFnBNVF292sfpfhiyiXCGSn9HZg5BcAz+ivBuSsl6Rk4ga1oEXAamhOXRFyMcjwr2DVtm40G65N3GLeH1Lvw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.27.4", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.27.4.tgz", + "integrity": "sha512-b7xaGIwdJlht8ZFCvMkpDN6uiSmnxxK56N2GDTMYPr2/gzvfdQN8rTfBsvVKmIVY/X7EM+/hJKEIbbHs9oA4tQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.27.4", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.27.4.tgz", + "integrity": "sha512-sR+OiKLwd15nmCdqpXMnuJ9W2kpy0KigzqScqHI3Hqwr7IXxBp3Yva+yJwoqh7rE8V77tdoheRYataNKL4QrPw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.27.4", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.27.4.tgz", + "integrity": "sha512-jnfpKe+p79tCnm4GVav68A7tUFeKQwQyLgESwEAUzyxk/TJr4QdGog9sqWNcUbr/bZt/O/HXouspuQDd9JxFSw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.27.4", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.27.4.tgz", + "integrity": "sha512-2kb4ceA/CpfUrIcTUl1wrP/9ad9Atrp5J94Lq69w7UwOMolPIGrfLSvAKJp0RTvkPPyn6CIWrNy13kyLikZRZQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.27.4", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.27.4.tgz", + "integrity": "sha512-aBYgcIxX/wd5n2ys0yESGeYMGF+pv6g0DhZr3G1ZG4jMfruU9Tl1i2Z+Wnj9/KjGz1lTLCcorqE2viePZqj4Eg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.27.4", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.27.4.tgz", + "integrity": "sha512-7nQOttdzVGth1iz57kxg9uCz57dxQLHWxopL6mYuYthohPKEK0vU0C3O21CcBK6KDlkYVcnDXY099HcCDXd9dA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.27.4", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.27.4.tgz", + "integrity": "sha512-oPtixtAIzgvzYcKBQM/qZ3R+9TEUd1aNJQu0HhGyqtx6oS7qTpvjheIWBbes4+qu1bNlo2V4cbkISr8q6gRBFA==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.27.4", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.27.4.tgz", + "integrity": "sha512-8mL/vh8qeCoRcFH2nM8wm5uJP+ZcVYGGayMavi8GmRJjuI3g1v6Z7Ni0JJKAJW+m0EtUuARb6Lmp4hMjzCBWzA==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.27.4", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.27.4.tgz", + "integrity": "sha512-1RdrWFFiiLIW7LQq9Q2NES+HiD4NyT8Itj9AUeCl0IVCA459WnPhREKgwrpaIfTOe+/2rdntisegiPWn/r/aAw==", + "cpu": [ + "mips64el" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.27.4", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.27.4.tgz", + "integrity": "sha512-tLCwNG47l3sd9lpfyx9LAGEGItCUeRCWeAx6x2Jmbav65nAwoPXfewtAdtbtit/pJFLUWOhpv0FpS6GQAmPrHA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.27.4", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.27.4.tgz", + "integrity": "sha512-BnASypppbUWyqjd1KIpU4AUBiIhVr6YlHx/cnPgqEkNoVOhHg+YiSVxM1RLfiy4t9cAulbRGTNCKOcqHrEQLIw==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.27.4", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.27.4.tgz", + "integrity": "sha512-+eUqgb/Z7vxVLezG8bVB9SfBie89gMueS+I0xYh2tJdw3vqA/0ImZJ2ROeWwVJN59ihBeZ7Tu92dF/5dy5FttA==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.27.4", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.27.4.tgz", + "integrity": "sha512-S5qOXrKV8BQEzJPVxAwnryi2+Iq5pB40gTEIT69BQONqR7JH1EPIcQ/Uiv9mCnn05jff9umq/5nqzxlqTOg9NA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-arm64": { + "version": "0.27.4", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.27.4.tgz", + "integrity": "sha512-xHT8X4sb0GS8qTqiwzHqpY00C95DPAq7nAwX35Ie/s+LO9830hrMd3oX0ZMKLvy7vsonee73x0lmcdOVXFzd6Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.27.4", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.27.4.tgz", + "integrity": "sha512-RugOvOdXfdyi5Tyv40kgQnI0byv66BFgAqjdgtAKqHoZTbTF2QqfQrFwa7cHEORJf6X2ht+l9ABLMP0dnKYsgg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-arm64": { + "version": "0.27.4", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.27.4.tgz", + "integrity": "sha512-2MyL3IAaTX+1/qP0O1SwskwcwCoOI4kV2IBX1xYnDDqthmq5ArrW94qSIKCAuRraMgPOmG0RDTA74mzYNQA9ow==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.27.4", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.27.4.tgz", + "integrity": "sha512-u8fg/jQ5aQDfsnIV6+KwLOf1CmJnfu1ShpwqdwC0uA7ZPwFws55Ngc12vBdeUdnuWoQYx/SOQLGDcdlfXhYmXQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openharmony-arm64": { + "version": "0.27.4", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.27.4.tgz", + "integrity": "sha512-JkTZrl6VbyO8lDQO3yv26nNr2RM2yZzNrNHEsj9bm6dOwwu9OYN28CjzZkH57bh4w0I2F7IodpQvUAEd1mbWXg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.27.4", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.27.4.tgz", + "integrity": "sha512-/gOzgaewZJfeJTlsWhvUEmUG4tWEY2Spp5M20INYRg2ZKl9QPO3QEEgPeRtLjEWSW8FilRNacPOg8R1uaYkA6g==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.27.4", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.27.4.tgz", + "integrity": "sha512-Z9SExBg2y32smoDQdf1HRwHRt6vAHLXcxD2uGgO/v2jK7Y718Ix4ndsbNMU/+1Qiem9OiOdaqitioZwxivhXYg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.27.4", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.27.4.tgz", + "integrity": "sha512-DAyGLS0Jz5G5iixEbMHi5KdiApqHBWMGzTtMiJ72ZOLhbu/bzxgAe8Ue8CTS3n3HbIUHQz/L51yMdGMeoxXNJw==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.27.4", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.27.4.tgz", + "integrity": "sha512-+knoa0BDoeXgkNvvV1vvbZX4+hizelrkwmGJBdT17t8FNPwG2lKemmuMZlmaNQ3ws3DKKCxpb4zRZEIp3UxFCg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@fortawesome/fontawesome-common-types": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-common-types/-/fontawesome-common-types-7.2.0.tgz", + "integrity": "sha512-IpR0bER9FY25p+e7BmFH25MZKEwFHTfRAfhOyJubgiDnoJNsSvJ7nigLraHtp4VOG/cy8D7uiV0dLkHOne5Fhw==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/@fortawesome/fontawesome-svg-core": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-svg-core/-/fontawesome-svg-core-7.2.0.tgz", + "integrity": "sha512-6639htZMjEkwskf3J+e6/iar+4cTNM9qhoWuRfj9F3eJD6r7iCzV1SWnQr2Mdv0QT0suuqU8BoJCZUyCtP9R4Q==", + "license": "MIT", + "peer": true, + "dependencies": { + "@fortawesome/fontawesome-common-types": "7.2.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@fortawesome/free-brands-svg-icons": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@fortawesome/free-brands-svg-icons/-/free-brands-svg-icons-7.2.0.tgz", + "integrity": "sha512-VNG8xqOip1JuJcC3zsVsKRQ60oXG9+oYNDCosjoU/H9pgYmLTEwWw8pE0jhPz/JWdHeUuK6+NQ3qsM4gIbdbYQ==", + "license": "(CC-BY-4.0 AND MIT)", + "dependencies": { + "@fortawesome/fontawesome-common-types": "7.2.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@fortawesome/svelte-fontawesome": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/@fortawesome/svelte-fontawesome/-/svelte-fontawesome-0.2.4.tgz", + "integrity": "sha512-AEC6wSm8YIDRygt1CiB7TnMcX3YKjhngdUp99IrOKGdsqK7PORoRnwyk3Sp6zW7t8XEFIEMf3UKeveLIxUSHQw==", + "license": "MIT", + "peerDependencies": { + "@fortawesome/fontawesome-svg-core": "~1 || ~6 || ~7", + "svelte": "~3 || ~4 || ~5" + } + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.13", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", + "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.0", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/remapping": { + "version": "2.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz", + "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==", + "license": "MIT", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", + "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", + "license": "MIT" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.31", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", + "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@lucide/svelte": { + "version": "1.17.0", + "resolved": "https://registry.npmjs.org/@lucide/svelte/-/svelte-1.17.0.tgz", + "integrity": "sha512-q06YCFBN5CO8cd1ADmLCxWRVMVb7xxvHzqC0lvNoxGa+FLW6Cd1Y1AOxgbQk4Iwe68vkAMCRveNHint4WoaVKg==", + "license": "ISC", + "peerDependencies": { + "svelte": "^5" + } + }, + "node_modules/@polka/url": { + "version": "1.0.0-next.29", + "resolved": "https://registry.npmjs.org/@polka/url/-/url-1.0.0-next.29.tgz", + "integrity": "sha512-wwQAWhWSuHaag8c4q/KN/vCoeOJYshAIvMQwD4GpSb3OiZklFfvAgmj0VCBBImRpuF/aFgIRzllXlVX93Jevww==", + "dev": true, + "license": "MIT" + }, + "node_modules/@rollup/rollup-android-arm-eabi": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.59.0.tgz", + "integrity": "sha512-upnNBkA6ZH2VKGcBj9Fyl9IGNPULcjXRlg0LLeaioQWueH30p6IXtJEbKAgvyv+mJaMxSm1l6xwDXYjpEMiLMg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-android-arm64": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.59.0.tgz", + "integrity": "sha512-hZ+Zxj3SySm4A/DylsDKZAeVg0mvi++0PYVceVyX7hemkw7OreKdCvW2oQ3T1FMZvCaQXqOTHb8qmBShoqk69Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-darwin-arm64": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.59.0.tgz", + "integrity": "sha512-W2Psnbh1J8ZJw0xKAd8zdNgF9HRLkdWwwdWqubSVk0pUuQkoHnv7rx4GiF9rT4t5DIZGAsConRE3AxCdJ4m8rg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-darwin-x64": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.59.0.tgz", + "integrity": "sha512-ZW2KkwlS4lwTv7ZVsYDiARfFCnSGhzYPdiOU4IM2fDbL+QGlyAbjgSFuqNRbSthybLbIJ915UtZBtmuLrQAT/w==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-freebsd-arm64": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.59.0.tgz", + "integrity": "sha512-EsKaJ5ytAu9jI3lonzn3BgG8iRBjV4LxZexygcQbpiU0wU0ATxhNVEpXKfUa0pS05gTcSDMKpn3Sx+QB9RlTTA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-freebsd-x64": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.59.0.tgz", + "integrity": "sha512-d3DuZi2KzTMjImrxoHIAODUZYoUUMsuUiY4SRRcJy6NJoZ6iIqWnJu9IScV9jXysyGMVuW+KNzZvBLOcpdl3Vg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-linux-arm-gnueabihf": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.59.0.tgz", + "integrity": "sha512-t4ONHboXi/3E0rT6OZl1pKbl2Vgxf9vJfWgmUoCEVQVxhW6Cw/c8I6hbbu7DAvgp82RKiH7TpLwxnJeKv2pbsw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm-musleabihf": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.59.0.tgz", + "integrity": "sha512-CikFT7aYPA2ufMD086cVORBYGHffBo4K8MQ4uPS/ZnY54GKj36i196u8U+aDVT2LX4eSMbyHtyOh7D7Zvk2VvA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-gnu": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.59.0.tgz", + "integrity": "sha512-jYgUGk5aLd1nUb1CtQ8E+t5JhLc9x5WdBKew9ZgAXg7DBk0ZHErLHdXM24rfX+bKrFe+Xp5YuJo54I5HFjGDAA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-musl": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.59.0.tgz", + "integrity": "sha512-peZRVEdnFWZ5Bh2KeumKG9ty7aCXzzEsHShOZEFiCQlDEepP1dpUl/SrUNXNg13UmZl+gzVDPsiCwnV1uI0RUA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loong64-gnu": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.59.0.tgz", + "integrity": "sha512-gbUSW/97f7+r4gHy3Jlup8zDG190AuodsWnNiXErp9mT90iCy9NKKU0Xwx5k8VlRAIV2uU9CsMnEFg/xXaOfXg==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loong64-musl": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.59.0.tgz", + "integrity": "sha512-yTRONe79E+o0FWFijasoTjtzG9EBedFXJMl888NBEDCDV9I2wGbFFfJQQe63OijbFCUZqxpHz1GzpbtSFikJ4Q==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-ppc64-gnu": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.59.0.tgz", + "integrity": "sha512-sw1o3tfyk12k3OEpRddF68a1unZ5VCN7zoTNtSn2KndUE+ea3m3ROOKRCZxEpmT9nsGnogpFP9x6mnLTCaoLkA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-ppc64-musl": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.59.0.tgz", + "integrity": "sha512-+2kLtQ4xT3AiIxkzFVFXfsmlZiG5FXYW7ZyIIvGA7Bdeuh9Z0aN4hVyXS/G1E9bTP/vqszNIN/pUKCk/BTHsKA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-gnu": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.59.0.tgz", + "integrity": "sha512-NDYMpsXYJJaj+I7UdwIuHHNxXZ/b/N2hR15NyH3m2qAtb/hHPA4g4SuuvrdxetTdndfj9b1WOmy73kcPRoERUg==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-musl": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.59.0.tgz", + "integrity": "sha512-nLckB8WOqHIf1bhymk+oHxvM9D3tyPndZH8i8+35p/1YiVoVswPid2yLzgX7ZJP0KQvnkhM4H6QZ5m0LzbyIAg==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-s390x-gnu": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.59.0.tgz", + "integrity": "sha512-oF87Ie3uAIvORFBpwnCvUzdeYUqi2wY6jRFWJAy1qus/udHFYIkplYRW+wo+GRUP4sKzYdmE1Y3+rY5Gc4ZO+w==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-gnu": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.59.0.tgz", + "integrity": "sha512-3AHmtQq/ppNuUspKAlvA8HtLybkDflkMuLK4DPo77DfthRb71V84/c4MlWJXixZz4uruIH4uaa07IqoAkG64fg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-musl": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.59.0.tgz", + "integrity": "sha512-2UdiwS/9cTAx7qIUZB/fWtToJwvt0Vbo0zmnYt7ED35KPg13Q0ym1g442THLC7VyI6JfYTP4PiSOWyoMdV2/xg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-openbsd-x64": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.59.0.tgz", + "integrity": "sha512-M3bLRAVk6GOwFlPTIxVBSYKUaqfLrn8l0psKinkCFxl4lQvOSz8ZrKDz2gxcBwHFpci0B6rttydI4IpS4IS/jQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ] + }, + "node_modules/@rollup/rollup-openharmony-arm64": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.59.0.tgz", + "integrity": "sha512-tt9KBJqaqp5i5HUZzoafHZX8b5Q2Fe7UjYERADll83O4fGqJ49O1FsL6LpdzVFQcpwvnyd0i+K/VSwu/o/nWlA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ] + }, + "node_modules/@rollup/rollup-win32-arm64-msvc": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.59.0.tgz", + "integrity": "sha512-V5B6mG7OrGTwnxaNUzZTDTjDS7F75PO1ae6MJYdiMu60sq0CqN5CVeVsbhPxalupvTX8gXVSU9gq+Rx1/hvu6A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-ia32-msvc": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.59.0.tgz", + "integrity": "sha512-UKFMHPuM9R0iBegwzKF4y0C4J9u8C6MEJgFuXTBerMk7EJ92GFVFYBfOZaSGLu6COf7FxpQNqhNS4c4icUPqxA==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-gnu": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.59.0.tgz", + "integrity": "sha512-laBkYlSS1n2L8fSo1thDNGrCTQMmxjYY5G0WFWjFFYZkKPjsMBsgJfGf4TLxXrF6RyhI60L8TMOjBMvXiTcxeA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-msvc": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.59.0.tgz", + "integrity": "sha512-2HRCml6OztYXyJXAvdDXPKcawukWY2GpR5/nxKp4iBgiO3wcoEGkAaqctIbZcNB6KlUQBIqt8VYkNSj2397EfA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@standard-schema/spec": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@standard-schema/spec/-/spec-1.1.0.tgz", + "integrity": "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==", + "dev": true, + "license": "MIT" + }, + "node_modules/@sveltejs/acorn-typescript": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/@sveltejs/acorn-typescript/-/acorn-typescript-1.0.9.tgz", + "integrity": "sha512-lVJX6qEgs/4DOcRTpo56tmKzVPtoWAaVbL4hfO7t7NVwl9AAXzQR6cihesW1BmNMPl+bK6dreu2sOKBP2Q9CIA==", + "license": "MIT", + "peerDependencies": { + "acorn": "^8.9.0" + } + }, + "node_modules/@sveltejs/adapter-static": { + "version": "3.0.10", + "resolved": "https://registry.npmjs.org/@sveltejs/adapter-static/-/adapter-static-3.0.10.tgz", + "integrity": "sha512-7D9lYFWJmB7zxZyTE/qxjksvMqzMuYrrsyh1f4AlZqeZeACPRySjbC3aFiY55wb1tWUaKOQG9PVbm74JcN2Iew==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@sveltejs/kit": "^2.0.0" + } + }, + "node_modules/@sveltejs/kit": { + "version": "2.55.0", + "resolved": "https://registry.npmjs.org/@sveltejs/kit/-/kit-2.55.0.tgz", + "integrity": "sha512-MdFRjevVxmAknf2NbaUkDF16jSIzXMWd4Nfah0Qp8TtQVoSp3bV4jKt8mX7z7qTUTWvgSaxtR0EG5WJf53gcuA==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@standard-schema/spec": "^1.0.0", + "@sveltejs/acorn-typescript": "^1.0.5", + "@types/cookie": "^0.6.0", + "acorn": "^8.14.1", + "cookie": "^0.6.0", + "devalue": "^5.6.4", + "esm-env": "^1.2.2", + "kleur": "^4.1.5", + "magic-string": "^0.30.5", + "mrmime": "^2.0.0", + "set-cookie-parser": "^3.0.0", + "sirv": "^3.0.0" + }, + "bin": { + "svelte-kit": "svelte-kit.js" + }, + "engines": { + "node": ">=18.13" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.0.0", + "@sveltejs/vite-plugin-svelte": "^3.0.0 || ^4.0.0-next.1 || ^5.0.0 || ^6.0.0-next.0 || ^7.0.0", + "svelte": "^4.0.0 || ^5.0.0-next.0", + "typescript": "^5.3.3", + "vite": "^5.0.3 || ^6.0.0 || ^7.0.0-beta.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "@opentelemetry/api": { + "optional": true + }, + "typescript": { + "optional": true + } + } + }, + "node_modules/@sveltejs/vite-plugin-svelte": { + "version": "6.2.4", + "resolved": "https://registry.npmjs.org/@sveltejs/vite-plugin-svelte/-/vite-plugin-svelte-6.2.4.tgz", + "integrity": "sha512-ou/d51QSdTyN26D7h6dSpusAKaZkAiGM55/AKYi+9AGZw7q85hElbjK3kEyzXHhLSnRISHOYzVge6x0jRZ7DXA==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@sveltejs/vite-plugin-svelte-inspector": "^5.0.0", + "deepmerge": "^4.3.1", + "magic-string": "^0.30.21", + "obug": "^2.1.0", + "vitefu": "^1.1.1" + }, + "engines": { + "node": "^20.19 || ^22.12 || >=24" + }, + "peerDependencies": { + "svelte": "^5.0.0", + "vite": "^6.3.0 || ^7.0.0" + } + }, + "node_modules/@sveltejs/vite-plugin-svelte-inspector": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/@sveltejs/vite-plugin-svelte-inspector/-/vite-plugin-svelte-inspector-5.0.2.tgz", + "integrity": "sha512-TZzRTcEtZffICSAoZGkPSl6Etsj2torOVrx6Uw0KpXxrec9Gg6jFWQ60Q3+LmNGfZSxHRCZL7vXVZIWmuV50Ig==", + "dev": true, + "license": "MIT", + "dependencies": { + "obug": "^2.1.0" + }, + "engines": { + "node": "^20.19 || ^22.12 || >=24" + }, + "peerDependencies": { + "@sveltejs/vite-plugin-svelte": "^6.0.0-next.0", + "svelte": "^5.0.0", + "vite": "^6.3.0 || ^7.0.0" + } + }, + "node_modules/@types/cookie": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-0.6.0.tgz", + "integrity": "sha512-4Kh9a6B2bQciAhf7FSuMRRkUWecJgJu9nPnx3yzpsfXX/c50REIqpHY4C82bXP90qrLtXtkDxTZosYO3UpOwlA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/estree": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", + "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==", + "license": "MIT" + }, + "node_modules/@types/trusted-types": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/@types/trusted-types/-/trusted-types-2.0.7.tgz", + "integrity": "sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==", + "license": "MIT" + }, + "node_modules/@typescript-eslint/types": { + "version": "8.57.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.57.0.tgz", + "integrity": "sha512-dTLI8PEXhjUC7B9Kre+u0XznO696BhXcTlOn0/6kf1fHaQW8+VjJAVHJ3eTI14ZapTxdkOmc80HblPQLaEeJdg==", + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/acorn": { + "version": "8.16.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.16.0.tgz", + "integrity": "sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==", + "license": "MIT", + "peer": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "license": "MIT", + "dependencies": { + "sprintf-js": "~1.0.2" + } + }, + "node_modules/aria-query": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.3.1.tgz", + "integrity": "sha512-Z/ZeOgVl7bcSYZ/u/rh0fOpvEpq//LZmdbkXyc7syVzjPAhfOa9ebsdTSjEBDU4vs5nC98Kfduj1uFo0qyET3g==", + "license": "Apache-2.0", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/axobject-query": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-4.1.0.tgz", + "integrity": "sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ==", + "license": "Apache-2.0", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/chokidar": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz", + "integrity": "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==", + "dev": true, + "license": "MIT", + "dependencies": { + "readdirp": "^4.0.1" + }, + "engines": { + "node": ">= 14.16.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/clsx": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz", + "integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/cookie": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.6.0.tgz", + "integrity": "sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/deepmerge": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", + "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/devalue": { + "version": "5.6.4", + "resolved": "https://registry.npmjs.org/devalue/-/devalue-5.6.4.tgz", + "integrity": "sha512-Gp6rDldRsFh/7XuouDbxMH3Mx8GMCcgzIb1pDTvNyn8pZGQ22u+Wa+lGV9dQCltFQ7uVw0MhRyb8XDskNFOReA==", + "license": "MIT" + }, + "node_modules/esbuild": { + "version": "0.27.4", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.27.4.tgz", + "integrity": "sha512-Rq4vbHnYkK5fws5NF7MYTU68FPRE1ajX7heQ/8QXXWqNgqqJ/GkmmyxIzUnf2Sr/bakf8l54716CcMGHYhMrrQ==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.27.4", + "@esbuild/android-arm": "0.27.4", + "@esbuild/android-arm64": "0.27.4", + "@esbuild/android-x64": "0.27.4", + "@esbuild/darwin-arm64": "0.27.4", + "@esbuild/darwin-x64": "0.27.4", + "@esbuild/freebsd-arm64": "0.27.4", + "@esbuild/freebsd-x64": "0.27.4", + "@esbuild/linux-arm": "0.27.4", + "@esbuild/linux-arm64": "0.27.4", + "@esbuild/linux-ia32": "0.27.4", + "@esbuild/linux-loong64": "0.27.4", + "@esbuild/linux-mips64el": "0.27.4", + "@esbuild/linux-ppc64": "0.27.4", + "@esbuild/linux-riscv64": "0.27.4", + "@esbuild/linux-s390x": "0.27.4", + "@esbuild/linux-x64": "0.27.4", + "@esbuild/netbsd-arm64": "0.27.4", + "@esbuild/netbsd-x64": "0.27.4", + "@esbuild/openbsd-arm64": "0.27.4", + "@esbuild/openbsd-x64": "0.27.4", + "@esbuild/openharmony-arm64": "0.27.4", + "@esbuild/sunos-x64": "0.27.4", + "@esbuild/win32-arm64": "0.27.4", + "@esbuild/win32-ia32": "0.27.4", + "@esbuild/win32-x64": "0.27.4" + } + }, + "node_modules/esm-env": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/esm-env/-/esm-env-1.2.2.tgz", + "integrity": "sha512-Epxrv+Nr/CaL4ZcFGPJIYLWFom+YeV1DqMLHJoEd9SYRxNbaFruBwfEX/kkHUJf55j2+TUbmDcmuilbP1TmXHA==", + "license": "MIT" + }, + "node_modules/esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "license": "BSD-2-Clause", + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/esrap": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/esrap/-/esrap-2.2.4.tgz", + "integrity": "sha512-suICpxAmZ9A8bzJjEl/+rLJiDKC0X4gYWUxT6URAWBLvlXmtbZd5ySMu/N2ZGEtMCAmflUDPSehrP9BQcsGcSg==", + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.4.15", + "@typescript-eslint/types": "^8.2.0" + } + }, + "node_modules/extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==", + "license": "MIT", + "dependencies": { + "is-extendable": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/fdir": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", + "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/gray-matter": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/gray-matter/-/gray-matter-4.0.3.tgz", + "integrity": "sha512-5v6yZd4JK3eMI3FqqCouswVqwugaA9r4dNZB1wwcmrD02QkV5H0y7XBQW8QwQqEaZY1pM9aqORSORhJRdNK44Q==", + "license": "MIT", + "dependencies": { + "js-yaml": "^3.13.1", + "kind-of": "^6.0.2", + "section-matter": "^1.0.0", + "strip-bom-string": "^1.0.0" + }, + "engines": { + "node": ">=6.0" + } + }, + "node_modules/is-extendable": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", + "integrity": "sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-reference": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/is-reference/-/is-reference-3.0.3.tgz", + "integrity": "sha512-ixkJoqQvAP88E6wLydLGGqCJsrFUnqoH6HnaczB8XmDH1oaWU+xxdptvikTgaEhtZ53Ky6YXiBuUI2WXLMCwjw==", + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.6" + } + }, + "node_modules/js-yaml": { + "version": "3.14.2", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.2.tgz", + "integrity": "sha512-PMSmkqxr106Xa156c2M265Z+FTrPl+oxd/rgOQy2tijQeK5TxQ43psO1ZCwhVOSdnn+RzkzlRz/eY4BgJBYVpg==", + "license": "MIT", + "dependencies": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/kleur": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/kleur/-/kleur-4.1.5.tgz", + "integrity": "sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/locate-character": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/locate-character/-/locate-character-3.0.0.tgz", + "integrity": "sha512-SW13ws7BjaeJ6p7Q6CO2nchbYEc3X3J6WrmTTDto7yMPqVSZTUyY5Tjbid+Ab8gLnATtygYtiDIJGQRRn2ZOiA==", + "license": "MIT" + }, + "node_modules/magic-string": { + "version": "0.30.21", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz", + "integrity": "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==", + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.5" + } + }, + "node_modules/marked": { + "version": "17.0.4", + "resolved": "https://registry.npmjs.org/marked/-/marked-17.0.4.tgz", + "integrity": "sha512-NOmVMM+KAokHMvjWmC5N/ZOvgmSWuqJB8FoYI019j4ogb/PeRMKoKIjReZ2w3376kkA8dSJIP8uD993Kxc0iRQ==", + "license": "MIT", + "bin": { + "marked": "bin/marked.js" + }, + "engines": { + "node": ">= 20" + } + }, + "node_modules/mri": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/mri/-/mri-1.2.0.tgz", + "integrity": "sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/mrmime": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/mrmime/-/mrmime-2.0.1.tgz", + "integrity": "sha512-Y3wQdFg2Va6etvQ5I82yUhGdsKrcYox6p7FfL1LbK2J4V01F9TGlepTIhnK24t7koZibmg82KGglhA1XK5IsLQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + } + }, + "node_modules/nanoid": { + "version": "3.3.11", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", + "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/obug": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/obug/-/obug-2.1.1.tgz", + "integrity": "sha512-uTqF9MuPraAQ+IsnPf366RG4cP9RtUi7MLO1N3KEc+wb0a6yKpeL0lmk2IB1jY5KHPAlTc6T/JRdC/YqxHNwkQ==", + "dev": true, + "funding": [ + "https://github.com/sponsors/sxzz", + "https://opencollective.com/debug" + ], + "license": "MIT" + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "dev": true, + "license": "ISC" + }, + "node_modules/picomatch": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", + "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/postcss": { + "version": "8.5.8", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.8.tgz", + "integrity": "sha512-OW/rX8O/jXnm82Ey1k44pObPtdblfiuWnrd8X7GJ7emImCOstunGbXUpp7HdBrFQX6rJzn3sPT397Wp5aCwCHg==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "nanoid": "^3.3.11", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/prettier": { + "version": "3.8.1", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.8.1.tgz", + "integrity": "sha512-UOnG6LftzbdaHZcKoPFtOcCKztrQ57WkHDeRD9t/PTQtmT0NHSeWWepj6pS0z/N7+08BHFDQVUrfmfMRcZwbMg==", + "dev": true, + "license": "MIT", + "peer": true, + "bin": { + "prettier": "bin/prettier.cjs" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + }, + "node_modules/prettier-plugin-svelte": { + "version": "3.5.1", + "resolved": "https://registry.npmjs.org/prettier-plugin-svelte/-/prettier-plugin-svelte-3.5.1.tgz", + "integrity": "sha512-65+fr5+cgIKWKiqM1Doum4uX6bY8iFCdztvvp2RcF+AJoieaw9kJOFMNcJo/bkmKYsxFaM9OsVZK/gWauG/5mg==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "prettier": "^3.0.0", + "svelte": "^3.2.0 || ^4.0.0-next.0 || ^5.0.0-next.0" + } + }, + "node_modules/readdirp": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz", + "integrity": "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 14.18.0" + }, + "funding": { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/rollup": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.59.0.tgz", + "integrity": "sha512-2oMpl67a3zCH9H79LeMcbDhXW/UmWG/y2zuqnF2jQq5uq9TbM9TVyXvA4+t+ne2IIkBdrLpAaRQAvo7YI/Yyeg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "1.0.8" + }, + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=18.0.0", + "npm": ">=8.0.0" + }, + "optionalDependencies": { + "@rollup/rollup-android-arm-eabi": "4.59.0", + "@rollup/rollup-android-arm64": "4.59.0", + "@rollup/rollup-darwin-arm64": "4.59.0", + "@rollup/rollup-darwin-x64": "4.59.0", + "@rollup/rollup-freebsd-arm64": "4.59.0", + "@rollup/rollup-freebsd-x64": "4.59.0", + "@rollup/rollup-linux-arm-gnueabihf": "4.59.0", + "@rollup/rollup-linux-arm-musleabihf": "4.59.0", + "@rollup/rollup-linux-arm64-gnu": "4.59.0", + "@rollup/rollup-linux-arm64-musl": "4.59.0", + "@rollup/rollup-linux-loong64-gnu": "4.59.0", + "@rollup/rollup-linux-loong64-musl": "4.59.0", + "@rollup/rollup-linux-ppc64-gnu": "4.59.0", + "@rollup/rollup-linux-ppc64-musl": "4.59.0", + "@rollup/rollup-linux-riscv64-gnu": "4.59.0", + "@rollup/rollup-linux-riscv64-musl": "4.59.0", + "@rollup/rollup-linux-s390x-gnu": "4.59.0", + "@rollup/rollup-linux-x64-gnu": "4.59.0", + "@rollup/rollup-linux-x64-musl": "4.59.0", + "@rollup/rollup-openbsd-x64": "4.59.0", + "@rollup/rollup-openharmony-arm64": "4.59.0", + "@rollup/rollup-win32-arm64-msvc": "4.59.0", + "@rollup/rollup-win32-ia32-msvc": "4.59.0", + "@rollup/rollup-win32-x64-gnu": "4.59.0", + "@rollup/rollup-win32-x64-msvc": "4.59.0", + "fsevents": "~2.3.2" + } + }, + "node_modules/sade": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/sade/-/sade-1.8.1.tgz", + "integrity": "sha512-xal3CZX1Xlo/k4ApwCFrHVACi9fBqJ7V+mwhBsuf/1IOKbBy098Fex+Wa/5QMubw09pSZ/u8EY8PWgevJsXp1A==", + "dev": true, + "license": "MIT", + "dependencies": { + "mri": "^1.1.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/section-matter": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/section-matter/-/section-matter-1.0.0.tgz", + "integrity": "sha512-vfD3pmTzGpufjScBh50YHKzEu2lxBWhVEHsNGoEXmCmn2hKGfeNLYMzCJpe8cD7gqX7TJluOVpBkAequ6dgMmA==", + "license": "MIT", + "dependencies": { + "extend-shallow": "^2.0.1", + "kind-of": "^6.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/set-cookie-parser": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/set-cookie-parser/-/set-cookie-parser-3.0.1.tgz", + "integrity": "sha512-n7Z7dXZhJbwuAHhNzkTti6Aw9QDDjZtm3JTpTGATIdNzdQz5GuFs22w90BcvF4INfnrL5xrX3oGsuqO5Dx3A1Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/sirv": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/sirv/-/sirv-3.0.2.tgz", + "integrity": "sha512-2wcC/oGxHis/BoHkkPwldgiPSYcpZK3JU28WoMVv55yHJgcZ8rlXvuG9iZggz+sU1d4bRgIGASwyWqjxu3FM0g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@polka/url": "^1.0.0-next.24", + "mrmime": "^2.0.0", + "totalist": "^3.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/source-map-js": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", + "license": "BSD-3-Clause" + }, + "node_modules/strip-bom-string": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/strip-bom-string/-/strip-bom-string-1.0.0.tgz", + "integrity": "sha512-uCC2VHvQRYu+lMh4My/sFNmF2klFymLX1wHJeXnbEJERpV/ZsVuonzerjfrGpIGF7LBVa1O7i9kjiWvJiFck8g==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/svelte": { + "version": "5.53.12", + "resolved": "https://registry.npmjs.org/svelte/-/svelte-5.53.12.tgz", + "integrity": "sha512-4x/uk4rQe/d7RhfvS8wemTfNjQ0bJbKvamIzRBfTe2eHHjzBZ7PZicUQrC2ryj83xxEacfA1zHKd1ephD1tAxA==", + "license": "MIT", + "peer": true, + "dependencies": { + "@jridgewell/remapping": "^2.3.4", + "@jridgewell/sourcemap-codec": "^1.5.0", + "@sveltejs/acorn-typescript": "^1.0.5", + "@types/estree": "^1.0.5", + "@types/trusted-types": "^2.0.7", + "acorn": "^8.12.1", + "aria-query": "5.3.1", + "axobject-query": "^4.1.0", + "clsx": "^2.1.1", + "devalue": "^5.6.4", + "esm-env": "^1.2.1", + "esrap": "^2.2.2", + "is-reference": "^3.0.3", + "locate-character": "^3.0.0", + "magic-string": "^0.30.11", + "zimmerframe": "^1.1.2" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/svelte-check": { + "version": "4.4.5", + "resolved": "https://registry.npmjs.org/svelte-check/-/svelte-check-4.4.5.tgz", + "integrity": "sha512-1bSwIRCvvmSHrlK52fOlZmVtUZgil43jNL/2H18pRpa+eQjzGt6e3zayxhp1S7GajPFKNM/2PMCG+DZFHlG9fw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.25", + "chokidar": "^4.0.1", + "fdir": "^6.2.0", + "picocolors": "^1.0.0", + "sade": "^1.7.4" + }, + "bin": { + "svelte-check": "bin/svelte-check" + }, + "engines": { + "node": ">= 18.0.0" + }, + "peerDependencies": { + "svelte": "^4.0.0 || ^5.0.0-next.0", + "typescript": ">=5.0.0" + } + }, + "node_modules/tinyglobby": { + "version": "0.2.15", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz", + "integrity": "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "fdir": "^6.5.0", + "picomatch": "^4.0.3" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/SuperchupuDev" + } + }, + "node_modules/totalist": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/totalist/-/totalist-3.0.1.tgz", + "integrity": "sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/typescript": { + "version": "5.9.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", + "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", + "dev": true, + "license": "Apache-2.0", + "peer": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/vite": { + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/vite/-/vite-7.3.1.tgz", + "integrity": "sha512-w+N7Hifpc3gRjZ63vYBXA56dvvRlNWRczTdmCBBa+CotUzAPf5b7YMdMR/8CQoeYE5LX3W4wj6RYTgonm1b9DA==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "esbuild": "^0.27.0", + "fdir": "^6.5.0", + "picomatch": "^4.0.3", + "postcss": "^8.5.6", + "rollup": "^4.43.0", + "tinyglobby": "^0.2.15" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + }, + "peerDependencies": { + "@types/node": "^20.19.0 || >=22.12.0", + "jiti": ">=1.21.0", + "less": "^4.0.0", + "lightningcss": "^1.21.0", + "sass": "^1.70.0", + "sass-embedded": "^1.70.0", + "stylus": ">=0.54.8", + "sugarss": "^5.0.0", + "terser": "^5.16.0", + "tsx": "^4.8.1", + "yaml": "^2.4.2" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "jiti": { + "optional": true + }, + "less": { + "optional": true + }, + "lightningcss": { + "optional": true + }, + "sass": { + "optional": true + }, + "sass-embedded": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + }, + "tsx": { + "optional": true + }, + "yaml": { + "optional": true + } + } + }, + "node_modules/vitefu": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vitefu/-/vitefu-1.1.2.tgz", + "integrity": "sha512-zpKATdUbzbsycPFBN71nS2uzBUQiVnFoOrr2rvqv34S1lcAgMKKkjWleLGeiJlZ8lwCXvtWaRn7R3ZC16SYRuw==", + "dev": true, + "license": "MIT", + "workspaces": [ + "tests/deps/*", + "tests/projects/*", + "tests/projects/workspace/packages/*" + ], + "peerDependencies": { + "vite": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-beta.0" + }, + "peerDependenciesMeta": { + "vite": { + "optional": true + } + } + }, + "node_modules/zimmerframe": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/zimmerframe/-/zimmerframe-1.1.4.tgz", + "integrity": "sha512-B58NGBEoc8Y9MWWCQGl/gq9xBCe4IiKM0a2x7GZdQKOW5Exr8S1W24J6OgM1njK8xCRGvAJIL/MxXHf6SkmQKQ==", + "license": "MIT" + } + } +} diff --git a/package.json b/package.json new file mode 100644 index 0000000..5d8a5f9 --- /dev/null +++ b/package.json @@ -0,0 +1,33 @@ +{ + "name": "5of12-site", + "private": true, + "version": "0.0.1", + "type": "module", + "scripts": { + "dev": "vite dev", + "build": "vite build", + "preview": "vite preview", + "prepare": "svelte-kit sync || echo ''", + "format": "prettier --write .", + "check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json", + "check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch" + }, + "devDependencies": { + "@sveltejs/adapter-static": "^3.0.10", + "@sveltejs/kit": "^2.50.2", + "@sveltejs/vite-plugin-svelte": "^6.2.4", + "prettier": "^3.8.1", + "prettier-plugin-svelte": "^3.5.1", + "svelte": "^5.51.0", + "svelte-check": "^4.4.2", + "typescript": "^5.9.3", + "vite": "^7.3.1" + }, + "dependencies": { + "@fortawesome/free-brands-svg-icons": "^7.2.0", + "@fortawesome/svelte-fontawesome": "^0.2.4", + "@lucide/svelte": "^1.17.0", + "gray-matter": "^4.0.3", + "marked": "^17.0.4" + } +} diff --git a/src/app.css b/src/app.css new file mode 100644 index 0000000..d3b0ae7 --- /dev/null +++ b/src/app.css @@ -0,0 +1,306 @@ +:root { + color-scheme: light; + --bg: #f6f3ec; + --bg-elevated: #fcfaf6; + --panel: rgba(255, 255, 255, 0.78); + --panel-strong: rgba(255, 255, 255, 0.94); + --text: #242424; + --muted: #6d685f; + --line: rgba(61, 61, 61, 0.12); + --line-strong: rgba(61, 61, 61, 0.22); + --shadow: 0 18px 60px rgba(61, 61, 61, 0.08); + --coral: #ff6575; + --orange: #ffaf51; + --yellow: #ffe57c; + --green: #a7e98a; + --teal: #72d2c8; + --neutral: #3d3d3d; + --coral-wash: rgba(255, 101, 117, 0.16); + --teal-wash: rgba(114, 210, 200, 0.14); + --yellow-wash: rgba(255, 229, 124, 0.14); + --radius-xl: 2rem; + --radius-lg: 1.5rem; + --site-width: min(1180px, calc(100vw - 2rem)); +} + +:root[data-theme="dark"] { + color-scheme: dark; + --bg: #151515; + --bg-elevated: #1b1b1b; + --panel: rgba(27, 27, 27, 0.78); + --panel-strong: rgba(34, 34, 34, 0.96); + --text: #f4efe5; + --muted: #b8b1a6; + --line: rgba(255, 255, 255, 0.08); + --line-strong: rgba(255, 255, 255, 0.16); + --shadow: 0 18px 60px rgba(0, 0, 0, 0.36); + --coral-wash: rgba(255, 101, 117, 0.18); + --teal-wash: rgba(114, 210, 200, 0.14); + --yellow-wash: rgba(255, 229, 124, 0.12); +} + +*, +*::before, +*::after { + box-sizing: border-box; +} + +html { + scroll-behavior: smooth; + background: var(--bg); +} + +body { + margin: 0; + min-height: 100vh; + background: + radial-gradient(circle at 8% 10%, var(--coral-wash), transparent 24rem), + radial-gradient(circle at 82% 12%, var(--teal-wash), transparent 26rem), + radial-gradient(circle at 50% 100%, var(--yellow-wash), transparent 28rem), + var(--bg); + color: var(--text); + font-family: + "Funnel Sans", + -apple-system, + BlinkMacSystemFont, + sans-serif; + text-rendering: optimizeLegibility; + -webkit-font-smoothing: antialiased; + animation: ambient-drift 34s ease-in-out infinite alternate; +} + +body::before { + content: ""; + position: fixed; + inset: 0; + pointer-events: none; + background-image: + linear-gradient(to right, transparent calc(100% - 1px), var(--line) 100%), + linear-gradient(to bottom, transparent calc(100% - 1px), var(--line) 100%); + background-size: 4.5rem 4.5rem; + opacity: 0.3; + mask-image: radial-gradient(circle at center, black 35%, transparent 95%); + animation: grid-drift 42s linear infinite; +} + +@keyframes ambient-drift { + to { + background-position: + 2rem -1rem, + -1.5rem 2rem, + 1rem 1.5rem, + 0 0; + } +} + +@keyframes grid-drift { + to { + background-position: 4.5rem 4.5rem; + } +} + +a { + color: inherit; + text-decoration: none; +} + +img, +video, +iframe { + display: block; + max-width: 100%; +} + +button, +input, +textarea, +select { + font: inherit; +} + +.panel { + border: 1px solid var(--line); + border-radius: var(--radius-xl); + background: var(--panel); + box-shadow: var(--shadow); +} + +.panel--nested { + background: var(--panel-strong); +} + +.section, +.post-page { + margin-top: 1.5rem; +} + +.section[id] { + scroll-margin-top: 7rem; +} + +.page-hero, +.post-hero { + margin-top: 1.5rem; + padding: clamp(1.5rem, 2vw, 2rem); +} + +.page-hero h1, +.post-hero h1 { + max-width: 15ch; + margin: 0; + font-size: clamp(2.7rem, 5vw, 4.5rem); + line-height: 0.96; + letter-spacing: -0.06em; + text-wrap: balance; +} + +.page-intro { + max-width: 42rem; + margin: 0; + font-size: clamp(1.2rem, 2.1vw, 1.55rem); + line-height: 1.4; + overflow-wrap: anywhere; +} + +.stack { + display: flex; + flex-direction: column; + gap: 1rem; +} + +.section-head { + display: grid; + grid-template-columns: minmax(0, 1fr) minmax(18rem, 24rem); + gap: 1.5rem; + align-items: end; + margin-bottom: 1.25rem; +} + +.section-head h2 { + margin: 0.35rem 0 0; + font-size: clamp(2rem, 3vw, 3rem); + line-height: 1.02; + letter-spacing: -0.05em; + text-wrap: balance; +} + +.site-footer__eyebrow, +.micro-label, +.card-kicker, +.section-kicker, +.principle-card__label, +.post-card__meta, +.stat-card__label { + color: var(--muted); + font-size: 0.82rem; + font-weight: 600; + letter-spacing: 0.08em; + text-transform: uppercase; +} + +.section-kicker { + display: inline-flex; + align-items: center; + gap: 0.75rem; + margin: 0; +} + +.section-kicker span { + display: inline-flex; + align-items: center; + justify-content: center; + min-width: 2.35rem; + height: 2.35rem; + padding: 0 0.7rem; + border: 1px solid var(--line); + border-radius: 999px; + background: var(--panel-strong); + color: var(--text); +} + +.section-copy { + color: var(--muted); + font-size: 1rem; + line-height: 1.6; + overflow-wrap: anywhere; +} + +.button-row { + display: flex; + flex-wrap: wrap; + gap: 0.75rem; +} + +.button { + display: inline-flex; + align-items: center; + justify-content: center; + min-height: 2.85rem; + padding: 0 1.15rem; + border: 1px solid var(--line-strong); + border-radius: 999px; + background: var(--panel-strong); + color: var(--text); + font-weight: 600; +} + +.button--primary { + border-color: var(--text); + background: var(--text); + color: var(--bg); +} + +.tone-coral { + --tone: var(--coral); +} + +.tone-orange { + --tone: var(--orange); +} + +.tone-yellow { + --tone: var(--yellow); +} + +.tone-green { + --tone: var(--green); +} + +.tone-teal { + --tone: var(--teal); +} + +.tone-neutral { + --tone: var(--neutral); +} + +@media (max-width: 960px) { + .section-head { + grid-template-columns: 1fr; + } +} + +@media (max-width: 720px) { + body::before { + background-size: 3rem 3rem; + } + + .button-row { + flex-direction: column; + } + + .button { + width: 100%; + } +} + +@media (prefers-reduced-motion: reduce) { + *, + *::before, + *::after { + scroll-behavior: auto !important; + animation-duration: 0.01ms !important; + animation-iteration-count: 1 !important; + transition-duration: 0.01ms !important; + } +} diff --git a/src/app.d.ts b/src/app.d.ts new file mode 100644 index 0000000..520c421 --- /dev/null +++ b/src/app.d.ts @@ -0,0 +1,13 @@ +// See https://svelte.dev/docs/kit/types#app.d.ts +// for information about these interfaces +declare global { + namespace App { + // interface Error {} + // interface Locals {} + // interface PageData {} + // interface PageState {} + // interface Platform {} + } +} + +export {}; diff --git a/src/app.html b/src/app.html new file mode 100644 index 0000000..5637ced --- /dev/null +++ b/src/app.html @@ -0,0 +1,23 @@ + + + + + + + %sveltekit.head% + + +
%sveltekit.body%
+ + diff --git a/src/lib/assets/favicon.svg b/src/lib/assets/favicon.svg new file mode 100644 index 0000000..cc5dc66 --- /dev/null +++ b/src/lib/assets/favicon.svg @@ -0,0 +1 @@ +svelte-logo \ No newline at end of file diff --git a/src/lib/components/ExperimentCard.svelte b/src/lib/components/ExperimentCard.svelte new file mode 100644 index 0000000..7fba132 --- /dev/null +++ b/src/lib/components/ExperimentCard.svelte @@ -0,0 +1,100 @@ + + +
+ + {experiment.imageAlt} + + +
+

WebAudio / WebMIDI

+

{experiment.title}

+

{experiment.description}

+ +
+ Launch + GitHub +
+
+
+ + diff --git a/src/lib/components/IconGlyph.svelte b/src/lib/components/IconGlyph.svelte new file mode 100644 index 0000000..b882a8a --- /dev/null +++ b/src/lib/components/IconGlyph.svelte @@ -0,0 +1,45 @@ + + + + + diff --git a/src/lib/components/PostCard.svelte b/src/lib/components/PostCard.svelte new file mode 100644 index 0000000..64667c9 --- /dev/null +++ b/src/lib/components/PostCard.svelte @@ -0,0 +1,121 @@ + + +
+ + {#if post.coverImage} + + {:else} +
+ Studio note +
+ {/if} +
+ +
+
+ {post.formattedDate} + {post.readingTime} min read +
+

+ {post.title} +

+

{post.excerpt}

+
+
+ + diff --git a/src/lib/components/SocialIcon.svelte b/src/lib/components/SocialIcon.svelte new file mode 100644 index 0000000..b10de5d --- /dev/null +++ b/src/lib/components/SocialIcon.svelte @@ -0,0 +1,35 @@ + + + + + diff --git a/src/lib/components/ThemeToggle.svelte b/src/lib/components/ThemeToggle.svelte new file mode 100644 index 0000000..2779dce --- /dev/null +++ b/src/lib/components/ThemeToggle.svelte @@ -0,0 +1,149 @@ + + + + + diff --git a/src/lib/components/WorkCard.svelte b/src/lib/components/WorkCard.svelte new file mode 100644 index 0000000..3f34695 --- /dev/null +++ b/src/lib/components/WorkCard.svelte @@ -0,0 +1,184 @@ + + +
+ + {#if item.preview.type === "video"} + + {:else} + {item.preview.alt} + {/if} + + +
+

{item.eyebrow}

+

{item.title}

+

{item.description}

+ + + +
+ {#each item.links as link, index} + + {link.label} + + {/each} +
+
+
+ + diff --git a/src/lib/content/site.ts b/src/lib/content/site.ts new file mode 100644 index 0000000..4e49eee --- /dev/null +++ b/src/lib/content/site.ts @@ -0,0 +1,532 @@ +export type AccentTone = "coral" | "orange" | "yellow" | "green" | "teal"; +export type IconName = + | "spark" + | "compass" + | "midi" + | "heart" + | "play" + | "hand" + | "xr" + | "globe" + | "game" + | "immersive"; + +export type WorkPreview = { + type: "image" | "video"; + src: string; + poster?: string; + alt: string; +}; + +export type WorkItem = { + title: string; + eyebrow: string; + description: string; + preview: WorkPreview; + links: Array<{ label: string; href: string }>; + metrics: string[]; + accent: AccentTone; +}; + +export type ExperimentItem = { + title: string; + description: string; + image: string; + imageAlt: string; + href: string; + github: string; + accent: AccentTone; +}; + +export type PrincipleItem = { + title: string; + description: string; + accent: AccentTone; + icon: IconName; +}; + +export type StatItem = { + label: string; + value: string; + icon: IconName; +}; + +export type BeliefItem = { + title: string; + accent: AccentTone; + icon: IconName; +}; + +export type ServiceItem = { + title: string; + description: string; + accent: AccentTone; + icon: IconName; +}; + +export type PartnerItem = { + name: string; + href: string; + logo?: string; + logoClass: string; + wordmark?: string; + secondaryMark?: string; +}; + +export type TechnologyItem = { + name: string; + description: string; + href: string; + logo?: string; + logoClass: string; + wordmark?: string; +}; + +export type TeamPortfolio = { + name: string; + fullName: string; + href: string; +}; + +export type PlayExperience = { + title: string; + eyebrow: string; + description: string; + href: string; + linkLabel: string; + accent: AccentTone; + icon: IconName; +}; + +export type SocialIconName = "instagram" | "linkedin" | "youtube" | "github"; + +export type SocialLink = { + label: string; + handle: string; + href: string; + icon: SocialIconName; +}; + +export type ContactRoute = { + title: string; + description: string; + href: string; + label: string; +}; + +export const siteMeta = { + title: "5of12", + description: + "5of12 is a UK creative technology studio building playful spatial, musical and web-first experiences.", +}; + +export const featuredWork: WorkItem[] = [ + { + title: "Playtonik", + eyebrow: "iOS musical instrument", + description: + "A playful musical fidget toy for iPhone and iPad with physics, haptics and deep MIDI connectivity.", + preview: { + type: "image", + src: "/assets/ADC_banner.png", + alt: "Playtonik physics shapes bouncing inside glowing musical containers.", + }, + links: [ + { label: "Explore Playtonik", href: "/playtonik/" }, + { + label: "App Store", + href: "https://apps.apple.com/gb/app/playtonik/id6738356927", + }, + ], + metrics: [ + "2025 MIDI Innovation Award", + "Physics-driven sound", + "MIDI in and out", + ], + accent: "coral", + }, + { + title: "MediaPipe Playground", + eyebrow: "Browser interaction prototype", + description: + "Gesture-led browser experiments exploring comfortable hand and body control with nothing more than a webcam.", + preview: { + type: "image", + src: "/assets/work/mediapipe-map.gif", + alt: "MediaPipe Playground map interaction controlled by two handed pinch gestures.", + }, + links: [ + { + label: "Open playground", + href: "https://5of12.github.io/MediaPipe-Playground", + }, + { + label: "Try an example", + href: "https://5of12.github.io/MediaPipe-Playground/examples/WorldInYourHands.html", + }, + ], + metrics: [ + "Web camera only", + "Single and two-hand input", + "Real-time interaction", + ], + accent: "yellow", + }, + { + title: "Cacophony", + eyebrow: "Gesture system for Unity", + description: + "A Unity gesture library built to make screen-based spatial interaction readable, reliable and fun.", + preview: { + type: "image", + src: "/assets/Cacophony_banner.png", + alt: "Cacophony gesture library banner with a hand performing a pinch gesture.", + }, + links: [ + { label: "Read the article", href: "/journal/a-cacophony-of-gestures/" }, + { label: "GitHub", href: "https://github.com/5of12/cacophony" }, + ], + metrics: [ + "Unity-first workflow", + "Platform-agnostic gestures", + "Action and reaction", + ], + accent: "teal", + }, +]; + +export const experiments: ExperimentItem[] = [ + { + title: "Pocket Operations", + description: + "Sketch patterns, send them to hardware over Web MIDI and export loops as .midi files.", + image: "/assets/experiments/pocket-operations-preview.png", + imageAlt: + "Pocket Operations screenshot showing pattern categories, transport controls and a grid sequencer.", + href: "https://5of12.github.io/PocketOperations/", + github: "https://github.com/5of12/PocketOperations", + accent: "orange", + }, + { + title: "MIDIWeb-Hub", + description: + "A curated directory of browser-based musical tools, utilities and WebMIDI experiments.", + image: "/assets/experiments/midiweb-hub-preview.png", + imageAlt: + "MIDIWeb-Hub screenshot showing tagged cards in a WebMIDI directory.", + href: "https://5of12.github.io/MIDIWeb-Hub/", + github: "https://github.com/5of12/MIDIWeb-Hub", + accent: "green", + }, + { + title: "Augment", + description: + "An Audio UX generator for polished clicks, pops and small expressive cues built in the browser.", + image: "/assets/experiments/augment-preview.png", + imageAlt: + "Augment screenshot showing interface sound controls, waveform preview and export button.", + href: "https://5of12.github.io/Augment/", + github: "https://github.com/5of12/Augment", + accent: "teal", + }, +]; + +export const studioPrinciples: PrincipleItem[] = [ + { + title: "Human", + description: "Designed with care, taste and feeling.", + accent: "coral", + icon: "heart", + }, + { + title: "Playful", + description: "Inviting experimentation and surprise.", + accent: "yellow", + icon: "play", + }, + { + title: "Useful", + description: "Built to be touched, heard and explored.", + accent: "green", + icon: "hand", + }, + { + title: "Curious", + description: "Unafraid of odd ideas and unexpected turns.", + accent: "teal", + icon: "compass", + }, +]; + +export const studioStats: StatItem[] = [ + { label: "Combined experience", value: "15+ years", icon: "spark" }, + { + label: "Core disciplines", + value: "Spatial, audio, interaction", + icon: "midi", + }, + { label: "Studio base", value: "UK studio", icon: "globe" }, +]; + +export const studioBeliefs: BeliefItem[] = [ + { title: "Play as a serious tool", accent: "coral", icon: "play" }, + { + title: "Bleeps, Bloops, Springs & Splines", + accent: "orange", + icon: "spark", + }, + { title: "Discovery as a way of working", accent: "yellow", icon: "compass" }, + { title: "Human-made design, no AI slop", accent: "green", icon: "heart" }, + { title: "Add MIDI wherever possible.", accent: "teal", icon: "midi" }, +]; + +export const playExperiences: PlayExperience[] = [ + { + title: "Playtonik", + eyebrow: "Musical fidget toy", + description: + "A tactile iPhone and iPad instrument where physics, haptics and MIDI turn little gestures into musical motion.", + href: "/playtonik/", + linkLabel: "Explore Playtonik", + accent: "coral", + icon: "midi", + }, + { + title: "Pezzi", + eyebrow: "WebXR game for VIVERSE", + description: + "Music in pieces: a cross-platform XR, desktop and mobile game built around playful listening and assembly.", + href: "https://www.viverse.com/dPASDhP", + linkLabel: "Play on VIVERSE", + accent: "yellow", + icon: "xr", + }, + { + title: "Unity experiments", + eyebrow: "Games, hackathons and instruments", + description: + "Rapid prototypes from Meta Hackathon work to Unity games and musical instrument experiments, made to test how interaction feels.", + href: "https://www.youtube.com/watch?v=gIsR3yy8NuY", + linkLabel: "Watch hackathon work", + accent: "teal", + icon: "game", + }, +]; + +export const services: ServiceItem[] = [ + { + title: "Rapid prototypes", + description: + "Early technical proofs, design prototypes and show-ready demos for ideas that need to be felt before they can be judged.", + accent: "coral", + icon: "spark", + }, + { + title: "Spatial computing", + description: + "XR, AR and mobile apps using hand tracking, gaze, haptics, scene understanding and spatial UX.", + accent: "yellow", + icon: "globe", + }, + { + title: "Novel interaction systems", + description: + "Gesture vocabularies, mid-air UI, touchless controls and multi-modal input systems for screens and spaces.", + accent: "teal", + icon: "hand", + }, + { + title: "Immersive demos", + description: + "Event, exhibition and executive demos that make technical value clear, robust and memorable.", + accent: "orange", + icon: "immersive", + }, + { + title: "XR app development", + description: + "RealityKit, ARKit and Unity builds from concept through implementation, polish and release.", + accent: "green", + icon: "compass", + }, + { + title: "Tools, plugins and SDKs", + description: + "Audio plugins, Unity utilities, browser tools and developer SDKs that turn prototypes into reusable systems.", + accent: "teal", + icon: "midi", + }, +]; + +export const partners: PartnerItem[] = [ + { + name: "Watershed", + href: "https://www.watershed.co.uk", + logo: "/assets/partners/watershed.webp", + logoClass: "watershed", + wordmark: "Watershed", + }, + { + name: "Pervasive Media Studio", + href: "https://www.watershed.co.uk/studio/", + logo: "/assets/partners/pervasive-media-studio.svg", + logoClass: "pervasive", + }, + { + name: "Uno Minda", + href: "https://www.unominda.com", + logo: "/assets/partners/uno-minda.png", + logoClass: "uno-minda", + }, + { + name: "Distance", + href: "https://distance.tech", + logo: "/assets/partners/distance.svg", + logoClass: "distance", + }, + { + name: "Ultraleap + ROLI", + href: "https://www.ultraleap.com", + logo: "/assets/partners/ultraleap.svg", + logoClass: "ultraleap", + secondaryMark: "ROLI", + }, + { + name: "50Hertz", + href: "https://www.50hertz.com/en/Company", + logo: "/assets/partners/50hertz.png", + logoClass: "50hertz", + }, + { + name: "SRT Marine", + href: "https://srt-marine.com", + logo: "/assets/partners/srt.svg", + logoClass: "SRT", + }, + { + name: "HTC VIVERSE", + href: "https://www.viverse.com", + logo: "/assets/partners/viverse.png", + logoClass: "viverse", + wordmark: "VIVERSE", + }, +]; + +export const technologies: TechnologyItem[] = [ + { + name: "Apple", + description: + "Cross-platform App Store development for iPhone, iPad, Mac and Apple Vision Pro.", + href: "https://developer.apple.com/", + logo: "/assets/technologies/apple.svg", + logoClass: "apple", + }, + { + name: "Meta", + description: + "Quest 3 and Quest 3S development for spatial apps and experiences.", + href: "https://developers.meta.com/horizon/", + logo: "/assets/technologies/meta.svg", + logoClass: "meta", + }, + { + name: "Unity", + description: + "Cross-platform games, rapid prototypes and reusable creative tooling.", + href: "https://unity.com/", + logo: "/assets/technologies/unity.svg", + logoClass: "unity", + }, + { + name: "Threlte", + description: "Svelte-native 3D and WebXR experiences for the browser.", + href: "https://threlte.xyz/", + logoClass: "threlte", + wordmark: "Threlte", + }, + { + name: "Svelte", + description: + "Fast, accessible websites and focused interactive interfaces.", + href: "https://svelte.dev/", + logo: "/assets/technologies/svelte.svg", + logoClass: "svelte", + }, +]; + +export const teamPortfolios: TeamPortfolio[] = [ + { + name: "Pete", + fullName: "Pete Nancollis", + href: "https://petenancollis.framer.website", + }, + { + name: "Tom", + fullName: "Tom Cartwright", + href: "https://tom-cartwright.com", + }, + { + name: "Ant", + fullName: "Ant Nasce", + href: "https://antiero.github.io/ant-portfolio/", + }, +]; + +export const socialLinks: SocialLink[] = [ + { + label: "Instagram", + handle: "@5of12studio", + href: "https://instagram.com/5of12studio", + icon: "instagram", + }, + { + label: "LinkedIn", + handle: "5of12", + href: "https://www.linkedin.com/company/5of12", + icon: "linkedin", + }, + { + label: "YouTube", + handle: "@5of12studio", + href: "https://www.youtube.com/@5of12studio", + icon: "youtube", + }, + { + label: "GitHub", + handle: "5of12", + href: "https://github.com/5of12", + icon: "github", + }, +]; + +export const contactRoutes: ContactRoute[] = [ + { + title: "Studio enquiries", + description: + "Immersive builds, prototypes, spatial interaction, events and research demos.", + href: "mailto:info@5of12.co.uk?subject=Studio%20enquiry", + label: "Start a project", + }, + { + title: "Playtonik support", + description: + "App support, MIDI setup questions, feature feedback and privacy questions.", + href: "mailto:info@5of12.co.uk?subject=Playtonik%20support", + label: "Contact support", + }, + { + title: "Open source", + description: + "Cacophony, MediaPipe Playground and browser-based music tools.", + href: "https://github.com/5of12", + label: "View GitHub", + }, +]; + +export const companyInfo = { + name: "5of12 LLP", + registration: "Limited Liability Partnership", + companyNumber: "OC453996", + email: "info@5of12.co.uk", + privacyHref: "/privacy/", +}; diff --git a/src/lib/content/types.ts b/src/lib/content/types.ts new file mode 100644 index 0000000..72bc448 --- /dev/null +++ b/src/lib/content/types.ts @@ -0,0 +1,11 @@ +export type JournalPost = { + slug: string; + title: string; + author: string; + date: string; + formattedDate: string; + excerpt: string; + html: string; + coverImage: string | null; + readingTime: number; +}; diff --git a/src/lib/index.ts b/src/lib/index.ts new file mode 100644 index 0000000..856f2b6 --- /dev/null +++ b/src/lib/index.ts @@ -0,0 +1 @@ +// place files you want to import through the `$lib` alias in this folder. diff --git a/src/lib/server/posts.ts b/src/lib/server/posts.ts new file mode 100644 index 0000000..6d8f3f3 --- /dev/null +++ b/src/lib/server/posts.ts @@ -0,0 +1,136 @@ +import matter from "gray-matter"; +import { marked } from "marked"; +import type { JournalPost } from "$lib/content/types"; + +const rawPosts = import.meta.glob("../../../_posts/*.{md,markdown}", { + query: "?raw", + import: "default", + eager: true, +}) as Record; + +marked.setOptions({ + gfm: true, + breaks: false, +}); + +const dateFormatter = new Intl.DateTimeFormat("en-GB", { + day: "numeric", + month: "long", + year: "numeric", +}); + +function getSlug(filePath: string) { + const fileName = filePath.split("/").pop() ?? filePath; + return fileName + .replace(/^\d{4}-\d{2}-\d{2}-/, "") + .replace(/\.(md|markdown)$/, ""); +} + +function getDate(filePath: string) { + const match = filePath.match(/(\d{4}-\d{2}-\d{2})-/); + return match?.[1] ?? "1970-01-01"; +} + +function humanizeSlug(slug: string) { + return slug + .split("-") + .map((part) => part.charAt(0).toUpperCase() + part.slice(1)) + .join(" "); +} + +function normalizeMarkdown(content: string) { + return content + .replace( + /\{%\s*post_url\s+([0-9]{4}-[0-9]{2}-[0-9]{2}-[a-z0-9-]+)\s*%\}/g, + (_, postName: string) => + `/journal/${postName.replace(/^\d{4}-\d{2}-\d{2}-/, "")}/`, + ) + .trim(); +} + +function extractExcerpt(content: string) { + const plainText = normalizeMarkdown(content) + .replace(//g, " ") + .replace(//g, " ") + .replace(/]*>/g, " ") + .replace(/!\[[^\]]*]\([^)]*\)/g, " ") + .replace(/^---+$/gm, " ") + .replace(/^#+\s.*$/gm, " ") + .replace(/^[-*]\s.*$/gm, " ") + .replace(/\[([^\]]+)\]\(([^)]+)\)/g, "$1") + .replace(/]*>(.*?)<\/a>/gi, "$1") + .replace(/<[^>]+>/g, " ") + .replace(/\s+/g, " ") + .trim(); + + const sentences = plainText + .split(/(?<=[.!?])\s+/) + .filter((sentence) => sentence.length > 35); + + return sentences.slice(0, 2).join(" ").trim(); +} + +function extractCoverImage(content: string) { + const markdownImage = content.match(/!\[[^\]]*]\((\/assets\/[^)\s]+)[^)]*\)/); + if (markdownImage?.[1]) { + return markdownImage[1]; + } + + const htmlImage = content.match(/]*src="([^"]+)"/); + if (htmlImage?.[1]) { + return htmlImage[1]; + } + + return null; +} + +function estimateReadingTime(content: string) { + const text = content + .replace(/<[^>]+>/g, " ") + .replace(/\[[^\]]+]\(([^)]+)\)/g, " ") + .replace(/\s+/g, " ") + .trim(); + + const words = text ? text.split(/\s+/).length : 0; + return Math.max(1, Math.round(words / 220)); +} + +function decorateLinks(html: string) { + return html.replace( + /]*target=)([^>]*)>/gi, + (_match, href: string, rest: string) => { + return ``; + }, + ); +} + +function parsePost(filePath: string, raw: string): JournalPost { + const slug = getSlug(filePath); + const date = getDate(filePath); + const { data, content } = matter(raw); + const markdown = normalizeMarkdown(content); + + return { + slug, + title: typeof data.title === "string" ? data.title : humanizeSlug(slug), + author: typeof data.author === "string" ? data.author : "5of12", + date, + formattedDate: dateFormatter.format(new Date(`${date}T00:00:00Z`)), + excerpt: extractExcerpt(content), + html: decorateLinks(marked.parse(markdown) as string), + coverImage: extractCoverImage(content), + readingTime: estimateReadingTime(content), + }; +} + +export const posts = Object.entries(rawPosts) + .map(([filePath, raw]) => parsePost(filePath, raw)) + .sort((a, b) => b.date.localeCompare(a.date)); + +export function getLatestPosts(count: number) { + return posts.slice(0, count); +} + +export function getPostBySlug(slug: string) { + return posts.find((post) => post.slug === slug) ?? null; +} diff --git a/src/routes/+layout.svelte b/src/routes/+layout.svelte new file mode 100644 index 0000000..70dc055 --- /dev/null +++ b/src/routes/+layout.svelte @@ -0,0 +1,450 @@ + + + + + + {siteMeta.title} · Creative Technology Studio + + + + + + + +
+ + +
+ {@render children()} +
+ +
+ +
+
+ + diff --git a/src/routes/+layout.ts b/src/routes/+layout.ts new file mode 100644 index 0000000..e325c17 --- /dev/null +++ b/src/routes/+layout.ts @@ -0,0 +1,2 @@ +export const prerender = true; +export const trailingSlash = "always"; diff --git a/src/routes/+page.server.ts b/src/routes/+page.server.ts new file mode 100644 index 0000000..fe80e20 --- /dev/null +++ b/src/routes/+page.server.ts @@ -0,0 +1,7 @@ +import { getLatestPosts } from "$lib/server/posts"; + +export function load() { + return { + latestPosts: getLatestPosts(3), + }; +} diff --git a/src/routes/+page.svelte b/src/routes/+page.svelte new file mode 100644 index 0000000..e013060 --- /dev/null +++ b/src/routes/+page.svelte @@ -0,0 +1,1038 @@ + + + + {siteMeta.title} + + + +
+
+
+ +

Interactions with Music.

+

We design playful, spatial experiences.

+

+ From rapid prototypes to show-ready demos and production apps, we turn + complex technology into things people can feel. +

+ + +
+ +
+ + +
+
+

We believe in

+
    + {#each studioBeliefs as belief} +
  • + + + + {belief.title} +
  • + {/each} +
+
+ +
+
+
+
+ +
+
+ The 5of12 team at a creative technology event. +
+ +
+

Who we are

+

Creative technologists working across sound, space and play.

+

+ We are a UK studio experienced in spatial computing, audio technology and + software delivery. We design and build immersive experiences for human + interaction. +

+ + +
+
+ +
+
+

Play

+

We like to design, build and play.

+

+ 5of12 builds games, instruments and spatial prototypes that invite people + to poke, listen, move and discover. Our work spans musical toys to XR + worlds, browser experiments and Unity hackathon builds. +

+ +
+ +
+ Abstract musical pieces floating around a waveform. + A waveform leading into a playful swinging shape. + +
+ +
+ {#each playExperiences as experience} + + {/each} +
+
+ + + +
+
+
+

Work

+

Products, prototypes and tools.

+
+

A few examples from the studio.

+
+ +
+ {#each featuredWork as item} + + {/each} +
+ +
+
+

Toolkit

+

Tech we design with / for

+
+ + +
+
+ +
+
+
+

Services

+

What we help build.

+
+

+ Focused creative technology work for teams exploring interaction, audio + and spatial interfaces. +

+
+ +
+ {#each services as service} +
+
+ +
+
+

{service.title}

+

{service.description}

+
+
+ {/each} +
+ +
+
+
+

Partners

+

Who we work with.

+
+

+ Teams and organisations we have collaborated with across creative + technology, mobility, energy, music and spatial computing. +

+
+ + +
+
+ +
+
+
+

Experiments

+

Web instruments and utilities.

+
+

+ WebAudio and WebMIDI tools that keep the web playful and practical. +

+
+ +
+ {#each experiments as experiment} + + {/each} +
+
+ +
+
+

Contact

+

Let's build together.

+
+ +
+ {#each contactRoutes as route} + + {/each} +
+ + +
+ +
+
+
+

Blog

+

Notes from the build process.

+
+

Thoughts from the making.

+
+ +
+ {#each data.latestPosts as post} + + {/each} +
+ + +
+ + diff --git a/src/routes/about/+page.svelte b/src/routes/about/+page.svelte new file mode 100644 index 0000000..1593a31 --- /dev/null +++ b/src/routes/about/+page.svelte @@ -0,0 +1,273 @@ + + + + About · {siteMeta.title} + + + +
+

About 5of12

+

Playful, thoughtful things for music, design and invention.

+

+ 5of12 is a creative technology studio based in the UK, formed by + ex-Ultraleap collaborators with more than fifteen years of combined product + and interaction experience. +

+
+ +
+
+

What we do

+

+ We design and prototype spatial interaction systems, XR experiences, + playful musical tools and screen-based experiments that make emerging + technology feel approachable. +

+

+ We believe in play as a serious tool, discovery as a way of working and + adding MIDI where it is deemed appropriate. +

+ +
+ +
+ {#each studioStats as stat} +
+
+ +
+

{stat.label}

+

{stat.value}

+
+ {/each} +
+
+ +
+
+ A hand testing an interactive prototype on a laptop. +
+ +
+

Services Studio practice

+

We make early ideas tangible enough to test.

+

+ Our work spans rapid prototypes, spatial computing, gesture systems, + immersive demos, XR apps and custom tools. +

+
    + {#each services as service} +
  • {service.title}
  • + {/each} +
+
+
+ +
+ + +
+ {#each studioPrinciples as principle} +
+
+ +
+

{principle.title}

+

{principle.description}

+
+ {/each} +
+
+ + diff --git a/src/routes/journal/+page.server.ts b/src/routes/journal/+page.server.ts new file mode 100644 index 0000000..bf7a504 --- /dev/null +++ b/src/routes/journal/+page.server.ts @@ -0,0 +1,7 @@ +import { posts } from "$lib/server/posts"; + +export function load() { + return { + posts, + }; +} diff --git a/src/routes/journal/+page.svelte b/src/routes/journal/+page.svelte new file mode 100644 index 0000000..08adc99 --- /dev/null +++ b/src/routes/journal/+page.svelte @@ -0,0 +1,52 @@ + + + + Blog · {siteMeta.title} + + + +
+

Blog

+

Writing from inside the work.

+

+ Thoughts and practical notes on building musical tools, spatial interfaces + and experimental interaction systems. +

+
+ +
+
+ {#each data.posts as post} + + {/each} +
+
+ + diff --git a/src/routes/journal/[slug]/+page.server.ts b/src/routes/journal/[slug]/+page.server.ts new file mode 100644 index 0000000..a3282b7 --- /dev/null +++ b/src/routes/journal/[slug]/+page.server.ts @@ -0,0 +1,14 @@ +import { error } from "@sveltejs/kit"; +import { getPostBySlug } from "$lib/server/posts"; + +export function load({ params }) { + const post = getPostBySlug(params.slug); + + if (!post) { + throw error(404, "Post not found"); + } + + return { + post, + }; +} diff --git a/src/routes/journal/[slug]/+page.svelte b/src/routes/journal/[slug]/+page.svelte new file mode 100644 index 0000000..140ced3 --- /dev/null +++ b/src/routes/journal/[slug]/+page.svelte @@ -0,0 +1,116 @@ + + + + {data.post.title} · {siteMeta.title} + + + +
+
+

Blog {data.post.formattedDate}

+

{data.post.title}

+
+ {data.post.author} + {data.post.readingTime} min read +
+
+ +
+ {@html data.post.html} +
+
+ + diff --git a/src/routes/playtonik/+page.svelte b/src/routes/playtonik/+page.svelte new file mode 100644 index 0000000..05e2abc --- /dev/null +++ b/src/routes/playtonik/+page.svelte @@ -0,0 +1,626 @@ + + + + Playtonik · {siteMeta.title} + + + +
+
+

Playtonik iOS musical instrument

+

Physics you can play.

+

+ A musical fidget app where bouncing shapes become sound, space and touch. +

+

+ Playtonik is a 2025 MIDI Innovation Award-winning instrument for iPhone + and iPad. Play immediately, then connect MIDI and Playtonik Pro when you + want deeper control. +

+ +
+ +
+ Playtonik app icon and 2025 MIDI Innovation Awards winner mark. +
+
+ +
+ Playtonik shapes containing bright musical objects. +
+ +
+
+

How it feels

+

Every note has weight, movement and a place in space.

+
+

+ Playtonik turns a familiar keyboard into a small physics playground. Notes + ricochet inside responsive shapes, making sound where they collide and + feeding that movement back through the device. +

+
+ +
+ {#each coreFeatures as feature, index} +
+
0{index + 1}
+
+ +
+
+

{feature.title}

+

{feature.description}

+
+
+ {/each} +
+ +
+
+

Interaction

+

Tap, strum, spin and move.

+

+ Playtonik is designed for direct, expressive play. Use touch, device + motion or an external keyboard, then shape the result with velocity, + latching and looping tools. +

+
+ Playtonik interaction modes including touch, motion, phone and MIDI keyboard input. +
+ +
+
+ +
+ +
+

Performance

+

Tools for finding a phrase and keeping it moving.

+
    + {#each performanceTools as tool} +
  • {tool}
  • + {/each} +
+
+
+ +
+
+
+

MIDI Input and output

+

Connect a keyboard, another instrument, or both.

+
+

+ Trigger Playtonik from external hardware, send its notes elsewhere, and + filter incoming MIDI to the selected scale. Note and CC input are included + in every version, with additional control available in Playtonik Pro. +

+
+ + Playtonik connected by MIDI to a keyboard and control surface. + +
+
+

CC input mapping

+

Map a controller to Playtonik's most useful performance parameters.

+
+ +
+ + + + + + + + + + {#each ccMappings as mapping} + + + + + + {/each} + +
DescriptionCCRange
{mapping.description}{mapping.cc}{mapping.range}
+
+
+
+ + + +
+
+

Available now

+

Start with the free app. Unlock Pro when you want more control.

+
+ Get Playtonik +
+ + diff --git a/src/routes/privacy/+page.svelte b/src/routes/privacy/+page.svelte new file mode 100644 index 0000000..f9c5d01 --- /dev/null +++ b/src/routes/privacy/+page.svelte @@ -0,0 +1,191 @@ + + + + Privacy Policy · {siteMeta.title} + + + +
+
+

Playtonik Privacy

+

Privacy Policy

+

+ This policy applies to the Playtonik app for mobile devices, provided by + {companyInfo.name} as a freemium service. +

+

Effective June 5, 2025

+
+ +
+

+ This privacy policy applies to the Playtonik app (referred to as the + “Application”) for mobile devices, created by {companyInfo.name} + (referred to as the “Service Provider”) as a freemium service. This service + is intended for use “AS IS”. +

+ +
+

Information collection and use

+

+ The Application does not obtain any information when you download and + use it. Registration is not required to use the Application. +

+
+ +
+

Location information

+

+ The Application does not collect precise information about the location + of your mobile device. +

+
+ +
+

Third-party access

+

+ Since the Application does not collect any information, no data is + shared with third parties. +

+
+ +
+

Opt-out rights

+

+ You can stop all collection of information by the Application by + uninstalling it. You may use the standard uninstall processes available + as part of your mobile device or through the mobile application + marketplace or network. +

+
+ +
+

Children

+

+ The Application is not used to knowingly solicit data from or market to + children under the age of 13. +

+

+ The Service Provider does not knowingly collect personally identifiable + information from children. The Service Provider encourages children + never to submit personally identifiable information through the + Application or Services. +

+

+ Parents and legal guardians are encouraged to monitor their children’s + internet usage and instruct them never to provide personally + identifiable information through the Application or Services without + permission. If you believe a child has provided personally identifiable + information, contact the Service Provider at + {companyInfo.email} so that the + necessary action can be taken. You must also be at least 16 years old to consent + to the processing of personally identifiable information in your country, + unless a parent or guardian may do so on your behalf. +

+
+ +
+

Security

+

+ The Service Provider is concerned about safeguarding the confidentiality + of your information. However, since the Application does not collect any + information, there is no risk of your data being accessed by + unauthorized individuals through the Application. +

+
+ +
+

Changes

+

+ This Privacy Policy may be updated from time to time. The Service + Provider will notify you of changes by updating this page. You are + advised to consult this Privacy Policy regularly, as continued use is + deemed approval of any changes. +

+
+ +
+

Your consent

+

+ By using the Application, you consent to the processing of information + as set forth in this Privacy Policy now and as amended by the Service + Provider. +

+
+ +
+

Contact us

+

+ If you have questions about privacy while using the Application or about + the Service Provider’s practices, email + {companyInfo.email}. +

+
+
+
+ + diff --git a/static/.nojekyll b/static/.nojekyll new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/static/.nojekyll @@ -0,0 +1 @@ + diff --git a/static/assets/5of12_Glow.png b/static/assets/5of12_Glow.png new file mode 100644 index 0000000..6db41b0 Binary files /dev/null and b/static/assets/5of12_Glow.png differ diff --git a/assets/5of12_Logo.png b/static/assets/5of12_Logo.png similarity index 100% rename from assets/5of12_Logo.png rename to static/assets/5of12_Logo.png diff --git a/assets/ADC_AlwaysMidi.png b/static/assets/ADC_AlwaysMidi.png similarity index 100% rename from assets/ADC_AlwaysMidi.png rename to static/assets/ADC_AlwaysMidi.png diff --git a/assets/ADC_Audio_Clip.mp4 b/static/assets/ADC_Audio_Clip.mp4 similarity index 100% rename from assets/ADC_Audio_Clip.mp4 rename to static/assets/ADC_Audio_Clip.mp4 diff --git a/assets/ADC_Bounce_Wide.mp4 b/static/assets/ADC_Bounce_Wide.mp4 similarity index 100% rename from assets/ADC_Bounce_Wide.mp4 rename to static/assets/ADC_Bounce_Wide.mp4 diff --git a/assets/ADC_BuildEverywhere.png b/static/assets/ADC_BuildEverywhere.png similarity index 100% rename from assets/ADC_BuildEverywhere.png rename to static/assets/ADC_BuildEverywhere.png diff --git a/assets/ADC_Interactions.png b/static/assets/ADC_Interactions.png similarity index 100% rename from assets/ADC_Interactions.png rename to static/assets/ADC_Interactions.png diff --git a/assets/ADC_Noisy_Bounces_Clip.mp4 b/static/assets/ADC_Noisy_Bounces_Clip.mp4 similarity index 100% rename from assets/ADC_Noisy_Bounces_Clip.mp4 rename to static/assets/ADC_Noisy_Bounces_Clip.mp4 diff --git a/assets/ADC_NonMusicalTiming.png b/static/assets/ADC_NonMusicalTiming.png similarity index 100% rename from assets/ADC_NonMusicalTiming.png rename to static/assets/ADC_NonMusicalTiming.png diff --git a/assets/ADC_PlaygroundOfSound.png b/static/assets/ADC_PlaygroundOfSound.png similarity index 100% rename from assets/ADC_PlaygroundOfSound.png rename to static/assets/ADC_PlaygroundOfSound.png diff --git a/assets/ADC_Playground_Clip.mp4 b/static/assets/ADC_Playground_Clip.mp4 similarity index 100% rename from assets/ADC_Playground_Clip.mp4 rename to static/assets/ADC_Playground_Clip.mp4 diff --git a/assets/ADC_PluginsQuestion.png b/static/assets/ADC_PluginsQuestion.png similarity index 100% rename from assets/ADC_PluginsQuestion.png rename to static/assets/ADC_PluginsQuestion.png diff --git a/assets/ADC_Profiler_View.png b/static/assets/ADC_Profiler_View.png similarity index 100% rename from assets/ADC_Profiler_View.png rename to static/assets/ADC_Profiler_View.png diff --git a/assets/ADC_SoundAllAround.png b/static/assets/ADC_SoundAllAround.png similarity index 100% rename from assets/ADC_SoundAllAround.png rename to static/assets/ADC_SoundAllAround.png diff --git a/assets/ADC_VisualPossibilities.png b/static/assets/ADC_VisualPossibilities.png similarity index 100% rename from assets/ADC_VisualPossibilities.png rename to static/assets/ADC_VisualPossibilities.png diff --git a/assets/ADC_Visuals_Clip.mp4 b/static/assets/ADC_Visuals_Clip.mp4 similarity index 100% rename from assets/ADC_Visuals_Clip.mp4 rename to static/assets/ADC_Visuals_Clip.mp4 diff --git a/assets/ADC_banner.png b/static/assets/ADC_banner.png similarity index 100% rename from assets/ADC_banner.png rename to static/assets/ADC_banner.png diff --git a/assets/Cacophonous.gif b/static/assets/Cacophonous.gif similarity index 100% rename from assets/Cacophonous.gif rename to static/assets/Cacophonous.gif diff --git a/assets/CacophonyOfGestures.png b/static/assets/CacophonyOfGestures.png similarity index 100% rename from assets/CacophonyOfGestures.png rename to static/assets/CacophonyOfGestures.png diff --git a/assets/Cacophony_banner.png b/static/assets/Cacophony_banner.png similarity index 100% rename from assets/Cacophony_banner.png rename to static/assets/Cacophony_banner.png diff --git a/assets/Grab-Release.gif b/static/assets/Grab-Release.gif similarity index 100% rename from assets/Grab-Release.gif rename to static/assets/Grab-Release.gif diff --git a/assets/Lightbulb.gif b/static/assets/Lightbulb.gif similarity index 100% rename from assets/Lightbulb.gif rename to static/assets/Lightbulb.gif diff --git a/static/assets/experiments/augment-preview.png b/static/assets/experiments/augment-preview.png new file mode 100644 index 0000000..d5bea65 Binary files /dev/null and b/static/assets/experiments/augment-preview.png differ diff --git a/static/assets/experiments/midiweb-hub-preview.png b/static/assets/experiments/midiweb-hub-preview.png new file mode 100644 index 0000000..f5bba12 Binary files /dev/null and b/static/assets/experiments/midiweb-hub-preview.png differ diff --git a/static/assets/experiments/pocket-operations-preview.png b/static/assets/experiments/pocket-operations-preview.png new file mode 100644 index 0000000..8ad2fa3 Binary files /dev/null and b/static/assets/experiments/pocket-operations-preview.png differ diff --git a/assets/iOSmidi/BluetoothMidiSetup.png b/static/assets/iOSmidi/BluetoothMidiSetup.png similarity index 100% rename from assets/iOSmidi/BluetoothMidiSetup.png rename to static/assets/iOSmidi/BluetoothMidiSetup.png diff --git a/assets/iOSmidi/NetworkMIDISetup.png b/static/assets/iOSmidi/NetworkMIDISetup.png similarity index 100% rename from assets/iOSmidi/NetworkMIDISetup.png rename to static/assets/iOSmidi/NetworkMIDISetup.png diff --git a/assets/iOSmidi/USBSetup.png b/static/assets/iOSmidi/USBSetup.png similarity index 100% rename from assets/iOSmidi/USBSetup.png rename to static/assets/iOSmidi/USBSetup.png diff --git a/assets/iOSmidi/VirtualDeviceSetup.png b/static/assets/iOSmidi/VirtualDeviceSetup.png similarity index 100% rename from assets/iOSmidi/VirtualDeviceSetup.png rename to static/assets/iOSmidi/VirtualDeviceSetup.png diff --git a/assets/looper/buffer_diagram.jpg b/static/assets/looper/buffer_diagram.jpg similarity index 100% rename from assets/looper/buffer_diagram.jpg rename to static/assets/looper/buffer_diagram.jpg diff --git a/assets/looper/lookahead_diagram.jpg b/static/assets/looper/lookahead_diagram.jpg similarity index 100% rename from assets/looper/lookahead_diagram.jpg rename to static/assets/looper/lookahead_diagram.jpg diff --git a/static/assets/partners/50hertz.png b/static/assets/partners/50hertz.png new file mode 100644 index 0000000..9452022 Binary files /dev/null and b/static/assets/partners/50hertz.png differ diff --git a/static/assets/partners/distance.svg b/static/assets/partners/distance.svg new file mode 100644 index 0000000..f3ae798 --- /dev/null +++ b/static/assets/partners/distance.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/static/assets/partners/pervasive-media-studio.svg b/static/assets/partners/pervasive-media-studio.svg new file mode 100644 index 0000000..bbd9bc9 --- /dev/null +++ b/static/assets/partners/pervasive-media-studio.svg @@ -0,0 +1,287 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/static/assets/partners/roli.svg b/static/assets/partners/roli.svg new file mode 100644 index 0000000..9364bf1 --- /dev/null +++ b/static/assets/partners/roli.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/static/assets/partners/srt.svg b/static/assets/partners/srt.svg new file mode 100644 index 0000000..e2bd2d5 --- /dev/null +++ b/static/assets/partners/srt.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/static/assets/partners/ultraleap.svg b/static/assets/partners/ultraleap.svg new file mode 100644 index 0000000..604359c --- /dev/null +++ b/static/assets/partners/ultraleap.svg @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + + + + + diff --git a/static/assets/partners/uno-minda.png b/static/assets/partners/uno-minda.png new file mode 100644 index 0000000..50a7d26 Binary files /dev/null and b/static/assets/partners/uno-minda.png differ diff --git a/static/assets/partners/viverse.png b/static/assets/partners/viverse.png new file mode 100644 index 0000000..0f7eae4 Binary files /dev/null and b/static/assets/partners/viverse.png differ diff --git a/static/assets/partners/watershed.webp b/static/assets/partners/watershed.webp new file mode 100644 index 0000000..38c8ed2 Binary files /dev/null and b/static/assets/partners/watershed.webp differ diff --git a/static/assets/technologies/apple.svg b/static/assets/technologies/apple.svg new file mode 100644 index 0000000..915e890 --- /dev/null +++ b/static/assets/technologies/apple.svg @@ -0,0 +1 @@ +Apple \ No newline at end of file diff --git a/static/assets/technologies/meta.svg b/static/assets/technologies/meta.svg new file mode 100644 index 0000000..385fb0a --- /dev/null +++ b/static/assets/technologies/meta.svg @@ -0,0 +1 @@ +Meta \ No newline at end of file diff --git a/static/assets/technologies/svelte.svg b/static/assets/technologies/svelte.svg new file mode 100644 index 0000000..a3f86d5 --- /dev/null +++ b/static/assets/technologies/svelte.svg @@ -0,0 +1 @@ +Svelte \ No newline at end of file diff --git a/static/assets/technologies/unity.svg b/static/assets/technologies/unity.svg new file mode 100644 index 0000000..340e548 --- /dev/null +++ b/static/assets/technologies/unity.svg @@ -0,0 +1 @@ +Unity \ No newline at end of file diff --git a/static/assets/work/mediapipe-map.gif b/static/assets/work/mediapipe-map.gif new file mode 100644 index 0000000..76c45c5 Binary files /dev/null and b/static/assets/work/mediapipe-map.gif differ diff --git a/static/assets/work/mediapipe-shark.gif b/static/assets/work/mediapipe-shark.gif new file mode 100644 index 0000000..5e973cb Binary files /dev/null and b/static/assets/work/mediapipe-shark.gif differ diff --git a/static/assets/work/mediapipe-starfield.gif b/static/assets/work/mediapipe-starfield.gif new file mode 100644 index 0000000..d87f468 Binary files /dev/null and b/static/assets/work/mediapipe-starfield.gif differ diff --git a/static/assets/work/playtonik-award.png b/static/assets/work/playtonik-award.png new file mode 100644 index 0000000..5b34a4d Binary files /dev/null and b/static/assets/work/playtonik-award.png differ diff --git a/static/assets/work/prototyping-desk.jpg b/static/assets/work/prototyping-desk.jpg new file mode 100644 index 0000000..0f976e8 Binary files /dev/null and b/static/assets/work/prototyping-desk.jpg differ diff --git a/static/assets/work/studio-team.jpg b/static/assets/work/studio-team.jpg new file mode 100644 index 0000000..d8a9866 Binary files /dev/null and b/static/assets/work/studio-team.jpg differ diff --git a/static/robots.txt b/static/robots.txt new file mode 100644 index 0000000..b6dd667 --- /dev/null +++ b/static/robots.txt @@ -0,0 +1,3 @@ +# allow crawling everything by default +User-agent: * +Disallow: diff --git a/svelte.config.js b/svelte.config.js new file mode 100644 index 0000000..3d3f45d --- /dev/null +++ b/svelte.config.js @@ -0,0 +1,14 @@ +import adapter from "@sveltejs/adapter-static"; + +/** @type {import('@sveltejs/kit').Config} */ +const config = { + kit: { + adapter: adapter(), + }, + vitePlugin: { + dynamicCompileOptions: ({ filename }) => + filename.includes("node_modules") ? undefined : { runes: true }, + }, +}; + +export default config; diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..c7b9df5 --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,20 @@ +{ + "extends": "./.svelte-kit/tsconfig.json", + "compilerOptions": { + "rewriteRelativeImportExtensions": true, + "allowJs": true, + "checkJs": true, + "esModuleInterop": true, + "forceConsistentCasingInFileNames": true, + "resolveJsonModule": true, + "skipLibCheck": true, + "sourceMap": true, + "strict": true, + "moduleResolution": "bundler" + } + // Path aliases are handled by https://svelte.dev/docs/kit/configuration#alias + // except $lib which is handled by https://svelte.dev/docs/kit/configuration#files + // + // To make changes to top-level options such as include and exclude, we recommend extending + // the generated config; see https://svelte.dev/docs/kit/configuration#typescript +} diff --git a/vite.config.ts b/vite.config.ts new file mode 100644 index 0000000..80864b9 --- /dev/null +++ b/vite.config.ts @@ -0,0 +1,6 @@ +import { sveltekit } from "@sveltejs/kit/vite"; +import { defineConfig } from "vite"; + +export default defineConfig({ + plugins: [sveltekit()], +});