diff --git a/.claude/launch.json b/.claude/launch.json new file mode 100644 index 0000000..8994e1e --- /dev/null +++ b/.claude/launch.json @@ -0,0 +1,17 @@ +{ + "version": "0.0.1", + "configurations": [ + { + "name": "VitePress Dev", + "runtimeExecutable": "/bin/bash", + "runtimeArgs": ["-c", "export PATH=/opt/homebrew/bin:/usr/local/bin:$PATH && cd '/Users/zhongkeyi/Library/Mobile Documents/com~apple~CloudDocs/Work/i2rt/doc/web' && npm run docs:dev"], + "port": 5173 + }, + { + "name": "VitePress Preview", + "runtimeExecutable": "/bin/bash", + "runtimeArgs": ["-c", "export PATH=/opt/homebrew/bin:/usr/local/bin:$PATH && cd '/Users/zhongkeyi/Library/Mobile Documents/com~apple~CloudDocs/Work/i2rt/doc/web' && npm run docs:preview"], + "port": 4173 + } + ] +} diff --git a/docs/.vitepress/config.mjs b/docs/.vitepress/config.mjs new file mode 100644 index 0000000..3ba5995 --- /dev/null +++ b/docs/.vitepress/config.mjs @@ -0,0 +1,139 @@ +import { defineConfig } from 'vitepress' + +const base = process.env.DEPLOY_TARGET === 'cloudflare' ? '/' : '/JH_i2rt/' + +export default defineConfig({ + title: 'I2RT Robotics', + description: 'Open robotics platform for research and embodied AI β€” YAM arms, Flow Base, and more.', + base, + appearance: true, + + head: [ + ['link', { rel: 'preconnect', href: 'https://fonts.googleapis.com' }], + ['link', { rel: 'preconnect', href: 'https://fonts.gstatic.com', crossorigin: '' }], + ['link', { href: 'https://fonts.googleapis.com/css2?family=IBM+Plex+Mono:wght@400;600&family=Inter:wght@300;400;500;600;700&display=swap', rel: 'stylesheet' }], + ['meta', { name: 'theme-color', content: '#855832' }], + ['meta', { property: 'og:type', content: 'website' }], + ['meta', { property: 'og:title', content: 'I2RT Robotics Docs' }], + ['meta', { property: 'og:description', content: 'Documentation for the YAM arm family, Flow Base, and Linear Bot.' }], + ], + + themeConfig: { + siteTitle: 'I2RT Docs', + + nav: [ + { text: 'Products', link: '/products/' }, + { text: 'Get Started', link: '/getting-started/installation' }, + { text: 'SDK', link: '/sdk/' }, + { text: 'Examples', link: '/examples/' }, + { text: 'Releases', link: '/releases/v1.0' }, + { text: 'i2rt.com', link: 'https://i2rt.com', target: '_blank' }, + ], + + sidebar: { + '/products/': [ + { + text: 'Product Family', + items: [ + { text: 'Overview', link: '/products/' }, + ], + }, + { + text: 'YAM Series', + collapsed: false, + items: [ + { text: 'YAM Series Overview', link: '/products/yam' }, + { text: 'YAM Arm', link: '/products/yam-arm' }, + { text: 'YAM Leader Arm', link: '/products/yam-leader' }, + { text: 'YAM Cell', link: '/products/yam-cell' }, + { text: 'YAM Box', link: '/products/yam-box' }, + ], + }, + { + text: 'Mobile', + items: [ + { text: 'Flow Base', link: '/products/flow-base' }, + { text: 'Linear Bot', link: '/products/linear-bot' }, + ], + }, + { + text: 'Motors', + items: [ + { text: 'Rovomotor β†—', link: 'https://rovomotor.com', target: '_blank' }, + ], + }, + ], + '/getting-started/': [ + { + text: 'Getting Started', + items: [ + { text: 'Installation', link: '/getting-started/installation' }, + { text: 'Hardware Setup', link: '/getting-started/hardware-setup' }, + { text: 'Quick Start', link: '/getting-started/quick-start' }, + ], + }, + ], + '/sdk/': [ + { + text: 'SDK Reference', + items: [ + { text: 'Overview', link: '/sdk/' }, + { text: 'YAM Arm API', link: '/sdk/yam-arm' }, + { text: 'Flow Base API', link: '/sdk/flow-base' }, + { text: 'Grippers', link: '/sdk/grippers' }, + ], + }, + ], + '/examples/': [ + { + text: 'Examples', + items: [ + { text: 'Overview', link: '/examples/' }, + { text: 'Bimanual Teleoperation', link: '/examples/bimanual-teleoperation' }, + { text: 'Record & Replay', link: '/examples/record-replay' }, + { text: 'Motor Control', link: '/examples/motor-control' }, + { text: 'MuJoCo Control', link: '/examples/control-with-mujoco' }, + ], + }, + ], + '/releases/': [ + { + text: 'Release Notes', + items: [ + { text: 'v1.0', link: '/releases/v1.0' }, + ], + }, + ], + '/support/': [ + { + text: 'Support', + items: [ + { text: 'Troubleshooting', link: '/support/troubleshooting' }, + ], + }, + ], + }, + + socialLinks: [ + { icon: 'github', link: 'https://github.com/i2rt-robotics/i2rt' }, + { + icon: { + svg: '', + }, + link: 'https://discord.gg/i2rt', + }, + ], + + footer: { + message: 'Released under the MIT License.', + copyright: 'Copyright Β© 2024 I2RT Robotics, LLC β€” Fremont, CA', + }, + + search: { provider: 'local' }, + + editLink: { + pattern: 'https://github.com/i2rt-robotics/i2rt/edit/main/docs/:path', + text: 'Edit this page on GitHub', + }, + }, +}) diff --git a/docs/.vitepress/theme/components/MediaPlaceholder.vue b/docs/.vitepress/theme/components/MediaPlaceholder.vue new file mode 100644 index 0000000..e209911 --- /dev/null +++ b/docs/.vitepress/theme/components/MediaPlaceholder.vue @@ -0,0 +1,14 @@ + + + diff --git a/docs/.vitepress/theme/components/RobotCompare.vue b/docs/.vitepress/theme/components/RobotCompare.vue new file mode 100644 index 0000000..825a2b3 --- /dev/null +++ b/docs/.vitepress/theme/components/RobotCompare.vue @@ -0,0 +1,910 @@ + + + + + diff --git a/docs/.vitepress/theme/components/RobotViewer.vue b/docs/.vitepress/theme/components/RobotViewer.vue new file mode 100644 index 0000000..979bd9c --- /dev/null +++ b/docs/.vitepress/theme/components/RobotViewer.vue @@ -0,0 +1,438 @@ + + + + + diff --git a/docs/.vitepress/theme/index.js b/docs/.vitepress/theme/index.js new file mode 100644 index 0000000..b7a81aa --- /dev/null +++ b/docs/.vitepress/theme/index.js @@ -0,0 +1,14 @@ +import DefaultTheme from 'vitepress/theme' +import './style.css' +import RobotViewer from './components/RobotViewer.vue' +import RobotCompare from './components/RobotCompare.vue' +import MediaPlaceholder from './components/MediaPlaceholder.vue' + +export default { + extends: DefaultTheme, + enhanceApp({ app }) { + app.component('RobotViewer', RobotViewer) + app.component('RobotCompare', RobotCompare) + app.component('MediaPlaceholder', MediaPlaceholder) + }, +} diff --git a/docs/.vitepress/theme/style.css b/docs/.vitepress/theme/style.css new file mode 100644 index 0000000..50a6f1f --- /dev/null +++ b/docs/.vitepress/theme/style.css @@ -0,0 +1,335 @@ +/* ============================================================ + I2RT Robotics β€” Custom VitePress Theme + Brand: Brown #855832 | Teal #4C6762 | Charcoal #11151C + Inspired by i2rt.com β€” warm, minimal, professional + ============================================================ */ + +:root { + --vp-c-brand-1: #855832; + --vp-c-brand-2: #6e4828; + --vp-c-brand-3: #5a3b20; + --vp-c-brand-soft: rgba(133, 88, 50, 0.12); + + --vp-c-bg: #ffffff; + --vp-c-bg-soft: #f7f5f2; + --vp-c-bg-mute: #edeae6; + + --vp-c-text-1: #1a1a1a; + --vp-c-text-2: #5c5c5c; + --vp-c-text-3: #8a8a8a; + + --vp-c-divider: rgba(0, 0, 0, 0.08); + + --vp-font-family-base: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif; + --vp-font-family-mono: 'IBM Plex Mono', 'Fira Code', monospace; + + --vp-home-hero-name-color: transparent; + --vp-home-hero-name-background: linear-gradient(135deg, #855832 0%, #4C6762 100%); + --vp-home-hero-image-background-image: radial-gradient(circle, rgba(133,88,50,0.15) 0%, rgba(76,103,98,0.08) 50%, transparent 70%); + --vp-home-hero-image-filter: blur(72px); + + --vp-nav-bg-color: rgba(255, 255, 255, 0.92); + + /* Wider layout so nav bar uses more horizontal space */ + --vp-layout-max-width: 1600px; + + /* Tip / Warning custom block colors */ + --vp-custom-block-tip-bg: rgba(76, 103, 98, 0.06); + --vp-custom-block-tip-border: rgba(76, 103, 98, 0.3); + --vp-custom-block-tip-text: #3a5a52; +} + +.dark { + --vp-c-bg: #1a1612; + --vp-c-bg-soft: #231e18; + --vp-c-bg-mute: #2e2820; + --vp-c-divider: rgba(255, 255, 255, 0.08); + --vp-c-text-1: #e8e4df; + --vp-c-text-2: #a69d93; + --vp-c-text-3: #7a7168; + --vp-nav-bg-color: rgba(26, 22, 18, 0.94); + --vp-sidebar-bg-color: #1e1914; +} + +/* ── Scrollbar ────────────────────────────────────────── */ +::-webkit-scrollbar { width: 6px; height: 6px; } +::-webkit-scrollbar-track { background: transparent; } +::-webkit-scrollbar-thumb { background: rgba(133, 88, 50, 0.25); border-radius: 3px; } +::-webkit-scrollbar-thumb:hover { background: rgba(133, 88, 50, 0.5); } + +/* ── Navbar ───────────────────────────────────────────── */ +.VPNav { + backdrop-filter: blur(16px); + -webkit-backdrop-filter: blur(16px); + border-bottom: 1px solid rgba(0, 0, 0, 0.06) !important; +} + +/* Widen the search button in the navbar */ +.VPNavBarSearch .DocSearch-Button, +.VPNavBarSearch button[aria-label="Search"] { + min-width: 260px !important; +} + +/* Stretch nav container edge-to-edge with comfortable padding */ +.VPNavBar > .wrapper { + max-width: 100% !important; + padding: 0 32px !important; +} +.VPNavBar > .wrapper > .container { + max-width: 100% !important; +} + +.VPNavBarTitle .title { + font-weight: 700; + letter-spacing: -0.02em; + color: #855832; +} + +/* ── Sidebar ──────────────────────────────────────────── */ +.VPSidebarItem.is-active > .item .link .text { + color: var(--vp-c-brand-1); + font-weight: 600; +} + +.VPSidebarItem.is-active > .item { + border-left: 2px solid var(--vp-c-brand-1); + padding-left: 12px; +} + +/* ── Code blocks ──────────────────────────────────────── */ +div[class*="language-"] { + background: #f7f5f2 !important; + border: 1px solid rgba(0, 0, 0, 0.06); + border-radius: 10px; +} + +.vp-code-group .tabs { + background: #edeae6; + border-bottom: 1px solid rgba(0, 0, 0, 0.06); +} + +.dark div[class*="language-"] { + background: #161210 !important; + border: 1px solid rgba(133, 88, 50, 0.1); + border-radius: 10px; +} + +.dark .vp-code-group .tabs { + background: #1e1914; + border-bottom: 1px solid rgba(133, 88, 50, 0.12); +} + +code { + font-family: var(--vp-font-family-mono); +} + +/* ── Badges ───────────────────────────────────────────── */ +.vp-badge.tip { background: rgba(76, 103, 98, 0.1); color: #4C6762; border: 1px solid rgba(76,103,98,0.25); } +.vp-badge.warning { background: rgba(133, 88, 50, 0.1); color: #855832; border: 1px solid rgba(133,88,50,0.25); } +.vp-badge.danger { background: rgba(220, 38, 38, 0.1); color: #dc2626; border: 1px solid rgba(220,38,38,0.2); } + +/* ── Home hero ────────────────────────────────────────── */ +.VPHero .name { + font-size: clamp(2rem, 5vw, 3.5rem); + line-height: 1.1; + letter-spacing: -0.04em; +} + +.VPHero .tagline { + font-size: clamp(1rem, 2.5vw, 1.25rem); + opacity: 0.75; + margin-top: 8px; +} + +/* ── Features ─────────────────────────────────────────── */ +.VPFeature { + background: var(--vp-c-bg-soft) !important; + border: 1px solid rgba(0, 0, 0, 0.06) !important; + border-radius: 12px !important; + transition: border-color 0.2s, transform 0.2s, box-shadow 0.2s; +} + +.VPFeature:hover { + border-color: rgba(133, 88, 50, 0.3) !important; + transform: translateY(-2px); + box-shadow: 0 4px 16px rgba(133, 88, 50, 0.06); +} + +/* ── Tables ───────────────────────────────────────────── */ +table { + border-collapse: collapse; +} + +th { + background: rgba(133, 88, 50, 0.05); + color: var(--vp-c-brand-1); + border: 1px solid rgba(0, 0, 0, 0.08); +} + +td { + border: 1px solid rgba(0, 0, 0, 0.06); +} + +tr:hover td { + background: rgba(133, 88, 50, 0.03); +} + +.dark th { + background: rgba(133, 88, 50, 0.1); + border: 1px solid rgba(133, 88, 50, 0.15); +} + +.dark td { + border: 1px solid rgba(255, 255, 255, 0.06); +} + +.dark tr:hover td { + background: rgba(133, 88, 50, 0.05); +} + +/* ── Tip / warning / danger blocks ───────────────────── */ +.custom-block.tip { + background: rgba(76, 103, 98, 0.05); + border-color: rgba(76, 103, 98, 0.3); +} + +.custom-block.warning { + background: rgba(133, 88, 50, 0.05); + border-color: rgba(133, 88, 50, 0.3); +} + +.custom-block.danger { + background: rgba(220, 38, 38, 0.05); + border-color: rgba(220, 38, 38, 0.25); +} + +.dark .custom-block.tip { + background: rgba(76, 103, 98, 0.08); + border-color: rgba(76, 103, 98, 0.35); +} + +.dark .custom-block.warning { + background: rgba(133, 88, 50, 0.08); + border-color: rgba(133, 88, 50, 0.35); +} + +.dark .custom-block.danger { + background: rgba(220, 38, 38, 0.08); + border-color: rgba(220, 38, 38, 0.3); +} + +/* ── Home page: remove VitePress page-layout padding ─── */ +.Layout .VPContent.is-home, +.Layout[data-layout="page"] .VPContent { + padding-top: 0 !important; +} + +/* ── Media placeholders ──────────────────────────────── */ +.media-placeholder { + position: relative; + background: linear-gradient(135deg, #f7f5f2 0%, #edeae6 100%); + border: 1px dashed rgba(133, 88, 50, 0.3); + border-radius: 12px; + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + gap: 12px; + padding: 40px 24px; + text-align: center; + margin: 24px 0; + overflow: hidden; +} + +.dark .media-placeholder { + background: linear-gradient(135deg, #1e1914 0%, #231e18 100%); + border-color: rgba(133, 88, 50, 0.25); +} + +.media-placeholder::before { + content: ''; + position: absolute; + inset: 0; + background: radial-gradient(ellipse at 50% 50%, rgba(133,88,50,0.04) 0%, transparent 70%); +} + +.media-placeholder .placeholder-icon { + font-size: 2.5rem; + filter: grayscale(0.3); + position: relative; +} + +.media-placeholder .placeholder-label { + font-size: 0.75rem; + font-weight: 600; + letter-spacing: 0.12em; + text-transform: uppercase; + color: var(--vp-c-brand-1); + position: relative; +} + +.media-placeholder .placeholder-desc { + font-size: 0.9rem; + color: var(--vp-c-text-2); + max-width: 400px; + line-height: 1.6; + position: relative; +} + +.media-placeholder.video-placeholder { + min-height: 280px; +} + +.media-placeholder.photo-placeholder { + min-height: 200px; +} + +/* ── Spec table ───────────────────────────────────────── */ +.spec-table th:first-child { width: 40%; } + +/* ── Product badge row ───────────────────────────────── */ +.product-badges { + display: flex; + flex-wrap: wrap; + gap: 8px; + margin: 16px 0; +} + +.product-badge { + display: inline-flex; + align-items: center; + gap: 6px; + padding: 4px 12px; + border-radius: 20px; + font-size: 0.8rem; + font-weight: 600; + border: 1px solid; +} + +.product-badge.available { + color: #4C6762; + border-color: rgba(76, 103, 98, 0.35); + background: rgba(76, 103, 98, 0.06); +} + +.product-badge.coming-soon { + color: #8a8a8a; + border-color: rgba(138, 138, 138, 0.25); + background: rgba(138, 138, 138, 0.04); +} + +/* ── Dark mode nav ───────────────────────────────────── */ +.dark .VPNav { + border-bottom: 1px solid rgba(133, 88, 50, 0.12) !important; +} + +/* ── Light 3D viewer border ──────────────────────────── */ +:root:not(.dark) .hero-viewer > div { + border: 1px solid rgba(0, 0, 0, 0.08) !important; + box-shadow: 0 4px 32px rgba(0, 0, 0, 0.06) !important; +} + +.dark .hero-viewer > div { + border: 1px solid rgba(133, 88, 50, 0.15) !important; + box-shadow: 0 0 60px rgba(133, 88, 50, 0.05), 0 0 120px rgba(76, 103, 98, 0.03) !important; +} diff --git a/docs/examples/bimanual-teleoperation.md b/docs/examples/bimanual-teleoperation.md new file mode 100644 index 0000000..23177d4 --- /dev/null +++ b/docs/examples/bimanual-teleoperation.md @@ -0,0 +1,106 @@ +# Bimanual Teleoperation + +**Location:** `examples/bimanual_lead_follower/` + +Run coordinated dual-arm teleoperation with two leader and two follower YAM arms. This is the primary example for the [YAM Cell](/products/yam-cell). + +## Hardware Required + +- 2Γ— YAM follower arms (any gripper) +- 2Γ— YAM leader arms (with `yam_teaching_handle` gripper) +- 4Γ— CANable USB-CAN adapters +- 1Γ— Workstation PC (Ubuntu 22.04) + +## Setup + + + +### 1. Assign persistent CAN IDs + +Plug **one CANable at a time** and follow the [Persistent CAN IDs](/getting-started/hardware-setup#persistent-can-ids) guide to assign each adapter a fixed name. + +Target layout: + +| Arm | Interface | +|-----|-----------| +| Left follower | `can_follower_l` | +| Right follower | `can_follower_r` | +| Left leader | `can_leader_l` | +| Right leader | `can_leader_r` | + +### 2. Verify all four interfaces + +```bash +ip a | grep can +# Expected: +# can_follower_r UP +# can_follower_l UP +# can_leader_r UP +# can_leader_l UP +``` + +### 3. Activate the virtual environment + +```bash +source .venv/bin/activate +``` + +### 4. Launch + +```bash +python examples/bimanual_lead_follower/bimanual_lead_follower.py +``` + +## Operation + +| Action | Result | +|--------|--------| +| Move either leader arm | Corresponding follower mirrors motion | +| Squeeze trigger on teaching handle | Follower gripper closes | +| **Top button (press once)** | **Enable synchronization** | +| **Top button (press again)** | **Disable synchronization** | + +::: tip Start position +Before enabling sync, move the leader arms to roughly match the follower arm positions. Large position errors on first sync can cause abrupt motion. +::: + +## Video + + + + + +## Architecture + +The example launches two `minimum_gello.py` instances internally β€” one per arm pair β€” sharing the same enable/disable logic through the top button. + +```python +# Conceptually equivalent to: +python examples/minimum_gello/minimum_gello.py --gripper linear_4310 --mode follower --can-channel can_follower_l --bilateral_kp 0.2 +python examples/minimum_gello/minimum_gello.py --gripper yam_teaching_handle --mode leader --can-channel can_leader_l --bilateral_kp 0.2 +# (mirrored for right pair) +``` + +## Troubleshooting + +| Symptom | Fix | +|---------|-----| +| Missing CAN interface | Check `ip a`, replug adapters one at a time | +| Arm not following | Ensure sync is enabled (top button) | +| Jittery motion | Lower `--bilateral_kp` to `0.1` | +| Motor timeout errors | Reduce loop latency; check USB-CAN adapter | + +## See Also + +- [YAM Cell](/products/yam-cell) +- [YAM Arm API](/sdk/yam-arm) +- [Hardware Setup](/getting-started/hardware-setup) diff --git a/docs/examples/control-with-mujoco.md b/docs/examples/control-with-mujoco.md new file mode 100644 index 0000000..a5fa57a --- /dev/null +++ b/docs/examples/control-with-mujoco.md @@ -0,0 +1,74 @@ +# MuJoCo Control Interface + +**Location:** `examples/control_with_mujoco/` + +Interactive MuJoCo viewer for i2rt robots. Visualises the robot in real time and lets you move it by dragging a target marker via inverse kinematics β€” no hardware required in simulation mode. + +## Hardware Required + +- None for simulation (`--sim` flag) +- 1Γ— YAM / YAM Pro / YAM Ultra / big_yam arm + CANable adapter for real hardware + +## Overview + +The interface has two modes toggled with **SPACE**: + +``` +VIS mode (default): + Robot joint states ──► MuJoCo viewer (gravity comp active on real hw) + +CONTROL mode (press SPACE): + Drag target marker ──► IK solver ──► Command arm +``` + +## Running + +### Simulation + +```bash +# YAM arm + linear_4310 gripper (default) +python examples/control_with_mujoco/control_with_mujoco.py --sim + +# big_yam arm +python examples/control_with_mujoco/control_with_mujoco.py --arm big_yam --gripper linear_4310 --sim + +# Arm only, no gripper +python examples/control_with_mujoco/control_with_mujoco.py --arm yam --gripper no_gripper --sim +``` + +### Real Hardware + +```bash +python examples/control_with_mujoco/control_with_mujoco.py --channel can0 +python examples/control_with_mujoco/control_with_mujoco.py --arm big_yam --gripper linear_4310 --channel can0 +``` + +## Arguments + +| Argument | Default | Description | +|----------|---------|-------------| +| `--arm` | `yam` | Arm type: `yam`, `yam_pro`, `yam_ultra`, `big_yam` | +| `--gripper` | `linear_4310` | Gripper: `linear_4310`, `linear_3507`, `crank_4310`, `yam_teaching_handle`, `no_gripper` | +| `--channel` | `can0` | CAN interface name (real hardware only) | +| `--sim` | off | Use simulation instead of real hardware | +| `--dt` | `0.02` | Control loop timestep in seconds | +| `--site` | `grasp_site` | MuJoCo site name used as end-effector | + +## Viewer Controls + +1. Press **SPACE** to enter CONTROL mode (marker turns red) +2. **Double-click** the red target sphere to select it +3. **Ctrl + right-drag** β€” translate the target +4. **Ctrl + left-drag** β€” rotate the target +5. Press **SPACE** again to return to VIS mode + +## Supported Arms and Grippers + +All YAM-family arm Γ— gripper combinations are supported: + +| Arm | Grippers | +|-----|---------| +| `yam` | `linear_4310`, `linear_3507`, `crank_4310`, `yam_teaching_handle`, `no_gripper` | +| `yam_pro` | same as yam | +| `yam_ultra` | same as yam | +| `big_yam` | same as yam | diff --git a/docs/examples/index.md b/docs/examples/index.md new file mode 100644 index 0000000..a455a98 --- /dev/null +++ b/docs/examples/index.md @@ -0,0 +1,26 @@ +# Examples + +All examples live in the [`examples/`](https://github.com/i2rt-robotics/i2rt/tree/main/examples) directory of the repository. Each example has its own README with step-by-step instructions. + +## Available Examples + +| Example | Hardware Needed | Complexity | +|---------|----------------|------------| +| [Bimanual Teleoperation](/examples/bimanual-teleoperation) | 4 YAM arms + 4 CANable | Intermediate | +| [Record & Replay Trajectory](/examples/record-replay) | 1+ YAM arm | Beginner | +| [Single Motor PD Control](/examples/motor-control) | 1 DM motor | Beginner | +| [MuJoCo Control Interface](/examples/control-with-mujoco) | None (sim) / 1 YAM arm | Beginner | + +::: tip More examples +Additional examples in the repository (not yet documented here): +- `examples/control_with_viser/` β€” Web-based robot visualization with Viser +- `examples/minimum_gello/` β€” Core leader-follower teleoperation script +::: + +## Running an Example + +```bash +cd /path/to/i2rt +source .venv/bin/activate +python examples// + +
+ +
+
+
Open Robotics Platform
+

+ I2RT Robotics +

+

+ Cost-effective, high-performance hardware built for learning-based robotics β€” + teleoperation-ready, policy-deployment-ready, and battle-tested in the real world. +

+ +
+ Fully Open Source + Production Ready + Python SDK +
+
+
+ + + +
+
+ +
+ + 🦾 +

YAM Arm Family

+

Low-cost, low-inertia 6-DOF arms designed for AI training and teleoperation β€” four tiers from research to production.

+ Learn more β†’ +
+ + πŸ›ž +

Flow Base

+

Omnidirectional holonomic platform with on-board Pi, remote control, and full Python API.

+ Learn more β†’ +
+ + πŸ“‘ +

Teleoperation Ready

+

Bilateral leader-follower teleop. YAM Cell collects bimanual demonstrations for embodied AI.

+ Learn more β†’ +
+ + 🐍 +

Python-First SDK

+

Plug-and-play API: gravity compensation, PD control, trajectory recording, and simulation.

+ Quick start β†’ +
+
+ +
+

Product Family

+ +
+ +
+
+

Up and running in minutes

+

Install the Python SDK, plug in the CAN adapter, and start controlling the arm in a single script.

+ Full Quick Start β†’ +
+
+ +```python +from i2rt.robots.get_robot import get_yam_robot +import numpy as np + +# Connect (zero-gravity mode by default) +robot = get_yam_robot(channel="can0") + +# Read current observations +obs = robot.get_observations() +print(obs["joint_pos"]) # (6,) arm joints in radians + +# Command the arm home (6 joints + 1 gripper) +robot.command_joint_pos(np.zeros(7)) +``` + +
+
+ +
+ Get Started β†’ + i2rt.com + support@i2rt.com +
+ +
+ + diff --git a/docs/products/flow-base.md b/docs/products/flow-base.md new file mode 100644 index 0000000..b5b7c8e --- /dev/null +++ b/docs/products/flow-base.md @@ -0,0 +1,209 @@ + + +# Flow Base + +
+ βœ“ Python SDK + βœ“ Omnidirectional + βœ“ Remote Control + βœ“ Raspberry Pi On-board +
+ +**Flow Base** is I2RT's omnidirectional holonomic mobile platform. Designed to pair with YAM arms, it enables precise whole-body mobile manipulation for tasks that demand exact positioning and free orientation. + + + + +## Tagline + +> *"It likes to move it move it"* β€” precise, omnidirectional control for tasks where positioning and stability are critical. + +## Key Features + +- **Holonomic drive** β€” simultaneous XY translation and rotation with no kinematic constraints +- **On-board Raspberry Pi** β€” pre-configured with i2rt SDK; SSH-accessible over Wi-Fi or Ethernet +- **CAN bus motor control** β€” same DM-series protocol as YAM arms +- **Remote controller** β€” joystick remote included for manual operation +- **API control** β€” full network Python API via `FlowBaseClient` +- **Odometry** β€” wheel odometry with reset; external sensor integration supported +- **Safety** β€” E-stop, velocity timeout (0.25 s), remote override + +## Specifications + +| Parameter | Value | +|-----------|-------| +| Drive | Holonomic (4-wheel) | +| Communication (external) | Ethernet (static IP `172.6.2.20`) / Wi-Fi | +| Communication (motors) | CAN bus | +| On-board computer | Raspberry Pi | +| Power | Internal battery | +| SSH credentials | `i2rt` / `root` | +| API port | `11323` | +| Velocity timeout | 0.25 s | + +## Photos & Videos + + + + + + + + +## Remote Control Layout + +| Input | Function | +|-------|----------| +| Left joystick | XY translation | +| Right joystick X | Rotation (yaw) | +| Right joystick Y | Linear rail lift (if equipped) | +| Left1 | Reset odometry | +| Mode | Toggle local ↔ global frame | +| Left2 | Override API commands (safety) | + +## Getting Started + +### 1. Unbox & power on + +Follow the [unboxing guide](https://www.canva.com/design/DAGvHpqzf-Y). Ensure: +- Battery is connected and charged +- E-stop is **not pressed** +- CAN selector switch is in the **UP** position + +### 2. SSH in + +```bash +# Wired (Ethernet, static IP) +ssh i2rt@172.6.2.20 + +# Or find the Pi on your LAN after Wi-Fi setup +ssh i2rt@ +# Password: root +``` + +### 3. Run joystick demo + +```bash +python i2rt/flow_base/flow_base_controller.py +``` + +### 4. Python API + +```python +from i2rt.flow_base.flow_base_controller import Vehicle +import time + +vehicle = Vehicle() +vehicle.start_control() + +# Move forward at 0.1 m/s for 1 second +start = time.time() +while time.time() - start < 1.0: + vehicle.set_target_velocity((0.1, 0.0, 0.0), frame="local") +``` + +## Coordinate Systems + +The base supports two control frames toggled with the **Mode** button on the remote: + +| Mode | Behaviour | +|------|-----------| +| **Local** | XY motion is relative to the base's current heading | +| **Global** | XY motion is relative to the world frame (headless mode) | + +::: warning Odometry drift +Wheel odometry accumulates error, especially during aggressive movements. For precise mobile manipulation, integrate a visual odometry sensor (RealSense T265, ZED Camera). Press **Left1** to reset odometry at any time. +::: + +## API Reference + +```python +from i2rt.flow_base.flow_base_client import FlowBaseClient + +client = FlowBaseClient(host="172.6.2.20") + +# Read wheel odometry +odom = client.get_odometry() +# {'translation': array([x, y]), 'rotation': array([theta])} + +# Reset odometry +client.reset_odometry() + +# Command velocity [x, y, theta] in m/s and rad/s +client.set_target_velocity([0.1, 0.0, 0.0], frame="local") +``` + +### Linear Rail (if equipped) + +```python +client = FlowBaseClient(host="172.6.2.20", with_linear_rail=True) + +# Get rail state (position, velocity, limit switches) +state = client.get_linear_rail_state() + +# Set rail velocity (rad/s) +client.set_linear_rail_velocity(0.5) + +# Combined base + rail command [x, y, theta, rail_vel] +client.set_target_velocity([0.1, 0.0, 0.0, 0.2], frame="local") +``` + +::: tip Linear rail safety +The rail homes to the lower limit on init and has hardware limit switches. Set velocity to `0.0` to stop β€” do not control the brake directly. Commands time out after **0.25 s** of inactivity. +::: + +## External CAN Control + +To bypass the on-board Pi and control the base from an external computer: + +1. Connect your CAN adapter to the external CAN connector +2. Set the CAN selector switch to the **DOWN** position +3. Clone the i2rt repo on your external machine and control via CAN directly + +## Troubleshooting + +| Symptom | Fix | +|---------|-----| +| Remote unresponsive | Toggle remote off and on to wake from sleep | +| Slow boot | Normal β€” screen firmware adds delay, SSH is available quickly | +| Inaccurate odometry | Expected with wheel odometry; use external visual sensor for precision | +| Linear rail not homing | Check GPIO connections and limit switches | +| Linear rail stuck at limit | Run `get_linear_rail_state()` to check switch status | + +## See Also + +- [Linear Bot](/products/linear-bot) β€” Flow Base + linear rail lift +- [Flow Base API](/sdk/flow-base) +- [Hardware Setup](/getting-started/hardware-setup) + + diff --git a/docs/products/index.md b/docs/products/index.md new file mode 100644 index 0000000..753d719 --- /dev/null +++ b/docs/products/index.md @@ -0,0 +1,25 @@ +# Products + +I2RT Robotics builds an open ecosystem of robotic arms, mobile bases, and teleoperation systems for research and embodied AI applications. + +## Product Family + +| Product | Category | Code Support | +|---------|----------|-------------| +| [YAM Series](/products/yam) | Robotic Arm | βœ… Full | +| [YAM Cell](/products/yam-cell) | Bimanual Teleoperation Station | βœ… Full | +| [YAM Box](/products/yam-box) | Enclosed Manipulation Station | πŸ”œ Coming soon | +| [Flow Base](/products/flow-base) | Holonomic Mobile Base | βœ… Full | +| [Linear Bot](/products/linear-bot) | Mobile Base + Linear Actuator | βœ… Full | + +## End Effectors + +| Gripper | Motor | Weight | Notes | +|---------|-------|--------|-------| +| `crank_4310` | DM4310 | β€” | Zero-linkage crank, minimal width | +| `linear_3507` | DM3507 | Light | Requires closed-position calibration | +| `linear_4310` | DM4310 | Medium | Higher gripping force | +| `yam_teaching_handle` | β€” | β€” | Leader arm with trigger + 2 buttons | +| `flexpoint_4310` | DM4310 | β€” | Adaptive compliant gripper for extreme-condition grasping | + +See [Grippers SDK](/sdk/grippers) for API details. diff --git a/docs/products/linear-bot.md b/docs/products/linear-bot.md new file mode 100644 index 0000000..8f79e41 --- /dev/null +++ b/docs/products/linear-bot.md @@ -0,0 +1,127 @@ + + +# Linear Bot + +
+ βœ“ Python SDK + βœ“ Full Mobile Manipulation + βœ“ Height Adjustment +
+ +**Linear Bot** is the [Flow Base](/products/flow-base) combined with a vertical linear rail actuator. The linear rail adds a height axis to the omnidirectional base, enabling the mounted YAM arm to reach objects at varying heights β€” from floor-level to shelf-height β€” without repositioning. + + + + +## System Architecture + +``` +β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” +β”‚ YAM Arm β”‚ ← 6-DOF manipulation +β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ +β”‚ Linear Rail β”‚ ← Vertical axis (Z height) +β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ +β”‚ Flow Base β”‚ ← XY + rotation (holonomic) +β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ +``` + +The three subsystems are controlled together through a unified Python API, giving the robot **9 degrees of freedom** (6-DOF arm + 3-DOF mobile base including linear rail). + +## Key Features + +- **Vertical height axis** β€” linear rail extends and retracts under API or remote control +- **Limit switches** β€” hardware safety stops at both rail ends; auto-home on initialization +- **Brake management** β€” brake automatically released on init, engaged on shutdown +- **Integrated API** β€” 4D base velocity commands `[x, y, ΞΈ, rail_vel]` +- **Safety timeouts** β€” both base and rail stop after 0.25 s without a heartbeat + +## Specifications + +| Parameter | Value | +|-----------|-------| +| Mobile base | Flow Base (holonomic) | +| Vertical actuator | Linear rail with DM-series motor | +| Arm (typical) | YAM or YAM Pro | +| Total DOF (arm + base + rail) | 9 | +| Rail control | Velocity [rad/s] | +| Rail velocity timeout | 0.25 s | +| Rail home | Lower limit (on init) | + +## Photos & Videos + + + + + + + +## Python API + +```python +from i2rt.flow_base.flow_base_client import FlowBaseClient + +client = FlowBaseClient(host="172.6.2.20", with_linear_rail=True) + +# Move forward + raise rail simultaneously +client.set_target_velocity([0.1, 0.0, 0.0, 0.05], frame="local") +# x y ΞΈ rail_vel + +# Get rail position and limit switch states +state = client.get_linear_rail_state() +print(state) # {'position': ..., 'velocity': ..., 'limit_switches': ...} + +# Stop rail +client.set_linear_rail_velocity(0.0) +``` + +## Important Notes + +::: warning Auto-homing on init +The linear rail homes to the **lower limit switch** on every initialization. Ensure there is clearance below the carriage before powering on. +::: + +::: tip Stopping the rail +Always set velocity to `0.0` to stop the rail. Do not try to engage the brake directly β€” the system manages brake state automatically. +::: + +## Pricing + +Starting at **$18,999**. Contact [sales@i2rt.com](mailto:sales@i2rt.com) for configuration options. + +## See Also + +- [Flow Base](/products/flow-base) β€” base-only configuration +- [Flow Base API](/sdk/flow-base) +- [YAM Arm Series](/products/yam) + + diff --git a/docs/products/motor-gf43x10-10.md b/docs/products/motor-gf43x10-10.md new file mode 100644 index 0000000..e9267d8 --- /dev/null +++ b/docs/products/motor-gf43x10-10.md @@ -0,0 +1,75 @@ + + +# GF43X10-10 + +
+ Reduction 10Γ— + 2.2 NΒ·m Rated + 172 RPM Output +
+ +The **GF43X10-10** uses a 10Γ— planetary gearbox β€” the lowest reduction in the GF43 family β€” delivering the highest output speed. It is the lightest and shortest of the three variants, suited for joints or mechanisms where speed matters more than peak torque. + +## Dimensions + + + +## Specifications + +| Parameter | Value | +|-----------|-------| +| Reduction Ratio | 10 | +| Rated Voltage | 24 V | +| Rated Bus Current | 2.3 A | +| Rated Phase Current | 2 A | +| Rated Power | 40 W | +| Rated Speed (output) | 172 RPM | +| Rated Torque | 2.2 NΒ·m | +| Peak Power | 70 W | +| Peak Torque | 7 NΒ·m | +| Torque Constant | 0.095 NΒ·m/A | +| Weight | 300 g | +| Gearbox Backlash | 7.5 arcmin | +| Motor Size (βŒ€ Γ— L, excl. pins) | 57 Γ— 45.9 mm | +| Communication | CAN bus | + +> All speeds refer to the **output shaft** unless otherwise noted. + +::: tip Lower backlash +The 10Γ— gearbox has **7.5 arcmin** backlash β€” half that of the 40Γ— models β€” which improves positional accuracy at the cost of torque multiplication. +::: + +## Features + +- Dual encoder with single-turn absolute output-shaft position β€” survives power-off +- Motor + driver in one housing; no external controller required +- CAN bus feedback: speed, position, torque, motor temperature +- Dual temperature protection (hardware + software) +- Trapezoidal acceleration/deceleration in position mode +- Visual debugging via host PC; supports firmware upgrade + +## Where to Buy + +Visit [i2rt.com](https://i2rt.com) or contact [sales@i2rt.com](mailto:sales@i2rt.com). + +## See Also + +- [GF43X40-16](/products/motor-gf43x40-16) β€” 40Γ— reduction, highest continuous torque +- [GF43X40-10](/products/motor-gf43x40-10) β€” 40Γ— reduction, mid-power compact variant +- [Motors Overview](/products/motors) + + diff --git a/docs/products/motor-gf43x40-10.md b/docs/products/motor-gf43x40-10.md new file mode 100644 index 0000000..8332b69 --- /dev/null +++ b/docs/products/motor-gf43x40-10.md @@ -0,0 +1,71 @@ + + +# GF43X40-10 + +
+ Reduction 40Γ— + 8.9 NΒ·m Rated + 28 NΒ·m Peak +
+ +The **GF43X40-10** is a compact mid-power variant of the GF43 joint module with a 40Γ— planetary gearbox. Lighter and shorter than the GF43X40-16, it offers the same reduction ratio with a lower continuous torque rating but a notably higher peak torque ceiling β€” suitable for applications that require strong intermittent bursts. + +## Dimensions + + + +## Specifications + +| Parameter | Value | +|-----------|-------| +| Reduction Ratio | 40 | +| Rated Voltage | 24 V | +| Rated Bus Current | 2.3 A | +| Rated Phase Current | 2 A | +| Rated Power | 40 W | +| Rated Speed (output) | 43 RPM | +| Rated Torque | 8.9 NΒ·m | +| Peak Power | 70 W | +| Peak Torque | 28 NΒ·m | +| Torque Constant | 0.095 NΒ·m/A | +| Weight | 362 g | +| Gearbox Backlash | 15 arcmin | +| Motor Size (βŒ€ Γ— L, excl. pins) | 57 Γ— 56.5 mm | +| Communication | CAN bus | + +> All speeds refer to the **output shaft** unless otherwise noted. + +## Features + +- Dual encoder with single-turn absolute output-shaft position β€” survives power-off +- Motor + driver in one housing; no external controller required +- CAN bus feedback: speed, position, torque, motor temperature +- Dual temperature protection (hardware + software) +- Trapezoidal acceleration/deceleration in position mode +- Visual debugging via host PC; supports firmware upgrade + +## Where to Buy + +Visit [i2rt.com](https://i2rt.com) or contact [sales@i2rt.com](mailto:sales@i2rt.com). + +## See Also + +- [GF43X40-16](/products/motor-gf43x40-16) β€” higher continuous torque variant +- [GF43X10-10](/products/motor-gf43x10-10) β€” 10Γ— reduction for higher-speed applications +- [Motors Overview](/products/motors) + + diff --git a/docs/products/motor-gf43x40-16.md b/docs/products/motor-gf43x40-16.md new file mode 100644 index 0000000..87bf77e --- /dev/null +++ b/docs/products/motor-gf43x40-16.md @@ -0,0 +1,75 @@ + + +# GF43X40-16 + +
+ Reduction 40Γ— + 14 NΒ·m Rated + 23.5 NΒ·m Peak +
+ +The **GF43X40-16** is the highest-power variant of the GF43 planetary joint module. It combines a 40Γ— planetary gearbox with a 24 V brushless DC motor and integrated CAN driver. Gears are vacuum-nitrided for durability; the concentrated-winding motor is optimized for low cogging torque and smooth motion. + +## Dimensions + + + +## Specifications + +| Parameter | Value | +|-----------|-------| +| Reduction Ratio | 40 | +| Rated Voltage | 24 V | +| Rated Bus Current | 4 A | +| Rated Phase Current | 3.5 A | +| Rated Power | 65 W | +| Rated Speed (output) | 44 RPM | +| Rated Torque | 14 NΒ·m | +| Peak Power | 90 W | +| Peak Torque | 23.5 NΒ·m | +| Torque Constant | 0.096 NΒ·m/A | +| Weight | 464.5 g | +| Gearbox Backlash | 15 arcmin | +| Motor Size (βŒ€ Γ— L, excl. pins) | 57 Γ— 62.5 mm | +| Communication | CAN bus | + +> All speeds refer to the **output shaft** unless otherwise noted. + +## Features + +- Dual encoder with single-turn absolute output-shaft position β€” survives power-off +- Motor + driver in one housing; no external controller required +- CAN bus feedback: speed, position, torque, motor temperature +- Dual temperature protection (hardware + software) +- Trapezoidal acceleration/deceleration in position mode +- Visual debugging via host PC; supports firmware upgrade + +## Where to Buy + +Visit [i2rt.com](https://i2rt.com) or contact [sales@i2rt.com](mailto:sales@i2rt.com). + +## See Also + +- [GF43X40-10](/products/motor-gf43x40-10) β€” lighter variant, same reduction, lower continuous torque +- [GF43X10-10](/products/motor-gf43x10-10) β€” 10Γ— reduction for higher-speed applications +- [Motors Overview](/products/motors) + + diff --git a/docs/products/motors.md b/docs/products/motors.md new file mode 100644 index 0000000..92b631c --- /dev/null +++ b/docs/products/motors.md @@ -0,0 +1,54 @@ +# Motors + +
+ βœ“ CAN Bus + βœ“ Dual Encoder + βœ“ Integrated Driver + βœ“ Planetary Reduction +
+ +I2RT's **GF series** are all-in-one joint modules β€” planetary gearbox, brushless DC motor, and driver integrated into a single compact housing. Gears are vacuum-nitrided for high strength and service life. The concentrated-winding motor design delivers high power density with optimized pole-arc ratio for low cogging torque and smooth motion. + +## Model Comparison + +| Model | Reduction Ratio | Rated Torque | Peak Torque | Rated Speed | Weight | Size (βŒ€ Γ— L) | +|-------|:-:|:-:|:-:|:-:|:-:|:-:| +| [GF43X40-16](/products/motor-gf43x40-16) | 40 | 14 NΒ·m | 23.5 NΒ·m | 44 RPM | 464.5 g | 57 Γ— 62.5 mm | +| [GF43X40-10](/products/motor-gf43x40-10) | 40 | 8.9 NΒ·m | 28 NΒ·m | 43 RPM | 362 g | 57 Γ— 56.5 mm | +| [GF43X10-10](/products/motor-gf43x10-10) | 10 | 2.2 NΒ·m | 7 NΒ·m | 172 RPM | 300 g | 57 Γ— 45.9 mm | + +All models share the same 24 V supply and CAN bus interface. + +## Key Features + +- **Dual encoder** β€” single-turn absolute output-shaft position; survives power-off without losing zero reference +- **Integrated driver** β€” compact single-unit assembly with no external controller required +- **CAN bus feedback** β€” real-time speed, position, torque, and motor temperature +- **Dual temperature protection** β€” hardware and software over-temperature shutdown +- **Trapezoidal motion profile** β€” configurable acceleration/deceleration in position mode +- **Visual debugging** β€” host-PC GUI for tuning and firmware upgrade + +## Communication + +All GF series motors communicate over **CAN bus (1 Mbit/s)**, the same bus used by YAM arm actuators. Multiple motors can share a single CAN channel using standard node addressing. + +```python +# Motor control follows the same CAN pattern as YAM joints +# See the YAM Arm SDK for protocol details +``` + +## Naming Convention + +``` +GF 43 X 40 - 16 +β”‚ β”‚ β”‚ └─ Motor variant (current/winding spec) +β”‚ β”‚ └─────── Reduction ratio +β”‚ └────────────── Outer diameter class (43 mm motor stator) +└────────────────── GF joint module series +``` + + diff --git a/docs/products/yam-arm.md b/docs/products/yam-arm.md new file mode 100644 index 0000000..b0aa0de --- /dev/null +++ b/docs/products/yam-arm.md @@ -0,0 +1,109 @@ + + +# YAM Arm + +
+ βœ“ Python SDK + βœ“ MuJoCo Sim + βœ“ Gravity Compensation +
+ +The **YAM Arm** is the follower/manipulation arm in the YAM family β€” a 6-DOF, CAN bus–driven manipulator built for real-world research and embodied AI data collection. Pair it with a [YAM Leader](/products/yam-leader) for teleoperation, or run it standalone with the Python SDK. + + + + +## Models + +| Model | Price | Notes | +|-------|-------|-------| +| **YAM** | $2,999 | Standard research arm | +| **YAM Pro** | $3,499 | Enhanced actuators | +| **YAM Ultra** | $4,299 | Highest spec standard arm | +| **BIG YAM** | $4,999 | Larger reach and payload | + +## Specifications + +| Parameter | Value | +|-----------|-------| +| Degrees of Freedom | 6 | +| Communication | CAN bus (1 Mbit/s) | +| Motor Series | DM series brushless | +| Control Modes | Joint position PD Β· Gravity compensation Β· Zero-gravity | +| Simulation | MuJoCo (MJCF + URDF provided) | +| Safety | 400 ms motor timeout (configurable) | +| Mounting | Table-top (standard) | + +## Grippers + +| Gripper | Motor | Notes | +|---------|-------|-------| +| `crank_4310` | DM4310 | Zero-linkage crank β€” minimal sweep width | +| `linear_3507` | DM3507 | Lightweight linear; requires closed-position calibration | +| `linear_4310` | DM4310 | Standard linear; slightly higher force | + +See [Grippers](/sdk/grippers) for calibration and model details. + +## 3D Model + +``` +i2rt/robot_models/arm/yam/ +β”œβ”€β”€ yam.urdf +β”œβ”€β”€ yam.xml +└── assets/ # STL meshes (visual + collision) +``` + +## Videos + + + + + + +## Quick Start + +```python +from i2rt.robots.motor_chain_robot import get_yam_robot +import numpy as np + +robot = get_yam_robot(channel="can0", gripper_type="linear_4310") + +# Read joint positions (radians) +q = robot.get_joint_pos() # shape: (6,) + +# Command home position +robot.command_joint_pos(np.zeros(6)) +``` + +## See Also + +- [YAM Leader](/products/yam-leader) β€” teaching handle for teleoperation +- [YAM Arm API](/sdk/yam-arm) +- [Grippers](/sdk/grippers) +- [Hardware Setup](/getting-started/hardware-setup) + + diff --git a/docs/products/yam-box.md b/docs/products/yam-box.md new file mode 100644 index 0000000..6c171ef --- /dev/null +++ b/docs/products/yam-box.md @@ -0,0 +1,57 @@ +# YAM Box + +
+ πŸ”œ Code Coming Soon + βœ“ Hardware Available +
+ +**YAM Box** is an all-in-one enclosed manipulation station built around the YAM arm family. It provides a self-contained, cable-managed workspace for manipulation research and automated data collection. + +::: warning Code support not yet available +The YAM Box hardware is available for purchase. Software and SDK support is under active development and will be released in an upcoming update. Sign up at [i2rt.com](https://i2rt.com) or join the [Discord](https://discord.gg/i2rt) to be notified. +::: + +## Overview + + + +## Intended Use Cases + +- **Automated data generation** β€” Run unattended overnight collection campaigns without cable snagging. +- **Demonstration stations** β€” Clean, professional setup for trade shows and lab demos. +- **Safe testing environments** β€” Enclosed workspace limits accidental contact during development. + +## What's Inside + + + +| Component | Description | +|-----------|-------------| +| YAM arm(s) | 1 or 2 YAM arms (depending on configuration) | +| Cable management | Internal routing to keep wiring clear of arm workspace | +| Electronics bay | CANable adapters, power distribution | +| Enclosure | Aluminum frame with clear polycarbonate panels | + +## Pricing + +Starting at **$3,500**. Contact [sales@i2rt.com](mailto:sales@i2rt.com) for custom configurations. + +## Stay Updated + +Join the I2RT community: +- [Discord](https://discord.gg/i2rt) +- [GitHub](https://github.com/i2rt-robotics/i2rt) β€” watch the repo for releases +- Email [support@i2rt.com](mailto:support@i2rt.com) + + diff --git a/docs/products/yam-cell.md b/docs/products/yam-cell.md new file mode 100644 index 0000000..f6917b3 --- /dev/null +++ b/docs/products/yam-cell.md @@ -0,0 +1,157 @@ + + +# YAM Cell + +
+ βœ“ Python SDK + βœ“ Bimanual + βœ“ Data Generation +
+ +**YAM Cell** is a complete bimanual teleoperation workstation built around two YAM leader arms and two YAM follower arms. It is designed for collecting high-quality manipulation demonstrations for training embodied AI models. + + + + +#### Mobile Variant + + + +## System Overview + +The YAM Cell pairs **leader arms** (with teaching handles) and **follower arms** in a bilateral teleoperation loop. An operator moves the leader arms naturally; the follower arms mirror the motion in real time with configurable force feedback. + +``` +Operator ──► Leader (YAM + teaching handle) + β”‚ bilateral link (CAN bus) + Follower (YAM + task gripper) ──► Task workspace +``` + +## Hardware Requirements + +| Component | Qty | Notes | +|-----------|-----|-------| +| YAM Follower arms | 2 | Any YAM tier | +| YAM Leader arms | 2 | Must use `yam_teaching_handle` gripper | +| CANable USB-CAN adapters | 4 | One per arm | +| Workstation PC | 1 | Ubuntu 22.04 recommended | + +## CAN Bus Layout + +Each arm requires a dedicated CAN channel. Assign persistent names using udev rules (see [Hardware Setup](/getting-started/hardware-setup)): + +| Arm | CAN name | +|-----|----------| +| Left follower | `can_follower_l` | +| Right follower | `can_follower_r` | +| Left leader | `can_leader_l` | +| Right leader | `can_leader_r` | + +## Videos + + + + + + +## Quick Start + +### 1. Configure CAN IDs + +Plug one CANable device at a time and assign each arm a persistent name: + +```bash +# Follow the instructions in: +doc/set_persist_id_socket_can.md +``` + +### 2. Verify connectivity + +```bash +ip a | grep can +# Expected: +# can_follower_r UP +# can_follower_l UP +# can_leader_r UP +# can_leader_l UP +``` + +### 3. Launch bimanual teleoperation + +```bash +cd /path/to/i2rt +source .venv/bin/activate +python examples/bimanual_lead_follower/bimanual_lead_follower.py +``` + +### 4. Enable synchronization + +Press the **top button** on either teaching handle once to begin tracking. Press again to pause. + +## Control Reference + +| Action | Result | +|--------|--------| +| Move leader arm | Follower mirrors motion | +| Squeeze trigger | Follower gripper closes | +| Top button (1Γ—) | Enable sync | +| Top button (2Γ—) | Pause sync | +| `--bilateral_kp` flag | Increase for more force feedback (default 0.2) | + +::: tip Bilateral stiffness +Start with `--bilateral_kp 0.1` and increase gradually. Values above `0.3` make the leader arm feel noticeably heavy. +::: + +## Data Logging + +Trajectory recording is built into the example: + +```python +from i2rt.robots.motor_chain_robot import get_yam_robot +# See examples/record_replay_trajectory/ for full dataset collection pipeline +``` + +## See Also + +- [Bimanual Teleoperation Example](/examples/bimanual-teleoperation) +- [Record & Replay](/examples/record-replay) +- [YAM Arm API](/sdk/yam-arm) + + diff --git a/docs/products/yam-leader.md b/docs/products/yam-leader.md new file mode 100644 index 0000000..087339b --- /dev/null +++ b/docs/products/yam-leader.md @@ -0,0 +1,115 @@ + + +# YAM Leader Arm + +
+ βœ“ Teleoperation + βœ“ Teaching Handle + βœ“ Bimanual Ready +
+ +The **YAM Leader** is the operator-side arm used for teleoperation. It is kinematically identical to the [YAM Arm](/products/yam-arm) but fitted with the `yam_teaching_handle` instead of a gripper. The operator holds the handle and moves the leader arm β€” the follower arm mirrors the motion in real time. + + + + +## Specifications + +| Parameter | Value | +|-----------|-------| +| Base arm | YAM (6-DOF, CAN bus) | +| End effector | `yam_teaching_handle` | +| Price | $2,999 | +| Typical use | Bimanual teleoperation (YAM Cell) | + +## Teaching Handle + + + +| Control | Function | +|---------|----------| +| **Trigger** | Open / close the follower gripper | +| **Top button** | Enable / disable arm synchronisation | +| **Second button** | User-programmable | + +### Reading the trigger + +```bash +python scripts/read_encoder.py --channel $CAN_CHANNEL +``` + +Example output: + +``` +[PassiveEncoderInfo(id=1294, position=0.004382, velocity=0.0, io_inputs=[0, 0])] +``` + +- `position` β†’ follower gripper command (`0.0` = open, `~1.0` = closed) +- `io_inputs` β†’ button states + +### Resetting encoder zero + +If the magnet has shifted or after repairs: + +```bash +python devices/config_passive_encoder.py --bus $CAN_CHANNEL reset-zero-position +``` + +Re-run `read_encoder.py` to confirm the trigger-released reading is near `0.0`. + +## Teleoperation Setup + +The leader arm is launched via `minimum_gello.py` in leader mode: + +```bash +python examples/minimum_gello/minimum_gello.py \ + --gripper yam_teaching_handle \ + --mode leader \ + --can-channel can_leader_l +``` + +For full bimanual setup see [Bimanual Teleoperation](/examples/bimanual-teleoperation). + +## Videos + + + + +## See Also + +- [YAM Arm](/products/yam-arm) β€” the follower arm +- [YAM Cell](/products/yam-cell) β€” full bimanual teleoperation station +- [Bimanual Teleoperation](/examples/bimanual-teleoperation) +- [Grippers](/sdk/grippers) + + diff --git a/docs/products/yam.md b/docs/products/yam.md new file mode 100644 index 0000000..8b0fdc2 --- /dev/null +++ b/docs/products/yam.md @@ -0,0 +1,134 @@ + + +# YAM Arm Series + +
+ βœ“ Python SDK + βœ“ MuJoCo Sim + βœ“ Gravity Compensation + βœ“ Teleoperation +
+ +**YAM** (Yet Another Manipulator) is I2RT's flagship robotic arm β€” a 6-DOF, CAN bus–driven manipulator designed for real-world research and embodied AI data collection. The YAM family spans four tiers to match different reach, payload, and budget requirements. + + + + + +## Model Overview + +| Model | Price | Notes | +|-------|-------|-------| +| **YAM** | $2,999 | Standard research arm | +| **YAM Pro** | $3,499 | Enhanced actuators | +| **YAM Ultra** | $4,299 | Highest spec standard arm | +| **BIG YAM** | $4,999 | Larger reach and payload | +| **YAM Leader** | $2,999 | Teaching handle for teleoperation | + +## Specifications + +| Parameter | Value | +|-----------|-------| +| Degrees of Freedom | 6 | +| Communication | CAN bus (1 Mbit/s) | +| Motor Series | DM series brushless | +| Control Modes | Joint position PD Β· Gravity compensation Β· Zero-gravity | +| Simulation | MuJoCo (MJCF + URDF provided) | +| Safety | 400 ms motor timeout (configurable) | +| Mounting | Table-top (standard) | + +## Grippers + +YAM supports four interchangeable end effectors: + + + + +| Gripper | Description | +|---------|-------------| +| `crank_4310` | Zero-linkage crank design β€” minimizes total gripper width for tight workspaces. | +| `linear_3507` | Lightweight linear gripper with DM3507 motor. Requires starting in the closed position for calibration. | +| `linear_4310` | Linear gripper with the heavier DM4310 motor. Marginally more gripping force. | +| `yam_teaching_handle` | Leader arm handle with a trigger for gripper and two programmable buttons. Used for teleoperation. | +| `flexpoint_4310` | Adaptive compliant gripper engineered for extreme-condition grasping β€” conforms to irregular, fragile, and complex geometries where rigid grippers fail. | + +## 3D Model + +The YAM URDF and MuJoCo XML are included in the repository: + +``` +i2rt/robot_models/arm/yam/ +β”œβ”€β”€ yam.urdf +β”œβ”€β”€ yam.xml +└── assets/ # STL meshes (visual + collision) +``` + +## Videos + + + + + + +## Getting Started + +1. [Install the SDK](/getting-started/installation) +2. [Set up CAN bus](/getting-started/hardware-setup) +3. See [YAM Arm API](/sdk/yam-arm) for the full Python reference +4. Try the [Quick Start](/getting-started/quick-start) + +```python +from i2rt.robots.motor_chain_robot import get_yam_robot +import numpy as np + +# Connect to the arm (zero-gravity mode on by default) +robot = get_yam_robot(channel="can0", zero_gravity_mode=True) + +# Read current joint positions +joints = robot.get_joint_pos() # shape: (6,) radians + +# Command a target configuration +robot.command_joint_pos(np.zeros(6)) +``` + +## Where to Buy + +Visit [i2rt.com](https://i2rt.com) or contact [sales@i2rt.com](mailto:sales@i2rt.com). + + diff --git a/docs/public/.nojekyll b/docs/public/.nojekyll new file mode 100644 index 0000000..e69de29 diff --git a/docs/public/images/crank-shaft-gripper/GP-4310-CS-1.webp b/docs/public/images/crank-shaft-gripper/GP-4310-CS-1.webp new file mode 100644 index 0000000..8d7b0b1 Binary files /dev/null and b/docs/public/images/crank-shaft-gripper/GP-4310-CS-1.webp differ diff --git a/docs/public/images/crank-shaft-gripper/GP-4310-CS-2.webp b/docs/public/images/crank-shaft-gripper/GP-4310-CS-2.webp new file mode 100644 index 0000000..75d45fe Binary files /dev/null and b/docs/public/images/crank-shaft-gripper/GP-4310-CS-2.webp differ diff --git a/docs/public/images/flexpoint-adaptive-gripper/GP-4310-FLX-1.webp b/docs/public/images/flexpoint-adaptive-gripper/GP-4310-FLX-1.webp new file mode 100644 index 0000000..41134ed Binary files /dev/null and b/docs/public/images/flexpoint-adaptive-gripper/GP-4310-FLX-1.webp differ diff --git a/docs/public/images/flexpoint-adaptive-gripper/GP-4310-FLX-2.webp b/docs/public/images/flexpoint-adaptive-gripper/GP-4310-FLX-2.webp new file mode 100644 index 0000000..4c3b058 Binary files /dev/null and b/docs/public/images/flexpoint-adaptive-gripper/GP-4310-FLX-2.webp differ diff --git a/docs/public/images/flexpoint-adaptive-gripper/GP-4310-FLX-3.webp b/docs/public/images/flexpoint-adaptive-gripper/GP-4310-FLX-3.webp new file mode 100644 index 0000000..2422d61 Binary files /dev/null and b/docs/public/images/flexpoint-adaptive-gripper/GP-4310-FLX-3.webp differ diff --git a/docs/public/images/flexpoint-adaptive-gripper/GP-4310-FLX-4.webp b/docs/public/images/flexpoint-adaptive-gripper/GP-4310-FLX-4.webp new file mode 100644 index 0000000..b66f719 Binary files /dev/null and b/docs/public/images/flexpoint-adaptive-gripper/GP-4310-FLX-4.webp differ diff --git a/docs/public/images/flexpoint-adaptive-gripper/GP-4310-FLX-5.webp b/docs/public/images/flexpoint-adaptive-gripper/GP-4310-FLX-5.webp new file mode 100644 index 0000000..cd644a3 Binary files /dev/null and b/docs/public/images/flexpoint-adaptive-gripper/GP-4310-FLX-5.webp differ diff --git a/docs/public/images/flow_base.webp b/docs/public/images/flow_base.webp new file mode 100644 index 0000000..a4aabe3 Binary files /dev/null and b/docs/public/images/flow_base.webp differ diff --git a/docs/public/images/flow_base_panel.webp b/docs/public/images/flow_base_panel.webp new file mode 100644 index 0000000..b3437e1 Binary files /dev/null and b/docs/public/images/flow_base_panel.webp differ diff --git a/docs/public/images/linear-gripper-3507/GP-3507-CTR-1.webp b/docs/public/images/linear-gripper-3507/GP-3507-CTR-1.webp new file mode 100644 index 0000000..4bba077 Binary files /dev/null and b/docs/public/images/linear-gripper-3507/GP-3507-CTR-1.webp differ diff --git a/docs/public/images/linear-gripper-3507/GP-3507-CTR-2.webp b/docs/public/images/linear-gripper-3507/GP-3507-CTR-2.webp new file mode 100644 index 0000000..d756d4b Binary files /dev/null and b/docs/public/images/linear-gripper-3507/GP-3507-CTR-2.webp differ diff --git a/docs/public/images/linear-gripper-4310/GP-4310-CTR-1.webp b/docs/public/images/linear-gripper-4310/GP-4310-CTR-1.webp new file mode 100644 index 0000000..9cbd9e1 Binary files /dev/null and b/docs/public/images/linear-gripper-4310/GP-4310-CTR-1.webp differ diff --git a/docs/public/images/linear-gripper-4310/GP-4310-CTR-2.webp b/docs/public/images/linear-gripper-4310/GP-4310-CTR-2.webp new file mode 100644 index 0000000..aab873a Binary files /dev/null and b/docs/public/images/linear-gripper-4310/GP-4310-CTR-2.webp differ diff --git a/docs/public/images/linear-gripper-4310/GP-4310-CTR-3.webp b/docs/public/images/linear-gripper-4310/GP-4310-CTR-3.webp new file mode 100644 index 0000000..04abea9 Binary files /dev/null and b/docs/public/images/linear-gripper-4310/GP-4310-CTR-3.webp differ diff --git a/docs/public/images/linear-gripper-4310/GP-4310-CTR-4.webp b/docs/public/images/linear-gripper-4310/GP-4310-CTR-4.webp new file mode 100644 index 0000000..4e8a9f2 Binary files /dev/null and b/docs/public/images/linear-gripper-4310/GP-4310-CTR-4.webp differ diff --git a/docs/public/images/linear_rail.webp b/docs/public/images/linear_rail.webp new file mode 100644 index 0000000..1df2e57 Binary files /dev/null and b/docs/public/images/linear_rail.webp differ diff --git a/docs/public/images/motors/image2.webp b/docs/public/images/motors/image2.webp new file mode 100644 index 0000000..0aebf1a Binary files /dev/null and b/docs/public/images/motors/image2.webp differ diff --git a/docs/public/images/motors/image3.webp b/docs/public/images/motors/image3.webp new file mode 100644 index 0000000..e92ac68 Binary files /dev/null and b/docs/public/images/motors/image3.webp differ diff --git a/docs/public/images/motors/image4.webp b/docs/public/images/motors/image4.webp new file mode 100644 index 0000000..c64cc98 Binary files /dev/null and b/docs/public/images/motors/image4.webp differ diff --git a/docs/public/images/motors/image5.webp b/docs/public/images/motors/image5.webp new file mode 100644 index 0000000..bdf7a6c Binary files /dev/null and b/docs/public/images/motors/image5.webp differ diff --git a/docs/public/images/motors/image6.webp b/docs/public/images/motors/image6.webp new file mode 100644 index 0000000..fb6dab0 Binary files /dev/null and b/docs/public/images/motors/image6.webp differ diff --git a/docs/public/images/motors/image7.webp b/docs/public/images/motors/image7.webp new file mode 100644 index 0000000..4332c5a Binary files /dev/null and b/docs/public/images/motors/image7.webp differ diff --git a/docs/public/images/remote.webp b/docs/public/images/remote.webp new file mode 100644 index 0000000..f7dde17 Binary files /dev/null and b/docs/public/images/remote.webp differ diff --git a/docs/public/images/yam-leader/YAM-ST-Leader-1.webp b/docs/public/images/yam-leader/YAM-ST-Leader-1.webp new file mode 100644 index 0000000..e1e68b4 Binary files /dev/null and b/docs/public/images/yam-leader/YAM-ST-Leader-1.webp differ diff --git a/docs/public/images/yam-leader/YAM-ST-Leader-2.webp b/docs/public/images/yam-leader/YAM-ST-Leader-2.webp new file mode 100644 index 0000000..b343a14 Binary files /dev/null and b/docs/public/images/yam-leader/YAM-ST-Leader-2.webp differ diff --git a/docs/public/images/yam-leader/YAM-ST-Leader-3.webp b/docs/public/images/yam-leader/YAM-ST-Leader-3.webp new file mode 100644 index 0000000..d96bb9d Binary files /dev/null and b/docs/public/images/yam-leader/YAM-ST-Leader-3.webp differ diff --git a/docs/public/images/yam-leader/YAM-ST-Leader-4.webp b/docs/public/images/yam-leader/YAM-ST-Leader-4.webp new file mode 100644 index 0000000..ab8db7a Binary files /dev/null and b/docs/public/images/yam-leader/YAM-ST-Leader-4.webp differ diff --git a/docs/public/images/yam-leader/YAM-ST-Leader-video.mp4 b/docs/public/images/yam-leader/YAM-ST-Leader-video.mp4 new file mode 100644 index 0000000..6fb557d Binary files /dev/null and b/docs/public/images/yam-leader/YAM-ST-Leader-video.mp4 differ diff --git a/docs/public/images/yam-mobile/YAM-Mobile-1.webp b/docs/public/images/yam-mobile/YAM-Mobile-1.webp new file mode 100644 index 0000000..de88b33 Binary files /dev/null and b/docs/public/images/yam-mobile/YAM-Mobile-1.webp differ diff --git a/docs/public/images/yam-mobile/YAM-Mobile-2.webp b/docs/public/images/yam-mobile/YAM-Mobile-2.webp new file mode 100644 index 0000000..7205ed6 Binary files /dev/null and b/docs/public/images/yam-mobile/YAM-Mobile-2.webp differ diff --git a/docs/public/images/yam-mobile/YAM-Mobile-only.webp b/docs/public/images/yam-mobile/YAM-Mobile-only.webp new file mode 100644 index 0000000..87777bc Binary files /dev/null and b/docs/public/images/yam-mobile/YAM-Mobile-only.webp differ diff --git a/docs/public/images/yam-standard/YAM-ST-GP-1.webp b/docs/public/images/yam-standard/YAM-ST-GP-1.webp new file mode 100644 index 0000000..318e0e7 Binary files /dev/null and b/docs/public/images/yam-standard/YAM-ST-GP-1.webp differ diff --git a/docs/public/images/yam-standard/YAM-ST-GP-2.webp b/docs/public/images/yam-standard/YAM-ST-GP-2.webp new file mode 100644 index 0000000..8182def Binary files /dev/null and b/docs/public/images/yam-standard/YAM-ST-GP-2.webp differ diff --git a/docs/public/images/yam-standard/YAM-ST-GP-video.mp4 b/docs/public/images/yam-standard/YAM-ST-GP-video.mp4 new file mode 100644 index 0000000..71a03e6 Binary files /dev/null and b/docs/public/images/yam-standard/YAM-ST-GP-video.mp4 differ diff --git a/docs/public/images/yam-station/DS-ST-1.webp b/docs/public/images/yam-station/DS-ST-1.webp new file mode 100644 index 0000000..d446269 Binary files /dev/null and b/docs/public/images/yam-station/DS-ST-1.webp differ diff --git a/docs/public/images/yam-station/DS-ST-2.webp b/docs/public/images/yam-station/DS-ST-2.webp new file mode 100644 index 0000000..74727b8 Binary files /dev/null and b/docs/public/images/yam-station/DS-ST-2.webp differ diff --git a/docs/public/images/yam-station/DS-ST-3.webp b/docs/public/images/yam-station/DS-ST-3.webp new file mode 100644 index 0000000..1ac048f Binary files /dev/null and b/docs/public/images/yam-station/DS-ST-3.webp differ diff --git a/docs/public/images/yam-station/DS-ST.mp4 b/docs/public/images/yam-station/DS-ST.mp4 new file mode 100644 index 0000000..ccfc5b0 Binary files /dev/null and b/docs/public/images/yam-station/DS-ST.mp4 differ diff --git a/docs/public/logo.svg b/docs/public/logo.svg new file mode 100644 index 0000000..a3a7777 --- /dev/null +++ b/docs/public/logo.svg @@ -0,0 +1,10 @@ + + + + + + + + + i2rt + diff --git a/docs/releases/v1.0.md b/docs/releases/v1.0.md new file mode 100644 index 0000000..05201a8 --- /dev/null +++ b/docs/releases/v1.0.md @@ -0,0 +1,59 @@ +# v1.0 Release Notes + +**Date:** 2026-03-03 + +## Highlights + +This release introduces a unified robot assembly API, modular arm + gripper MJCF models, simulation support, and a cleaner SDK surface for downstream consumers. + +## Unified Robot Assembly + +- **`get_yam_robot()` now supports all arm variants** via the new `arm_type` parameter (`yam`, `yam_pro`, `yam_ultra`, `big_yam`). The separate `get_big_yam_robot()` function has been removed. +- **New `ArmType` enum** in `i2rt.robots.utils` for selecting arm variants. +- **Motor wrap-around correction**: the assembly routine now reads initial motor positions and applies Β±2Ο€ offsets automatically, preventing jump discontinuities on startup. + +## Modular Arm + Gripper Models + +- **Arm and gripper MJCF files are now separate** under `robot_models/arm/` and `robot_models/gripper/`. At runtime, `combine_arm_and_gripper_xml()` merges the arm and gripper XMLs by replacing the `link_6` subtree and combining assets. +- **End-effector mass/inertia overrides**: pass `ee_mass` and `ee_inertia` to `get_yam_robot()` to customise the link_6 inertial properties without editing XML files. +- Removed legacy monolithic model directories (`robot_models/yam/`, `robot_models/big_yam/`, `robot_models/arx_r5/`). + +## Simulation Support + +- **`get_yam_robot(sim=True)`** returns a `SimRobot` backed by MuJoCo β€” no CAN hardware required. Useful for testing policies and control loops offline. + +## Gripper Changes + +- **Default gripper type** changed from `crank_4310` to `linear_4310`. +- **Explicit calibration opt-in**: gripper auto-detection is now controlled by the `enable_gripper_calibration` flag instead of being inferred from the gripper type. `crank_4310` no longer triggers calibration by default. +- Gripper limit detection tuned: `position_stable_count` threshold reduced from 6 to 3 for faster calibration. The `close_offset` parameter has been removed. + +## Motor Driver Cleanup + +- Removed `max_step_time` tracking from the control loop. +- Linear rail imports in `flow_base_controller.py` are now lazy to avoid import errors when the linear rail hardware module is not present. + +## SDK & API + +- `joint_state_saver_factory` signature changed from `Callable[[str], Any]` to `Callable[[], Any]`. +- `_last_gripper_command_qpos` initialises to `1` (fully open) instead of `None`. +- `start_recording()` / `stop_recording()` methods are still available on `MotorChainRobot` (moved to bottom of class, no behaviour change). +- Base `Robot` class now includes default no-op `reinit()` and `close()` methods. +- `GripperType.from_string_name()` and the new `ArmType.from_string_name()` use direct enum construction for cleaner error messages. + +## Dependencies + +- `mink` bumped from `0.0.11` to `>=0.0.13`. +- `pydantic` / `pydantic-core` removed from core dependencies. +- `viser>=0.2.0` added. +- `pytest-xdist` added to dev dependencies. +- `mujoco` is now a required import in `minimum_gello.py` (no longer optional). + +## Removed + +- `get_big_yam_robot()` β€” use `get_yam_robot(arm_type=ArmType.BIG_YAM)` instead. +- `robot_models/yam/`, `robot_models/big_yam/`, `robot_models/arx_r5/` directories. +- `doc/set_persist_id_socket_can.md` and `doc/yam_handle_readme.md` β€” content moved to online docs. +- `dm_driver_single_motor_example.py` and `motor_chain_example.py` β€” use `examples/` directory instead. +- `mujoco_visualizer.py` β€” functionality covered by existing visualiser utilities. +- `GripperType.get_gripper_default_test_torque()` β€” replaced by `test_torque` parameter on `MotorChainRobot`. diff --git a/docs/sdk/flow-base.md b/docs/sdk/flow-base.md new file mode 100644 index 0000000..a79f5e7 --- /dev/null +++ b/docs/sdk/flow-base.md @@ -0,0 +1,171 @@ +# Flow Base API + +The Flow Base SDK has two layers: + +| Class | Location | Use | +|-------|----------|-----| +| `Vehicle` | `flow_base_controller.py` | Runs **on-board** the Pi β€” joystick demo | +| `FlowBaseClient` | `flow_base_client.py` | Runs **remotely** β€” network Python API | + +## `FlowBaseClient` + +For remote control from your development machine. + +```python +from i2rt.flow_base.flow_base_client import FlowBaseClient + +client = FlowBaseClient( + host="172.6.2.20", + with_linear_rail=False, +) +``` + +| Parameter | Type | Default | Description | +|-----------|------|---------|-------------| +| `host` | `str` | `"localhost"` | IP address of the Flow Base Pi | +| `with_linear_rail` | `bool` | `False` | Set `True` if the linear rail module is installed | + +::: tip No port parameter +The port is hardcoded internally using `BASE_DEFAULT_PORT`. You only need to specify the host IP. +::: + +--- + +## Movement Commands + +### `set_target_velocity(velocity, frame)` + +```python +import numpy as np + +# 3D (base only) +client.set_target_velocity(np.array([vx, vy, omega]), frame="local") + +# 4D (base + linear rail) +client.set_target_velocity(np.array([vx, vy, omega, rail_vel]), frame="local") +``` + +| Parameter | Unit | Description | +|-----------|------|-------------| +| `vx` | m/s | Forward/backward | +| `vy` | m/s | Left/right (strafe) | +| `omega` | rad/s | Rotation (yaw rate) | +| `rail_vel` | rad/s | Linear rail speed (positive = up) | +| `frame` | β€” | `"local"` (relative to base) or `"global"` (world frame) | + +::: warning Velocity must be a NumPy array +`set_target_velocity()` expects a `np.ndarray` with shape `(3,)` or `(4,)`. Pass `np.array([...])`, not a plain Python list. +::: + +::: warning Velocity timeout +The base stops automatically if no command arrives within **0.25 seconds**. `FlowBaseClient` maintains a heartbeat automatically while connected via a background thread (20 ms interval). +::: + +--- + +## Odometry + +### `get_odometry() β†’ dict` + +```python +odom = client.get_odometry() +# {'translation': array([x, y]), 'rotation': array(theta)} +``` + +Wheel odometry only. Errors accumulate over time β€” integrate visual odometry (RealSense T265, ZED) for precise localization. + +### `reset_odometry() β†’ None` + +Resets position and heading to zero. + +--- + +## Linear Rail API + +Only available when `with_linear_rail=True`. + +### `get_linear_rail_state() β†’ dict` + +```python +state = client.get_linear_rail_state() +# { +# 'position': float, +# 'velocity': float, +# 'upper_limit_triggered': bool, +# 'lower_limit_triggered': bool, +# } +``` + +### `set_linear_rail_velocity(velocity: float) β†’ None` + +```python +client.set_linear_rail_velocity(0.5) # raise +client.set_linear_rail_velocity(0.0) # stop +client.set_linear_rail_velocity(-0.5) # lower +``` + +::: tip Auto-homing +The rail homes to the **lower limit switch** on init. Ensure clearance below before powering on. +::: + +--- + +## Cleanup + +Always close the client when done to stop the background heartbeat thread: + +```python +client.close() +``` + +--- + +## Command-line Client + +Quick functional tests without writing Python: + +```bash +# Read odometry +python i2rt/flow_base/flow_base_client.py --command get_odometry --host 172.6.2.20 + +# Reset odometry +python i2rt/flow_base/flow_base_client.py --command reset_odometry --host 172.6.2.20 + +# Run a short movement test (base will move) +python i2rt/flow_base/flow_base_client.py --command test_command --host 172.6.2.20 + +# Test linear rail (rail will move) +python i2rt/flow_base/flow_base_client.py --command test_linear_rail --host 172.6.2.20 + +# Monitor linear rail state +python i2rt/flow_base/flow_base_client.py --command get_linear_rail_state --host 172.6.2.20 +``` + +--- + +## `Vehicle` (On-board Controller) + +Runs directly on the Pi. Used for the joystick demo. + +```python +from i2rt.flow_base.flow_base_controller import Vehicle +import time + +v = Vehicle() +v.start_control() + +start = time.time() +while time.time() - start < 2.0: + v.set_target_velocity((0.15, 0.0, 0.0), frame="local") +``` + +--- + +## Coordinate Frames + +| Frame | Description | +|-------|-------------| +| `local` | Relative to the current base orientation. Joystick forward = robot forward regardless of heading. | +| `global` | World frame from odometry zero. Similar to drone headless mode. Accumulates error. | + +Switch frames at runtime via the remote **Mode** button, or programmatically by passing `frame=` to `set_target_velocity`. diff --git a/docs/sdk/grippers.md b/docs/sdk/grippers.md new file mode 100644 index 0000000..ebb3c62 --- /dev/null +++ b/docs/sdk/grippers.md @@ -0,0 +1,133 @@ +# Grippers + +YAM supports five interchangeable end-effector options. The gripper type is specified when creating the robot: + +```python +from i2rt.robots.get_robot import get_yam_robot +from i2rt.robots.utils import GripperType + +robot = get_yam_robot(channel="can0", gripper_type=GripperType.LINEAR_4310) +``` + +## Gripper Reference + +### `crank_4310` + +Zero-linkage crank gripper powered by the DM4310 motor. The crank mechanism minimizes the total gripper width β€” ideal for reaching into tight spaces. + + + +| Property | Value | +|----------|-------| +| Motor | DM4310 | +| Mechanism | Zero-linkage crank | +| Calibration | Not required β€” fixed limits (0.0 to -2.7 rad) | +| PD Gains | kp=20, kd=0.5 | +| Best for | Narrow workspace, minimizing sweep width | + +--- + +### `linear_3507` + +Lightweight linear gripper with a DM3507 motor. Smaller and lighter than the 4310 variant. + + + +| Property | Value | +|----------|-------| +| Motor | DM3507 | +| Mechanism | Linear actuator | +| Calibration | **Required** β€” auto-detected on startup | +| PD Gains | kp=10, kd=0.3 | +| Best for | Weight-sensitive setups | + +::: warning Calibration required +Because the motor travels more than 2pi radians over the full stroke, the `linear_3507` needs to know its start position. On startup, the SDK automatically runs a calibration routine that moves the gripper in both directions to detect limits. Ensure the gripper can move freely during initialization. +::: + +--- + +### `linear_4310` + +Standard linear gripper with the heavier DM4310 motor. Slightly more gripping force than the 3507. + + + +| Property | Value | +|----------|-------| +| Motor | DM4310 | +| Mechanism | Linear actuator | +| Calibration | **Required** β€” same auto-calibration as `linear_3507` | +| PD Gains | kp=20, kd=0.5 | +| Best for | General-purpose tasks, higher force | + +--- + +### `yam_teaching_handle` + +The leader arm handle β€” not a manipulation gripper, but a hand controller for teleoperation. + + + +| Feature | Description | +|---------|-------------| +| Trigger | Controls follower gripper open/close | +| Top button | Enable/disable arm synchronization | +| Second button | User-programmable | + +For full usage β€” trigger reading, encoder calibration, and teleoperation setup β€” see the [YAM Leader Arm](/products/yam-leader) page. + +--- + +### `no_gripper` + +Arm-only configuration with no end effector. Use when the application doesn't require grasping. + +```python +robot = get_yam_robot(gripper_type=GripperType.NO_GRIPPER) +# robot.num_dofs() returns 6 (arm joints only) +``` + +--- + +## Gripper Models + +MuJoCo XML models for each gripper. Arm and gripper models are combined at runtime: + +``` +i2rt/robot_models/gripper/ +β”œβ”€β”€ crank_4310/ +β”‚ β”œβ”€β”€ crank_4310.xml +β”‚ └── assets/link_6_collision.stl +β”œβ”€β”€ linear_3507/ +β”‚ β”œβ”€β”€ linear_3507.xml +β”‚ └── assets/ gripper.stl tip_left.stl tip_right.stl +β”œβ”€β”€ linear_4310/ +β”‚ β”œβ”€β”€ linear_4310.xml +β”‚ └── assets/ gripper.stl tip_left.stl tip_right.stl +β”œβ”€β”€ yam_teaching_handle/ +β”‚ └── yam_teaching_handle.xml +└── no_gripper/ + └── no_gripper.xml +``` + +## Gripper Force Limiting + +The SDK includes automatic gripper force limiting when the gripper is clogged (stalled against an object). This is enabled by default with `limit_gripper_force=50.0` N. The system monitors motor effort and speed to detect when the gripper has hit an object, then limits the applied torque accordingly. + +## See Also + +- [YAM Arm API](/sdk/yam-arm) β€” `get_observations()` for reading gripper state +- [Bimanual Teleoperation](/examples/bimanual-teleoperation) diff --git a/docs/sdk/index.md b/docs/sdk/index.md new file mode 100644 index 0000000..1faaf27 --- /dev/null +++ b/docs/sdk/index.md @@ -0,0 +1,24 @@ +# SDK Reference + +The `i2rt` package provides Python interfaces for all I2RT hardware. Everything is importable from the top-level package after installing with `uv pip install -e .`. + +## Modules + +| Module | Description | +|--------|-------------| +| `i2rt.robots.get_robot` | Factory function `get_yam_robot()` for creating arm instances | +| `i2rt.robots.motor_chain_robot` | `MotorChainRobot` class β€” joint control, gravity compensation | +| `i2rt.robots.robot` | `Robot` protocol β€” abstract interface for all robots | +| `i2rt.robots.sim_robot` | `SimRobot` β€” MuJoCo-based simulation robot | +| `i2rt.robots.utils` | `ArmType`, `GripperType` enums, XML combiner, gripper utilities | +| `i2rt.flow_base.flow_base_controller` | Flow Base on-board control (runs on Pi) | +| `i2rt.flow_base.flow_base_client` | Flow Base remote network client | +| `i2rt.motor_drivers` | Low-level DM series motor communication (CAN bus) | +| `i2rt.motor_config_tool` | One-time motor configuration utilities (zero offset, timeout) | +| `i2rt.utils` | MuJoCo helpers, Viser visualization, gamepad, encoder utilities | + +## Pages + +- [YAM Arm API](/sdk/yam-arm) +- [Flow Base API](/sdk/flow-base) +- [Grippers](/sdk/grippers) diff --git a/docs/sdk/yam-arm.md b/docs/sdk/yam-arm.md new file mode 100644 index 0000000..d075c3d --- /dev/null +++ b/docs/sdk/yam-arm.md @@ -0,0 +1,245 @@ +# YAM Arm API + +## Import + +```python +from i2rt.robots.get_robot import get_yam_robot +from i2rt.robots.utils import ArmType, GripperType +``` + +## `get_yam_robot()` + +Factory function β€” the recommended way to create a robot instance. + +```python +robot = get_yam_robot( + channel="can0", + arm_type=ArmType.YAM, + gripper_type=GripperType.LINEAR_4310, + zero_gravity_mode=True, + ee_mass=None, + ee_inertia=None, + sim=False, +) +``` + +| Parameter | Type | Default | Description | +|-----------|------|---------|-------------| +| `channel` | `str` | `"can0"` | CAN interface name (e.g. `can0`, `can_follower_l`). Ignored in sim mode. | +| `arm_type` | `ArmType` | `ArmType.YAM` | Arm variant: `YAM`, `YAM_PRO`, `YAM_ULTRA`, `BIG_YAM` | +| `gripper_type` | `GripperType` | `GripperType.LINEAR_4310` | Gripper type. See [Grippers](/sdk/grippers) | +| `zero_gravity_mode` | `bool` | `True` | Enable gravity compensation on init | +| `ee_mass` | `float \| None` | `None` | End-effector mass override (kg) for MuJoCo inertial | +| `ee_inertia` | `np.ndarray \| None` | `None` | End-effector inertia override β€” 10-element array `[ipos(3), quat(4), diaginertia(3)]` | +| `sim` | `bool` | `False` | If `True`, return a `SimRobot` (no hardware needed) | + +**Returns:** `MotorChainRobot` instance (or `SimRobot` when `sim=True`). + +::: tip Arm types +Since v1.0, all arm variants use the same factory function. Pass `arm_type=ArmType.BIG_YAM` instead of the removed `get_big_yam_robot()`. +::: + +::: tip Zero-gravity vs PD mode +With `zero_gravity_mode=True` the arm floats β€” great for teleoperation. With `False`, the arm holds its current joint positions as PD targets. Use `False` when operating without the motor safety timeout. +::: + +--- + +## `MotorChainRobot` + +### `num_dofs() β†’ int` + +Returns the number of controllable degrees of freedom (arm joints + gripper if present). + +```python +n = robot.num_dofs() +# 7 (6 arm joints + 1 gripper), or 6 if no gripper +``` + +### `get_joint_pos() β†’ np.ndarray` + +Returns the current joint positions as a NumPy array in **radians**. Includes all DOFs (arm + gripper). + +```python +q = robot.get_joint_pos() +# shape: (7,) for 6-joint arm + gripper +# shape: (6,) for arm-only (no_gripper) +``` + +### `command_joint_pos(joint_pos: np.ndarray) β†’ None` + +Commands all joints to move to `joint_pos` (radians). The controller uses PD tracking. For robots with a gripper, the last element controls the gripper position (normalized 0–1 for linear grippers). + +```python +import numpy as np +robot.command_joint_pos(np.zeros(7)) # move arm to home, close gripper +``` + +::: warning Joint limits +Joint limits are defined in the MuJoCo XML model (e.g. `i2rt/robot_models/arm/yam/yam.xml`). A 0.15 rad safety buffer is applied automatically. Exceeding limits can cause motor errors. +::: + +### `command_joint_state(joint_state: dict) β†’ None` + +Commands joints with position, velocity, and optional PD gains. + +```python +robot.command_joint_state({ + "pos": target_positions, # np.ndarray + "vel": target_velocities, # np.ndarray + "kp": custom_kp, # optional, overrides defaults + "kd": custom_kd, # optional, overrides defaults +}) +``` + +### `get_observations() β†’ dict` + +Returns a dictionary of all robot observations. This is the **primary method** for reading robot state. + +```python +obs = robot.get_observations() +# Without gripper: +# obs["joint_pos"] β€” (6,) joint positions +# obs["joint_vel"] β€” (6,) joint velocities +# obs["joint_eff"] β€” (6,) joint efforts (torques) +# +# With gripper: +# obs["joint_pos"] β€” (6,) arm joint positions only +# obs["joint_vel"] β€” (6,) arm joint velocities +# obs["joint_eff"] β€” (6,) arm joint efforts +# obs["gripper_pos"] β€” (1,) gripper position +# obs["gripper_vel"] β€” (1,) gripper velocity +# obs["gripper_eff"] β€” (1,) gripper effort +``` + +### `move_joints(target, time_interval_s=2.0) β†’ None` + +Smoothly interpolates from the current position to `target` over `time_interval_s` seconds (blocking). + +```python +robot.move_joints(np.zeros(7), time_interval_s=3.0) +``` + +### `zero_torque_mode() β†’ None` + +Enters zero-torque mode β€” all PD gains are set to zero, motors produce no active torque. + +### `update_kp_kd(kp, kd) β†’ None` + +Update the PD gains at runtime. + +```python +robot.update_kp_kd(kp=new_kp_array, kd=new_kd_array) +``` + +### `close() β†’ None` + +Safely shuts down the robot: stops the control thread and closes the CAN interface. + +```python +robot.close() +``` + +--- + +## Command-line: Zero-gravity test + +```bash +# Arm enters gravity-compensated floating mode +python i2rt/robots/get_robot.py \ + --channel can0 \ + --gripper linear_4310 + +# Test with BIG YAM +python i2rt/robots/get_robot.py \ + --arm big_yam \ + --channel can0 + +# Simulation mode (no hardware needed) +python i2rt/robots/get_robot.py --sim +``` + +--- + +## Motor Configuration Utilities + +### Set timeout + +```bash +# Disable the 400 ms safety timeout +python i2rt/motor_config_tool/set_timeout.py --channel can0 +python i2rt/motor_config_tool/set_timeout.py --channel can0 # run twice + +# Re-enable +python i2rt/motor_config_tool/set_timeout.py --channel can0 --timeout +``` + +### Zero motor offset + +```bash +# Zero motor ID 1 (run for each motor 1–6 as needed) +python i2rt/motor_config_tool/set_zero.py --channel can0 --motor_id 1 +``` + +--- + +## MuJoCo Models + +The SDK uses MuJoCo for gravity computation, simulation, and visualization. Arm and gripper models are combined at runtime via `combine_arm_and_gripper_xml()`. + +``` +i2rt/robot_models/ +β”œβ”€β”€ arm/ +β”‚ β”œβ”€β”€ yam/yam.xml +β”‚ β”œβ”€β”€ yam_pro/yam_pro.xml +β”‚ β”œβ”€β”€ yam_ultra/yam_ultra.xml +β”‚ └── big_yam/big_yam.xml +└── gripper/ + β”œβ”€β”€ crank_4310/crank_4310.xml + β”œβ”€β”€ linear_3507/linear_3507.xml + β”œβ”€β”€ linear_4310/linear_4310.xml + β”œβ”€β”€ yam_teaching_handle/yam_teaching_handle.xml + └── no_gripper/no_gripper.xml +``` + +Launch the visualizer without hardware: + +```bash +python examples/minimum_gello/minimum_gello.py --mode visualizer_local +``` + +--- + +## Leader–Follower Script + +`examples/minimum_gello/minimum_gello.py` is the primary teleoperation entry point: + +``` +usage: minimum_gello.py [options] + + --gripper TYPE Gripper type (default: linear_4310) + --mode MODE follower | leader | visualizer_local + --can-channel CHAN CAN interface (default: can0) + --bilateral_kp FLOAT Bilateral stiffness 0.1–0.3 (default: 0.2) +``` + +Higher `bilateral_kp` = leader arm feels heavier (more force feedback from follower load). + +--- + +## Arm Hardware Variants + +| Arm Type | Shoulder Motors | Elbow/Wrist Motors | Gravity Factor | Notes | +|----------|----------------|-------------------|----------------|-------| +| `YAM` | 3Γ— DM4340 | 3Γ— DM4310 | 1.3 | Standard arm | +| `YAM_PRO` | 3Γ— DM4340 | 3Γ— DM4310 | 1.3 | Same as YAM | +| `YAM_ULTRA` | 3Γ— DM4340 | 3Γ— DM4310 | 1.3 | Different joint 3 limit | +| `BIG_YAM` | 2Γ— DM6248 | 2Γ— DM4340 + 2Γ— DM4310 | 1.0 | Heavier, reversed joint 2 | + +--- + +## See Also + +- [Quick Start](/getting-started/quick-start) +- [Grippers](/sdk/grippers) +- [Bimanual Teleoperation Example](/examples/bimanual-teleoperation) diff --git a/docs/support/troubleshooting.md b/docs/support/troubleshooting.md new file mode 100644 index 0000000..f175d10 --- /dev/null +++ b/docs/support/troubleshooting.md @@ -0,0 +1,113 @@ +# Troubleshooting + +## CAN Bus Issues + +### `ls -l /sys/class/net/can*` shows no devices + +- Unplug and replug the USB-CAN adapter +- Try a different USB port +- Run `dmesg | tail -20` to check for USB errors +- Verify the adapter firmware (some CANable units need flashing) + +### `RTNETLINK answers: Device or resource busy` + +```bash +sh scripts/reset_all_can.sh +``` + +If that fails, unplug the USB-CAN adapter, wait 5 seconds, and replug. + +### CAN interface is `UP` but no motor response + +- Verify CAN bitrate matches: `1000000` (1 Mbit/s) +- Check that the motor is powered (indicator LED on) +- Check cable polarity (CAN-H, CAN-L, GND) +- Verify motor ID matches what the code expects + +--- + +## YAM Arm Issues + +### Motor timeout errors (arm enters damping mode) + +The default 400 ms timeout is triggering β€” your control loop is too slow. + +Options: +1. Optimize the control loop to send commands faster than 400 ms +2. Disable the timeout for testing (see [Hardware Setup](/getting-started/hardware-setup#motor-configuration)) +3. Contact [sales@i2rt.com](mailto:sales@i2rt.com) for bulk firmware with timeout disabled + +### Arm drifts or vibrates in zero-gravity mode + +- Add a PD target to stabilize when using no timeout: + ```python + robot = get_yam_robot(channel="can0", zero_gravity_mode=False) + ``` +- Check for loose cable connections at each joint +- Verify the URDF/MuJoCo model matches your arm configuration + +### Gripper doesn't reach full open/close (linear gripper) + +The linear gripper needs to start in the closed position. Calibrate: +1. Power off the arm +2. Manually close the gripper fingers completely +3. Power on and initialize normally + +--- + +## Flow Base Issues + +### Remote is unresponsive + +Toggle the remote power switch off, wait 3 seconds, power back on. The remote enters sleep mode after inactivity. + +### Odometry is inaccurate + +Wheel odometry is inherently imprecise. For precise localization: +- Use `reset_odometry()` at known positions +- Integrate a visual odometry sensor (RealSense T265, ZED) + +### Linear rail not homing + +1. Check GPIO connections between the Pi and limit switch +2. Run `get_linear_rail_state()` to inspect switch state +3. Manually verify both limit switches activate when pressed + +### Base keeps stopping unexpectedly + +The 0.25 s velocity timeout is triggering. Ensure `FlowBaseClient` maintains its heartbeat β€” verify your control loop sends commands at > 4 Hz. + +### `RTNETLINK answers: Device or resource busy` (Flow Base Pi) + +```bash +ssh i2rt@172.6.2.20 +sh ~/i2rt/scripts/reset_all_can.sh +``` + +--- + +## Installation Issues + +### `uv pip install -e .` fails with build errors + +```bash +sudo apt install build-essential python3-dev linux-headers-$(uname -r) +uv pip install -e . +``` + +### MuJoCo viewer doesn't open + +- Ensure you have a display (or set up virtual framebuffer for headless) +- Try: `export DISPLAY=:0` before running +- On SSH sessions: `export MUJOCO_GL=egl` for off-screen rendering + +--- + +## Getting Help + +| Channel | Link | +|---------|------| +| GitHub Issues | [github.com/i2rt-robotics/i2rt/issues](https://github.com/i2rt-robotics/i2rt/issues) | +| Discord | [discord.gg/i2rt](https://discord.gg/i2rt) | +| Email | [support@i2rt.com](mailto:support@i2rt.com) | +| Sales | [sales@i2rt.com](mailto:sales@i2rt.com) | diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..216764e --- /dev/null +++ b/package-lock.json @@ -0,0 +1,2520 @@ +{ + "name": "i2rt-docs", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "i2rt-docs", + "dependencies": { + "three": "^0.170.0" + }, + "devDependencies": { + "vitepress": "^1.6.3" + } + }, + "node_modules/@algolia/abtesting": { + "version": "1.15.1", + "resolved": "https://registry.npmjs.org/@algolia/abtesting/-/abtesting-1.15.1.tgz", + "integrity": "sha512-2yuIC48rUuHGhU1U5qJ9kJHaxYpJ0jpDHJVI5ekOxSMYXlH4+HP+pA31G820lsAznfmu2nzDV7n5RO44zIY1zw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@algolia/client-common": "5.49.1", + "@algolia/requester-browser-xhr": "5.49.1", + "@algolia/requester-fetch": "5.49.1", + "@algolia/requester-node-http": "5.49.1" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@algolia/autocomplete-core": { + "version": "1.17.7", + "resolved": "https://registry.npmjs.org/@algolia/autocomplete-core/-/autocomplete-core-1.17.7.tgz", + "integrity": "sha512-BjiPOW6ks90UKl7TwMv7oNQMnzU+t/wk9mgIDi6b1tXpUek7MW0lbNOUHpvam9pe3lVCf4xPFT+lK7s+e+fs7Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@algolia/autocomplete-plugin-algolia-insights": "1.17.7", + "@algolia/autocomplete-shared": "1.17.7" + } + }, + "node_modules/@algolia/autocomplete-plugin-algolia-insights": { + "version": "1.17.7", + "resolved": "https://registry.npmjs.org/@algolia/autocomplete-plugin-algolia-insights/-/autocomplete-plugin-algolia-insights-1.17.7.tgz", + "integrity": "sha512-Jca5Ude6yUOuyzjnz57og7Et3aXjbwCSDf/8onLHSQgw1qW3ALl9mrMWaXb5FmPVkV3EtkD2F/+NkT6VHyPu9A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@algolia/autocomplete-shared": "1.17.7" + }, + "peerDependencies": { + "search-insights": ">= 1 < 3" + } + }, + "node_modules/@algolia/autocomplete-preset-algolia": { + "version": "1.17.7", + "resolved": "https://registry.npmjs.org/@algolia/autocomplete-preset-algolia/-/autocomplete-preset-algolia-1.17.7.tgz", + "integrity": "sha512-ggOQ950+nwbWROq2MOCIL71RE0DdQZsceqrg32UqnhDz8FlO9rL8ONHNsI2R1MH0tkgVIDKI/D0sMiUchsFdWA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@algolia/autocomplete-shared": "1.17.7" + }, + "peerDependencies": { + "@algolia/client-search": ">= 4.9.1 < 6", + "algoliasearch": ">= 4.9.1 < 6" + } + }, + "node_modules/@algolia/autocomplete-shared": { + "version": "1.17.7", + "resolved": "https://registry.npmjs.org/@algolia/autocomplete-shared/-/autocomplete-shared-1.17.7.tgz", + "integrity": "sha512-o/1Vurr42U/qskRSuhBH+VKxMvkkUVTLU6WZQr+L5lGZZLYWyhdzWjW0iGXY7EkwRTjBqvN2EsR81yCTGV/kmg==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@algolia/client-search": ">= 4.9.1 < 6", + "algoliasearch": ">= 4.9.1 < 6" + } + }, + "node_modules/@algolia/client-abtesting": { + "version": "5.49.1", + "resolved": "https://registry.npmjs.org/@algolia/client-abtesting/-/client-abtesting-5.49.1.tgz", + "integrity": "sha512-h6M7HzPin+45/l09q0r2dYmocSSt2MMGOOk5c4O5K/bBBlEwf1BKfN6z+iX4b8WXcQQhf7rgQwC52kBZJt/ZZw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@algolia/client-common": "5.49.1", + "@algolia/requester-browser-xhr": "5.49.1", + "@algolia/requester-fetch": "5.49.1", + "@algolia/requester-node-http": "5.49.1" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@algolia/client-analytics": { + "version": "5.49.1", + "resolved": "https://registry.npmjs.org/@algolia/client-analytics/-/client-analytics-5.49.1.tgz", + "integrity": "sha512-048T9/Z8OeLmTk8h76QUqaNFp7Rq2VgS2Zm6Y2tNMYGQ1uNuzePY/udB5l5krlXll7ZGflyCjFvRiOtlPZpE9g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@algolia/client-common": "5.49.1", + "@algolia/requester-browser-xhr": "5.49.1", + "@algolia/requester-fetch": "5.49.1", + "@algolia/requester-node-http": "5.49.1" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@algolia/client-common": { + "version": "5.49.1", + "resolved": "https://registry.npmjs.org/@algolia/client-common/-/client-common-5.49.1.tgz", + "integrity": "sha512-vp5/a9ikqvf3mn9QvHN8PRekn8hW34aV9eX+O0J5mKPZXeA6Pd5OQEh2ZWf7gJY6yyfTlLp5LMFzQUAU+Fpqpg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@algolia/client-insights": { + "version": "5.49.1", + "resolved": "https://registry.npmjs.org/@algolia/client-insights/-/client-insights-5.49.1.tgz", + "integrity": "sha512-B6N7PgkvYrul3bntTz/l6uXnhQ2bvP+M7NqTcayh681tSqPaA5cJCUBp/vrP7vpPRpej4Eeyx2qz5p0tE/2N2g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@algolia/client-common": "5.49.1", + "@algolia/requester-browser-xhr": "5.49.1", + "@algolia/requester-fetch": "5.49.1", + "@algolia/requester-node-http": "5.49.1" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@algolia/client-personalization": { + "version": "5.49.1", + "resolved": "https://registry.npmjs.org/@algolia/client-personalization/-/client-personalization-5.49.1.tgz", + "integrity": "sha512-v+4DN+lkYfBd01Hbnb9ZrCHe7l+mvihyx218INRX/kaCXROIWUDIT1cs3urQxfE7kXBFnLsqYeOflQALv/gA5w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@algolia/client-common": "5.49.1", + "@algolia/requester-browser-xhr": "5.49.1", + "@algolia/requester-fetch": "5.49.1", + "@algolia/requester-node-http": "5.49.1" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@algolia/client-query-suggestions": { + "version": "5.49.1", + "resolved": "https://registry.npmjs.org/@algolia/client-query-suggestions/-/client-query-suggestions-5.49.1.tgz", + "integrity": "sha512-Un11cab6ZCv0W+Jiak8UktGIqoa4+gSNgEZNfG8m8eTsXGqwIEr370H3Rqwj87zeNSlFpH2BslMXJ/cLNS1qtg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@algolia/client-common": "5.49.1", + "@algolia/requester-browser-xhr": "5.49.1", + "@algolia/requester-fetch": "5.49.1", + "@algolia/requester-node-http": "5.49.1" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@algolia/client-search": { + "version": "5.49.1", + "resolved": "https://registry.npmjs.org/@algolia/client-search/-/client-search-5.49.1.tgz", + "integrity": "sha512-Nt9hri7nbOo0RipAsGjIssHkpLMHHN/P7QqENywAq5TLsoYDzUyJGny8FEiD/9KJUxtGH8blGpMedilI6kK3rA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@algolia/client-common": "5.49.1", + "@algolia/requester-browser-xhr": "5.49.1", + "@algolia/requester-fetch": "5.49.1", + "@algolia/requester-node-http": "5.49.1" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@algolia/ingestion": { + "version": "1.49.1", + "resolved": "https://registry.npmjs.org/@algolia/ingestion/-/ingestion-1.49.1.tgz", + "integrity": "sha512-b5hUXwDqje0Y4CpU6VL481DXgPgxpTD5sYMnfQTHKgUispGnaCLCm2/T9WbJo1YNUbX3iHtYDArp804eD6CmRQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@algolia/client-common": "5.49.1", + "@algolia/requester-browser-xhr": "5.49.1", + "@algolia/requester-fetch": "5.49.1", + "@algolia/requester-node-http": "5.49.1" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@algolia/monitoring": { + "version": "1.49.1", + "resolved": "https://registry.npmjs.org/@algolia/monitoring/-/monitoring-1.49.1.tgz", + "integrity": "sha512-bvrXwZ0WsL3rN6Q4m4QqxsXFCo6WAew7sAdrpMQMK4Efn4/W920r9ptOuckejOSSvyLr9pAWgC5rsHhR2FYuYw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@algolia/client-common": "5.49.1", + "@algolia/requester-browser-xhr": "5.49.1", + "@algolia/requester-fetch": "5.49.1", + "@algolia/requester-node-http": "5.49.1" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@algolia/recommend": { + "version": "5.49.1", + "resolved": "https://registry.npmjs.org/@algolia/recommend/-/recommend-5.49.1.tgz", + "integrity": "sha512-h2yz3AGeGkQwNgbLmoe3bxYs8fac4An1CprKTypYyTU/k3Q+9FbIvJ8aS1DoBKaTjSRZVoyQS7SZQio6GaHbZw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@algolia/client-common": "5.49.1", + "@algolia/requester-browser-xhr": "5.49.1", + "@algolia/requester-fetch": "5.49.1", + "@algolia/requester-node-http": "5.49.1" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@algolia/requester-browser-xhr": { + "version": "5.49.1", + "resolved": "https://registry.npmjs.org/@algolia/requester-browser-xhr/-/requester-browser-xhr-5.49.1.tgz", + "integrity": "sha512-2UPyRuUR/qpqSqH8mxFV5uBZWEpxhGPHLlx9Xf6OVxr79XO2ctzZQAhsmTZ6X22x+N8MBWpB9UEky7YU2HGFgA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@algolia/client-common": "5.49.1" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@algolia/requester-fetch": { + "version": "5.49.1", + "resolved": "https://registry.npmjs.org/@algolia/requester-fetch/-/requester-fetch-5.49.1.tgz", + "integrity": "sha512-N+xlE4lN+wpuT+4vhNEwPVlrfN+DWAZmSX9SYhbz986Oq8AMsqdntOqUyiOXVxYsQtfLwmiej24vbvJGYv1Qtw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@algolia/client-common": "5.49.1" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@algolia/requester-node-http": { + "version": "5.49.1", + "resolved": "https://registry.npmjs.org/@algolia/requester-node-http/-/requester-node-http-5.49.1.tgz", + "integrity": "sha512-zA5bkUOB5PPtTr182DJmajCiizHp0rCJQ0Chf96zNFvkdESKYlDeYA3tQ7r2oyHbu/8DiohAQ5PZ85edctzbXA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@algolia/client-common": "5.49.1" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@babel/helper-string-parser": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz", + "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.28.5.tgz", + "integrity": "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/parser": { + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.0.tgz", + "integrity": "sha512-IyDgFV5GeDUVX4YdF/3CPULtVGSXXMLh1xVIgdCgxApktqnQV0r7/8Nqthg+8YLGaAtdyIlo2qIdZrbCv4+7ww==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.29.0" + }, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/types": { + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.0.tgz", + "integrity": "sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-string-parser": "^7.27.1", + "@babel/helper-validator-identifier": "^7.28.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@docsearch/css": { + "version": "3.8.2", + "resolved": "https://registry.npmjs.org/@docsearch/css/-/css-3.8.2.tgz", + "integrity": "sha512-y05ayQFyUmCXze79+56v/4HpycYF3uFqB78pLPrSV5ZKAlDuIAAJNhaRi8tTdRNXh05yxX/TyNnzD6LwSM89vQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@docsearch/js": { + "version": "3.8.2", + "resolved": "https://registry.npmjs.org/@docsearch/js/-/js-3.8.2.tgz", + "integrity": "sha512-Q5wY66qHn0SwA7Taa0aDbHiJvaFJLOJyHmooQ7y8hlwwQLQ/5WwCcoX0g7ii04Qi2DJlHsd0XXzJ8Ypw9+9YmQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@docsearch/react": "3.8.2", + "preact": "^10.0.0" + } + }, + "node_modules/@docsearch/react": { + "version": "3.8.2", + "resolved": "https://registry.npmjs.org/@docsearch/react/-/react-3.8.2.tgz", + "integrity": "sha512-xCRrJQlTt8N9GU0DG4ptwHRkfnSnD/YpdeaXe02iKfqs97TkZJv60yE+1eq/tjPcVnTW8dP5qLP7itifFVV5eg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@algolia/autocomplete-core": "1.17.7", + "@algolia/autocomplete-preset-algolia": "1.17.7", + "@docsearch/css": "3.8.2", + "algoliasearch": "^5.14.2" + }, + "peerDependencies": { + "@types/react": ">= 16.8.0 < 19.0.0", + "react": ">= 16.8.0 < 19.0.0", + "react-dom": ">= 16.8.0 < 19.0.0", + "search-insights": ">= 1 < 3" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "react": { + "optional": true + }, + "react-dom": { + "optional": true + }, + "search-insights": { + "optional": true + } + } + }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.21.5.tgz", + "integrity": "sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.21.5.tgz", + "integrity": "sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.21.5.tgz", + "integrity": "sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.21.5.tgz", + "integrity": "sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.21.5.tgz", + "integrity": "sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.21.5.tgz", + "integrity": "sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.21.5.tgz", + "integrity": "sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.21.5.tgz", + "integrity": "sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.21.5.tgz", + "integrity": "sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.21.5.tgz", + "integrity": "sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.21.5.tgz", + "integrity": "sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.21.5.tgz", + "integrity": "sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.21.5.tgz", + "integrity": "sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==", + "cpu": [ + "mips64el" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.21.5.tgz", + "integrity": "sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.21.5.tgz", + "integrity": "sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.21.5.tgz", + "integrity": "sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.21.5.tgz", + "integrity": "sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.21.5.tgz", + "integrity": "sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.21.5.tgz", + "integrity": "sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.21.5.tgz", + "integrity": "sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.21.5.tgz", + "integrity": "sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.21.5.tgz", + "integrity": "sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.21.5.tgz", + "integrity": "sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@iconify-json/simple-icons": { + "version": "1.2.71", + "resolved": "https://registry.npmjs.org/@iconify-json/simple-icons/-/simple-icons-1.2.71.tgz", + "integrity": "sha512-rNoDFbq1fAYiEexBvrw613/xiUOPEu5MKVV/X8lI64AgdTzLQUUemr9f9fplxUMPoxCBP2rWzlhOEeTHk/Sf0Q==", + "dev": true, + "license": "CC0-1.0", + "dependencies": { + "@iconify/types": "*" + } + }, + "node_modules/@iconify/types": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@iconify/types/-/types-2.0.0.tgz", + "integrity": "sha512-+wluvCrRhXrhyOmRDJ3q8mux9JkKy5SJ/v8ol2tu4FVjyYvtEzkc/3pK15ET6RKg4b4w4BmTk1+gsCUhf21Ykg==", + "dev": true, + "license": "MIT" + }, + "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==", + "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/@shikijs/core": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@shikijs/core/-/core-2.5.0.tgz", + "integrity": "sha512-uu/8RExTKtavlpH7XqnVYBrfBkUc20ngXiX9NSrBhOVZYv/7XQRKUyhtkeflY5QsxC0GbJThCerruZfsUaSldg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@shikijs/engine-javascript": "2.5.0", + "@shikijs/engine-oniguruma": "2.5.0", + "@shikijs/types": "2.5.0", + "@shikijs/vscode-textmate": "^10.0.2", + "@types/hast": "^3.0.4", + "hast-util-to-html": "^9.0.4" + } + }, + "node_modules/@shikijs/engine-javascript": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@shikijs/engine-javascript/-/engine-javascript-2.5.0.tgz", + "integrity": "sha512-VjnOpnQf8WuCEZtNUdjjwGUbtAVKuZkVQ/5cHy/tojVVRIRtlWMYVjyWhxOmIq05AlSOv72z7hRNRGVBgQOl0w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@shikijs/types": "2.5.0", + "@shikijs/vscode-textmate": "^10.0.2", + "oniguruma-to-es": "^3.1.0" + } + }, + "node_modules/@shikijs/engine-oniguruma": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@shikijs/engine-oniguruma/-/engine-oniguruma-2.5.0.tgz", + "integrity": "sha512-pGd1wRATzbo/uatrCIILlAdFVKdxImWJGQ5rFiB5VZi2ve5xj3Ax9jny8QvkaV93btQEwR/rSz5ERFpC5mKNIw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@shikijs/types": "2.5.0", + "@shikijs/vscode-textmate": "^10.0.2" + } + }, + "node_modules/@shikijs/langs": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@shikijs/langs/-/langs-2.5.0.tgz", + "integrity": "sha512-Qfrrt5OsNH5R+5tJ/3uYBBZv3SuGmnRPejV9IlIbFH3HTGLDlkqgHymAlzklVmKBjAaVmkPkyikAV/sQ1wSL+w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@shikijs/types": "2.5.0" + } + }, + "node_modules/@shikijs/themes": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@shikijs/themes/-/themes-2.5.0.tgz", + "integrity": "sha512-wGrk+R8tJnO0VMzmUExHR+QdSaPUl/NKs+a4cQQRWyoc3YFbUzuLEi/KWK1hj+8BfHRKm2jNhhJck1dfstJpiw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@shikijs/types": "2.5.0" + } + }, + "node_modules/@shikijs/transformers": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@shikijs/transformers/-/transformers-2.5.0.tgz", + "integrity": "sha512-SI494W5X60CaUwgi8u4q4m4s3YAFSxln3tzNjOSYqq54wlVgz0/NbbXEb3mdLbqMBztcmS7bVTaEd2w0qMmfeg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@shikijs/core": "2.5.0", + "@shikijs/types": "2.5.0" + } + }, + "node_modules/@shikijs/types": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@shikijs/types/-/types-2.5.0.tgz", + "integrity": "sha512-ygl5yhxki9ZLNuNpPitBWvcy9fsSKKaRuO4BAlMyagszQidxcpLAr0qiW/q43DtSIDxO6hEbtYLiFZNXO/hdGw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@shikijs/vscode-textmate": "^10.0.2", + "@types/hast": "^3.0.4" + } + }, + "node_modules/@shikijs/vscode-textmate": { + "version": "10.0.2", + "resolved": "https://registry.npmjs.org/@shikijs/vscode-textmate/-/vscode-textmate-10.0.2.tgz", + "integrity": "sha512-83yeghZ2xxin3Nj8z1NMd/NCuca+gsYXswywDy5bHvwlWL8tpTQmzGeUuHd9FC3E/SBEMvzJRwWEOz5gGes9Qg==", + "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==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/hast": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/hast/-/hast-3.0.4.tgz", + "integrity": "sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/unist": "*" + } + }, + "node_modules/@types/linkify-it": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/@types/linkify-it/-/linkify-it-5.0.0.tgz", + "integrity": "sha512-sVDA58zAw4eWAffKOaQH5/5j3XeayukzDk+ewSsnv3p4yJEZHCCzMDiZM8e0OUrRvmpGZ85jf4yDHkHsgBNr9Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/markdown-it": { + "version": "14.1.2", + "resolved": "https://registry.npmjs.org/@types/markdown-it/-/markdown-it-14.1.2.tgz", + "integrity": "sha512-promo4eFwuiW+TfGxhi+0x3czqTYJkG8qB17ZUJiVF10Xm7NLVRSLUsfRTU/6h1e24VvRnXCx+hG7li58lkzog==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/linkify-it": "^5", + "@types/mdurl": "^2" + } + }, + "node_modules/@types/mdast": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/@types/mdast/-/mdast-4.0.4.tgz", + "integrity": "sha512-kGaNbPh1k7AFzgpud/gMdvIm5xuECykRR+JnWKQno9TAXVa6WIVCGTPvYGekIDL4uwCZQSYbUxNBSb1aUo79oA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/unist": "*" + } + }, + "node_modules/@types/mdurl": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@types/mdurl/-/mdurl-2.0.0.tgz", + "integrity": "sha512-RGdgjQUZba5p6QEFAVx2OGb8rQDL/cPRG7GiedRzMcJ1tYnUANBncjbSB1NRGwbvjcPeikRABz2nshyPk1bhWg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/unist": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.3.tgz", + "integrity": "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/web-bluetooth": { + "version": "0.0.21", + "resolved": "https://registry.npmjs.org/@types/web-bluetooth/-/web-bluetooth-0.0.21.tgz", + "integrity": "sha512-oIQLCGWtcFZy2JW77j9k8nHzAOpqMHLQejDA48XXMWH6tjCQHz5RCFz1bzsmROyL6PUm+LLnUiI4BCn221inxA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@ungap/structured-clone": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.3.0.tgz", + "integrity": "sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g==", + "dev": true, + "license": "ISC" + }, + "node_modules/@vitejs/plugin-vue": { + "version": "5.2.4", + "resolved": "https://registry.npmjs.org/@vitejs/plugin-vue/-/plugin-vue-5.2.4.tgz", + "integrity": "sha512-7Yx/SXSOcQq5HiiV3orevHUFn+pmMB4cgbEkDYgnkUWb0WfeQ/wa2yFv6D5ICiCQOVpjA7vYDXrC7AGO8yjDHA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.0.0 || >=20.0.0" + }, + "peerDependencies": { + "vite": "^5.0.0 || ^6.0.0", + "vue": "^3.2.25" + } + }, + "node_modules/@vue/compiler-core": { + "version": "3.5.29", + "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.5.29.tgz", + "integrity": "sha512-cuzPhD8fwRHk8IGfmYaR4eEe4cAyJEL66Ove/WZL7yWNL134nqLddSLwNRIsFlnnW1kK+p8Ck3viFnC0chXCXw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.29.0", + "@vue/shared": "3.5.29", + "entities": "^7.0.1", + "estree-walker": "^2.0.2", + "source-map-js": "^1.2.1" + } + }, + "node_modules/@vue/compiler-dom": { + "version": "3.5.29", + "resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.5.29.tgz", + "integrity": "sha512-n0G5o7R3uBVmVxjTIYcz7ovr8sy7QObFG8OQJ3xGCDNhbG60biP/P5KnyY8NLd81OuT1WJflG7N4KWYHaeeaIg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vue/compiler-core": "3.5.29", + "@vue/shared": "3.5.29" + } + }, + "node_modules/@vue/compiler-sfc": { + "version": "3.5.29", + "resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.5.29.tgz", + "integrity": "sha512-oJZhN5XJs35Gzr50E82jg2cYdZQ78wEwvRO6Y63TvLVTc+6xICzJHP1UIecdSPPYIbkautNBanDiWYa64QSFIA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.29.0", + "@vue/compiler-core": "3.5.29", + "@vue/compiler-dom": "3.5.29", + "@vue/compiler-ssr": "3.5.29", + "@vue/shared": "3.5.29", + "estree-walker": "^2.0.2", + "magic-string": "^0.30.21", + "postcss": "^8.5.6", + "source-map-js": "^1.2.1" + } + }, + "node_modules/@vue/compiler-ssr": { + "version": "3.5.29", + "resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.5.29.tgz", + "integrity": "sha512-Y/ARJZE6fpjzL5GH/phJmsFwx3g6t2KmHKHx5q+MLl2kencADKIrhH5MLF6HHpRMmlRAYBRSvv347Mepf1zVNw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vue/compiler-dom": "3.5.29", + "@vue/shared": "3.5.29" + } + }, + "node_modules/@vue/devtools-api": { + "version": "7.7.9", + "resolved": "https://registry.npmjs.org/@vue/devtools-api/-/devtools-api-7.7.9.tgz", + "integrity": "sha512-kIE8wvwlcZ6TJTbNeU2HQNtaxLx3a84aotTITUuL/4bzfPxzajGBOoqjMhwZJ8L9qFYDU/lAYMEEm11dnZOD6g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vue/devtools-kit": "^7.7.9" + } + }, + "node_modules/@vue/devtools-kit": { + "version": "7.7.9", + "resolved": "https://registry.npmjs.org/@vue/devtools-kit/-/devtools-kit-7.7.9.tgz", + "integrity": "sha512-PyQ6odHSgiDVd4hnTP+aDk2X4gl2HmLDfiyEnn3/oV+ckFDuswRs4IbBT7vacMuGdwY/XemxBoh302ctbsptuA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vue/devtools-shared": "^7.7.9", + "birpc": "^2.3.0", + "hookable": "^5.5.3", + "mitt": "^3.0.1", + "perfect-debounce": "^1.0.0", + "speakingurl": "^14.0.1", + "superjson": "^2.2.2" + } + }, + "node_modules/@vue/devtools-shared": { + "version": "7.7.9", + "resolved": "https://registry.npmjs.org/@vue/devtools-shared/-/devtools-shared-7.7.9.tgz", + "integrity": "sha512-iWAb0v2WYf0QWmxCGy0seZNDPdO3Sp5+u78ORnyeonS6MT4PC7VPrryX2BpMJrwlDeaZ6BD4vP4XKjK0SZqaeA==", + "dev": true, + "license": "MIT", + "dependencies": { + "rfdc": "^1.4.1" + } + }, + "node_modules/@vue/reactivity": { + "version": "3.5.29", + "resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.5.29.tgz", + "integrity": "sha512-zcrANcrRdcLtmGZETBxWqIkoQei8HaFpZWx/GHKxx79JZsiZ8j1du0VUJtu4eJjgFvU/iKL5lRXFXksVmI+5DA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vue/shared": "3.5.29" + } + }, + "node_modules/@vue/runtime-core": { + "version": "3.5.29", + "resolved": "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.5.29.tgz", + "integrity": "sha512-8DpW2QfdwIWOLqtsNcds4s+QgwSaHSJY/SUe04LptianUQ/0xi6KVsu/pYVh+HO3NTVvVJjIPL2t6GdeKbS4Lg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vue/reactivity": "3.5.29", + "@vue/shared": "3.5.29" + } + }, + "node_modules/@vue/runtime-dom": { + "version": "3.5.29", + "resolved": "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.5.29.tgz", + "integrity": "sha512-AHvvJEtcY9tw/uk+s/YRLSlxxQnqnAkjqvK25ZiM4CllCZWzElRAoQnCM42m9AHRLNJ6oe2kC5DCgD4AUdlvXg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vue/reactivity": "3.5.29", + "@vue/runtime-core": "3.5.29", + "@vue/shared": "3.5.29", + "csstype": "^3.2.3" + } + }, + "node_modules/@vue/server-renderer": { + "version": "3.5.29", + "resolved": "https://registry.npmjs.org/@vue/server-renderer/-/server-renderer-3.5.29.tgz", + "integrity": "sha512-G/1k6WK5MusLlbxSE2YTcqAAezS+VuwHhOvLx2KnQU7G2zCH6KIb+5Wyt6UjMq7a3qPzNEjJXs1hvAxDclQH+g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vue/compiler-ssr": "3.5.29", + "@vue/shared": "3.5.29" + }, + "peerDependencies": { + "vue": "3.5.29" + } + }, + "node_modules/@vue/shared": { + "version": "3.5.29", + "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.5.29.tgz", + "integrity": "sha512-w7SR0A5zyRByL9XUkCfdLs7t9XOHUyJ67qPGQjOou3p6GvBeBW+AVjUUmlxtZ4PIYaRvE+1LmK44O4uajlZwcg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@vueuse/core": { + "version": "12.8.2", + "resolved": "https://registry.npmjs.org/@vueuse/core/-/core-12.8.2.tgz", + "integrity": "sha512-HbvCmZdzAu3VGi/pWYm5Ut+Kd9mn1ZHnn4L5G8kOQTPs/IwIAmJoBrmYk2ckLArgMXZj0AW3n5CAejLUO+PhdQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/web-bluetooth": "^0.0.21", + "@vueuse/metadata": "12.8.2", + "@vueuse/shared": "12.8.2", + "vue": "^3.5.13" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, + "node_modules/@vueuse/integrations": { + "version": "12.8.2", + "resolved": "https://registry.npmjs.org/@vueuse/integrations/-/integrations-12.8.2.tgz", + "integrity": "sha512-fbGYivgK5uBTRt7p5F3zy6VrETlV9RtZjBqd1/HxGdjdckBgBM4ugP8LHpjolqTj14TXTxSK1ZfgPbHYyGuH7g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vueuse/core": "12.8.2", + "@vueuse/shared": "12.8.2", + "vue": "^3.5.13" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + }, + "peerDependencies": { + "async-validator": "^4", + "axios": "^1", + "change-case": "^5", + "drauu": "^0.4", + "focus-trap": "^7", + "fuse.js": "^7", + "idb-keyval": "^6", + "jwt-decode": "^4", + "nprogress": "^0.2", + "qrcode": "^1.5", + "sortablejs": "^1", + "universal-cookie": "^7" + }, + "peerDependenciesMeta": { + "async-validator": { + "optional": true + }, + "axios": { + "optional": true + }, + "change-case": { + "optional": true + }, + "drauu": { + "optional": true + }, + "focus-trap": { + "optional": true + }, + "fuse.js": { + "optional": true + }, + "idb-keyval": { + "optional": true + }, + "jwt-decode": { + "optional": true + }, + "nprogress": { + "optional": true + }, + "qrcode": { + "optional": true + }, + "sortablejs": { + "optional": true + }, + "universal-cookie": { + "optional": true + } + } + }, + "node_modules/@vueuse/metadata": { + "version": "12.8.2", + "resolved": "https://registry.npmjs.org/@vueuse/metadata/-/metadata-12.8.2.tgz", + "integrity": "sha512-rAyLGEuoBJ/Il5AmFHiziCPdQzRt88VxR+Y/A/QhJ1EWtWqPBBAxTAFaSkviwEuOEZNtW8pvkPgoCZQ+HxqW1A==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, + "node_modules/@vueuse/shared": { + "version": "12.8.2", + "resolved": "https://registry.npmjs.org/@vueuse/shared/-/shared-12.8.2.tgz", + "integrity": "sha512-dznP38YzxZoNloI0qpEfpkms8knDtaoQ6Y/sfS0L7Yki4zh40LFHEhur0odJC6xTHG5dxWVPiUWBXn+wCG2s5w==", + "dev": true, + "license": "MIT", + "dependencies": { + "vue": "^3.5.13" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, + "node_modules/algoliasearch": { + "version": "5.49.1", + "resolved": "https://registry.npmjs.org/algoliasearch/-/algoliasearch-5.49.1.tgz", + "integrity": "sha512-X3Pp2aRQhg4xUC6PQtkubn5NpRKuUPQ9FPDQlx36SmpFwwH2N0/tw4c+NXV3nw3PsgeUs+BuWGP0gjz3TvENLQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@algolia/abtesting": "1.15.1", + "@algolia/client-abtesting": "5.49.1", + "@algolia/client-analytics": "5.49.1", + "@algolia/client-common": "5.49.1", + "@algolia/client-insights": "5.49.1", + "@algolia/client-personalization": "5.49.1", + "@algolia/client-query-suggestions": "5.49.1", + "@algolia/client-search": "5.49.1", + "@algolia/ingestion": "1.49.1", + "@algolia/monitoring": "1.49.1", + "@algolia/recommend": "5.49.1", + "@algolia/requester-browser-xhr": "5.49.1", + "@algolia/requester-fetch": "5.49.1", + "@algolia/requester-node-http": "5.49.1" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/birpc": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/birpc/-/birpc-2.9.0.tgz", + "integrity": "sha512-KrayHS5pBi69Xi9JmvoqrIgYGDkD6mcSe/i6YKi3w5kekCLzrX4+nawcXqrj2tIp50Kw/mT/s3p+GVK0A0sKxw==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, + "node_modules/ccount": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/ccount/-/ccount-2.0.1.tgz", + "integrity": "sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==", + "dev": true, + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/character-entities-html4": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/character-entities-html4/-/character-entities-html4-2.1.0.tgz", + "integrity": "sha512-1v7fgQRj6hnSwFpq1Eu0ynr/CDEw0rXo2B61qXrLNdHZmPKgb7fqS1a2JwF0rISo9q77jDI8VMEHoApn8qDoZA==", + "dev": true, + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/character-entities-legacy": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/character-entities-legacy/-/character-entities-legacy-3.0.0.tgz", + "integrity": "sha512-RpPp0asT/6ufRm//AJVwpViZbGM/MkjQFxJccQRHmISF/22NBtsHqAWmL+/pmkPWoIUJdWyeVleTl1wydHATVQ==", + "dev": true, + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/comma-separated-tokens": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/comma-separated-tokens/-/comma-separated-tokens-2.0.3.tgz", + "integrity": "sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg==", + "dev": true, + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/copy-anything": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/copy-anything/-/copy-anything-4.0.5.tgz", + "integrity": "sha512-7Vv6asjS4gMOuILabD3l739tsaxFQmC+a7pLZm02zyvs8p977bL3zEgq3yDk5rn9B0PbYgIv++jmHcuUab4RhA==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-what": "^5.2.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/mesqueeb" + } + }, + "node_modules/csstype": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz", + "integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/dequal": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", + "integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/devlop": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/devlop/-/devlop-1.1.0.tgz", + "integrity": "sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA==", + "dev": true, + "license": "MIT", + "dependencies": { + "dequal": "^2.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/emoji-regex-xs": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex-xs/-/emoji-regex-xs-1.0.0.tgz", + "integrity": "sha512-LRlerrMYoIDrT6jgpeZ2YYl/L8EulRTt5hQcYjy5AInh7HWXKimpqx68aknBFpGL2+/IcogTcaydJEgaTmOpDg==", + "dev": true, + "license": "MIT" + }, + "node_modules/entities": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/entities/-/entities-7.0.1.tgz", + "integrity": "sha512-TWrgLOFUQTH994YUyl1yT4uyavY5nNB5muff+RtWaqNVCAK408b5ZnnbNAUEWLTCpum9w6arT70i1XdQ4UeOPA==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/esbuild": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.21.5.tgz", + "integrity": "sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=12" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.21.5", + "@esbuild/android-arm": "0.21.5", + "@esbuild/android-arm64": "0.21.5", + "@esbuild/android-x64": "0.21.5", + "@esbuild/darwin-arm64": "0.21.5", + "@esbuild/darwin-x64": "0.21.5", + "@esbuild/freebsd-arm64": "0.21.5", + "@esbuild/freebsd-x64": "0.21.5", + "@esbuild/linux-arm": "0.21.5", + "@esbuild/linux-arm64": "0.21.5", + "@esbuild/linux-ia32": "0.21.5", + "@esbuild/linux-loong64": "0.21.5", + "@esbuild/linux-mips64el": "0.21.5", + "@esbuild/linux-ppc64": "0.21.5", + "@esbuild/linux-riscv64": "0.21.5", + "@esbuild/linux-s390x": "0.21.5", + "@esbuild/linux-x64": "0.21.5", + "@esbuild/netbsd-x64": "0.21.5", + "@esbuild/openbsd-x64": "0.21.5", + "@esbuild/sunos-x64": "0.21.5", + "@esbuild/win32-arm64": "0.21.5", + "@esbuild/win32-ia32": "0.21.5", + "@esbuild/win32-x64": "0.21.5" + } + }, + "node_modules/estree-walker": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", + "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==", + "dev": true, + "license": "MIT" + }, + "node_modules/focus-trap": { + "version": "7.8.0", + "resolved": "https://registry.npmjs.org/focus-trap/-/focus-trap-7.8.0.tgz", + "integrity": "sha512-/yNdlIkpWbM0ptxno3ONTuf+2g318kh2ez3KSeZN5dZ8YC6AAmgeWz+GasYYiBJPFaYcSAPeu4GfhUaChzIJXA==", + "dev": true, + "license": "MIT", + "dependencies": { + "tabbable": "^6.4.0" + } + }, + "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/hast-util-to-html": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/hast-util-to-html/-/hast-util-to-html-9.0.5.tgz", + "integrity": "sha512-OguPdidb+fbHQSU4Q4ZiLKnzWo8Wwsf5bZfbvu7//a9oTYoqD/fWpe96NuHkoS9h0ccGOTe0C4NGXdtS0iObOw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0", + "@types/unist": "^3.0.0", + "ccount": "^2.0.0", + "comma-separated-tokens": "^2.0.0", + "hast-util-whitespace": "^3.0.0", + "html-void-elements": "^3.0.0", + "mdast-util-to-hast": "^13.0.0", + "property-information": "^7.0.0", + "space-separated-tokens": "^2.0.0", + "stringify-entities": "^4.0.0", + "zwitch": "^2.0.4" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hast-util-whitespace": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/hast-util-whitespace/-/hast-util-whitespace-3.0.0.tgz", + "integrity": "sha512-88JUN06ipLwsnv+dVn+OIYOvAuvBMy/Qoi6O7mQHxdPXpjy+Cd6xRkWwux7DKO+4sYILtLBRIKgsdpS2gQc7qw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hookable": { + "version": "5.5.3", + "resolved": "https://registry.npmjs.org/hookable/-/hookable-5.5.3.tgz", + "integrity": "sha512-Yc+BQe8SvoXH1643Qez1zqLRmbA5rCL+sSmk6TVos0LWVfNIB7PGncdlId77WzLGSIB5KaWgTaNTs2lNVEI6VQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/html-void-elements": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/html-void-elements/-/html-void-elements-3.0.0.tgz", + "integrity": "sha512-bEqo66MRXsUGxWHV5IP0PUiAWwoEjba4VCzg0LjFJBpchPaTfyfCKTG6bc5F8ucKec3q5y6qOdGyYTSBEvhCrg==", + "dev": true, + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/is-what": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/is-what/-/is-what-5.5.0.tgz", + "integrity": "sha512-oG7cgbmg5kLYae2N5IVd3jm2s+vldjxJzK1pcu9LfpGuQ93MQSzo0okvRna+7y5ifrD+20FE8FvjusyGaz14fw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/mesqueeb" + } + }, + "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==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.5" + } + }, + "node_modules/mark.js": { + "version": "8.11.1", + "resolved": "https://registry.npmjs.org/mark.js/-/mark.js-8.11.1.tgz", + "integrity": "sha512-1I+1qpDt4idfgLQG+BNWmrqku+7/2bi5nLf4YwF8y8zXvmfiTBY3PV3ZibfrjBueCByROpuBjLLFCajqkgYoLQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/mdast-util-to-hast": { + "version": "13.2.1", + "resolved": "https://registry.npmjs.org/mdast-util-to-hast/-/mdast-util-to-hast-13.2.1.tgz", + "integrity": "sha512-cctsq2wp5vTsLIcaymblUriiTcZd0CwWtCbLvrOzYCDZoWyMNV8sZ7krj09FSnsiJi3WVsHLM4k6Dq/yaPyCXA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0", + "@types/mdast": "^4.0.0", + "@ungap/structured-clone": "^1.0.0", + "devlop": "^1.0.0", + "micromark-util-sanitize-uri": "^2.0.0", + "trim-lines": "^3.0.0", + "unist-util-position": "^5.0.0", + "unist-util-visit": "^5.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-util-character": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.1.tgz", + "integrity": "sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-util-encode": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-encode/-/micromark-util-encode-2.0.1.tgz", + "integrity": "sha512-c3cVx2y4KqUnwopcO9b/SCdo2O67LwJJ/UyqGfbigahfegL9myoEFoDYZgkT7f36T0bLrM9hZTAaAyH+PCAXjw==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark-util-sanitize-uri": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-sanitize-uri/-/micromark-util-sanitize-uri-2.0.1.tgz", + "integrity": "sha512-9N9IomZ/YuGGZZmQec1MbgxtlgougxTodVwDzzEouPKo3qFWvymFHWcnDi2vzV1ff6kas9ucW+o3yzJK9YB1AQ==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-encode": "^2.0.0", + "micromark-util-symbol": "^2.0.0" + } + }, + "node_modules/micromark-util-symbol": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.1.tgz", + "integrity": "sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark-util-types": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/micromark-util-types/-/micromark-util-types-2.0.2.tgz", + "integrity": "sha512-Yw0ECSpJoViF1qTU4DC6NwtC4aWGt1EkzaQB8KPPyCRR8z9TWeV0HbEFGTO+ZY1wB22zmxnJqhPyTpOVCpeHTA==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/minisearch": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/minisearch/-/minisearch-7.2.0.tgz", + "integrity": "sha512-dqT2XBYUOZOiC5t2HRnwADjhNS2cecp9u+TJRiJ1Qp/f5qjkeT5APcGPjHw+bz89Ms8Jp+cG4AlE+QZ/QnDglg==", + "dev": true, + "license": "MIT" + }, + "node_modules/mitt": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/mitt/-/mitt-3.0.1.tgz", + "integrity": "sha512-vKivATfr97l2/QBCYAkXYDbrIWPM2IIKEl7YPhjCvKlG3kE2gm+uBo6nEXK3M5/Ffh/FLpKExzOQ3JJoJGFKBw==", + "dev": true, + "license": "MIT" + }, + "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/oniguruma-to-es": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/oniguruma-to-es/-/oniguruma-to-es-3.1.1.tgz", + "integrity": "sha512-bUH8SDvPkH3ho3dvwJwfonjlQ4R80vjyvrU8YpxuROddv55vAEJrTuCuCVUhhsHbtlD9tGGbaNApGQckXhS8iQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex-xs": "^1.0.0", + "regex": "^6.0.1", + "regex-recursion": "^6.0.2" + } + }, + "node_modules/perfect-debounce": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/perfect-debounce/-/perfect-debounce-1.0.0.tgz", + "integrity": "sha512-xCy9V055GLEqoFaHoC1SoLIaLmWctgCUaBaWxDZ7/Zx4CTyX7cJQLJOok/orfjZAh9kEYpjJa4d0KcJmCbctZA==", + "dev": true, + "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/postcss": { + "version": "8.5.6", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz", + "integrity": "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==", + "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/preact": { + "version": "10.28.4", + "resolved": "https://registry.npmjs.org/preact/-/preact-10.28.4.tgz", + "integrity": "sha512-uKFfOHWuSNpRFVTnljsCluEFq57OKT+0QdOiQo8XWnQ/pSvg7OpX5eNOejELXJMWy+BwM2nobz0FkvzmnpCNsQ==", + "dev": true, + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/preact" + } + }, + "node_modules/property-information": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/property-information/-/property-information-7.1.0.tgz", + "integrity": "sha512-TwEZ+X+yCJmYfL7TPUOcvBZ4QfoT5YenQiJuX//0th53DE6w0xxLEtfK3iyryQFddXuvkIk51EEgrJQ0WJkOmQ==", + "dev": true, + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/regex": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/regex/-/regex-6.1.0.tgz", + "integrity": "sha512-6VwtthbV4o/7+OaAF9I5L5V3llLEsoPyq9P1JVXkedTP33c7MfCG0/5NOPcSJn0TzXcG9YUrR0gQSWioew3LDg==", + "dev": true, + "license": "MIT", + "dependencies": { + "regex-utilities": "^2.3.0" + } + }, + "node_modules/regex-recursion": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/regex-recursion/-/regex-recursion-6.0.2.tgz", + "integrity": "sha512-0YCaSCq2VRIebiaUviZNs0cBz1kg5kVS2UKUfNIx8YVs1cN3AV7NTctO5FOKBA+UT2BPJIWZauYHPqJODG50cg==", + "dev": true, + "license": "MIT", + "dependencies": { + "regex-utilities": "^2.3.0" + } + }, + "node_modules/regex-utilities": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/regex-utilities/-/regex-utilities-2.3.0.tgz", + "integrity": "sha512-8VhliFJAWRaUiVvREIiW2NXXTmHs4vMNnSzuJVhscgmGav3g9VDxLrQndI3dZZVVdp0ZO/5v0xmX516/7M9cng==", + "dev": true, + "license": "MIT" + }, + "node_modules/rfdc": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.4.1.tgz", + "integrity": "sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==", + "dev": true, + "license": "MIT" + }, + "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/search-insights": { + "version": "2.17.3", + "resolved": "https://registry.npmjs.org/search-insights/-/search-insights-2.17.3.tgz", + "integrity": "sha512-RQPdCYTa8A68uM2jwxoY842xDhvx3E5LFL1LxvxCNMev4o5mLuokczhzjAgGwUZBAmOKZknArSxLKmXtIi2AxQ==", + "dev": true, + "license": "MIT", + "peer": true + }, + "node_modules/shiki": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/shiki/-/shiki-2.5.0.tgz", + "integrity": "sha512-mI//trrsaiCIPsja5CNfsyNOqgAZUb6VpJA+340toL42UpzQlXpwRV9nch69X6gaUxrr9kaOOa6e3y3uAkGFxQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@shikijs/core": "2.5.0", + "@shikijs/engine-javascript": "2.5.0", + "@shikijs/engine-oniguruma": "2.5.0", + "@shikijs/langs": "2.5.0", + "@shikijs/themes": "2.5.0", + "@shikijs/types": "2.5.0", + "@shikijs/vscode-textmate": "^10.0.2", + "@types/hast": "^3.0.4" + } + }, + "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/space-separated-tokens": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/space-separated-tokens/-/space-separated-tokens-2.0.2.tgz", + "integrity": "sha512-PEGlAwrG8yXGXRjW32fGbg66JAlOAwbObuqVoJpv/mRgoWDQfgH1wDPvtzWyUSNAXBGSk8h755YDbbcEy3SH2Q==", + "dev": true, + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/speakingurl": { + "version": "14.0.1", + "resolved": "https://registry.npmjs.org/speakingurl/-/speakingurl-14.0.1.tgz", + "integrity": "sha512-1POYv7uv2gXoyGFpBCmpDVSNV74IfsWlDW216UPjbWufNf+bSU6GdbDsxdcxtfwb4xlI3yxzOTKClUosxARYrQ==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/stringify-entities": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/stringify-entities/-/stringify-entities-4.0.4.tgz", + "integrity": "sha512-IwfBptatlO+QCJUo19AqvrPNqlVMpW9YEL2LIVY+Rpv2qsjCGxaDLNRgeGsQWJhfItebuJhsGSLjaBbNSQ+ieg==", + "dev": true, + "license": "MIT", + "dependencies": { + "character-entities-html4": "^2.0.0", + "character-entities-legacy": "^3.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/superjson": { + "version": "2.2.6", + "resolved": "https://registry.npmjs.org/superjson/-/superjson-2.2.6.tgz", + "integrity": "sha512-H+ue8Zo4vJmV2nRjpx86P35lzwDT3nItnIsocgumgr0hHMQ+ZGq5vrERg9kJBo5AWGmxZDhzDo+WVIJqkB0cGA==", + "dev": true, + "license": "MIT", + "dependencies": { + "copy-anything": "^4" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/tabbable": { + "version": "6.4.0", + "resolved": "https://registry.npmjs.org/tabbable/-/tabbable-6.4.0.tgz", + "integrity": "sha512-05PUHKSNE8ou2dwIxTngl4EzcnsCDZGJ/iCLtDflR/SHB/ny14rXc+qU5P4mG9JkusiV7EivzY9Mhm55AzAvCg==", + "dev": true, + "license": "MIT" + }, + "node_modules/three": { + "version": "0.170.0", + "resolved": "https://registry.npmjs.org/three/-/three-0.170.0.tgz", + "integrity": "sha512-FQK+LEpYc0fBD+J8g6oSEyyNzjp+Q7Ks1C568WWaoMRLW+TkNNWmenWeGgJjV105Gd+p/2ql1ZcjYvNiPZBhuQ==", + "license": "MIT" + }, + "node_modules/trim-lines": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/trim-lines/-/trim-lines-3.0.1.tgz", + "integrity": "sha512-kRj8B+YHZCc9kQYdWfJB2/oUl9rA99qbowYYBtr4ui4mZyAQ2JpvVBd/6U2YloATfqBhBTSMhTpgBHtU0Mf3Rg==", + "dev": true, + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/unist-util-is": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/unist-util-is/-/unist-util-is-6.0.1.tgz", + "integrity": "sha512-LsiILbtBETkDz8I9p1dQ0uyRUWuaQzd/cuEeS1hoRSyW5E5XGmTzlwY1OrNzzakGowI9Dr/I8HVaw4hTtnxy8g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-position": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/unist-util-position/-/unist-util-position-5.0.0.tgz", + "integrity": "sha512-fucsC7HjXvkB5R3kTCO7kUjRdrS0BJt3M/FPxmHMBOm8JQi2BsHAHFsy27E0EolP8rp0NzXsJ+jNPyDWvOJZPA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-stringify-position": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-4.0.0.tgz", + "integrity": "sha512-0ASV06AAoKCDkS2+xw5RXJywruurpbC4JZSm7nr7MOt1ojAzvyyaO+UxZf18j8FCF6kmzCZKcAgN/yu2gm2XgQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-visit": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/unist-util-visit/-/unist-util-visit-5.1.0.tgz", + "integrity": "sha512-m+vIdyeCOpdr/QeQCu2EzxX/ohgS8KbnPDgFni4dQsfSCtpz8UqDyY5GjRru8PDKuYn7Fq19j1CQ+nJSsGKOzg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "unist-util-is": "^6.0.0", + "unist-util-visit-parents": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-visit-parents": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/unist-util-visit-parents/-/unist-util-visit-parents-6.0.2.tgz", + "integrity": "sha512-goh1s1TBrqSqukSc8wrjwWhL0hiJxgA8m4kFxGlQ+8FYQ3C/m11FcTs4YYem7V664AhHVvgoQLk890Ssdsr2IQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "unist-util-is": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/vfile": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/vfile/-/vfile-6.0.3.tgz", + "integrity": "sha512-KzIbH/9tXat2u30jf+smMwFCsno4wHVdNmzFyL+T/L3UGqqk6JKfVqOFOZEpZSHADH1k40ab6NUIXZq422ov3Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "vfile-message": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/vfile-message": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/vfile-message/-/vfile-message-4.0.3.tgz", + "integrity": "sha512-QTHzsGd1EhbZs4AsQ20JX1rC3cOlt/IWJruk893DfLRr57lcnOeMaWG4K0JrRta4mIJZKth2Au3mM3u03/JWKw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "unist-util-stringify-position": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/vite": { + "version": "5.4.21", + "resolved": "https://registry.npmjs.org/vite/-/vite-5.4.21.tgz", + "integrity": "sha512-o5a9xKjbtuhY6Bi5S3+HvbRERmouabWbyUcpXXUA1u+GNUKoROi9byOJ8M0nHbHYHkYICiMlqxkg1KkYmm25Sw==", + "dev": true, + "license": "MIT", + "dependencies": { + "esbuild": "^0.21.3", + "postcss": "^8.4.43", + "rollup": "^4.20.0" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^18.0.0 || >=20.0.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + }, + "peerDependencies": { + "@types/node": "^18.0.0 || >=20.0.0", + "less": "*", + "lightningcss": "^1.21.0", + "sass": "*", + "sass-embedded": "*", + "stylus": "*", + "sugarss": "*", + "terser": "^5.4.0" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "less": { + "optional": true + }, + "lightningcss": { + "optional": true + }, + "sass": { + "optional": true + }, + "sass-embedded": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + } + } + }, + "node_modules/vitepress": { + "version": "1.6.4", + "resolved": "https://registry.npmjs.org/vitepress/-/vitepress-1.6.4.tgz", + "integrity": "sha512-+2ym1/+0VVrbhNyRoFFesVvBvHAVMZMK0rw60E3X/5349M1GuVdKeazuksqopEdvkKwKGs21Q729jX81/bkBJg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@docsearch/css": "3.8.2", + "@docsearch/js": "3.8.2", + "@iconify-json/simple-icons": "^1.2.21", + "@shikijs/core": "^2.1.0", + "@shikijs/transformers": "^2.1.0", + "@shikijs/types": "^2.1.0", + "@types/markdown-it": "^14.1.2", + "@vitejs/plugin-vue": "^5.2.1", + "@vue/devtools-api": "^7.7.0", + "@vue/shared": "^3.5.13", + "@vueuse/core": "^12.4.0", + "@vueuse/integrations": "^12.4.0", + "focus-trap": "^7.6.4", + "mark.js": "8.11.1", + "minisearch": "^7.1.1", + "shiki": "^2.1.0", + "vite": "^5.4.14", + "vue": "^3.5.13" + }, + "bin": { + "vitepress": "bin/vitepress.js" + }, + "peerDependencies": { + "markdown-it-mathjax3": "^4", + "postcss": "^8" + }, + "peerDependenciesMeta": { + "markdown-it-mathjax3": { + "optional": true + }, + "postcss": { + "optional": true + } + } + }, + "node_modules/vue": { + "version": "3.5.29", + "resolved": "https://registry.npmjs.org/vue/-/vue-3.5.29.tgz", + "integrity": "sha512-BZqN4Ze6mDQVNAni0IHeMJ5mwr8VAJ3MQC9FmprRhcBYENw+wOAAjRj8jfmN6FLl0j96OXbR+CjWhmAmM+QGnA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vue/compiler-dom": "3.5.29", + "@vue/compiler-sfc": "3.5.29", + "@vue/runtime-dom": "3.5.29", + "@vue/server-renderer": "3.5.29", + "@vue/shared": "3.5.29" + }, + "peerDependencies": { + "typescript": "*" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/zwitch": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/zwitch/-/zwitch-2.0.4.tgz", + "integrity": "sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==", + "dev": true, + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + } + } +} diff --git a/package.json b/package.json new file mode 100644 index 0000000..874f576 --- /dev/null +++ b/package.json @@ -0,0 +1,15 @@ +{ + "name": "i2rt-docs", + "private": true, + "scripts": { + "docs:dev": "bash scripts/copy_doc_models.sh && vitepress dev docs", + "docs:build": "bash scripts/copy_doc_models.sh && vitepress build docs", + "docs:preview": "vitepress preview docs" + }, + "devDependencies": { + "vitepress": "^1.6.3" + }, + "dependencies": { + "three": "^0.170.0" + } +} diff --git a/tests/test_robot_variants.py b/tests/test_robot_variants.py new file mode 100644 index 0000000..57b5ebf --- /dev/null +++ b/tests/test_robot_variants.py @@ -0,0 +1,219 @@ +"""Simulation-mode tests for all YAM arm x gripper combinations. + +Run with: + pytest tests/test_robot_variants.py -v +""" + +import mujoco +import numpy as np +import pytest + +from i2rt.robots.get_robot import _ARM_JOINT_LIMITS, get_yam_robot +from i2rt.robots.motor_chain_robot import MotorChainRobot +from i2rt.robots.utils import ArmType, GripperType, combine_arm_and_gripper_xml + +# All YAM-family arm variants +YAM_ARMS = [ + ArmType.YAM, + ArmType.YAM_PRO, + ArmType.YAM_ULTRA, + ArmType.BIG_YAM, +] + +# Grippers that work with the YAM family +YAM_GRIPPERS = [ + GripperType.LINEAR_4310, + GripperType.LINEAR_3507, + GripperType.CRANK_4310, + GripperType.YAM_TEACHING_HANDLE, + GripperType.NO_GRIPPER, +] + + +# --------------------------------------------------------------------------- +# Helper +# --------------------------------------------------------------------------- + + +def make_robot(arm_type: ArmType, gripper_type: GripperType) -> MotorChainRobot: + """Create a SimRobot for the given arm/gripper pair.""" + return get_yam_robot(arm_type=arm_type, gripper_type=gripper_type, sim=True) + + +# --------------------------------------------------------------------------- +# All arm x gripper combos: smoke-test loading +# --------------------------------------------------------------------------- + + +@pytest.mark.parametrize("arm_type", YAM_ARMS) +@pytest.mark.parametrize("gripper_type", YAM_GRIPPERS) +def test_sim_robot_loads(arm_type: ArmType, gripper_type: GripperType) -> None: + """Every arm/gripper combination should load without error in sim mode.""" + robot = make_robot(arm_type, gripper_type) + + pos = robot.get_joint_pos() + assert isinstance(pos, np.ndarray) + assert pos.ndim == 1 + assert len(pos) > 0 + + obs = robot.get_observations() + assert "joint_pos" in obs + assert "joint_vel" in obs + + # Commanding zeros should not raise + robot.command_joint_pos(np.zeros_like(pos)) + + robot.close() + + +# --------------------------------------------------------------------------- +# DOF counts +# --------------------------------------------------------------------------- + + +@pytest.mark.parametrize("arm_type", YAM_ARMS) +@pytest.mark.parametrize( + "gripper_type,expected_dofs,has_gripper_obs", + [ + (GripperType.LINEAR_4310, 7, True), + (GripperType.LINEAR_3507, 7, True), + (GripperType.CRANK_4310, 7, True), + (GripperType.YAM_TEACHING_HANDLE, 6, False), + (GripperType.NO_GRIPPER, 6, False), + ], +) +def test_dof_count(arm_type: ArmType, gripper_type: GripperType, expected_dofs: int, has_gripper_obs: bool) -> None: + """Robots with an active gripper motor should report 7 DOFs, arm-only 6.""" + robot = make_robot(arm_type, gripper_type) + + assert robot.num_dofs() == expected_dofs + + obs = robot.get_observations() + if has_gripper_obs: + assert "gripper_pos" in obs + assert obs["gripper_pos"].shape == (1,) + else: + assert "gripper_pos" not in obs + + robot.close() + + +# --------------------------------------------------------------------------- +# Per-arm joint limits +# --------------------------------------------------------------------------- + + +@pytest.mark.parametrize("arm_type", YAM_ARMS) +def test_joint_limits_match_arm_type(arm_type: ArmType) -> None: + """Each arm variant should embed its own joint limits (XML range Β± 0.15 buffer).""" + robot = make_robot(arm_type, GripperType.NO_GRIPPER) + info = robot.get_robot_info() + limits = info["joint_limits"] + + expected = _ARM_JOINT_LIMITS[arm_type] + np.testing.assert_allclose(limits[:, 0], expected[:, 0] - 0.15, atol=1e-6) + np.testing.assert_allclose(limits[:, 1], expected[:, 1] + 0.15, atol=1e-6) + + robot.close() + + +# --------------------------------------------------------------------------- +# big_yam specifics +# --------------------------------------------------------------------------- + + +def test_big_yam_no_gripper_is_arm_only() -> None: + """big_yam + no_gripper should give a 6-DOF arm-only robot.""" + robot = make_robot(ArmType.BIG_YAM, GripperType.NO_GRIPPER) + info = robot.get_robot_info() + + assert robot.num_dofs() == 6 + assert info["gripper_index"] is None + assert "gripper_pos" not in robot.get_observations() + + robot.close() + + +# --------------------------------------------------------------------------- +# MuJoCo XML combination sanity +# --------------------------------------------------------------------------- + + +@pytest.mark.parametrize("arm_type", YAM_ARMS) +@pytest.mark.parametrize("gripper_type", YAM_GRIPPERS) +def test_combined_xml_loads_in_mujoco(arm_type: ArmType, gripper_type: GripperType) -> None: + """The combined arm+gripper XML must be loadable by MuJoCo.""" + xml_path = combine_arm_and_gripper_xml(arm_type.get_xml_path(), gripper_type.get_xml_path()) + model = mujoco.MjModel.from_xml_path(xml_path) + + assert model.nq > 0 + assert model.njnt > 0 + + +# --------------------------------------------------------------------------- +# EE site frame convention at zero pose +# --------------------------------------------------------------------------- + + +def _get_ee_site_axes(arm_type: ArmType, gripper_type: GripperType) -> tuple[np.ndarray, np.ndarray, np.ndarray]: + """Load combined model at qpos=0 and return grasp_site (x, y, z) world axes.""" + xml_path = combine_arm_and_gripper_xml(arm_type.get_xml_path(), gripper_type.get_xml_path()) + model = mujoco.MjModel.from_xml_path(xml_path) + data = mujoco.MjData(model) + data.qpos[:] = 0 + mujoco.mj_forward(model, data) + + # Prefer grasp_site; fall back to tcp_site (teaching handle has no grasp_site) + site_id = mujoco.mj_name2id(model, mujoco.mjtObj.mjOBJ_SITE, "grasp_site") + if site_id < 0: + site_id = mujoco.mj_name2id(model, mujoco.mjtObj.mjOBJ_SITE, "tcp_site") + assert site_id >= 0, f"No grasp_site or tcp_site in {arm_type.value}+{gripper_type.value}" + + xmat = data.site_xmat[site_id].reshape(3, 3) + return xmat[:, 0], xmat[:, 1], xmat[:, 2] + + +@pytest.mark.parametrize("arm_type", YAM_ARMS) +@pytest.mark.parametrize("gripper_type", YAM_GRIPPERS) +def test_grasp_site_frame_at_zero_pose(arm_type: ArmType, gripper_type: GripperType) -> None: + """At qpos=0 the EE site frame must be: X down, Y left, Z front. + + Concretely: + - X axis β‰ˆ world [0, 0, -1] (pointing down) + - Y axis is horizontal (z-component β‰ˆ 0) + - Z axis is horizontal (z-component β‰ˆ 0, pointing front) + """ + x_axis, y_axis, z_axis = _get_ee_site_axes(arm_type, gripper_type) + label = f"{arm_type.value}+{gripper_type.value}" + + # X should point down (world -Z) + np.testing.assert_allclose( + x_axis, + [0, 0, -1], + atol=1e-3, + err_msg=f"{label}: X axis should point down [0,0,-1], got {x_axis}", + ) + # Z (front) should be horizontal + assert abs(z_axis[2]) < 1e-3, f"{label}: Z axis should be horizontal (front), z-component={z_axis[2]:.6f}" + # Y (left) should be horizontal + assert abs(y_axis[2]) < 1e-3, f"{label}: Y axis should be horizontal (left), z-component={y_axis[2]:.6f}" + + +@pytest.mark.parametrize("arm_type", YAM_ARMS) +def test_grasp_site_consistent_across_grippers(arm_type: ArmType) -> None: + """All grippers on the same arm must produce the same EE site orientation at zero pose.""" + reference = None + ref_gripper = None + for gripper_type in YAM_GRIPPERS: + x, y, z = _get_ee_site_axes(arm_type, gripper_type) + axes = np.column_stack([x, y, z]) + if reference is None: + reference = axes + ref_gripper = gripper_type + else: + np.testing.assert_allclose( + axes, + reference, + atol=1e-3, + err_msg=(f"{arm_type.value}: {gripper_type.value} site frame differs from {ref_gripper.value}"), + ) diff --git a/wrangler.toml b/wrangler.toml new file mode 100644 index 0000000..7d66086 --- /dev/null +++ b/wrangler.toml @@ -0,0 +1,5 @@ +name = "internaldoc" +compatibility_date = "2024-09-23" + +[assets] +directory = "docs/.vitepress/dist"