haixuantao commited on
Commit
44359eb
·
1 Parent(s): 2043c60

Deploy XoQ examples (OpenArm, Camera, URDF viewer)

Browse files
.gitattributes CHANGED
@@ -33,3 +33,4 @@ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
33
  *.zip filter=lfs diff=lfs merge=lfs -text
34
  *.zst filter=lfs diff=lfs merge=lfs -text
35
  *tfevents* filter=lfs diff=lfs merge=lfs -text
 
 
33
  *.zip filter=lfs diff=lfs merge=lfs -text
34
  *.zst filter=lfs diff=lfs merge=lfs -text
35
  *tfevents* filter=lfs diff=lfs merge=lfs -text
36
+ *.stl filter=lfs diff=lfs merge=lfs -text
README.md CHANGED
@@ -1,12 +1,8 @@
1
  ---
2
- title: Openarm
3
- emoji: 📈
4
- colorFrom: green
5
- colorTo: gray
6
  sdk: static
7
  pinned: false
8
- license: apache-2.0
9
- short_description: Realtime Open Arm
10
  ---
11
-
12
- Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
1
  ---
2
+ title: OpenArm
3
+ emoji: 🤖
4
+ colorFrom: blue
5
+ colorTo: green
6
  sdk: static
7
  pinned: false
 
 
8
  ---
 
 
assets/URDFLoader-CL7UVBjw.js ADDED
The diff for this file is too large to render. See raw diff
 
assets/camera-M5W9d3UM.js ADDED
@@ -0,0 +1 @@
 
 
1
+ import{c as U,f as k}from"./connect-DkGLCYAo.js";const x=new URLSearchParams(location.search),R="https://cdn.1ms.ai",D="anon/camera-0",C=document.getElementById("relayUrl"),L=document.getElementById("path");C.value=x.get("relay")||R;L.value=x.get("path")||D;const a=document.getElementById("video"),S=document.getElementById("log"),h=document.getElementById("startBtn"),b=document.getElementById("stopBtn"),M=document.getElementById("status"),A=document.getElementById("groupCount"),F=document.getElementById("bytesReceived"),T=document.getElementById("bufferLength");let g=null,$=!1,l=null,d=null,p=0,B=0,E=[];function n(t,e="info"){const o=document.createElement("div");o.className=`log-entry log-${e}`,o.textContent=`[${new Date().toLocaleTimeString()}] ${t}`,S.appendChild(o),S.scrollTop=S.scrollHeight,console.log(t)}function V(t){return t<1024?`${t} B`:t<1024*1024?`${(t/1024).toFixed(1)} KB`:`${(t/(1024*1024)).toFixed(2)} MB`}function w(){if(A.textContent=p,F.textContent=V(B),a.buffered.length>0){const t=a.buffered.end(0)-a.currentTime;T.textContent=`${Math.max(0,t).toFixed(1)}s`}}function f(t){M.textContent=t}function H(){if(E.length>0&&d&&!d.updating){const t=E.shift();try{d.appendBuffer(t)}catch(e){n(`Append error: ${e.message}`,"error")}}}async function P(t){if(!d||d.updating){E.push(t);return}try{d.appendBuffer(t)}catch(e){n(`Append error: ${e.message}`,"error")}}function j(t){const e=new Uint8Array(t),o=r=>r.toString(16).padStart(2,"0").toUpperCase();for(let r=0;r<e.length-11;r++){if(e[r+4]===97&&e[r+5]===118&&e[r+6]===99&&e[r+7]===67){const c=r+8;if(c+4<=e.length)return`avc1.${o(e[c+1])}${o(e[c+2])}${o(e[c+3])}`}if(e[r+4]===97&&e[r+5]===118&&e[r+6]===49&&e[r+7]===67){const c=r+8;if(c+4<=e.length){const u=e[c+1]>>5&7,y=e[c+1]&31,i=e[c+2]>>7&1,s=e[c+2]>>6&1,v=e[c+2]>>5&1,m=s?v?12:10:8,I=String(y).padStart(2,"0");return`av01.${u}.${I}${i?"H":"M"}.${String(m).padStart(2,"0")}`}}}return null}async function N(t){const e=j(t);if(!e)throw n("Could not detect codec from init segment","error"),new Error("No codec detected");const o=`video/mp4; codecs="${e}"`;if(!MediaSource.isTypeSupported(o))throw n(`Codec not supported: ${o}`,"error"),new Error(`Codec not supported: ${o}`);return n(`Detected codec: ${e}`,"success"),new Promise((r,c)=>{l=new MediaSource,a.src=URL.createObjectURL(l),l.addEventListener("sourceopen",()=>{n("MediaSource opened","success"),n(`Using codec: ${o}`,"success"),d=l.addSourceBuffer(o),d.mode="segments",d.addEventListener("updateend",()=>{H(),w(),a.paused&&a.buffered.length>0&&a.play().catch(()=>{})}),d.addEventListener("error",u=>{n(`SourceBuffer error: ${u.type}`,"error"),console.error("SourceBuffer error:",u)}),r()}),l.addEventListener("error",c)})}h.addEventListener("click",async()=>{try{const t=C.value,e=L.value,o=`${t}/${e}`;h.disabled=!0,b.disabled=!1,$=!0,p=0,B=0,E=[],f("Connecting..."),n(`Connecting to ${o}...`),g=await U(new URL(o)),n("Connected!","success"),f("Subscribing...");const c=g.consume(k("")).subscribe("video",0);n("Subscribed to video track","success"),f("Streaming");let u=!1;for(;$;){const y=await c.nextGroup();if(!y){n("Track ended");break}for(;$;){const i=await y.readFrame();if(!i)break;p++,B+=i.byteLength;const s=new Uint8Array(i),v=Array.from(s.slice(0,8)).map(m=>m.toString(16).padStart(2,"0")).join(" ");if(p===1)n(`First segment: ${i.byteLength} bytes [${v}...]`,"data"),s[4]===102&&s[5]===116&&s[6]===121&&s[7]===112?n("Valid ftyp box detected (init segment)","success"):s[4]===109&&s[5]===111&&s[6]===111&&s[7]===102&&n("moof box (media segment without init?)","error");else if(p<=5){const m=String.fromCharCode(s[4],s[5],s[6],s[7]);n(`Segment ${p}: ${i.byteLength} bytes, box=${m}`,"data")}u||(await N(i),u=!0),await P(i),w()}}f("Ended")}catch(t){n(`Error: ${t.message}`,"error"),console.error(t),f("Error")}finally{h.disabled=!1,b.disabled=!0}});b.addEventListener("click",async()=>{$=!1,f("Stopping...");try{await(g==null?void 0:g.close())}catch{}if(g=null,(l==null?void 0:l.readyState)==="open")try{l.endOfStream()}catch{}h.disabled=!1,b.disabled=!0,f("Disconnected"),n("Disconnected","success")});a.addEventListener("error",t=>{const e=a.error;n(`Video error: ${(e==null?void 0:e.message)||"unknown"} (code: ${e==null?void 0:e.code})`,"error")});a.addEventListener("loadedmetadata",()=>{n(`Video metadata loaded: ${a.videoWidth}x${a.videoHeight}`,"success")});a.addEventListener("canplay",()=>{n("Video can play!","success")});setInterval(w,1e3);n("Ready. Enter relay URL and path, then click Connect.","info");(x.has("relay")||x.has("path"))&&(n("Auto-connecting from query params...","info"),h.click());
assets/connect-DkGLCYAo.js ADDED
@@ -0,0 +1,2 @@
 
 
 
1
+ var Ha=Object.defineProperty;var vn=i=>{throw TypeError(i)};var za=(i,e,t)=>e in i?Ha(i,e,{enumerable:!0,configurable:!0,writable:!0,value:t}):i[e]=t;var o=(i,e,t)=>za(i,typeof e!="symbol"?e+"":e,t),en=(i,e,t)=>e.has(i)||vn("Cannot "+t);var n=(i,e,t)=>(en(i,e,"read from private field"),t?t.call(i):e.get(i)),c=(i,e,t)=>e.has(i)?vn("Cannot add the same private member more than once"):e instanceof WeakSet?e.add(i):e.set(i,t),l=(i,e,t,s)=>(en(i,e,"write to private field"),s?s.call(i,t):e.set(i,t),t),d=(i,e,t)=>(en(i,e,"access private method"),t);var bs=(i,e,t,s)=>({set _(r){l(i,e,r,t)},get _(){return n(i,e,s)}});(function(){const e=document.createElement("link").relList;if(e&&e.supports&&e.supports("modulepreload"))return;for(const r of document.querySelectorAll('link[rel="modulepreload"]'))s(r);new MutationObserver(r=>{for(const a of r)if(a.type==="childList")for(const u of a.addedNodes)u.tagName==="LINK"&&u.rel==="modulepreload"&&s(u)}).observe(document,{childList:!0,subtree:!0});function t(r){const a={};return r.integrity&&(a.integrity=r.integrity),r.referrerPolicy&&(a.referrerPolicy=r.referrerPolicy),r.crossOrigin==="use-credentials"?a.credentials="include":r.crossOrigin==="anonymous"?a.credentials="omit":a.credentials="same-origin",a}function s(r){if(r.ep)return;r.ep=!0;const a=t(r);fetch(r.href,a)}})();var kn=Object.prototype.hasOwnProperty;function En(i,e,t){for(t of i.keys())if(qt(t,e))return t}function qt(i,e){var t,s,r;if(i===e)return!0;if(i&&e&&(t=i.constructor)===e.constructor){if(t===Date)return i.getTime()===e.getTime();if(t===RegExp)return i.toString()===e.toString();if(t===Array){if((s=i.length)===e.length)for(;s--&&qt(i[s],e[s]););return s===-1}if(t===Set){if(i.size!==e.size)return!1;for(s of i)if(r=s,r&&typeof r=="object"&&(r=En(e,r),!r)||!e.has(r))return!1;return!0}if(t===Map){if(i.size!==e.size)return!1;for(s of i)if(r=s[0],r&&typeof r=="object"&&(r=En(e,r),!r)||!qt(s[1],e.get(r)))return!1;return!0}if(t===ArrayBuffer)i=new Uint8Array(i),e=new Uint8Array(e);else if(t===DataView){if((s=i.byteLength)===e.byteLength)for(;s--&&i.getInt8(s)===e.getInt8(s););return s===-1}if(ArrayBuffer.isView(i)){if((s=i.byteLength)===e.byteLength)for(;s--&&i[s]===e[s];);return s===-1}if(!t||typeof i=="object"){s=0;for(t in i)if(kn.call(i,t)&&++s&&!kn.call(e,t)||!(t in e)||!qt(i[t],e[t]))return!1;return Object.keys(e).length===s}}return i!==i&&e!==e}const _a={},Xa=typeof _a<"u"&&!1,In=Symbol.for("@moq/signals");var Tn,A,ge,j;Tn=In;const fn=class fn{constructor(e){c(this,A);c(this,ge,new Set);c(this,j,new Set);o(this,Tn,!0);l(this,A,e)}static from(e){return typeof e=="object"&&e!==null&&In in e?e:new fn(e)}get(){return n(this,A)}peek(){return n(this,A)}set(e,t){const s=n(this,A);if(l(this,A,e),t===!1||t===void 0&&s===n(this,A)||n(this,ge).size===0&&n(this,j).size===0)return;const r=n(this,ge),a=n(this,j);l(this,j,new Set),queueMicrotask(()=>{if(t===void 0&&qt(s,n(this,A))){for(const u of a)n(this,j).add(u);return}for(const u of r)try{u(e)}catch(h){console.error("signal subscriber error",h)}for(const u of a)try{u(e)}catch(h){console.error("signal changed error",h)}})}update(e,t=!0){const s=e(n(this,A));this.set(s,t)}mutate(e,t=!0){const s=e(n(this,A));return this.set(n(this,A),t),s}subscribe(e){return n(this,ge).add(e),()=>n(this,ge).delete(e)}changed(e){return n(this,j).add(e),()=>n(this,j).delete(e)}watch(e){const t=this.subscribe(e);return queueMicrotask(()=>e(n(this,A))),t}static async race(...e){const t=[],s=await new Promise(r=>{for(const a of e)t.push(a.changed(r))});for(const r of t)r();return s}};A=new WeakMap,ge=new WeakMap,j=new WeakMap;let E=fn;var un,nt,m,Z,Y,it,at,me,ot,Zt,Yt,ue,ps,Mn;const $t=class $t{constructor(e){c(this,ue);c(this,nt);c(this,m,[]);c(this,Z,[]);c(this,Y,[]);c(this,it);c(this,at,!1);c(this,me);c(this,ot);c(this,Zt);c(this,Yt);l(this,nt,e),l(this,ot,new Promise(t=>{l(this,me,t)})),l(this,Yt,new Promise(t=>{l(this,Zt,t)})),e&&d(this,ue,ps).call(this)}get(e){if(n(this,m)===void 0)return e.peek();const t=e.peek(),s=e.changed(()=>d(this,ue,ps).call(this));return n(this,Z).push(s),t}set(e,t,...s){if(n(this,m)===void 0)return;e.set(t);const r=s[0],a=r===void 0?void 0:r;this.cleanup(()=>e.set(a))}spawn(e){const t=e().catch(s=>{console.error("spawn error",s)});n(this,m)!==void 0&&n(this,Y).push(t)}timer(e,t){if(n(this,m)===void 0)return;let s;s=setTimeout(()=>{s=void 0,e()},t),this.cleanup(()=>s&&clearTimeout(s))}timeout(e,t){if(n(this,m)===void 0)return;const s=new $t(e);let r=setTimeout(()=>{s.close(),r=void 0},t);n(this,m).push(()=>{r&&(clearTimeout(r),s.close())})}animate(e){if(n(this,m)===void 0)return;let t=requestAnimationFrame(s=>{e(s),t=void 0});this.cleanup(()=>{t&&cancelAnimationFrame(t)})}interval(e,t){if(n(this,m)===void 0)return;const s=setInterval(()=>{e()},t);this.cleanup(()=>clearInterval(s))}effect(e){if(n(this,m)===void 0)return;const t=new $t(e);n(this,m).push(()=>t.close())}subscribe(e,t){if(n(this,m)===void 0){t(e.peek());return}this.effect(s=>{const r=s.get(e);t(r)})}event(e,t,s,r){n(this,m)!==void 0&&(e.addEventListener(t,s,r),this.cleanup(()=>e.removeEventListener(t,s,r)))}reload(){d(this,ue,ps).call(this)}cleanup(e){if(n(this,m)===void 0){e();return}n(this,m).push(e)}close(){if(n(this,m)!==void 0){n(this,Zt).call(this),n(this,me).call(this);for(const e of n(this,m))e();l(this,m,void 0);for(const e of n(this,Z))e();n(this,Z).length=0,n(this,Y).length=0}}get closed(){return n(this,Yt)}get cancel(){return n(this,ot)}};un=new WeakMap,nt=new WeakMap,m=new WeakMap,Z=new WeakMap,Y=new WeakMap,it=new WeakMap,at=new WeakMap,me=new WeakMap,ot=new WeakMap,Zt=new WeakMap,Yt=new WeakMap,ue=new WeakSet,ps=function(){n(this,at)||(l(this,at,!0),queueMicrotask(()=>d(this,ue,Mn).call(this).catch(e=>{console.error("effect error",e,n(this,it))})))},Mn=async function(){if(n(this,m)!==void 0){n(this,me).call(this),l(this,ot,new Promise(e=>{l(this,me,e)}));for(const e of n(this,Z))e();n(this,Z).length=0;for(const e of n(this,m))e();if(n(this,m).length=0,n(this,Y).length>0)try{let e;const t=new Promise(s=>{e=setTimeout(()=>{s()},5e3)});await Promise.race([Promise.all(n(this,Y)),t]),e&&clearTimeout(e),n(this,Y).length=0}catch(e){console.error("async effect error",e),n(this,it)&&console.error("stack",n(this,it))}n(this,m)!==void 0&&(l(this,at,!1),n(this,nt)&&n(this,nt).call(this,this))}},c($t,un,new FinalizationRegistry(e=>{console.warn(`Signals was garbage collected without being closed:
2
+ ${e}`)}));let xn=$t;function fs(...i){return i.join("/").replace(/\/+/g,"/").replace(/^\/+/,"").replace(/\/+$/,"")}function Ka(i,e){return i===""?!0:e.startsWith(i)?e.length===i.length?!0:e[i.length]==="/":!1}function Sn(i,e){return Ka(i,e)?i===""?e:e.length===i.length?"":e.slice(i.length+1):null}function qn(i,e){return i===""?e:e===""?i:`${i}/${e}`}function ys(){return""}class Ja{constructor(){o(this,"queue",new E([]));o(this,"closed",new E(!1))}}class Dn{constructor(e=ys()){o(this,"state",new Ja);o(this,"prefix");o(this,"closed");this.prefix=e,this.closed=new Promise(t=>{const s=this.state.closed.subscribe(r=>{r&&(t(r instanceof Error?r:void 0),s())})})}append(e){if(this.state.closed.peek())throw new Error("announced is closed");this.state.queue.mutate(t=>{t.push(e)})}close(e){this.state.closed.set(e??!0),this.state.queue.mutate(t=>{t.length=0})}async next(){for(;;){const e=this.state.queue.peek().shift();if(e)return e;const t=this.state.closed.peek();if(t instanceof Error)throw t;if(t)return;await E.race(this.state.queue,this.state.closed)}}}class Qa{constructor(){o(this,"frames",new E([]));o(this,"closed",new E(!1));o(this,"total",new E(0))}}let hn=class{constructor(e){o(this,"sequence");o(this,"state",new Qa);o(this,"closed");this.sequence=e,this.closed=new Promise(t=>{const s=this.state.closed.subscribe(r=>{r&&(t(r instanceof Error?r:void 0),s())})})}writeFrame(e){if(this.state.closed.peek())throw new Error("group is closed");this.state.frames.mutate(t=>{t.push(e)}),this.state.total.update(t=>t+1)}writeString(e){this.writeFrame(new TextEncoder().encode(e))}writeJson(e){this.writeString(JSON.stringify(e))}writeBool(e){this.writeFrame(new Uint8Array([e?1:0]))}async readFrame(){for(;;){const t=this.state.frames.peek().shift();if(t)return t;const s=this.state.closed.peek();if(s instanceof Error)throw s;if(s)return;await E.race(this.state.frames,this.state.closed)}}async readFrameSequence(){for(;;){const e=this.state.frames.peek(),t=e.shift();if(t)return{sequence:this.state.total.peek()-e.length-1,data:t};const s=this.state.closed.peek();if(s instanceof Error)throw s;if(s)return;await E.race(this.state.frames,this.state.closed)}}async readString(){const e=await this.readFrame();return e?new TextDecoder().decode(e):void 0}async readJson(){const e=await this.readString();return e?JSON.parse(e):void 0}async readBool(){const e=await this.readFrame();return e?e[0]===1:void 0}close(e){this.state.closed.set(e??!0)}};class Za{constructor(){o(this,"groups",new E([]));o(this,"closed",new E(!1))}}var ve;class Ya{constructor(e){o(this,"name");o(this,"state",new Za);c(this,ve);o(this,"closed");this.name=e,this.closed=new Promise(t=>{const s=this.state.closed.subscribe(r=>{r&&(t(r instanceof Error?r:void 0),s())})})}appendGroup(){if(this.state.closed.peek())throw new Error("track is closed");const e=new hn(n(this,ve)??0);return l(this,ve,e.sequence+1),this.state.groups.mutate(t=>{t.push(e),t.sort((s,r)=>s.sequence-r.sequence)}),e}writeGroup(e){if(this.state.closed.peek())throw new Error("track is closed");if(e.sequence<(n(this,ve)??0)){e.close();return}l(this,ve,e.sequence+1),this.state.groups.mutate(t=>{t.push(e),t.sort((s,r)=>s.sequence-r.sequence)})}writeFrame(e){const t=this.appendGroup();t.writeFrame(e),t.close()}writeString(e){const t=this.appendGroup();t.writeString(e),t.close()}writeJson(e){const t=this.appendGroup();t.writeJson(e),t.close()}writeBool(e){const t=this.appendGroup();t.writeBool(e),t.close()}async nextGroup(){for(;;){const e=this.state.groups.peek();if(e.length>0)return e.shift();const t=this.state.closed.peek();if(t instanceof Error)throw t;if(t)return;await E.race(this.state.groups,this.state.closed)}}async readFrame(){var e;return(e=await this.readFrameSequence())==null?void 0:e.data}async readFrameSequence(){var e;for(;;){const t=this.state.groups.peek();for(;t.length>1;){const h=t[0].state.frames.peek(),w=h.shift();if(w){const g=t[0].state.total.peek()-h.length-1;return{group:t[0].sequence,frame:g,data:w}}(e=t.shift())==null||e.close()}if(t.length===0){const h=this.state.closed.peek();if(h instanceof Error)throw h;if(h)return;await E.race(this.state.groups,this.state.closed);continue}const s=t[0],r=s.state.frames.peek(),a=r.shift();if(a){const h=s.state.total.peek()-r.length-1;return{group:s.sequence,frame:h,data:a}}const u=this.state.closed.peek();if(u instanceof Error)throw u;if(u)return;await E.race(this.state.groups,this.state.closed,s.state.frames)}}async readString(){const e=await this.readFrame();if(e)return new TextDecoder().decode(e)}async readJson(){const e=await this.readString();if(e)return JSON.parse(e)}async readBool(){const e=await this.readFrame();if(e){if(e.byteLength!==1||!(e[0]===0||e[0]===1))throw new Error("invalid bool frame");return e[0]===1}}close(e){this.state.closed.set(e??!0);for(const t of this.state.groups.peek())t.close(e)}}ve=new WeakMap;class eo{constructor(){o(this,"requested",new E([]));o(this,"closed",new E(!1))}}class Fn{constructor(){o(this,"state",new eo);o(this,"closed");this.closed=new Promise(e=>{const t=this.state.closed.subscribe(s=>{s&&(e(s instanceof Error?s:void 0),t())})})}async requested(){for(;;){const e=this.state.requested.peek().pop();if(e)return e;const t=this.state.closed.peek();if(t instanceof Error)throw t;if(t)return;await E.race(this.state.requested,this.state.closed)}}subscribe(e,t){const s=new Ya(e);if(this.state.closed.peek())throw new Error(`broadcast is closed: ${this.state.closed.peek()}`);return this.state.requested.mutate(r=>{r.push({track:s,priority:t}),r.sort((a,u)=>a.priority-u.priority)}),s}close(e){this.state.closed.set(e??!0);for(const{track:t}of this.state.requested.peek())t.close(e);this.state.requested.mutate(t=>{t.length=0})}}const be=class be{constructor(e){o(this,"value");if(e<0n||e>be.MAX)throw new Error(`VarInt value out of range: ${e}`);this.value=e}static from(e){return new be(BigInt(e))}size(){const e=this.value;if(e<2n**6n)return 1;if(e<2n**14n)return 2;if(e<2n**30n)return 4;if(e<2n**62n)return 8;throw new Error("VarInt value too large")}encode(e){const t=this.value,s=this.size();if(e.byteOffset+e.byteLength+s>e.buffer.byteLength)throw new Error("destination buffer too small");const r=new DataView(e.buffer,e.byteOffset+e.byteLength,s);if(s===1)r.setUint8(0,Number(t));else if(s===2)r.setUint16(0,16384|Number(t),!1);else if(s===4)r.setUint32(0,2<<30|Number(t),!1);else if(s===8)r.setBigUint64(0,3n<<62n|t,!1);else throw new Error("VarInt value too large");return new Uint8Array(e.buffer,e.byteOffset,e.byteLength+s)}static decode(e){if(e.byteLength<1)throw new Error("Unexpected end of buffer");const t=new DataView(e.buffer,e.byteOffset),s=t.getUint8(0),r=s>>6;let a,u;switch(r){case 0:a=BigInt(s&63),u=1;break;case 1:if(2>e.length)throw new Error("Unexpected end of buffer");a=BigInt(t.getUint16(0,!1)&16383),u=2;break;case 2:if(4>e.length)throw new Error("Unexpected end of buffer");a=BigInt(t.getUint32(0,!1)&1073741823),u=4;break;case 3:if(8>e.length)throw new Error("Unexpected end of buffer");a=t.getBigUint64(0,!1)&0x3fffffffffffffffn,u=8;break;default:throw new Error("Invalid VarInt tag")}const h=new Uint8Array(e.buffer,e.byteOffset+u,e.byteLength-u);return[new be(a),h]}};o(be,"MAX",(1n<<62n)-1n),o(be,"MAX_SIZE",8);let $=be;const Q={Bi:0,Uni:1};class qe{constructor(e){o(this,"value");this.value=e}static create(e,t,s){let r=e<<2n;return t===Q.Uni&&(r|=0x02n),s&&(r|=0x01n),new qe($.from(r))}get dir(){return(this.value.value&0x02n)!==0n?Q.Uni:Q.Bi}get serverInitiated(){return(this.value.value&0x01n)!==0n}canRecv(e){return this.dir===Q.Uni?this.serverInitiated!==e:!0}canSend(e){return this.dir===Q.Uni?this.serverInitiated===e:!0}}const Gn=4,jn=5,Wn=8,sn=9,Vn=29;function $n(i){switch(i.type){case"stream":{let e=new Uint8Array(new ArrayBuffer(9+i.data.length),0,1);return e[0]=i.fin?sn:Wn,e=i.id.value.encode(e),e=new Uint8Array(e.buffer,e.byteOffset,e.byteLength+i.data.length),e.set(i.data,e.byteLength-i.data.length),e}case"reset_stream":{let e=new Uint8Array(new ArrayBuffer(17),0,1);return e[0]=Gn,e=i.id.value.encode(e),e=i.code.encode(e),e}case"stop_sending":{let e=new Uint8Array(new ArrayBuffer(17),0,1);return e[0]=jn,e=i.id.value.encode(e),e=i.code.encode(e),e}case"connection_close":{const e=new TextEncoder().encode(i.reason);let t=new Uint8Array(new ArrayBuffer(9+e.length),0,1);return t[0]=Vn,t=i.code.encode(t),t=new Uint8Array(t.buffer,t.byteOffset,t.byteLength+e.length),t.set(e,t.byteLength-e.length),t}}}function to(i){if(i.length===0)throw new Error("Invalid frame: empty buffer");const e=i[0];i=i.slice(1);let t;if(e===Gn){[t,i]=$.decode(i);const s=new qe(t);return[t,i]=$.decode(i),{type:"reset_stream",id:s,code:t}}if(e===jn){[t,i]=$.decode(i);const s=new qe(t);return[t,i]=$.decode(i),{type:"stop_sending",id:s,code:t}}if(e===Vn){[t,i]=$.decode(i);const s=t,r=new TextDecoder().decode(i);return{type:"connection_close",code:s,reason:r}}if(e===Wn||e===sn)return[t,i]=$.decode(i),{type:"stream",id:new qe(t),data:i,fin:e===sn};throw new Error(`Invalid frame type: ${e}`)}class so{constructor(){o(this,"incomingHighWaterMark");o(this,"incomingMaxAge");o(this,"maxDatagramSize");o(this,"outgoingHighWaterMark");o(this,"outgoingMaxAge");o(this,"readable");o(this,"writable");this.incomingHighWaterMark=1024,this.incomingMaxAge=null,this.maxDatagramSize=1200,this.outgoingHighWaterMark=1024,this.outgoingMaxAge=null,this.readable=new ReadableStream({}),this.writable=new WritableStream({})}}var U,ee,N,es,I,L,Ns,Ls,ts,ss,ke,Ee,Rs,Hn,f,zn,_n,Xn,Kn,Jn,Qn,Zn,ye,K,gs;const Ts=class Ts{constructor(e,t){c(this,f);c(this,U);c(this,ee,!1);c(this,N);c(this,es);c(this,I,new Map);c(this,L,new Map);c(this,Ns,0n);c(this,Ls,0n);o(this,"ready");c(this,ts);o(this,"closed");c(this,ss);o(this,"incomingBidirectionalStreams");c(this,ke);o(this,"incomingUnidirectionalStreams");c(this,Ee);o(this,"datagrams",new so);var s;if(t!=null&&t.requireUnreliable)throw new Error("not allowed to use WebSocket; requireUnreliable is true");if(t!=null&&t.serverCertificateHashes&&console.warn("serverCertificateHashes is not supported; trying anyway"),e=d(s=Ts,Rs,Hn).call(s,e),l(this,U,new WebSocket(e,["webtransport"])),this.ready=new Promise(r=>{l(this,ts,r)}),this.closed=new Promise(r=>{l(this,ss,r)}),n(this,U).binaryType="arraybuffer",n(this,U).onopen=()=>n(this,ts).call(this),n(this,U).onmessage=r=>d(this,f,zn).call(this,r),n(this,U).onerror=r=>d(this,f,_n).call(this,r),n(this,U).onclose=r=>d(this,f,Xn).call(this,r),this.incomingBidirectionalStreams=new ReadableStream({start:r=>{l(this,ke,r)}}),this.incomingUnidirectionalStreams=new ReadableStream({start:r=>{l(this,Ee,r)}}),!n(this,ke)||!n(this,Ee))throw new Error("ReadableStream didn't call start")}async createBidirectionalStream(){if(await this.ready,n(this,N))throw n(this,es)||new Error("Connection closed");const e=qe.create(bs(this,Ls)._++,Q.Bi,n(this,ee)),t=new WritableStream({start:r=>{n(this,I).set(e.value.value,r)},write:async r=>{await Promise.race([d(this,f,ye).call(this,{type:"stream",id:e,data:r,fin:!1}),this.closed])},abort:r=>{console.warn("abort",r),d(this,f,K).call(this,{type:"reset_stream",id:e,code:$.from(0)}),n(this,I).delete(e.value.value)},close:async()=>{await Promise.race([d(this,f,ye).call(this,{type:"stream",id:e,data:new Uint8Array,fin:!0}),this.closed]),n(this,I).delete(e.value.value)}});return{readable:new ReadableStream({start:r=>{n(this,L).set(e.value.value,r)},cancel:async()=>{d(this,f,K).call(this,{type:"stop_sending",id:e,code:$.from(0)}),n(this,L).delete(e.value.value)}}),writable:t}}async createUnidirectionalStream(){if(await this.ready,n(this,N))throw n(this,N);const e=qe.create(bs(this,Ns)._++,Q.Uni,n(this,ee)),t=this;return new WritableStream({start:r=>{n(t,I).set(e.value.value,r)},async write(r){var a;await Promise.race([d(a=t,f,ye).call(a,{type:"stream",id:e,data:r,fin:!1}),t.closed])},abort(r){var a;console.warn("abort",r),d(a=t,f,K).call(a,{type:"reset_stream",id:e,code:$.from(0)}),n(t,I).delete(e.value.value)},async close(){var r;await Promise.race([d(r=t,f,ye).call(r,{type:"stream",id:e,data:new Uint8Array,fin:!0}),t.closed]),n(t,I).delete(e.value.value)}})}close(e){if(n(this,N))return;const t=(e==null?void 0:e.closeCode)??0,s=(e==null?void 0:e.reason)??"";d(this,f,K).call(this,{type:"connection_close",code:$.from(t),reason:s}),setTimeout(()=>{n(this,U).close()},100),d(this,f,gs).call(this,t,s)}get congestionControl(){return"default"}};U=new WeakMap,ee=new WeakMap,N=new WeakMap,es=new WeakMap,I=new WeakMap,L=new WeakMap,Ns=new WeakMap,Ls=new WeakMap,ts=new WeakMap,ss=new WeakMap,ke=new WeakMap,Ee=new WeakMap,Rs=new WeakSet,Hn=function(e){const t=typeof e=="string"?new URL(e):e;let s=t.protocol;if(s==="https:")s="wss:";else if(s==="http:")s="ws:";else if(s!=="ws:"&&s!=="wss:")throw new Error(`Unsupported protocol: ${s}`);return`${s}//${t.host}${t.pathname}${t.search}`},f=new WeakSet,zn=function(e){if(!(e.data instanceof ArrayBuffer))return;const t=new Uint8Array(e.data);try{const s=to(t);d(this,f,Kn).call(this,s)}catch(s){console.error("Failed to decode frame:",s),this.close({closeCode:1002,reason:"Protocol violation"})}},_n=function(e){n(this,N)||(l(this,N,new Error(`WebSocket error: ${e.type}`)),d(this,f,gs).call(this,1006,"WebSocket error"))},Xn=function(e){n(this,N)||(l(this,N,new Error(`Connection closed: ${e.code} ${e.reason}`)),d(this,f,gs).call(this,e.code,e.reason))},Kn=function(e){if(e.type==="stream")d(this,f,Jn).call(this,e);else if(e.type==="reset_stream")d(this,f,Qn).call(this,e);else if(e.type==="stop_sending")d(this,f,Zn).call(this,e);else if(e.type==="connection_close")l(this,es,new Error(`Connection closed: ${e.code.value}: ${e.reason}`)),n(this,U).close();else{const t=e;throw new Error(`Unknown frame type: ${t}`)}},Jn=async function(e){const t=e.id.value.value;if(!e.id.canRecv(n(this,ee)))throw new Error("Invalid stream ID direction");let s=n(this,L).get(t);if(!s){if(e.id.serverInitiated===n(this,ee))return;if(!e.id.canRecv(n(this,ee)))throw new Error("received write-only stream");const r=new ReadableStream({start:a=>{s=a,n(this,L).set(t,a)},cancel:()=>{d(this,f,K).call(this,{type:"stop_sending",id:e.id,code:$.from(0)}),n(this,L).delete(t)}});if(!s)throw new Error("ReadableStream didn't call start");if(e.id.dir===Q.Bi){const a=new WritableStream({start:u=>{n(this,I).set(t,u)},write:async u=>{await Promise.race([d(this,f,ye).call(this,{type:"stream",id:e.id,data:u,fin:!1}),this.closed])},abort:u=>{console.warn("abort",u),d(this,f,K).call(this,{type:"reset_stream",id:e.id,code:$.from(0)}),n(this,I).delete(t)},close:async()=>{await Promise.race([d(this,f,ye).call(this,{type:"stream",id:e.id,data:new Uint8Array,fin:!0}),this.closed]),n(this,I).delete(t)}});n(this,ke).enqueue({readable:r,writable:a})}else n(this,Ee).enqueue(r)}e.data.byteLength>0&&s.enqueue(e.data),e.fin&&(s.close(),n(this,L).delete(t))},Qn=function(e){const t=e.id.value.value,s=n(this,L).get(t);s&&(s.error(new Error(`RESET_STREAM: ${e.code.value}`)),n(this,L).delete(t))},Zn=function(e){const t=e.id.value.value,s=n(this,I).get(t);s&&(s.error(new Error(`STOP_SENDING: ${e.code.value}`)),n(this,I).delete(t),d(this,f,K).call(this,{type:"reset_stream",id:e.id,code:e.code}))},ye=async function(e){for(;n(this,U).bufferedAmount>64*1024;)await new Promise(s=>setTimeout(s,10));const t=$n(e);n(this,U).send(t)},K=function(e){const t=$n(e);n(this,U).send(t)},gs=function(e,t){n(this,ss).call(this,{closeCode:e,reason:t});try{n(this,ke).close()}catch{}try{n(this,Ee).close()}catch{}for(const s of n(this,I).values())try{s.error(n(this,N))}catch{}for(const s of n(this,L).values())try{s.error(n(this,N))}catch{}n(this,I).clear(),n(this,L).clear()},c(Ts,Rs);let vs=Ts;const Yn=2**6-1,ei=2**14-1,ti=2**30-1,ro=2**31-1,ln=Number.MAX_SAFE_INTEGER,An=1024*1024*64;let ks=class rn{constructor(e){o(this,"reader");o(this,"writer");this.writer=new Ae(e.writable),this.reader=new Qr(e.readable)}static async accept(e){for(;;){const t=e.incomingBidirectionalStreams.getReader(),s=await t.read();return t.releaseLock(),s.done?void 0:new rn(s.value)}}static async open(e,t){return new rn(await e.createBidirectionalStream({sendOrder:t}))}close(){this.writer.close(),this.reader.stop(new Error("cancel"))}abort(e){this.writer.reset(e),this.reader.stop(e)}};var k,rs,te,v,ms,J,G;class Qr{constructor(e,t){c(this,v);c(this,k);c(this,rs);c(this,te);var s;l(this,k,t??new Uint8Array),l(this,rs,e),l(this,te,(s=n(this,rs))==null?void 0:s.getReader())}async read(e){return e===0?new Uint8Array:(await d(this,v,J).call(this,e),d(this,v,G).call(this,e))}async readAll(){for(;await d(this,v,ms).call(this););return d(this,v,G).call(this,n(this,k).byteLength)}async string(){const e=await this.u53(),t=await this.read(e);return new TextDecoder().decode(t)}async bool(){const e=await this.u8();if(e===0)return!1;if(e===1)return!0;throw new Error("invalid bool value")}async u8(){return await d(this,v,J).call(this,1),d(this,v,G).call(this,1)[0]}async u16(){await d(this,v,J).call(this,2);const t=new DataView(n(this,k).buffer,n(this,k).byteOffset,2).getUint16(0);return d(this,v,G).call(this,2),t}async u53(){const e=await this.u62();if(e>ln)throw new Error("value larger than 53-bits; use v62 instead");return Number(e)}async u62(){await d(this,v,J).call(this,1);const e=(n(this,k)[0]&192)>>6;if(e===0){const r=d(this,v,G).call(this,1)[0];return BigInt(r)&0x3fn}if(e===1){await d(this,v,J).call(this,2);const r=d(this,v,G).call(this,2),a=new DataView(r.buffer,r.byteOffset,r.byteLength);return BigInt(a.getUint16(0))&0x3fffn}if(e===2){await d(this,v,J).call(this,4);const r=d(this,v,G).call(this,4),a=new DataView(r.buffer,r.byteOffset,r.byteLength);return BigInt(a.getUint32(0))&0x3fffffffn}await d(this,v,J).call(this,8);const t=d(this,v,G).call(this,8);return new DataView(t.buffer,t.byteOffset,t.byteLength).getBigUint64(0)&0x3fffffffffffffffn}async done(){return n(this,k).byteLength>0?!1:!await d(this,v,ms).call(this)}stop(e){var t;(t=n(this,te))==null||t.cancel(e).catch(()=>{})}get closed(){var e;return((e=n(this,te))==null?void 0:e.closed)??Promise.resolve()}}k=new WeakMap,rs=new WeakMap,te=new WeakMap,v=new WeakSet,ms=async function(){if(!n(this,te))return!1;const e=await n(this,te).read();if(e.done)return!1;if(e.value.byteLength===0)throw new Error("unexpected empty chunk");const t=new Uint8Array(e.value);if(n(this,k).byteLength===0)l(this,k,t);else{const s=new Uint8Array(n(this,k).byteLength+t.byteLength);s.set(n(this,k)),s.set(t,n(this,k).byteLength),l(this,k,s)}return!0},J=async function(e){if(e>An)throw new Error(`read size ${e} exceeds max size ${An}`);for(;n(this,k).byteLength<e;)if(!await d(this,v,ms).call(this))throw new Error("unexpected end of stream")},G=function(e){const t=new Uint8Array(n(this,k).buffer,n(this,k).byteOffset,e);return l(this,k,new Uint8Array(n(this,k).buffer,n(this,k).byteOffset+e,n(this,k).byteLength-e)),t};var se,ns,D;const yn=class yn{constructor(e){c(this,se);c(this,ns);c(this,D);l(this,ns,e),l(this,D,new ArrayBuffer(8)),l(this,se,n(this,ns).getWriter())}async bool(e){await this.write(Es(n(this,D),e?1:0))}async u8(e){await this.write(Es(n(this,D),e))}async u16(e){await this.write(wn(n(this,D),e))}async i32(e){if(Math.abs(e)>ro)throw new Error(`overflow, value larger than 32-bits: ${e.toString()}`);await this.write(no(n(this,D),e))}async u53(e){if(e<0)throw new Error(`underflow, value is negative: ${e.toString()}`);if(e>ln)throw new Error(`overflow, value larger than 53-bits: ${e.toString()}`);await this.write(io(n(this,D),e))}async u62(e){if(e<0)throw new Error(`underflow, value is negative: ${e.toString()}`);await this.write(ao(n(this,D),e))}async write(e){await n(this,se).write(e)}async string(e){const t=new TextEncoder().encode(e);await this.u53(t.byteLength),await this.write(t)}close(){n(this,se).close().catch(()=>{})}get closed(){return n(this,se).closed}reset(e){n(this,se).abort(e).catch(()=>{})}static async open(e){const t=await e.createUnidirectionalStream();return new yn(t)}};se=new WeakMap,ns=new WeakMap,D=new WeakMap;let Ae=yn;function Es(i,e){const t=new Uint8Array(i,0,1);return t[0]=e,t}function wn(i,e){const t=new DataView(i,0,2);return t.setUint16(0,e),new Uint8Array(t.buffer,t.byteOffset,t.byteLength)}function no(i,e){const t=new DataView(i,0,4);return t.setInt32(0,e),new Uint8Array(t.buffer,t.byteOffset,t.byteLength)}function si(i,e){const t=new DataView(i,0,4);return t.setUint32(0,e),new Uint8Array(t.buffer,t.byteOffset,t.byteLength)}function io(i,e){if(e<=Yn)return Es(i,e);if(e<=ei)return wn(i,e|16384);if(e<=ti)return si(i,e|2147483648);if(e<=ln)return ri(i,BigInt(e)|0xc000000000000000n);throw new Error(`overflow, value larger than 53-bits: ${e.toString()}`)}function ao(i,e){return e<Yn?Es(i,Number(e)):e<ei?wn(i,Number(e)|16384):e<=ti?si(i,Number(e)|2147483648):ri(i,BigInt(e)|0xc000000000000000n)}function ri(i,e){const t=new DataView(i,0,8);return t.setBigUint64(0,e),new Uint8Array(t.buffer,t.byteOffset,t.byteLength)}var ct;class ni{constructor(e){c(this,ct);l(this,ct,e.incomingUnidirectionalStreams.getReader())}async next(){const e=await n(this,ct).read();if(!e.done)return new Qr(e.value)}close(){n(this,ct).cancel()}}ct=new WeakMap;function C(i){return i instanceof Error?i:new Error(String(i))}function oo(i){throw new Error(`unreachable: ${i}`)}const co=new Error("request for lock canceled");var uo=function(i,e,t,s){function r(a){return a instanceof t?a:new t(function(u){u(a)})}return new(t||(t=Promise))(function(a,u){function h(y){try{g(s.next(y))}catch(q){u(q)}}function w(y){try{g(s.throw(y))}catch(q){u(q)}}function g(y){y.done?a(y.value):r(y.value).then(h,w)}g((s=s.apply(i,e||[])).next())})};class ho{constructor(e,t=co){this._value=e,this._cancelError=t,this._queue=[],this._weightedWaiters=[]}acquire(e=1,t=0){if(e<=0)throw new Error(`invalid weight ${e}: must be positive`);return new Promise((s,r)=>{const a={resolve:s,reject:r,weight:e,priority:t},u=ii(this._queue,h=>t<=h.priority);u===-1&&e<=this._value?this._dispatchItem(a):this._queue.splice(u+1,0,a)})}runExclusive(e){return uo(this,arguments,void 0,function*(t,s=1,r=0){const[a,u]=yield this.acquire(s,r);try{return yield t(a)}finally{u()}})}waitForUnlock(e=1,t=0){if(e<=0)throw new Error(`invalid weight ${e}: must be positive`);return this._couldLockImmediately(e,t)?Promise.resolve():new Promise(s=>{this._weightedWaiters[e-1]||(this._weightedWaiters[e-1]=[]),lo(this._weightedWaiters[e-1],{resolve:s,priority:t})})}isLocked(){return this._value<=0}getValue(){return this._value}setValue(e){this._value=e,this._dispatchQueue()}release(e=1){if(e<=0)throw new Error(`invalid weight ${e}: must be positive`);this._value+=e,this._dispatchQueue()}cancel(){this._queue.forEach(e=>e.reject(this._cancelError)),this._queue=[]}_dispatchQueue(){for(this._drainUnlockWaiters();this._queue.length>0&&this._queue[0].weight<=this._value;)this._dispatchItem(this._queue.shift()),this._drainUnlockWaiters()}_dispatchItem(e){const t=this._value;this._value-=e.weight,e.resolve([t,this._newReleaser(e.weight)])}_newReleaser(e){let t=!1;return()=>{t||(t=!0,this.release(e))}}_drainUnlockWaiters(){if(this._queue.length===0)for(let e=this._value;e>0;e--){const t=this._weightedWaiters[e-1];t&&(t.forEach(s=>s.resolve()),this._weightedWaiters[e-1]=[])}else{const e=this._queue[0].priority;for(let t=this._value;t>0;t--){const s=this._weightedWaiters[t-1];if(!s)continue;const r=s.findIndex(a=>a.priority<=e);(r===-1?s:s.splice(0,r)).forEach(a=>a.resolve())}}}_couldLockImmediately(e,t){return(this._queue.length===0||this._queue[0].priority<t)&&e<=this._value}}function lo(i,e){const t=ii(i,s=>e.priority<=s.priority);i.splice(t+1,0,e)}function ii(i,e){for(let t=i.length-1;t>=0;t--)if(e(i[t]))return t;return-1}var wo=function(i,e,t,s){function r(a){return a instanceof t?a:new t(function(u){u(a)})}return new(t||(t=Promise))(function(a,u){function h(y){try{g(s.next(y))}catch(q){u(q)}}function w(y){try{g(s.throw(y))}catch(q){u(q)}}function g(y){y.done?a(y.value):r(y.value).then(h,w)}g((s=s.apply(i,e||[])).next())})};class Un{constructor(e){this._semaphore=new ho(1,e)}acquire(){return wo(this,arguments,void 0,function*(e=0){const[,t]=yield this._semaphore.acquire(1,e);return t})}runExclusive(e,t=0){return this._semaphore.runExclusive(()=>e(),1,t)}isLocked(){return this._semaphore.isLocked()}waitForUnlock(e=0){return this._semaphore.waitForUnlock(1,e)}release(){this._semaphore.isLocked()&&this._semaphore.release()}cancel(){return this._semaphore.cancel()}}async function b(i,e){let t=new Uint8Array;const s=new Ae(new WritableStream({write(r){const a=t.byteLength+r.byteLength;if(a>t.buffer.byteLength){const u=Math.max(a,t.buffer.byteLength*2),h=new ArrayBuffer(u),w=new Uint8Array(h,0,a);w.set(t),w.set(r,t.byteLength),t=w}else t=new Uint8Array(t.buffer,0,a),t.set(r,a-r.byteLength)}}));try{await e(s)}finally{s.close()}if(await s.closed,t.byteLength>65535)throw new Error(`Message too large: ${t.byteLength} bytes (max 65535)`);await i.u16(t.byteLength),await i.write(t)}async function p(i,e){const t=await i.u16(),s=await i.read(t),r=new Qr(void 0,s),a=await e(r);if(!await r.done())throw new Error("Message decoding consumed too few bytes");return a}var Cs,ai,Os,oi;const At=class At{constructor(e,t,s,r,a,u,h,w,g){c(this,Cs);o(this,"requestId");o(this,"trackNamespace");o(this,"trackName");o(this,"subscriberPriority");o(this,"groupOrder");o(this,"startGroup");o(this,"startObject");o(this,"endGroup");o(this,"endObject");this.requestId=e,this.trackNamespace=t,this.trackName=s,this.subscriberPriority=r,this.groupOrder=a,this.startGroup=u,this.startObject=h,this.endGroup=w,this.endObject=g}async encode(e){return b(e,d(this,Cs,ai).bind(this))}static async decode(e){return p(e,d(At,Os,oi))}};Cs=new WeakSet,ai=async function(e){throw new Error("FETCH messages are not supported")},Os=new WeakSet,oi=async function(e){throw new Error("FETCH messages are not supported")},c(At,Os),o(At,"id",22);let Ot=At;var Bs,ci,Ms,di;const Ut=class Ut{constructor(e){c(this,Bs);o(this,"requestId");this.requestId=e}async encode(e){return b(e,d(this,Bs,ci).bind(this))}static async decode(e){return p(e,d(Ut,Ms,di))}};Bs=new WeakSet,ci=async function(e){throw new Error("FETCH_OK messages are not supported")},Ms=new WeakSet,di=async function(e){throw new Error("FETCH_OK messages are not supported")},c(Ut,Ms),o(Ut,"id",24);let Bt=Ut;var Ds,ui,Fs,hi;const Pt=class Pt{constructor(e,t,s){c(this,Ds);o(this,"requestId");o(this,"errorCode");o(this,"reasonPhrase");this.requestId=e,this.errorCode=t,this.reasonPhrase=s}async encode(e){return b(e,d(this,Ds,ui).bind(this))}static async decode(e){return p(e,d(Pt,Fs,hi))}};Ds=new WeakSet,ui=async function(e){throw new Error("FETCH_ERROR messages are not supported")},Fs=new WeakSet,hi=async function(e){throw new Error("FETCH_ERROR messages are not supported")},c(Pt,Fs),o(Pt,"id",25);let Mt=Pt;var Gs,li,js,wi;const Nt=class Nt{constructor(e){c(this,Gs);o(this,"requestId");this.requestId=e}async encode(e){return b(e,d(this,Gs,li).bind(this))}static async decode(e){return p(e,d(Nt,js,wi))}};Gs=new WeakSet,li=async function(e){throw new Error("FETCH_CANCEL messages are not supported")},js=new WeakSet,wi=async function(e){throw new Error("FETCH_CANCEL messages are not supported")},c(Nt,js),o(Nt,"id",23);let Dt=Nt;var Ws,fi,Vs,yi;const Le=class Le{constructor(e){c(this,Ws);o(this,"newSessionUri");this.newSessionUri=e}async encode(e){return b(e,d(this,Ws,fi).bind(this))}static async decode(e){return p(e,d(Le,Vs,yi))}};Ws=new WeakSet,fi=async function(e){await e.string(this.newSessionUri)},Vs=new WeakSet,yi=async function(e){const t=await e.string();return new Le(t)},c(Le,Vs),o(Le,"id",16);let Ft=Le;async function le(i,e){const t=e.split("/");await i.u53(t.length);for(const s of t)await i.string(s)}async function we(i){const e=[],t=await i.u53();for(let s=0;s<t;s++)e.push(await i.string());return fs(...e)}const tn={MaxRequestId:2n,Implementation:7n};class O{constructor(){o(this,"vars");o(this,"bytes");this.vars=new Map,this.bytes=new Map}get size(){return this.vars.size+this.bytes.size}setBytes(e,t){if(e%2n!==1n)throw new Error(`invalid parameter id: ${e.toString()}, must be odd`);this.bytes.set(e,t)}setVarint(e,t){if(e%2n!==0n)throw new Error(`invalid parameter id: ${e.toString()}, must be even`);this.vars.set(e,t)}getBytes(e){if(e%2n!==1n)throw new Error(`invalid parameter id: ${e.toString()}, must be odd`);return this.bytes.get(e)}getVarint(e){if(e%2n!==0n)throw new Error(`invalid parameter id: ${e.toString()}, must be even`);return this.vars.get(e)}removeBytes(e){if(e%2n!==1n)throw new Error(`invalid parameter id: ${e.toString()}, must be odd`);return this.bytes.delete(e)}removeVarint(e){if(e%2n!==0n)throw new Error(`invalid parameter id: ${e.toString()}, must be even`);return this.vars.delete(e)}async encode(e){await e.u53(this.vars.size+this.bytes.size);for(const[t,s]of this.vars)await e.u62(t),await e.u62(s);for(const[t,s]of this.bytes)await e.u62(t),await e.u53(s.length),await e.write(s)}static async decode(e){const t=await e.u53(),s=new O;for(let r=0;r<t;r++){const a=await e.u62();if(a%2n===0n){if(s.vars.has(a))throw new Error(`duplicate parameter id: ${a.toString()}`);const u=await e.u62();s.setVarint(a,u)}else{if(s.bytes.has(a))throw new Error(`duplicate parameter id: ${a.toString()}`);const u=await e.u53(),h=await e.read(u);s.setBytes(a,h)}}return s}}var Hs,bi,zs,pi;const Re=class Re{constructor(e,t,s,r,a,u,h,w){c(this,Hs);o(this,"requestId");o(this,"trackNamespace");o(this,"trackName");o(this,"trackAlias");o(this,"groupOrder");o(this,"contentExists");o(this,"largest");o(this,"forward");this.requestId=e,this.trackNamespace=t,this.trackName=s,this.trackAlias=r,this.groupOrder=a,this.contentExists=u,this.largest=h,this.forward=w}async encode(e){return b(e,d(this,Hs,bi).bind(this))}static async decode(e){return p(e,d(Re,zs,pi))}};Hs=new WeakSet,bi=async function(e){if(await e.u62(this.requestId),await le(e,this.trackNamespace),await e.string(this.trackName),await e.u62(this.trackAlias),await e.u8(this.groupOrder),await e.bool(this.contentExists),this.contentExists!==!!this.largest)throw new Error("contentExists and largest must both be true or false");this.largest&&(await e.u62(this.largest.groupId),await e.u62(this.largest.objectId)),await e.bool(this.forward),await e.u53(0)},zs=new WeakSet,pi=async function(e){const t=await e.u62(),s=await we(e),r=await e.string(),a=await e.u62(),u=await e.u8(),h=await e.bool(),w=h?{groupId:await e.u62(),objectId:await e.u62()}:void 0,g=await e.bool();return await O.decode(e),new Re(t,s,r,a,u,h,w,g)},c(Re,zs),o(Re,"id",29);let Gt=Re;var _s,gi,Xs,mi;const Lt=class Lt{constructor(){c(this,_s)}async encode(e){return b(e,d(this,_s,gi).bind(this))}static async decode(e){return p(e,d(Lt,Xs,mi))}};_s=new WeakSet,gi=async function(e){throw new Error("PUBLISH_OK messages are not supported")},Xs=new WeakSet,mi=async function(e){throw new Error("PUBLISH_OK messages are not supported")},c(Lt,Xs),o(Lt,"id",30);let jt=Lt;var Ks,vi,Js,ki;const Te=class Te{constructor(e,t,s){c(this,Ks);o(this,"requestId");o(this,"errorCode");o(this,"reasonPhrase");this.requestId=e,this.errorCode=t,this.reasonPhrase=s}async encode(e){return b(e,d(this,Ks,vi).bind(this))}static async decode(e){return p(e,d(Te,Js,ki))}};Ks=new WeakSet,vi=async function(e){await e.u62(this.requestId),await e.u62(BigInt(this.errorCode)),await e.string(this.reasonPhrase)},Js=new WeakSet,ki=async function(e){const t=await e.u62(),s=Number(await e.u62()),r=await e.string();return new Te(t,s,r)},c(Te,Js),o(Te,"id",31);let ft=Te;var Qs,Ei,Zs,Ii;const Ce=class Ce{constructor(e,t,s){c(this,Qs);o(this,"requestId");o(this,"statusCode");o(this,"reasonPhrase");this.requestId=e,this.statusCode=t,this.reasonPhrase=s}async encode(e){return b(e,d(this,Qs,Ei).bind(this))}static async decode(e){return p(e,d(Ce,Zs,Ii))}};Qs=new WeakSet,Ei=async function(e){await e.u62(this.requestId),await e.u62(BigInt(this.statusCode)),await e.u62(BigInt(0)),await e.string(this.reasonPhrase)},Zs=new WeakSet,Ii=async function(e){const t=await e.u62(),s=Number(await e.u62());await e.u62();const r=await e.string();return new Ce(t,s,r)},c(Ce,Zs),o(Ce,"id",11);let Ue=Ce;var Ys,xi,er,Si;const Oe=class Oe{constructor(e,t){c(this,Ys);o(this,"requestId");o(this,"trackNamespace");this.requestId=e,this.trackNamespace=t}async encode(e){return b(e,d(this,Ys,xi).bind(this))}static async decode(e){return p(e,d(Oe,er,Si))}};Ys=new WeakSet,xi=async function(e){await e.u62(this.requestId),await le(e,this.trackNamespace),await e.u53(0)},er=new WeakSet,Si=async function(e){const t=await e.u62(),s=await we(e);return await O.decode(e),new Oe(t,s)},c(Oe,er),o(Oe,"id",6);let yt=Oe;var tr,qi,sr,$i;const Be=class Be{constructor(e){c(this,tr);o(this,"requestId");this.requestId=e}async encode(e){return b(e,d(this,tr,qi).bind(this))}static async decode(e){return p(e,d(Be,sr,$i))}};tr=new WeakSet,qi=async function(e){await e.u62(this.requestId)},sr=new WeakSet,$i=async function(e){const t=await e.u62();return new Be(t)},c(Be,sr),o(Be,"id",7);let Wt=Be;var rr,Ai,nr,Ui;const Me=class Me{constructor(e,t,s){c(this,rr);o(this,"requestId");o(this,"errorCode");o(this,"reasonPhrase");this.requestId=e,this.errorCode=t,this.reasonPhrase=s}async encode(e){return b(e,d(this,rr,Ai).bind(this))}static async decode(e){return p(e,d(Me,nr,Ui))}};rr=new WeakSet,Ai=async function(e){await e.u62(this.requestId),await e.u62(BigInt(this.errorCode)),await e.string(this.reasonPhrase)},nr=new WeakSet,Ui=async function(e){const t=await e.u62(),s=Number(await e.u62()),r=await e.string();return new Me(t,s,r)},c(Me,nr),o(Me,"id",8);let Vt=Me;var ir,Pi,ar,Ni;const De=class De{constructor(e,t=0,s=""){c(this,ir);o(this,"trackNamespace");o(this,"errorCode");o(this,"reasonPhrase");this.trackNamespace=e,this.errorCode=t,this.reasonPhrase=s}async encode(e){return b(e,d(this,ir,Pi).bind(this))}static async decode(e){return p(e,d(De,ar,Ni))}};ir=new WeakSet,Pi=async function(e){await le(e,this.trackNamespace),await e.u62(BigInt(this.errorCode)),await e.string(this.reasonPhrase)},ar=new WeakSet,Ni=async function(e){const t=await we(e),s=Number(await e.u62()),r=await e.string();return new De(t,s,r)},c(De,ar),o(De,"id",12);let Ht=De;var or,Li,cr,Ri;const Fe=class Fe{constructor(e){c(this,or);o(this,"trackNamespace");this.trackNamespace=e}async encode(e){return b(e,d(this,or,Li).bind(this))}static async decode(e){return p(e,d(Fe,cr,Ri))}};or=new WeakSet,Li=async function(e){await le(e,this.trackNamespace)},cr=new WeakSet,Ri=async function(e){const t=await we(e);return new Fe(t)},c(Fe,cr),o(Fe,"id",9);let bt=Fe;var dr,Ti,ur,Ci;const Ge=class Ge{constructor(e){c(this,dr);o(this,"requestId");this.requestId=e}async encode(e){return b(e,d(this,dr,Ti).bind(this))}static async decode(e){return p(e,d(Ge,ur,Ci))}};dr=new WeakSet,Ti=async function(e){await e.u62(this.requestId)},ur=new WeakSet,Ci=async function(e){return new Ge(await e.u62())},c(Ge,ur),o(Ge,"id",21);let zt=Ge;var hr,Oi,lr,Bi;const je=class je{constructor(e){c(this,hr);o(this,"requestId");this.requestId=e}async encode(e){return b(e,d(this,hr,Oi).bind(this))}static async decode(e){return p(e,d(je,lr,Bi))}};hr=new WeakSet,Oi=async function(e){await e.u62(this.requestId)},lr=new WeakSet,Bi=async function(e){return new je(await e.u62())},c(je,lr),o(je,"id",26);let _t=je;const fo=128;var wr,Mi,fr,Di;const We=class We{constructor(e,t=new O){c(this,wr);o(this,"versions");o(this,"parameters");this.versions=e,this.parameters=t}async encode(e){return b(e,d(this,wr,Mi).bind(this))}static async decode(e){return p(e,d(We,fr,Di))}};wr=new WeakSet,Mi=async function(e){await e.u53(this.versions.length);for(const t of this.versions)await e.u53(t);await this.parameters.encode(e)},fr=new WeakSet,Di=async function(e){const t=await e.u53();if(t>fo)throw new Error(`too many versions: ${t}`);const s=[];for(let a=0;a<t;a++){const u=await e.u53();s.push(u)}const r=await O.decode(e);return new We(s,r)},c(We,fr),o(We,"id",32);let pt=We;var yr,Fi,br,Gi;const Ve=class Ve{constructor(e,t=new O){c(this,yr);o(this,"version");o(this,"parameters");this.version=e,this.parameters=t}async encode(e){return b(e,d(this,yr,Fi).bind(this))}static async decode(e){return p(e,d(Ve,br,Gi))}};yr=new WeakSet,Fi=async function(e){await e.u53(this.version),await this.parameters.encode(e)},br=new WeakSet,Gi=async function(e){const t=await e.u53(),s=await O.decode(e);return new Ve(t,s)},c(Ve,br),o(Ve,"id",33);let gt=Ve;const ji=2;var z,pr,Wi,gr,Vi;let Is=(z=class{constructor(e,t,s,r){c(this,pr);o(this,"requestId");o(this,"trackNamespace");o(this,"trackName");o(this,"subscriberPriority");this.requestId=e,this.trackNamespace=t,this.trackName=s,this.subscriberPriority=r}async encode(e){return b(e,d(this,pr,Wi).bind(this))}static async decode(e){return p(e,d(z,gr,Vi))}},pr=new WeakSet,Wi=async function(e){await e.u62(this.requestId),await le(e,this.trackNamespace),await e.string(this.trackName),await e.u8(this.subscriberPriority),await e.u8(ji),await e.bool(!0),await e.u53(2),await e.u53(0)},gr=new WeakSet,Vi=async function(e){const t=await e.u62(),s=await we(e),r=await e.string(),a=await e.u8(),u=await e.u8();if(u>2)throw new Error(`unknown group order: ${u}`);const h=await e.bool();if(!h)throw new Error(`unsupported forward value: ${h}`);const w=await e.u53();if(w!==1&&w!==2)throw new Error(`unsupported filter type: ${w}`);return await O.decode(e),new z(t,s,r,a)},c(z,gr),o(z,"id",3),z);var _,mr,Hi,vr,zi;let xs=(_=class{constructor(e,t){c(this,mr);o(this,"requestId");o(this,"trackAlias");this.requestId=e,this.trackAlias=t}async encode(e){return b(e,d(this,mr,Hi).bind(this))}static async decode(e){return p(e,d(_,vr,zi))}},mr=new WeakSet,Hi=async function(e){await e.u62(this.requestId),await e.u62(this.trackAlias),await e.u62(0n),await e.u8(ji),await e.bool(!1),await e.u53(0)},vr=new WeakSet,zi=async function(e){const t=await e.u62(),s=await e.u62(),r=await e.u62();if(r!==BigInt(0))throw new Error(`unsupported expires: ${r}`);return await e.u8(),await e.bool()&&(await e.u62(),await e.u62()),await O.decode(e),new _(t,s)},c(_,vr),o(_,"id",4),_);var kr,_i,Er,Xi;const He=class He{constructor(e,t,s){c(this,kr);o(this,"requestId");o(this,"errorCode");o(this,"reasonPhrase");this.requestId=e,this.errorCode=t,this.reasonPhrase=s}async encode(e){return b(e,d(this,kr,_i).bind(this))}static async decode(e){return p(e,d(He,Er,Xi))}};kr=new WeakSet,_i=async function(e){await e.u62(this.requestId),await e.u62(BigInt(this.errorCode)),await e.string(this.reasonPhrase)},Er=new WeakSet,Xi=async function(e){const t=await e.u62(),s=Number(await e.u62()),r=await e.string();return new He(t,s,r)},c(He,Er),o(He,"id",5);let mt=He;var Ir,Ki,xr,Ji;const ze=class ze{constructor(e){c(this,Ir);o(this,"requestId");this.requestId=e}async encode(e){return b(e,d(this,Ir,Ki).bind(this))}static async decode(e){return p(e,d(ze,xr,Ji))}};Ir=new WeakSet,Ki=async function(e){await e.u62(this.requestId)},xr=new WeakSet,Ji=async function(e){const t=await e.u62();return new ze(t)},c(ze,xr),o(ze,"id",10);let vt=ze;var Sr,Qi,qr,Zi;const _e=class _e{constructor(e,t){c(this,Sr);o(this,"namespace");o(this,"requestId");this.namespace=e,this.requestId=t}async encode(e){return b(e,d(this,Sr,Qi).bind(this))}static async decode(e){return p(e,d(_e,qr,Zi))}};Sr=new WeakSet,Qi=async function(e){await e.u62(this.requestId),await le(e,this.namespace),await e.u53(0)},qr=new WeakSet,Zi=async function(e){const t=await e.u62(),s=await we(e);return await O.decode(e),new _e(s,t)},c(_e,qr),o(_e,"id",17);let kt=_e;var $r,Yi,Ar,ea;const Xe=class Xe{constructor(e){c(this,$r);o(this,"requestId");this.requestId=e}async encode(e){return b(e,d(this,$r,Yi).bind(this))}static async decode(e){return p(e,d(Xe,Ar,ea))}};$r=new WeakSet,Yi=async function(e){await e.u62(this.requestId)},Ar=new WeakSet,ea=async function(e){const t=await e.u62();return new Xe(t)},c(Xe,Ar),o(Xe,"id",18);let Xt=Xe;var Ur,ta,Pr,sa;const Ke=class Ke{constructor(e,t,s){c(this,Ur);o(this,"requestId");o(this,"errorCode");o(this,"reasonPhrase");this.requestId=e,this.errorCode=t,this.reasonPhrase=s}async encode(e){return b(e,d(this,Ur,ta).bind(this))}static async decode(e){return p(e,d(Ke,Pr,sa))}};Ur=new WeakSet,ta=async function(e){await e.u62(this.requestId),await e.u62(BigInt(this.errorCode)),await e.string(this.reasonPhrase)},Pr=new WeakSet,sa=async function(e){const t=await e.u62(),s=Number(await e.u62()),r=await e.string();return new Ke(t,s,r)},c(Ke,Pr),o(Ke,"id",19);let Kt=Ke;var Nr,ra,Lr,na;const Je=class Je{constructor(e){c(this,Nr);o(this,"requestId");this.requestId=e}async encode(e){return b(e,d(this,Nr,ra).bind(this))}static async decode(e){return p(e,d(Je,Lr,na))}};Nr=new WeakSet,ra=async function(e){await e.u62(this.requestId)},Lr=new WeakSet,na=async function(e){const t=await e.u62();return new Je(t)},c(Je,Lr),o(Je,"id",20);let Et=Je;var Rr,ia,Tr,aa;const Qe=class Qe{constructor(e,t){c(this,Rr);o(this,"trackNamespace");o(this,"trackName");this.trackNamespace=e,this.trackName=t}async encode(e){return b(e,d(this,Rr,ia).bind(this))}static async decode(e){return p(e,d(Qe,Tr,aa))}};Rr=new WeakSet,ia=async function(e){await le(e,this.trackNamespace),await e.string(this.trackName)},Tr=new WeakSet,aa=async function(e){const t=await we(e),s=await e.string();return new Qe(t,s)},c(Qe,Tr),o(Qe,"id",13);let Jt=Qe;var Cr,oa,Or,ca;const M=class M{constructor(e,t,s,r,a){c(this,Cr);o(this,"trackNamespace");o(this,"trackName");o(this,"statusCode");o(this,"lastGroupId");o(this,"lastObjectId");this.trackNamespace=e,this.trackName=t,this.statusCode=s,this.lastGroupId=r,this.lastObjectId=a}async encode(e){return b(e,d(this,Cr,oa).bind(this))}static async decode(e){return p(e,d(M,Or,ca))}};Cr=new WeakSet,oa=async function(e){await le(e,this.trackNamespace),await e.string(this.trackName),await e.u62(BigInt(this.statusCode)),await e.u62(this.lastGroupId),await e.u62(this.lastObjectId)},Or=new WeakSet,ca=async function(e){const t=await we(e),s=await e.string(),r=Number(await e.u62()),a=await e.u62(),u=await e.u62();return new M(t,s,r,a,u)},c(M,Or),o(M,"id",14),o(M,"STATUS_IN_PROGRESS",0),o(M,"STATUS_NOT_FOUND",1),o(M,"STATUS_NOT_AUTHORIZED",2),o(M,"STATUS_ENDED",3);let Pe=M;const Pn={[pt.id]:pt,[gt.id]:gt,[Is.id]:Is,[xs.id]:xs,[mt.id]:mt,[yt.id]:yt,[Wt.id]:Wt,[Vt.id]:Vt,[bt.id]:bt,[vt.id]:vt,[Ue.id]:Ue,[Ht.id]:Ht,[Jt.id]:Jt,[Pe.id]:Pe,[Ft.id]:Ft,[Ot.id]:Ot,[Dt.id]:Dt,[Bt.id]:Bt,[Mt.id]:Mt,[kt.id]:kt,[Xt.id]:Xt,[Kt.id]:Kt,[Et.id]:Et,[Gt.id]:Gt,[jt.id]:jt,[ft.id]:ft,[zt.id]:zt,[_t.id]:_t};var is,re,ne,Ie,Br,Mr;class yo{constructor(e,t){o(this,"stream");c(this,is,0n);c(this,re);c(this,ne);c(this,Ie);c(this,Br,new Un);c(this,Mr,new Un);this.stream=e,l(this,re,t),l(this,ne,new Promise(s=>{l(this,Ie,s)}))}async write(e){console.debug("message write",e),await n(this,Br).runExclusive(async()=>{await this.stream.writer.u53(e.constructor.id),await e.encode(this.stream.writer)})}async read(){return await n(this,Mr).runExclusive(async()=>{const e=await this.stream.reader.u53();if(!(e in Pn))throw new Error(`Unknown control message type: ${e}`);try{const t=await Pn[e].decode(this.stream.reader);return console.debug("message read",t),t}catch(t){throw console.error("failed to decode message",e,t),t}})}maxRequestId(e){if(e<=n(this,re))throw new Error(`max request id must be greater than current max request id: max=${e} current=${n(this,re)}`);l(this,re,e),n(this,Ie).call(this),l(this,ne,new Promise(t=>{l(this,Ie,t)}))}async nextRequestId(){for(;;){const e=n(this,is);if(e<n(this,re))return l(this,is,n(this,is)+2n),e;if(!n(this,ne))return;console.warn("blocked on max request id"),await n(this,ne)}}close(){n(this,Ie).call(this),l(this,ne,void 0)}}is=new WeakMap,re=new WeakMap,ne=new WeakMap,Ie=new WeakMap,Br=new WeakMap,Mr=new WeakMap;const Nn=3;let da=class ua{constructor(e,t,s,r,a){o(this,"flags");o(this,"trackAlias");o(this,"groupId");o(this,"subGroupId");o(this,"publisherPriority");this.flags=a,this.trackAlias=e,this.groupId=t,this.subGroupId=s,this.publisherPriority=r}async encode(e){if(!this.flags.hasSubgroup&&this.subGroupId!==0)throw new Error(`Subgroup ID must be 0 if hasSubgroup is false: ${this.subGroupId}`);let t=16;this.flags.hasExtensions&&(t|=1),this.flags.hasSubgroupObject&&(t|=2),this.flags.hasSubgroup&&(t|=4),this.flags.hasEnd&&(t|=8),await e.u53(t),await e.u62(this.trackAlias),await e.u53(this.groupId),this.flags.hasSubgroup&&await e.u53(this.subGroupId),await e.u8(0)}static async decode(e){const t=await e.u53();if(t<16||t>31)throw new Error(`Unsupported group type: ${t}`);const s={hasExtensions:(t&1)!==0,hasSubgroupObject:(t&2)!==0,hasSubgroup:(t&4)!==0,hasEnd:(t&8)!==0},r=await e.u62(),a=await e.u53(),u=s.hasSubgroup?await e.u53():0,h=await e.u8();return new ua(r,a,u,h,s)}};class rt{constructor(e){o(this,"payload");this.payload=e}async encode(e,t){await e.u53(0),t.hasExtensions&&await e.u53(0),this.payload!==void 0?(await e.u53(this.payload.byteLength),this.payload.byteLength===0?await e.u53(0):await e.write(this.payload)):(await e.u53(0),await e.u53(Nn))}static async decode(e,t){const s=await e.u53();if(s!==0&&console.warn(`object ID delta is not supported, ignoring: ${s}`),t.hasExtensions){const u=await e.u53();await e.read(u)}const r=await e.u53();if(r>0){const u=await e.read(r);return new rt(u)}const a=await e.u53();if(t.hasEnd){if(a===0)return new rt(new Uint8Array(0))}else if(a===0||a===Nn)return new rt;throw new Error(`Unsupported object status: ${a}`)}}var as,T,dt,he,ha,la,wa,Cn;let bo=(Cn=class{constructor(e,t){c(this,he);c(this,as);c(this,T);c(this,dt,new Map);l(this,as,e),l(this,T,t)}publish(e,t){n(this,dt).set(e,t),d(this,he,ha).call(this,e,t)}async handleSubscribe(e){const t=e.trackNamespace,s=n(this,dt).get(t);if(!s){const u=new mt(e.requestId,404,"Broadcast not found");await n(this,T).write(u);return}const r=s.subscribe(e.trackName,e.subscriberPriority),a=new xs(e.requestId,e.requestId);await n(this,T).write(a),console.debug(`publish ok: broadcast=${t} track=${r.name}`),d(this,he,la).call(this,e.requestId,t,r)}async handleTrackStatusRequest(e){const t=new Pe(e.trackNamespace,e.trackName,Pe.STATUS_NOT_FOUND,0n,0n);await n(this,T).write(t)}async handleUnsubscribe(e){}async handlePublishNamespaceOk(e){}async handlePublishNamespaceError(e){}async handlePublishNamespaceCancel(e){}async handleSubscribeNamespace(e){}async handleUnsubscribeNamespace(e){}},as=new WeakMap,T=new WeakMap,dt=new WeakMap,he=new WeakSet,ha=async function(e,t){try{const s=await n(this,T).nextRequestId();if(s===void 0)return;const r=new yt(s,e);await n(this,T).write(r),await t.closed;const a=new bt(e);await n(this,T).write(a)}catch(s){const r=C(s);console.warn(`announce failed: broadcast=${e} error=${r.message}`)}finally{t.close(),n(this,dt).delete(e)}},la=async function(e,t,s){try{for(;;){const a=await s.nextGroup();if(!a)break;d(this,he,wa).call(this,e,a)}console.debug(`publish done: broadcast=${t} track=${s.name}`);const r=new Ue(e,200,"OK");await n(this,T).write(r)}catch(r){const a=C(r);console.warn(`publish error: broadcast=${t} track=${s.name} error=${a.message}`);const u=new Ue(e,500,a.message);await n(this,T).write(u)}finally{s.close()}},wa=async function(e,t){try{const s=await Ae.open(n(this,as)),r=new da(e,t.sequence,0,0,{hasExtensions:!1,hasSubgroup:!1,hasSubgroupObject:!1,hasEnd:!0});console.debug("sending group header",r),await r.encode(s);try{for(;;){const a=await Promise.race([t.readFrame(),s.closed]);if(!a)break;await new rt(a).encode(s,r.flags)}s.close()}catch(a){s.reset(C(a))}}finally{t.close()}},Cn);var B,ie,xe,ut,Se,ae,It,fa,ya,On;let po=(On=class{constructor(e){c(this,It);c(this,B);c(this,ie,new Set);c(this,xe,new Set);c(this,ut,new Map);c(this,Se,new Map);c(this,ae,new Map);l(this,B,e)}announced(e=ys()){const t=new Dn(e);for(const s of n(this,ie))s.startsWith(e)&&t.append({path:s,active:!0});return n(this,xe).add(t),d(this,It,fa).call(this,t,e).finally(()=>{n(this,xe).delete(t)}),t}consume(e){const t=new Fn;return(async()=>{for(;;){const s=await t.requested();if(!s)break;d(this,It,ya).call(this,e,s)}})(),t}async handleSubscribeOk(e){const t=n(this,ae).get(e.requestId);t?t.resolve(e):console.warn("handleSubscribeOk unknown requestId",e.requestId)}async handleSubscribeError(e){const t=n(this,ae).get(e.requestId);t?t.reject(new Error(`SUBSCRIBE_ERROR: code=${e.errorCode} reason=${e.reasonPhrase}`)):console.warn("handleSubscribeError unknown requestId",e.requestId)}async handleGroup(e,t){const s=new hn(e.groupId);e.subGroupId!==0&&console.warn("subgroup ID is not supported, ignoring");try{let r=n(this,Se).get(e.trackAlias);r===void 0&&(r=e.trackAlias,console.warn("unknown track alias, using request ID"));const a=n(this,ut).get(r);if(!a)throw new Error(`unknown track: trackAlias=${e.trackAlias} requestId=${n(this,Se).get(e.trackAlias)}`);for(a.writeGroup(s);await Promise.race([t.done(),s.closed,a.closed])===!1;){const h=await rt.decode(t,e.flags);if(h.payload===void 0)break;s.writeFrame(h.payload)}s.close()}catch(r){const a=C(r);s.close(a),t.stop(a)}}async handlePublish(e){const t=new ft(e.requestId,500,"publish not supported");await n(this,B).write(t)}async handlePublishDone(e){const t=n(this,ae).get(e.requestId);t&&t.reject(new Error(`PUBLISH_DONE: code=${e.statusCode} reason=${e.reasonPhrase}`))}async handlePublishNamespace(e){if(n(this,ie).has(e.trackNamespace)){console.warn("duplicate PUBLISH_NAMESPACE message");return}n(this,ie).add(e.trackNamespace),console.debug(`announced: broadcast=${e.trackNamespace} active=true`);for(const t of n(this,xe))t.append({path:e.trackNamespace,active:!0})}async handlePublishNamespaceDone(e){if(!n(this,ie).has(e.trackNamespace)){console.warn("unknown PUBLISH_NAMESPACE_DONE message");return}n(this,ie).delete(e.trackNamespace),console.debug(`announced: broadcast=${e.trackNamespace} active=false`);for(const t of n(this,xe))t.append({path:e.trackNamespace,active:!1})}async handleSubscribeNamespaceOk(e){}async handleSubscribeNamespaceError(e){throw new Error("SUBSCRIBE_NAMESPACE_ERROR messages are not supported")}async handleTrackStatus(e){throw new Error("TRACK_STATUS messages are not supported")}},B=new WeakMap,ie=new WeakMap,xe=new WeakMap,ut=new WeakMap,Se=new WeakMap,ae=new WeakMap,It=new WeakSet,fa=async function(e,t){const s=await n(this,B).nextRequestId();if(s!==void 0)try{n(this,B).write(new kt(t,s)),await e.closed}finally{n(this,B).write(new Et(s))}},ya=async function(e,t){const s=await n(this,B).nextRequestId();if(s===void 0)return;n(this,ut).set(s,t.track),console.debug(`subscribe start: id=${s} broadcast=${e} track=${t.track.name}`);const r=new Is(s,e,t.track.name,t.priority),a=new Promise((u,h)=>{n(this,ae).set(s,{resolve:u,reject:h})});await n(this,B).write(r);try{const u=await a;n(this,Se).set(u.trackAlias,s),console.debug(`subscribe ok: id=${s} broadcast=${e} track=${t.track.name}`);try{await t.track.closed;const h=new vt(s);await n(this,B).write(h),console.debug(`unsubscribe: id=${s} broadcast=${e} track=${t.track.name}`)}finally{n(this,Se).delete(u.trackAlias)}}catch(u){const h=C(u);t.track.close(h),console.warn(`subscribe error: id=${s} broadcast=${e} track=${t.track.name} error=${h.message}`)}finally{n(this,ut).delete(s),n(this,ae).delete(s)}},On);var W,V,R,x,ht,S,ba,pa,ga,ma,va,ka,Ea,Bn;let go=(Bn=class{constructor(e,t,s,r){c(this,S);o(this,"url");c(this,W);c(this,V);c(this,R);c(this,x);c(this,ht,!1);this.url=e,l(this,W,t),l(this,V,new yo(s,r)),n(this,W).closed.finally(()=>{n(this,V).close()}),l(this,R,new bo(n(this,W),n(this,V))),l(this,x,new po(n(this,V))),d(this,S,ba).call(this)}close(){if(!n(this,ht)){l(this,ht,!0);try{n(this,W).close()}catch{}}}publish(e,t){n(this,R).publish(e,t)}announced(e=ys()){return n(this,x).announced(e)}consume(e){return n(this,x).consume(e)}get closed(){return n(this,W).closed.then(()=>{})}},W=new WeakMap,V=new WeakMap,R=new WeakMap,x=new WeakMap,ht=new WeakMap,S=new WeakSet,ba=async function(){const e=d(this,S,pa).call(this),t=d(this,S,ka).call(this);try{await Promise.all([e,t])}catch(s){n(this,ht)||console.error("fatal error running connection",s)}finally{this.close()}},pa=async function(){for(;;)try{const e=await n(this,V).read();if(e instanceof Is)await n(this,R).handleSubscribe(e);else if(e instanceof vt)await n(this,R).handleUnsubscribe(e);else if(e instanceof Jt)await n(this,R).handleTrackStatusRequest(e);else if(e instanceof Wt)await n(this,R).handlePublishNamespaceOk(e);else if(e instanceof Vt)await n(this,R).handlePublishNamespaceError(e);else if(e instanceof Ht)await n(this,R).handlePublishNamespaceCancel(e);else if(e instanceof yt)await n(this,x).handlePublishNamespace(e);else if(e instanceof bt)await n(this,x).handlePublishNamespaceDone(e);else if(e instanceof xs)await n(this,x).handleSubscribeOk(e);else if(e instanceof mt)await n(this,x).handleSubscribeError(e);else if(e instanceof Ue)await n(this,x).handlePublishDone(e);else if(e instanceof Pe)await n(this,x).handleTrackStatus(e);else if(e instanceof Ft)await d(this,S,ga).call(this,e);else if(e instanceof pt)await d(this,S,ma).call(this,e);else if(e instanceof gt)await d(this,S,va).call(this,e);else if(e instanceof kt)await n(this,R).handleSubscribeNamespace(e);else if(e instanceof Xt)await n(this,x).handleSubscribeNamespaceOk(e);else if(e instanceof Kt)await n(this,x).handleSubscribeNamespaceError(e);else if(e instanceof Et)await n(this,R).handleUnsubscribeNamespace(e);else if(e instanceof Gt)await n(this,x).handlePublish(e);else{if(e instanceof jt)throw new Error("PUBLISH_OK messages are not supported");if(e instanceof ft)throw new Error("PUBLISH_ERROR messages are not supported");if(e instanceof Ot)throw new Error("FETCH messages are not supported");if(e instanceof Bt)throw new Error("FETCH_OK messages are not supported");if(e instanceof Mt)throw new Error("FETCH_ERROR messages are not supported");if(e instanceof Dt)throw new Error("FETCH_CANCEL messages are not supported");e instanceof zt?n(this,V).maxRequestId(e.requestId):e instanceof _t?console.warn("ignoring REQUESTS_BLOCKED message"):oo(e)}}catch(e){console.error("error processing control message",e);break}console.warn("control stream closed")},ga=async function(e){console.warn(`MOQLITE_INCOMPATIBLE: Received GOAWAY with redirect URI: ${e.newSessionUri}`),this.close()},ma=async function(e){console.error("Unexpected CLIENT_SETUP message received after connection established"),this.close()},va=async function(e){console.error("Unexpected SERVER_SETUP message received after connection established"),this.close()},ka=async function(){const e=new ni(n(this,W));for(;;){const t=await e.next();if(!t)break;d(this,S,Ea).call(this,t).then(()=>{t.stop(new Error("cancel"))}).catch(s=>{t.stop(s)})}},Ea=async function(e){try{const t=await da.decode(e);console.debug("received group header",t),await n(this,x).handleGroup(t,e)}catch(t){console.error("error processing object stream",t)}},Bn);const Ln={DRAFT_07:4278190087,DRAFT_14:4278190094};async function fe(i,e){let t=new Uint8Array;const s=new Ae(new WritableStream({write(r){const a=t.byteLength+r.byteLength;if(a>t.buffer.byteLength){const u=Math.max(a,t.buffer.byteLength*2),h=new ArrayBuffer(u),w=new Uint8Array(h,0,a);w.set(t),w.set(r,t.byteLength),t=w}else t=new Uint8Array(t.buffer,0,a),t.set(r,a-r.byteLength)}}));await e(s),s.close(),await s.closed,await i.u53(t.byteLength),await i.write(t)}async function X(i,e){const t=await i.u53(),s=await i.read(t),r=new Qr(void 0,s),a=await e(r);if(!await r.done())throw new Error("Message decoding consumed too few bytes");return a}async function Zr(i,e){if(!await i.done())return await X(i,e)}var Dr,Ia,os,nn;const Ze=class Ze{constructor(e,t){c(this,Dr);o(this,"suffix");o(this,"active");this.suffix=e,this.active=t}async encode(e){return fe(e,d(this,Dr,Ia).bind(this))}static async decode(e){return X(e,d(Ze,os,nn))}static async decodeMaybe(e){return Zr(e,d(Ze,os,nn))}};Dr=new WeakSet,Ia=async function(e){await e.bool(this.active),await e.string(this.suffix)},os=new WeakSet,nn=async function(e){const t=await e.bool(),s=fs(await e.string());return new Ze(s,t)},c(Ze,os);let Qt=Ze;var Fr,xa,Gr,Sa;const Rt=class Rt{constructor(e){c(this,Fr);o(this,"prefix");this.prefix=e}async encode(e){return fe(e,d(this,Fr,xa).bind(this))}static async decode(e){return X(e,d(Rt,Gr,Sa))}};Fr=new WeakSet,xa=async function(e){await e.string(this.prefix)},Gr=new WeakSet,Sa=async function(e){const t=fs(await e.string());return new Rt(t)},c(Rt,Gr);let Ss=Rt;var jr,qa,Wr,$a;const Tt=class Tt{constructor(e){c(this,jr);o(this,"suffixes");this.suffixes=e}async encode(e){return fe(e,d(this,jr,qa).bind(this))}static async decode(e){return X(e,d(Tt,Wr,$a))}};jr=new WeakSet,qa=async function(e){await e.u53(this.suffixes.length);for(const t of this.suffixes)await e.string(t)},Wr=new WeakSet,$a=async function(e){const t=await e.u53(),s=[];for(let r=0;r<t;r++)s.push(fs(await e.string()));return new Tt(s)},c(Tt,Wr);let qs=Tt;var Vr,Aa,cs,an;const Ye=class Ye{constructor(e,t){c(this,Vr);o(this,"subscribe");o(this,"sequence");this.subscribe=e,this.sequence=t}async encode(e){return fe(e,d(this,Vr,Aa).bind(this))}static async decode(e){return X(e,d(Ye,cs,an))}static async decodeMaybe(e){return Zr(e,d(Ye,cs,an))}};Vr=new WeakSet,Aa=async function(e){await e.u62(this.subscribe),await e.u53(this.sequence)},cs=new WeakSet,an=async function(e){return new Ye(await e.u62(),await e.u53())},c(Ye,cs);let $s=Ye;const pe={DRAFT_01:4279086337,DRAFT_02:4279086338};var Hr,Ua,ds,on;const et=class et{constructor(e){c(this,Hr);o(this,"priority");this.priority=e}async encode(e){return fe(e,d(this,Hr,Ua).bind(this))}static async decode(e){return X(e,d(et,ds,on))}static async decodeMaybe(e){return Zr(e,d(et,ds,on))}};Hr=new WeakSet,Ua=async function(e){await e.u8(this.priority)},ds=new WeakSet,on=async function(e){const t=await e.u8();return new et(t)},c(et,ds);let As=et;var zr,Pa,_r,Na;const Ct=class Ct{constructor(e,t,s,r){c(this,zr);o(this,"id");o(this,"broadcast");o(this,"track");o(this,"priority");this.id=e,this.broadcast=t,this.track=s,this.priority=r}async encode(e){return fe(e,d(this,zr,Pa).bind(this))}static async decode(e){return X(e,d(Ct,_r,Na))}};zr=new WeakSet,Pa=async function(e){await e.u62(this.id),await e.string(this.broadcast),await e.string(this.track),await e.u8(this.priority)},_r=new WeakSet,Na=async function(e){const t=await e.u62(),s=fs(await e.string()),r=await e.string(),a=await e.u8();return new Ct(t,s,r,a)},c(Ct,_r);let Us=Ct;var Xr,La,Kr,Ra;const tt=class tt{constructor({version:e,priority:t=void 0}){c(this,Xr);o(this,"version");o(this,"priority");this.version=e,this.priority=t}async encode(e){return fe(e,d(this,Xr,La).bind(this))}static async decode(e,t){return X(e,d(tt,Kr,Ra).bind(tt,t))}};Xr=new WeakSet,La=async function(e){if(this.version!==pe.DRAFT_02)if(this.version===pe.DRAFT_01)await e.u8(this.priority??0);else{const t=this.version;throw new Error(`unsupported version: ${t}`)}},Kr=new WeakSet,Ra=async function(e,t){let s;if(e!==pe.DRAFT_02)if(e===pe.DRAFT_01)s=await t.u8();else{const r=e;throw new Error(`unsupported version: ${r}`)}return new tt({version:e,priority:s})},c(tt,Kr);let Ps=tt;var us,H,xt,Ta,Ca;class mo{constructor(e,t){c(this,xt);o(this,"version");c(this,us);c(this,H,new E(new Map));l(this,us,e),this.version=t}publish(e,t){n(this,H).mutate(s=>{if(!s)throw new Error("closed");s.set(e,t)}),t.closed.finally(()=>{n(this,H).mutate(s=>{s==null||s.delete(e)})})}async runAnnounce(e,t){console.debug(`announce: prefix=${e.prefix}`);let s=new Set;const r=n(this,H).peek();if(!r)return;for(const u of r.keys()){const h=Sn(e.prefix,u);h!==null&&(console.debug(`announce: broadcast=${u} active=true`),s.add(h))}for(await new qs([...s]).encode(t.writer);;){let u;const h=new Promise(y=>{u=n(this,H).changed(y)}),w=await Promise.race([h,t.reader.closed]);if(u(),!w)break;const g=new Set;for(const y of w.keys()){const q=Sn(e.prefix,y);q!==null&&g.add(q)}for(const y of g.difference(s))console.debug(`announce: broadcast=${y} active=true`),await new Qt(y,!0).encode(t.writer);for(const y of s.difference(g))console.debug(`announce: broadcast=${y} active=false`),await new Qt(y,!1).encode(t.writer);s=g}}async runSubscribe(e,t){var a;const s=(a=n(this,H).peek())==null?void 0:a.get(e.broadcast);if(!s){console.debug(`publish unknown: broadcast=${e.broadcast}`),t.writer.reset(new Error("not found"));return}const r=s.subscribe(e.track,e.priority);try{await new Ps({version:this.version,priority:e.priority}).encode(t.writer),console.debug(`publish ok: broadcast=${e.broadcast} track=${r.name}`);const h=d(this,xt,Ta).call(this,e.id,e.broadcast,r,t.writer);for(;;){const w=As.decodeMaybe(t.reader),g=await Promise.any([h,w]);if(!g)break;g instanceof As&&console.warn("subscribe update not supported",g)}console.debug(`publish done: broadcast=${e.broadcast} track=${r.name}`),t.close(),r.close()}catch(u){const h=C(u);console.warn(`publish error: broadcast=${e.broadcast} track=${r.name} error=${h.message}`),r.close(h),t.abort(h)}}close(){n(this,H).update(e=>{for(const t of(e==null?void 0:e.values())??[])t.close()})}}us=new WeakMap,H=new WeakMap,xt=new WeakSet,Ta=async function(e,t,s,r){try{for(;;){const a=s.nextGroup(),u=await Promise.race([a,r.closed]);if(!u){a.then(h=>h==null?void 0:h.close()).catch(()=>{});break}d(this,xt,Ca).call(this,e,u)}console.debug(`publish close: broadcast=${t} track=${s.name}`),s.close(),r.close()}catch(a){const u=C(a);console.warn(`publish error: broadcast=${t} track=${s.name} error=${u.message}`),s.close(u),r.reset(u)}},Ca=async function(e,t){const s=new $s(e,t.sequence);try{const r=await Ae.open(n(this,us));await r.u8(0),await s.encode(r);try{for(;;){const a=await Promise.race([t.readFrame(),r.closed]);if(!a)break;await r.u53(a.byteLength),await r.write(a)}r.close(),t.close()}catch(a){const u=C(a);r.reset(u),t.close(u)}}catch(r){const a=C(r);t.close(a)}};var Jr,Oa,hs,dn;const st=class st{constructor(e){c(this,Jr);o(this,"bitrate");this.bitrate=e}async encode(e){return fe(e,d(this,Jr,Oa).bind(this))}static async decode(e){return X(e,d(st,hs,dn))}static async decodeMaybe(e){return Zr(e,d(st,hs,dn))}};Jr=new WeakSet,Oa=async function(e){await e.u53(this.bitrate)},hs=new WeakSet,dn=async function(e){const t=await e.u53();return new st(t)},c(st,hs);let cn=st;const $e={Session:0,Announce:1,Subscribe:2,ClientCompat:32,ServerCompat:33};var lt,oe,ls,St,Ba,Ma;class vo{constructor(e,t){c(this,St);c(this,lt);o(this,"version");c(this,oe,new Map);c(this,ls,0n);l(this,lt,e),this.version=t}announced(e=ys()){const t=new Dn;return d(this,St,Ba).call(this,t,e),t}consume(e){const t=new Fn;return(async()=>{for(;;){const s=await t.requested();if(!s)break;d(this,St,Ma).call(this,e,s)}})(),t}async runGroup(e,t){const s=n(this,oe).get(e.subscribe);if(!s){if(e.subscribe>=n(this,ls))throw new Error(`unknown subscription: id=${e.subscribe}`);return}const r=new hn(e.sequence);s.writeGroup(r);try{for(;await Promise.race([t.done(),s.closed,r.closed])===!1;){const u=await t.u53(),h=await t.read(u);if(!h)break;r.writeFrame(h)}r.close(),t.stop(new Error("cancel"))}catch(a){const u=C(a);r.close(u),t.stop(u)}}close(){for(const e of n(this,oe).values())e.close();n(this,oe).clear()}}lt=new WeakMap,oe=new WeakMap,ls=new WeakMap,St=new WeakSet,Ba=async function(e,t){console.debug(`announced: prefix=${t}`);const s=new Ss(t);try{const r=await ks.open(n(this,lt));await r.writer.u53($e.Announce),await s.encode(r.writer);const a=await qs.decode(r.reader);for(const u of a.suffixes){const h=qn(t,u);console.debug(`announced: broadcast=${h} active=true`),e.append({path:h,active:!0})}for(;;){const u=await Promise.race([Qt.decodeMaybe(r.reader),e.closed]);if(!u)break;if(u instanceof Error)throw u;const h=qn(t,u.suffix);console.debug(`announced: broadcast=${h} active=${u.active}`),e.append({path:h,active:u.active})}e.close()}catch(r){e.close(C(r))}},Ma=async function(e,t){const s=bs(this,ls)._++;n(this,oe).set(s,t.track),console.debug(`subscribe start: id=${s} broadcast=${e} track=${t.track.name}`);const r=new Us(s,e,t.track.name,t.priority),a=await ks.open(n(this,lt));await a.writer.u53($e.Subscribe),await r.encode(a.writer);try{await Ps.decode(a.reader,this.version),console.debug(`subscribe ok: id=${s} broadcast=${e} track=${t.track.name}`),await Promise.race([a.reader.closed,t.track.closed]),t.track.close(),a.close(),console.debug(`subscribe close: id=${s} broadcast=${e} track=${t.track.name}`)}catch(u){const h=C(u);t.track.close(h),console.warn(`subscribe error: id=${s} broadcast=${e} track=${t.track.name} error=${h.message}`),a.abort(h)}finally{n(this,oe).delete(s)}};var F,ws,ce,de,wt,P,Da,Fa,Ga,ja,Wa,Va;class ko{constructor(e,t,s,r){c(this,P);o(this,"url");o(this,"version");c(this,F);c(this,ws);c(this,ce);c(this,de);c(this,wt,!1);this.url=e,l(this,F,t),l(this,ws,s),this.version=r,l(this,ce,new mo(n(this,F),this.version)),l(this,de,new vo(n(this,F),this.version)),d(this,P,Da).call(this)}close(){if(!n(this,wt)){l(this,wt,!0),n(this,ce).close(),n(this,de).close();try{n(this,F).close()}catch{}}}publish(e,t){n(this,ce).publish(e,t)}announced(e=ys()){return n(this,de).announced(e)}consume(e){return n(this,de).consume(e)}get closed(){return n(this,F).closed.then(()=>{})}}F=new WeakMap,ws=new WeakMap,ce=new WeakMap,de=new WeakMap,wt=new WeakMap,P=new WeakSet,Da=async function(){const e=d(this,P,Fa).call(this),t=d(this,P,Ga).call(this),s=d(this,P,Wa).call(this);try{await Promise.all([e,t,s])}catch(r){n(this,wt)||console.error("fatal error running connection",r)}finally{this.close()}},Fa=async function(){try{for(;await cn.decodeMaybe(n(this,ws).reader););}finally{console.warn("session stream closed")}},Ga=async function(){for(;;){const e=await ks.accept(n(this,F));if(!e)break;d(this,P,ja).call(this,e).catch(t=>{e.writer.reset(t)}).finally(()=>{e.writer.close()})}},ja=async function(e){const t=await e.reader.u53();if(t===$e.Session)throw new Error("duplicate session stream");if(t===$e.Announce){const s=await Ss.decode(e.reader);await n(this,ce).runAnnounce(s,e);return}else if(t===$e.Subscribe){const s=await Us.decode(e.reader);await n(this,ce).runSubscribe(s,e);return}else throw new Error(`unknown stream type: ${t.toString()}`)},Wa=async function(){const e=new ni(n(this,F));for(;;){const t=await e.next();if(!t)break;d(this,P,Va).call(this,t).then(()=>{t.stop(new Error("cancel"))}).catch(s=>{t.stop(s)})}},Va=async function(e){const t=await e.u8();if(t===0){const s=await $s.decode(e);await n(this,de).runGroup(s,e)}else throw new Error(`unknown stream type: ${t.toString()}`)};function Eo(i){if(i=i.startsWith("0x")?i.slice(2):i,i.length%2)throw new Error("invalid hex string length");const e=i.match(/.{2}/g);if(!e)throw new Error("invalid hex string format");return new Uint8Array(e.map(t=>parseInt(t,16)))}const Rn=new Set;async function Po(i,e){var pn,gn,mn;let t;const s=new Promise(Yr=>{t=Yr}),r=globalThis.WebTransport?Io(i,s,e==null?void 0:e.webtransport):void 0,a=!r||Rn.has(i.toString())?0:((pn=e==null?void 0:e.websocket)==null?void 0:pn.delay)??200,u=((gn=e==null?void 0:e.websocket)==null?void 0:gn.enabled)!==!1?xo(((mn=e==null?void 0:e.websocket)==null?void 0:mn.url)??i,a,s):void 0;if(!u&&!r)throw new Error("no transport available; WebTransport not supported and WebSocket is disabled");const h=await Promise.any(r?u?[u,r]:[r]:[u]);if(t&&t(),!h)throw new Error("no transport available");h instanceof vs&&(console.warn(i.toString(),"using WebSocket fallback; the user experience may be degraded"),Rn.add(i.toString()));const w=await ks.open(h);await w.writer.u53($e.ClientCompat);const g=new TextEncoder,y=new O;y.setVarint(tn.MaxRequestId,42069n),y.setBytes(tn.Implementation,g.encode("moq-lite-js"));const q=new pt([pe.DRAFT_02,pe.DRAFT_01,Ln.DRAFT_14],y);console.debug(i.toString(),"sending client setup",q),await q.encode(w.writer);const bn=await w.reader.u53();if(bn!==$e.ServerCompat)throw new Error(`unsupported server message type: ${bn.toString()}`);const Ne=await gt.decode(w.reader);if(console.debug(i.toString(),"received server setup",Ne),Object.values(pe).includes(Ne.version))return console.debug(i.toString(),"moq-lite session established"),new ko(i,h,w,Ne.version);if(Object.values(Ln).includes(Ne.version)){const Yr=Ne.parameters.getVarint(tn.MaxRequestId)??0n;return console.debug(i.toString(),"moq-ietf session established"),new go(i,h,w,Yr)}else throw new Error(`unsupported server version: ${Ne.version.toString()}`)}async function Io(i,e,t){let s=i;const r={allowPooling:!1,congestionControl:"low-latency",...t};if(i.protocol==="http:"){const h=new URL(i);h.pathname="/certificate.sha256",h.search="",console.warn(h.toString(),"performing an insecure fingerprint fetch; use https:// in production");const w=await Promise.race([fetch(h),e]);if(!w)return;const g=await Promise.race([w.text(),e]);if(g===void 0)return;r.serverCertificateHashes=(r.serverCertificateHashes||[]).concat([{algorithm:"sha-256",value:Eo(g)}]),s=new URL(i),s.protocol="https:"}const a=new WebTransport(s,r);if(!await Promise.race([a.ready.then(()=>!0),e])){a.close();return}return a}async function xo(i,e,t){const s=new Promise(h=>setTimeout(h,e));if(!await Promise.race([t,s.then(()=>!0)]))return;e&&console.debug(i.toString(),`no WebTransport after ${e}ms, attempting WebSocket fallback`);const a=new vs(i);if(!await Promise.race([a.ready.then(()=>!0),t])){a.close();return}return a}export{Fn as B,Po as c,fs as f};
assets/download_meshes.sh ADDED
@@ -0,0 +1,15 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/bin/bash
2
+ # Download OpenArm STL meshes from openarm.dev
3
+ BASE="https://openarm.dev/urdf/openarm_v1_0/meshes"
4
+ DIR="$(dirname "$0")/meshes"
5
+
6
+ mkdir -p "$DIR/arm/v10/visual" "$DIR/body/v10/visual" "$DIR/ee/openarm_hand/visual"
7
+
8
+ for i in 0 1 2 3 4 5 6 7; do
9
+ curl -sL "$BASE/arm/v10/visual/link${i}.stl" -o "$DIR/arm/v10/visual/link${i}.stl" &
10
+ done
11
+ curl -sL "$BASE/body/v10/visual/body_link0.stl" -o "$DIR/body/v10/visual/body_link0.stl" &
12
+ curl -sL "$BASE/ee/openarm_hand/visual/hand.stl" -o "$DIR/ee/openarm_hand/visual/hand.stl" &
13
+ curl -sL "$BASE/ee/openarm_hand/visual/finger.stl" -o "$DIR/ee/openarm_hand/visual/finger.stl" &
14
+ wait
15
+ echo "Downloaded $(find "$DIR" -name '*.stl' | wc -l) mesh files"
assets/meshes/.gitignore ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ # STL meshes downloaded from openarm.dev (~14MB)
2
+ # Run: curl script or see js/examples/assets/download_meshes.sh
3
+ *.stl
assets/openarm-DqhZ0Caw.js ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
 
1
+ import{c as It,f as bt,B as de}from"./connect-DkGLCYAo.js";import{W as ue,S as he,A as fe,D as jt,P as me,O as pe,G as ge,a as ye,B as Vt,b as Ct,c as we,d as ve,e as xe,M as Qt,f as Ie,g as be,U as Ce,h as Ee,i as $e,C as Be,L as Fe,j as Re,k as lt}from"./URDFLoader-CL7UVBjw.js";const $=new URLSearchParams(location.search),ot="openarm.",dt=(t,e)=>$.get(t)||localStorage.getItem(ot+t)||e,Y=document.getElementById("relayUrl"),ut=document.getElementById("leftPath"),ht=document.getElementById("rightPath"),ft=document.getElementById("depthPath"),mt=document.getElementById("certHash");Y.value=dt("relay","https://cdn.1ms.ai");ut.value=$.get("left")||$.get("path")||localStorage.getItem(ot+"left")||"anon/xoq-can-can0/state";ht.value=dt("right","anon/xoq-can-can1/state");ft.value=dt("depth","");mt.value=dt("certHash","");const Pe={relay:Y,left:ut,right:ht,depth:ft,certHash:mt,camX:document.getElementById("camX"),camY:document.getElementById("camY"),camZ:document.getElementById("camZ"),camRoll:document.getElementById("camRoll"),camPitch:document.getElementById("camPitch"),camYaw:document.getElementById("camYaw"),queryRate:document.getElementById("queryRate"),ptSize:document.getElementById("ptSize")};for(const[t,e]of Object.entries(Pe)){const n=localStorage.getItem(ot+t);n&&!$.has(t)&&(e.value=n),e.addEventListener("input",()=>localStorage.setItem(ot+t,e.value))}const T=document.getElementById("log"),O=document.getElementById("startBtn"),st=document.getElementById("stopBtn"),g=document.getElementById("queryBtn"),Se=document.getElementById("statusText"),rt=[{name:"J1",desc:"Shoulder pan",canId:17,color:16739125},{name:"J2",desc:"Shoulder lift",canId:18,color:16747586},{name:"J3",desc:"Shoulder rot",canId:19,color:16755021},{name:"J4",desc:"Elbow flex",canId:20,color:16765286},{name:"J5",desc:"Wrist roll",canId:21,color:448160},{name:"J6",desc:"Wrist pitch",canId:22,color:1149618},{name:"J7",desc:"Wrist rot",canId:23,color:473932},{name:"Grip",desc:"Gripper",canId:24,color:8599788}],kt=["L_J1","L_J2","L_J3","L_J4","L_J5","L_J6","L_J7"],Mt=["R_J1","R_J2","R_J3","R_J4","R_J5","R_J6","R_J7"];function Xt(){return new Array(8).fill(null).map(()=>({angle:0,velocity:0,torque:0,tempMos:0,tempRotor:0,updated:!1}))}const N=Xt(),j=Xt();let at=[],ct=!1,Et=0,$t=0,it=0,At=performance.now();const q={left:{conn:null,broadcast:null,track:null,group:null},right:{conn:null,broadcast:null,track:null,group:null}};let Z=null,k=!1,H=0,wt=0;function c(t,e="info"){const n=document.createElement("div");n.className=`log-entry log-${e}`,n.textContent=`[${new Date().toLocaleTimeString()}] ${t}`,T.appendChild(n),T.children.length>200&&T.removeChild(T.firstChild),T.scrollTop=T.scrollHeight}function Le(t){return t<1024?`${t} B`:t<1024*1024?`${(t/1024).toFixed(1)} K`:`${(t/(1024*1024)).toFixed(1)} M`}function b(t){Se.textContent=t}function Zt(t,e){const n=document.getElementById(t),s=[];for(let o=0;o<rt.length;o++){const r=rt[o],a=document.createElement("div");a.className="joint-row",a.innerHTML=`
2
+ <span class="joint-label" style="color:#${r.color.toString(16).padStart(6,"0")}">${r.name}</span>
3
+ <span class="joint-angle" id="${e}-angle-${o}">0.0&deg;</span>
4
+ <span class="joint-vel" id="${e}-vel-${o}">0.0</span>
5
+ <span class="joint-tau" id="${e}-tau-${o}">0.0</span>
6
+ `,n.appendChild(a),s.push({angle:a.querySelector(`#${e}-angle-${o}`),vel:a.querySelector(`#${e}-vel-${o}`),tau:a.querySelector(`#${e}-tau-${o}`)})}return s}const ke=Zt("leftJointRows","l"),Me=Zt("rightJointRows","r");function Ae(t){const e=new DataView(t.buffer,t.byteOffset,t.byteLength);if(t.length<6)return null;const n=t[0],s=e.getUint32(1,!0),o=t[5];if(t.length<6+o)return null;const r=t.slice(6,6+o);return{flags:n,canId:s,dataLen:o,data:r}}function _e(t){if(t.length<8)return null;const e=t[1]<<8|t[2],n=t[3]<<4|t[4]>>4,s=(t[4]&15)<<8|t[5],o=12.5,r=e/65535*(2*o)-o,a=45,l=n/4095*(2*a)-a,i=18,d=s/4095*(2*i)-i,h=t[6],u=t[7];return{qRad:r,vel:l,tau:d,tempMos:h,tempRotor:u}}function Bt(){const t=mt.value.trim(),e={};if(t){const n=t.replace(/[^0-9a-fA-F]/g,""),s=new Uint8Array(n.length/2);for(let o=0;o<s.length;o++)s[o]=parseInt(n.substr(o*2,2),16);e.webtransport={serverCertificateHashes:[{algorithm:"sha-256",value:s.buffer}]},c(`Using cert hash: ${n.slice(0,16)}...`,"data")}return e}function Kt(t){const e=new Uint8Array(t),n=s=>s.toString(16).padStart(2,"0").toUpperCase();for(let s=0;s<e.length-11;s++){if(e[s+4]===97&&e[s+5]===118&&e[s+6]===99&&e[s+7]===67){const o=s+8;if(o+4<=e.length)return`avc1.${n(e[o+1])}${n(e[o+2])}${n(e[o+3])}`}if(e[s+4]===97&&e[s+5]===118&&e[s+6]===49&&e[s+7]===67){const o=s+8;if(o+4<=e.length){const r=e[o+1]>>5&7,a=e[o+1]&31,l=e[o+2]>>7&1,i=e[o+2]>>6&1,d=e[o+2]>>5&1,h=i?d?12:10:8,u=String(a).padStart(2,"0");return`av01.${r}.${u}${l?"H":"M"}.${String(h).padStart(2,"0")}`}}}return null}function te(t){return t.length>=8&&t[4]===102&&t[5]===116&&t[6]===121&&t[7]===112}function ee(t,e){const n=[e.charCodeAt(0),e.charCodeAt(1),e.charCodeAt(2),e.charCodeAt(3)];let s=0;for(;s<t.length-8;){const o=t[s]<<24|t[s+1]<<16|t[s+2]<<8|t[s+3];if(t[s+4]===n[0]&&t[s+5]===n[1]&&t[s+6]===n[2]&&t[s+7]===n[3])return s;if(o<8)break;s+=o}return-1}function De(t){const e=ee(t,"mdat");if(e<0)return null;const n=t[e]<<24|t[e+1]<<16|t[e+2]<<8|t[e+3];return t.subarray(e+8,e+n)}function Te(t){for(let e=0;e<t.length-11;e++)if(t[e+4]===97&&t[e+5]===118&&t[e+6]===49&&t[e+7]===67){const n=t[e]<<24|t[e+1]<<16|t[e+2]<<8|t[e+3];return t.slice(e+8,e+n)}return null}class Je{constructor(){this.decoder=null,this.configured=!1,this.configuredCodec=null,this.latestY=null,this.is10bit=!1,this.width=0,this.height=0,this.frameCount=0,this.copyBuf=null}onData(e){const n=new Uint8Array(e);if(te(n)){if(!this.configured){const r=Te(n),a=Kt(n);r&&a&&this.configure(a,r)}const o=ee(n,"moof");o>=0&&this.decodeSample(n.subarray(o),!0)}else this.configured&&this.decodeSample(n,!1)}configure(e,n){if(this.configuredCodec===e)return;if(this.decoder)try{this.decoder.close()}catch{}this.decoder=new VideoDecoder({output:o=>this.processFrame(o).catch(r=>console.error("Depth frame error:",r)),error:o=>console.error("Depth decoder error:",o)});const s=n.buffer.slice(n.byteOffset,n.byteOffset+n.byteLength);this.decoder.configure({codec:e,description:s,hardwareAcceleration:"prefer-software"}),this.configured=!0,this.configuredCodec=e,c(`Depth WebCodecs: ${e}`,"data")}decodeSample(e,n){const s=De(e);if(!s)return;const o=this.frameCount*(1e6/30);this.decoder.decode(new EncodedVideoChunk({type:n?"key":"delta",timestamp:o,data:s})),this.frameCount++}async processFrame(e){try{const n=e.displayWidth,s=e.displayHeight,o=n*s,r=e.format;this.fmtLogged||(c(`Depth frame format: ${r}, ${n}x${s}`,"data"),this.fmtLogged=!0);let a=!1;if(r){a=r.includes("10");const l=e.allocationSize();(!this.copyBuf||this.copyBuf.byteLength<l)&&(this.copyBuf=new ArrayBuffer(l));const i=await e.copyTo(this.copyBuf),d=i[0].offset,h=i[0].stride;if(a){(!this.latestY||this.latestY.length!==o)&&(this.latestY=new Uint16Array(o));const u=h/2,f=new Uint16Array(this.copyBuf);if(u===n)this.latestY.set(new Uint16Array(this.copyBuf,d,o));else for(let m=0;m<s;m++)this.latestY.set(f.subarray(d/2+m*u,d/2+m*u+n),m*n)}else{(!this.latestY||this.latestY.length!==o)&&(this.latestY=new Uint8Array(o));const u=new Uint8Array(this.copyBuf);if(h===n)this.latestY.set(new Uint8Array(this.copyBuf,d,o));else for(let f=0;f<s;f++)this.latestY.set(u.subarray(d+f*h,d+f*h+n),f*n)}}else{(!this.offCanvas||this.offCanvas.width!==n||this.offCanvas.height!==s)&&(this.offCanvas=new OffscreenCanvas(n,s),this.offCtx=this.offCanvas.getContext("2d",{willReadFrequently:!0})),this.offCtx.drawImage(e,0,0);const l=this.offCtx.getImageData(0,0,n,s).data;(!this.latestY||this.latestY.length!==o)&&(this.latestY=new Uint8Array(o));for(let i=0;i<o;i++)this.latestY[i]=l[i*4];a=!1,this.canvasFallbackLogged||(c("Depth: GPU frame, using canvas fallback (8-bit)","info"),this.canvasFallbackLogged=!0)}this.is10bit=a,this.width=n,this.height=s}finally{e.close()}}destroy(){if(this.decoder)try{this.decoder.close()}catch{}this.decoder=null,this.configured=!1,this.latestY=null}}class qe{constructor(e,n){this.video=e,this.label=n,this.ms=null,this.sb=null,this.queue=[],this.ready=!1,this.frames=0,this.seekIv=null}onData(e){if(this.frames++,!this.ready){if(!te(e))return;const n=Kt(e);if(!n){c(`${this.label}: cannot detect codec`,"error");return}this.initMse(n,e);return}this.enqueue(e)}initMse(e,n){const s=`video/mp4; codecs="${e}"`;if(c(`${this.label}: ${s}`,"data"),!MediaSource.isTypeSupported(s)){c(`${this.label}: unsupported`,"error");return}this.ms=new MediaSource,this.video.src=URL.createObjectURL(this.ms),this.ms.addEventListener("sourceopen",()=>{try{this.sb=this.ms.addSourceBuffer(s),this.sb.mode="segments",this.sb.addEventListener("updateend",()=>this.flush()),this.ready=!0,this.enqueue(n),this.video.play().catch(()=>{}),this.seekIv=setInterval(()=>{if(this.video.buffered.length>0){const o=this.video.buffered.end(this.video.buffered.length-1);o-this.video.currentTime>.5&&(this.video.currentTime=o-.05);const r=this.video.buffered.start(0);if(o-r>10&&!this.sb.updating)try{this.sb.remove(r,o-5)}catch{}}},500)}catch(o){c(`${this.label}: init failed: ${o.message}`,"error")}})}enqueue(e){this.queue.push(e),this.flush()}flush(){if(!(!this.sb||this.sb.updating||!this.queue.length))try{this.sb.appendBuffer(this.queue.shift())}catch(e){c(`${this.label}: ${e.message}`,"error")}}destroy(){if(this.seekIv&&clearInterval(this.seekIv),this.queue=[],this.ready=!1,this.ms&&this.ms.readyState==="open")try{this.ms.endOfStream()}catch{}this.video.src=""}}let W=null,p=null,G=null,J=!1;async function Ue(){const t=ft.value.trim();if(!t)return;const n=`${Y.value.trim()}/${t}`;W=new qe(document.getElementById("colorVideo"),"Color"),p=new Je;const s=Bt();c(`[depth] Connecting to ${n}...`),G=await It(new URL(n),s),c("[depth] Connected","success");const o=G.consume(bt("")),r=o.subscribe("video",0),a=o.subscribe("depth",0);c("[depth] Subscribed to video + depth tracks","success"),J=!0;async function l(i,d,h){for(;J;){const u=await i.nextGroup();if(!u){c(`[depth] ${h} track ended`);break}for(;J;){const f=await u.readFrame();if(!f)break;d(new Uint8Array(f))}}}l(r,i=>W.onData(i),"video").catch(i=>{J&&c(`[depth] video error: ${i.message}`,"error")}),l(a,i=>p.onData(i),"depth").catch(i=>{J&&c(`[depth] depth error: ${i.message}`,"error")}),c("[depth] Receiving frames...","success")}function ne(){if(J=!1,G){try{G.close()}catch{}G=null}W&&(W.destroy(),W=null),p&&(p.destroy(),p=null),C.setDrawRange(0,0)}function Ye(){return new Uint8Array([128,0,128,0,0,0,8,0])}function He(t,e){const n=new Uint8Array(6+e.length);return n[0]=0,n[1]=t&255,n[2]=t>>8&255,n[3]=t>>16&255,n[4]=t>>24&255,n[5]=e.length,n.set(e,6),n}async function _t(t,e){const n=Y.value,s=e.replace(/\/state$/,""),o=`${n}/${s}/commands`,r=q[t];c(`[${t}] Connecting commands to ${o}...`);const a=Bt();r.conn=await Promise.race([It(new URL(o),a),new Promise((i,d)=>setTimeout(()=>d(new Error(`[${t}] Command connection timeout`)),8e3))]),r.broadcast=new de,r.conn.publish(bt(""),r.broadcast),c(`[${t}] Waiting for CAN server to subscribe (10s)...`);const l=await Promise.race([r.broadcast.requested(),new Promise((i,d)=>setTimeout(()=>d(new Error(`[${t}] No subscriber after 10s — is moq-can-server running?`)),1e4))]);if(!l){c(`[${t}] Command broadcast closed`,"error");return}r.track=l.track,c(`[${t}] Command track active`,"success")}async function Oe(){const t=ut.value.trim(),e=ht.value.trim(),n=[];t&&n.push(_t("left",t)),e&&n.push(_t("right",e)),await Promise.all(n);const s=Ye();H=0,wt=0;const o=[];if(q.left.track&&o.push(q.left),q.right.track&&o.push(q.right),o.length===0){c("No command tracks connected","error");return}const r=parseInt(document.getElementById("queryRate").value)||200,a=Math.max(1,Math.round(1e3/r));Z=setInterval(()=>{const l=o[wt%o.length];if(!l.track)return;const i=H+1,d=He(i,s);l.group=l.track.appendGroup(),l.group.writeFrame(d),l.group.close(),H=(H+1)%8,H===0&&wt++},a),c(`Query loop started at ${r}Hz (${o.length} arm${o.length>1?"s":""})`,"success")}function Ft(){Z&&(clearInterval(Z),Z=null);for(const t of["left","right"]){const e=q[t];if(e.group=null,e.track){try{e.track.close()}catch{}e.track=null}if(e.broadcast){try{e.broadcast.close()}catch{}e.broadcast=null}if(e.conn){try{e.conn.close()}catch{}e.conn=null}}c("Query loop stopped")}const Rt=document.getElementById("threeCanvas");let B;try{B=new ue({canvas:Rt,antialias:!0}),B.setPixelRatio(window.devicePixelRatio),B.setClearColor(1710638)}catch(t){c(`WebGL not available: ${t.message} (3D disabled, MoQ still works)`,"error"),B=null}const F=new he,We=new fe(16777215,.4);F.add(We);const oe=new jt(16777215,.8);oe.position.set(5,10,7);F.add(oe);const se=new jt(4491519,.3);se.position.set(-5,3,-5);F.add(se);const U=new me(50,1,.01,100);U.position.set(1,.8,1.2);U.lookAt(0,.4,0);const V=new pe(U,Rt);V.target.set(0,.4,0);V.enableDamping=!0;V.dampingFactor=.1;V.update();const Ge=new ge(2,20,3355477,2236996);F.add(Ge);const ze=new ye(.1);F.add(ze);const I=640,M=480,re=I*M,K=new Float32Array(re*3),tt=new Float32Array(re*3),C=new Vt;C.setAttribute("position",new Ct(K,3));C.setAttribute("color",new Ct(tt,3));C.setDrawRange(0,0);const Pt=new we({size:.002,vertexColors:!0,sizeAttenuation:!0}),ae=new ve(C,Pt);ae.scale.set(.001,.001,.001);const A=new xe;F.add(A);A.add(ae);const Ne=new Qt(new Ie(.012,12,8),new be({color:16720418}));A.add(Ne);let X=null;function je(){X&&A.remove(X);const t=604.2,e=603.5,n=0,s=.3,o=(1023<<n)*.001,r=s*(I/2)/t,a=s*(M/2)/e,l=o*(I/2)/t,i=o*(M/2)/e,d=new Float32Array([-r,a,s,r,a,s,r,-a,s,-r,-a,s,-l,i,o,l,i,o,l,-i,o,-l,-i,o]),h=[0,1,1,2,2,3,3,0,4,5,5,6,6,7,7,4,0,4,1,5,2,6,3,7],u=new Vt;u.setAttribute("position",new Ct(d,3)),u.setIndex(h),X=new Fe(u,new Re({color:16729156,opacity:.5,transparent:!0})),A.add(X)}je();const St=document.createElement("canvas");St.width=I;St.height=M;const Dt=St.getContext("2d",{willReadFrequently:!0}),Ve=document.getElementById("colorPreview").getContext("2d"),Tt=document.getElementById("depthPreview").getContext("2d"),Qe=document.getElementById("pcStats");let Jt=0,vt=0;function Xe(){const t=document.getElementById("colorVideo");if(!t.videoWidth||!p||!p.latestY)return;const e=1,n=604.2,s=603.5,o=322.7,r=252.7,a=0;Dt.drawImage(t,0,0,I,M),Ve.drawImage(t,0,0,128,96);const l=p.latestY,i=p.width,d=p.height,h=128,u=96,f=Tt.createImageData(h,u),m=f.data,x=i/h,R=d/u;for(let w=0;w<u;w++)for(let v=0;v<h;v++){const Q=l[Math.floor(w*R)*i+Math.floor(v*x)],S=p.is10bit?Q>>2:Q,E=(w*h+v)*4;m[E]=S,m[E+1]=S,m[E+2]=S,m[E+3]=255}Tt.putImageData(f,0,0);const P=Dt.getImageData(0,0,I,M).data;let _=0;for(let w=0;w<M;w+=e)for(let v=0;v<I;v+=e){const Q=w*I+v,S=l[Q];if(S<2)continue;const E=p.is10bit?S<<a:S<<4,D=_*3;K[D]=-(v-o)*E/n,K[D+1]=-(w-r)*E/s,K[D+2]=E;const yt=(w*I+v)*4;tt[D]=P[yt]/255,tt[D+1]=P[yt+1]/255,tt[D+2]=P[yt+2]/255,_++}C.attributes.position.needsUpdate=!0,C.attributes.color.needsUpdate=!0,C.setDrawRange(0,_),C.computeBoundingSphere(),Jt++,vt||(vt=performance.now());const pt=(performance.now()-vt)/1e3,gt=pt>0?(Jt/pt).toFixed(1):"0";Qe.textContent=`${_.toLocaleString()} pts | ${gt} fps | step=${e}`}document.getElementById("ptSize").addEventListener("input",t=>{Pt.size=parseFloat(t.target.value)*.001});Pt.size=parseFloat(document.getElementById("ptSize").value)*.001;const qt=new lt,Ut=new lt,Yt=new lt,xt=new lt;function ce(){const t=parseFloat(document.getElementById("camX").value)||0,e=parseFloat(document.getElementById("camY").value)||0,n=parseFloat(document.getElementById("camZ").value)||0,s=(parseFloat(document.getElementById("camRoll").value)||0)*Math.PI/180,o=(parseFloat(document.getElementById("camPitch").value)||0)*Math.PI/180,r=(parseFloat(document.getElementById("camYaw").value)||0)*Math.PI/180;A.position.set(t,e,n),qt.makeRotationX(s),Ut.makeRotationY(o),Yt.makeRotationZ(r),xt.multiplyMatrices(Yt,Ut),xt.multiply(qt),A.setRotationFromMatrix(xt)}for(const t of["camX","camY","camZ","camRoll","camPitch","camYaw"])document.getElementById(t).addEventListener("input",ce);ce();let y=null;const ie=new Ce;ie.loadMeshCb=(t,e,n)=>{t.endsWith(".stl")?new Ee(e).load(t,s=>{n(new Qt(s,new $e))},null,s=>n(null,s)):t.endsWith(".dae")?new Be(e).load(t,s=>n(s.scene),null,s=>n(null,s)):n(null,new Error(`Unknown mesh format: ${t}`))};b("Loading 3D model...");c("Loading URDF model...");ie.load("./assets/openarm_v10.urdf",t=>{y=t,y.rotation.x=-Math.PI/2,F.add(y),b("Idle"),c("3D model loaded","success")},void 0,t=>{c(`URDF load error: ${t}`,"error"),b("Model load failed")});const Ze=-1.0472,Ht=.044;function Ot(t){return Math.max(0,Math.min(Ht,Ht*(t/Ze)))}function Ke(){if(!y)return;for(let n=0;n<7;n++)y.joints[kt[n]]&&y.joints[kt[n]].setJointValue(N[n].angle),y.joints[Mt[n]]&&y.joints[Mt[n]].setJointValue(j[n].angle);const t=Ot(N[7].angle),e=Ot(j[7].angle);y.joints.L_EE&&y.joints.L_EE.setJointValue(t),y.joints.R_EE&&y.joints.R_EE.setJointValue(e)}function tn(){function t(n,s){for(let o=0;o<rt.length;o++){const r=s[o],a=(r.angle*180/Math.PI).toFixed(1);n[o].angle.innerHTML=`${a}&deg;`,n[o].vel.textContent=r.velocity.toFixed(1),n[o].tau.textContent=r.torque.toFixed(1)}}t(ke,N),t(Me,j),document.getElementById("frameCount").textContent=Et,document.getElementById("bytesReceived").textContent=Le($t);const e=performance.now();e-At>=1e3&&(document.getElementById("canFps").textContent=it,it=0,At=e),document.getElementById("lastUpdate").textContent=new Date().toLocaleTimeString().split(" ")[0]}function Lt(){if(!B)return;const t=Rt.parentElement,e=t.clientWidth,n=t.clientHeight;B.setSize(e,n),U.aspect=e/n,U.updateProjectionMatrix()}window.addEventListener("resize",Lt);requestAnimationFrame(Lt);let z="3d";const Wt=document.getElementById("view3d"),Gt=document.getElementById("viewCamera"),L=document.getElementById("viewToggle"),et=document.getElementById("colorFullCanvas"),nt=document.getElementById("depthFullCanvas"),en=et.getContext("2d"),zt=nt.getContext("2d");L.addEventListener("click",()=>{z==="3d"?(z="camera",Wt.style.display="none",Gt.style.display="block",L.textContent="3D",L.style.background="#00d4ff",L.style.color="#000"):(z="3d",Wt.style.display="",Gt.style.display="none",L.textContent="Camera",L.style.background="#2a2a4a",L.style.color="#aaa",Lt())});function nn(){if(z!=="camera")return;const t=document.getElementById("colorVideo");if(t.videoWidth&&(et.width!==t.videoWidth&&(et.width=t.videoWidth,et.height=t.videoHeight),en.drawImage(t,0,0)),p&&p.latestY){const e=p.latestY,n=p.width,s=p.height;nt.width!==n&&(nt.width=n,nt.height=s);const o=zt.createImageData(n,s),r=o.data;for(let a=0;a<n*s;a++){const l=p.is10bit?e[a]>>2:e[a];r[a*4]=l,r[a*4+1]=l,r[a*4+2]=l,r[a*4+3]=255}zt.putImageData(o,0,0)}}function le(){if(requestAnimationFrame(le),Ke(),z==="camera"){nn();return}B&&(V.update(),Xe(),B.render(F,U))}le();async function Nt(t,e,n){const o=`${Y.value}/${e}`;c(`[${t}] Connecting to ${o}...`);const r=Bt(),a=await Promise.race([It(new URL(o),r),new Promise((d,h)=>setTimeout(()=>h(new Error(`[${t}] Connection timeout`)),8e3))]);at.push(a),c(`[${t}] Connected`,"success");const i=a.consume(bt("")).subscribe("can",0);for(c(`[${t}] Subscribed to 'can' track`,"success");ct;){const d=await i.nextGroup();if(!d){c(`[${t}] Track ended`);break}for(;ct;){const h=await d.readFrame();if(!h)break;const u=new Uint8Array(h);$t+=u.length,Et++,it++;const f=Ae(u);if(!f)continue;const m=rt.findIndex(R=>R.canId===f.canId);if(m<0)continue;const x=_e(f.data);if(x&&(n[m].angle=x.qRad,n[m].velocity=x.vel,n[m].torque=x.tau,n[m].tempMos=x.tempMos,n[m].tempRotor=x.tempRotor,n[m].updated=!0,m===7)){const R=(x.qRad*180/Math.PI).toFixed(1),P=`_lastGripDeg_${t}`;if(!window[P]||Math.abs(parseFloat(R)-window[P])>.5){window[P]=parseFloat(R);const _=t==="left"?"right":"left",gt=((t==="left"?j:N)[7].angle*180/Math.PI).toFixed(1);c(`[GRIP] ${t}=${R}° (${_}=${gt}°) canId=0x${f.canId.toString(16)}`,"data")}}}}}O.addEventListener("click",async()=>{try{const t=ut.value.trim(),e=ht.value.trim(),n=ft.value.trim();if(!t&&!e&&!n){c("No paths configured","error");return}O.disabled=!0,st.disabled=!1,ct=!0,Et=0,$t=0,it=0,at=[],b("Connecting..."),c(`WebTransport: ${typeof WebTransport<"u"?"supported":"NOT supported"}`,"data");const s=Y.value;if(!mt.value.trim())try{const a=await fetch(`${s}/certificate.sha256`);a.ok&&c(`Relay cert: ${(await a.text()).trim().slice(0,32)}...`,"data")}catch{}t&&e&&t===e&&c(`WARNING: Left and Right arms use the same path "${t}" — gripper cross-talk expected!`,"error");const r=[];t&&r.push(Nt("left",t,N)),e&&r.push(Nt("right",e,j));try{await Ue()}catch(a){c(`[depth] ${a.message}`,"error")}g.disabled=!1,b("Streaming"),await Promise.all(r),b("Ended")}catch(t){c(`Error: ${t.message}`,"error"),console.error(t),b("Error")}finally{k&&(Ft(),k=!1,g.classList.remove("active"),g.textContent="Query Motors"),ne(),g.disabled=!0,O.disabled=!1,st.disabled=!0}});st.addEventListener("click",async()=>{ct=!1,k&&(Ft(),k=!1,g.classList.remove("active"),g.textContent="Query Motors"),g.disabled=!0,b("Stopping..."),ne();for(const t of at)try{t.close()}catch{}at=[],O.disabled=!1,st.disabled=!0,b("Disconnected"),c("Disconnected","success")});g.addEventListener("click",async()=>{if(k)Ft(),k=!1,g.classList.remove("active"),g.textContent="Query Motors";else{g.disabled=!0,g.textContent="Starting...";try{await Oe(),k=!0,g.classList.add("active"),g.textContent="Stop Query",g.disabled=!1}catch(t){c(`Query start error: ${t.message}`,"error"),console.error(t),g.textContent="Query Motors",g.disabled=!1}}});setInterval(tn,100);c("Ready. Click Connect to start.","info");($.has("left")||$.has("right")||$.has("path")||$.has("depth"))&&(c("Auto-connecting from query params...","info"),O.click());
assets/openarm_v10.urdf ADDED
@@ -0,0 +1,836 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?xml version="1.0" ?>
2
+ <!-- =================================================================================== -->
3
+ <!-- | This document was autogenerated by xacro from v10.urdf.xacro | -->
4
+ <!-- | EDITING THIS FILE BY HAND IS NOT RECOMMENDED | -->
5
+ <!-- =================================================================================== -->
6
+ <robot name="openarm">
7
+ <!--
8
+ DEPRECATION NOTICE
9
+ argument arm_type is no longer supported and will be removed in the future.
10
+ This argument is ignored.
11
+ -->
12
+ <!-- Should the robot be spawned in Gazebo with effort interfaces?" -->
13
+ <!-- <xacro:arg name="gazebo_effort" default="false" /> -->
14
+ <!-- ========================================================== -->
15
+ <!-- Adds the required tags to simulate one joint in gazebo -->
16
+ <!-- -->
17
+ <!-- joint - Name of the openarm joint to simulate -->
18
+ <!-- transmission - type of the transmission of the joint -->
19
+ <!-- ========================================================== -->
20
+ <!-- <xacro:macro name="gazebo-joint" params="joint transmission:=hardware_interface/EffortJointInterface">
21
+ <gazebo reference="${joint}">
22
+ <provideFeedback>true</provideFeedback>
23
+ </gazebo>
24
+ <transmission name="${joint}_transmission">
25
+ <type>transmission_interface/SimpleTransmission</type>
26
+ <joint name="${joint}">
27
+ <hardwareInterface>${transmission}</hardwareInterface>
28
+ </joint>
29
+ <actuator name="${joint}_motor">
30
+ <hardwareInterface>${transmission}</hardwareInterface>
31
+ </actuator>
32
+ </transmission>
33
+ </xacro:macro> -->
34
+ <!-- <xacro:macro name="gazebo-friction" params="link mu">
35
+ <gazebo reference="${link}">
36
+ <collision>
37
+ <max_contacts>10</max_contacts>
38
+ <surface>
39
+ <contact>
40
+ <ode>
41
+ <max_vel>0</max_vel>
42
+ <min_depth>0.001</min_depth>
43
+ </ode>
44
+ </contact>
45
+ <friction>
46
+ <ode>
47
+ <mu>${mu}</mu>
48
+ <mu2>${mu}</mu2>
49
+ </ode>
50
+ </friction>
51
+ <bounce/>
52
+ </surface>
53
+ </collision>
54
+ </gazebo>
55
+ </xacro:macro> -->
56
+ <!-- ========================================================== -->
57
+ <!-- Adds the required tags to simulate one joint in gazebo -->
58
+ <!-- -->
59
+ <!-- joint - Name of the openarm joint to simulate -->
60
+ <!-- transmission - type of the transmission of the joint -->
61
+ <!-- ========================================================== -->
62
+ <!-- <xacro:macro name="gazebo-joint" params="joint transmission:=hardware_interface/EffortJointInterface">
63
+ <gazebo reference="${joint}">
64
+ <provideFeedback>true</provideFeedback>
65
+ </gazebo>
66
+ <transmission name="${joint}_transmission">
67
+ <type>transmission_interface/SimpleTransmission</type>
68
+ <joint name="${joint}">
69
+ <hardwareInterface>${transmission}</hardwareInterface>
70
+ </joint>
71
+ <actuator name="${joint}_motor">
72
+ <hardwareInterface>${transmission}</hardwareInterface>
73
+ </actuator>
74
+ </transmission>
75
+ </xacro:macro> -->
76
+ <!-- <xacro:macro name="gazebo-friction" params="link mu">
77
+ <gazebo reference="${link}">
78
+ <collision>
79
+ <max_contacts>10</max_contacts>
80
+ <surface>
81
+ <contact>
82
+ <ode>
83
+ <max_vel>0</max_vel>
84
+ <min_depth>0.001</min_depth>
85
+ </ode>
86
+ </contact>
87
+ <friction>
88
+ <ode>
89
+ <mu>${mu}</mu>
90
+ <mu2>${mu}</mu2>
91
+ </ode>
92
+ </friction>
93
+ <bounce/>
94
+ </surface>
95
+ </collision>
96
+ </gazebo>
97
+ </xacro:macro> -->
98
+ <!-- arm_type: Namespace of the robot arm. Serves to differentiate between arms in case of multiple instances. -->
99
+ <!-- joint_limits: description of the joint limits that comes from a YAML file. Example definition: ${xacro.load_yaml('$(find openarm_description)/robots/fr3/joint_limits.yaml')} -->
100
+ <!-- kinematics: description of the kinematics that comes from a YAML file. Example definition: ${xacro.load_yaml('$(find openarm_description)/robots/fr3/kinematics.yaml')} -->
101
+ <!-- inertials: description of the inertials that comes from a YAML file. Example definition: ${xacro.load_yaml('$(find openarm_description)/robots/fr3/inertials.yaml')} -->
102
+ <!-- Is the robot being simulated in gazebo? -->
103
+ <!-- <xacro:arg name="gazebo" default="false" /> -->
104
+ <material name="light_gray">
105
+ <color rgba="0.4 0.4 0.4 1.0"/>
106
+ </material>
107
+ <material name="gray">
108
+ <color rgba="0.2117647058823529 0.2117647058823529 0.2117647058823529 1.0"/>
109
+ </material>
110
+ <material name="dark_gray">
111
+ <color rgba="0.1607843137254902 0.1607843137254902 0.1607843137254902 1.0"/>
112
+ </material>
113
+ <material name="light_black">
114
+ <color rgba="0.08 0.08 0.08 1.0"/>
115
+ </material>
116
+ <material name="black">
117
+ <color rgba="0.0 0.0 0.0 1.0"/>
118
+ </material>
119
+ <link name="world"/>
120
+ <joint name="openarm_body_world_joint" type="fixed">
121
+ <parent link="world"/>
122
+ <child link="openarm_body_link0"/>
123
+ <origin rpy="0 0 -2.36" xyz="0 0 0"/>
124
+ </joint>
125
+ <link name="openarm_body_link0">
126
+ <visual name="openarm_body_link0_visual">
127
+ <origin rpy="0.0 0.0 0.0" xyz="0.0 0.0 0.0"/>
128
+ <geometry>
129
+ <mesh filename="./meshes/body/v10/visual/body_link0.stl" scale="0.001 0.001 0.001"/>
130
+ </geometry>
131
+ <material name="light_black"/>
132
+ </visual>
133
+ <collision name="openarm_body_link0_collision">
134
+ <origin rpy="0.0 0.0 0.0" xyz="0.0 0.0 0.0"/>
135
+ <geometry>
136
+ </geometry>
137
+ </collision>
138
+ <inertial>
139
+ <origin rpy="0.0 0.0 0.0" xyz="0.0 0.0 0.0"/>
140
+ <mass value="13.89"/>
141
+ <inertia ixx="1.653" ixy="0.0" ixz="0.0" iyy="1.653" iyz="0.0" izz="0.051"/>
142
+ </inertial>
143
+ </link>
144
+ <!-- Define a property that defaults to 'arm_prefix_arm_type' concatenated with an underscore if 'no_prefix' is not set -->
145
+ <!-- <xacro:if value="${gazebo}">
146
+ <xacro:property name="connected_to" value="" />
147
+ </xacro:if> -->
148
+ <!-- <link name="${connected_to}">
149
+ </link> -->
150
+ <joint name="openarm_left_openarm_body_link0_joint" type="fixed">
151
+ <parent link="openarm_body_link0"/>
152
+ <child link="openarm_left_link0"/>
153
+ <origin rpy="-1.5708 0 0" xyz="0.0 0.031 0.698"/>
154
+ </joint>
155
+ <link name="openarm_left_link0">
156
+ <visual name="openarm_left_link0_visual">
157
+ <origin rpy="0.0 0.0 0.0" xyz="0.0 0.0 0.0"/>
158
+ <geometry>
159
+ <mesh filename="./meshes/arm/v10/visual/link0.stl" scale="0.001 -0.001 0.001"/>
160
+ </geometry>
161
+ <material name="light_black"/>
162
+ </visual>
163
+ <collision name="openarm_left_link0_collision">
164
+ <origin rpy="0.0 0.0 0.0" xyz="0.0 0.0 0.0"/>
165
+ <geometry>
166
+
167
+
168
+ </geometry>
169
+ </collision>
170
+ <inertial>
171
+ <origin rpy="0.0 0.0 0.0" xyz="-0.0009483362816297526 0.0001580207020448382 0.03076860287587199"/>
172
+ <mass value="1.1432284943239561"/>
173
+ <inertia ixx="0.001128" ixy="-4e-06" ixz="-3.3e-05" iyy="0.000962" iyz="-7e-06" izz="0.00147"/>
174
+ </inertial>
175
+ </link>
176
+ <link name="openarm_left_link1">
177
+ <visual name="openarm_left_link1_visual">
178
+ <origin rpy="0.0 0.0 0.0" xyz="-0.0 0.0 -0.0625"/>
179
+ <geometry>
180
+ <mesh filename="./meshes/arm/v10/visual/link1.stl" scale="0.001 -0.001 0.001"/>
181
+ </geometry>
182
+ <material name="light_black"/>
183
+ </visual>
184
+ <collision name="openarm_left_link1_collision">
185
+ <origin rpy="0.0 0.0 0.0" xyz="-0.0 0.0 -0.0625"/>
186
+ <geometry>
187
+
188
+
189
+ </geometry>
190
+ </collision>
191
+ <inertial>
192
+ <origin rpy="0.0 0.0 0.0" xyz="0.0011467657911800769 3.319987657026362e-05 0.05395284380736254"/>
193
+ <mass value="1.1416684646202298"/>
194
+ <inertia ixx="0.001567" ixy="-1e-06" ixz="-2.9e-05" iyy="0.001273" iyz="-0.0" izz="0.001016"/>
195
+ </inertial>
196
+ </link>
197
+ <joint name="L_J1" type="revolute">
198
+ <origin rpy="0 0 0" xyz="0.0 0.0 0.0625"/>
199
+ <parent link="openarm_left_link0"/>
200
+ <child link="openarm_left_link1"/>
201
+ <axis xyz="0 0 1"/>
202
+ <limit effort="54" lower="-3.490659" upper="1.3962629999999998" velocity="45"/>
203
+ </joint>
204
+ <link name="openarm_left_link2">
205
+ <visual name="openarm_left_link2_visual">
206
+ <origin rpy="0.0 0.0 0.0" xyz="0.0301 0.0 -0.1225"/>
207
+ <geometry>
208
+ <mesh filename="./meshes/arm/v10/visual/link2.stl" scale="0.001 -0.001 0.001"/>
209
+ </geometry>
210
+ <material name="light_black"/>
211
+ </visual>
212
+ <collision name="openarm_left_link2_collision">
213
+ <origin rpy="0.0 0.0 0.0" xyz="0.0301 0.0 -0.1225"/>
214
+ <geometry>
215
+
216
+
217
+ </geometry>
218
+ </collision>
219
+ <inertial>
220
+ <origin rpy="0.0 0.0 0.0" xyz="0.00839629182351943 -2.0145102027597523e-08 0.03256649300522363"/>
221
+ <mass value="0.2775092746011571"/>
222
+ <inertia ixx="0.000359" ixy="-0.0" ixz="-0.000109" iyy="0.000376" iyz="0.0" izz="0.000232"/>
223
+ </inertial>
224
+ </link>
225
+ <joint name="L_J2" type="revolute">
226
+ <origin rpy="-1.57079632679 0 0" xyz="-0.0301 0.0 0.06"/>
227
+ <parent link="openarm_left_link1"/>
228
+ <child link="openarm_left_link2"/>
229
+ <axis xyz="-1 0 0"/>
230
+ <limit effort="54" lower="-3.3161253267948965" upper="0.17453267320510335" velocity="45"/>
231
+ </joint>
232
+ <link name="openarm_left_link3">
233
+ <visual name="openarm_left_link3_visual">
234
+ <origin rpy="0.0 0.0 0.0" xyz="-0.0 -0.0 -0.18875"/>
235
+ <geometry>
236
+ <mesh filename="./meshes/arm/v10/visual/link3.stl" scale="0.001 -0.001 0.001"/>
237
+ </geometry>
238
+ <material name="dark_gray"/>
239
+ </visual>
240
+ <collision name="openarm_left_link3_collision">
241
+ <origin rpy="0.0 0.0 0.0" xyz="-0.0 -0.0 -0.18875"/>
242
+ <geometry>
243
+
244
+
245
+ </geometry>
246
+ </collision>
247
+ <inertial>
248
+ <origin rpy="0.0 0.0 0.0" xyz="-0.002104752099628911 0.0005549085042607548 0.08847470545721961"/>
249
+ <mass value="1.073863338202347"/>
250
+ <inertia ixx="0.004372" ixy="-0.0" ixz="1.1e-05" iyy="0.004319" iyz="-3.6e-05" izz="0.000661"/>
251
+ </inertial>
252
+ </link>
253
+ <joint name="L_J3" type="revolute">
254
+ <origin rpy="0 0 0" xyz="0.0301 0.0 0.06625"/>
255
+ <parent link="openarm_left_link2"/>
256
+ <child link="openarm_left_link3"/>
257
+ <axis xyz="0 0 1"/>
258
+ <limit effort="28" lower="-1.570796" upper="1.570796" velocity="8"/>
259
+ </joint>
260
+ <link name="openarm_left_link4">
261
+ <visual name="openarm_left_link4_visual">
262
+ <origin rpy="0.0 0.0 0.0" xyz="0.0 -0.0315 -0.3425"/>
263
+ <geometry>
264
+ <mesh filename="./meshes/arm/v10/visual/link4.stl" scale="0.001 0.001 0.001"/>
265
+ </geometry>
266
+ <material name="gray"/>
267
+ </visual>
268
+ <collision name="openarm_left_link4_collision">
269
+ <origin rpy="0.0 0.0 0.0" xyz="0.0 -0.0315 -0.3425"/>
270
+ <geometry>
271
+
272
+
273
+ </geometry>
274
+ </collision>
275
+ <inertial>
276
+ <origin rpy="0.0 0.0 0.0" xyz="-0.0029006831074562967 -0.03030575826634669 0.06339637422196209"/>
277
+ <mass value="1.3699337287025453"/>
278
+ <inertia ixx="0.001577" ixy="-5e-06" ixz="-7.5e-05" iyy="0.001346" iyz="0.000108" izz="0.001104"/>
279
+ </inertial>
280
+ </link>
281
+ <joint name="L_J4" type="revolute">
282
+ <origin rpy="0 0 0" xyz="-0.0 0.0315 0.15375"/>
283
+ <parent link="openarm_left_link3"/>
284
+ <child link="openarm_left_link4"/>
285
+ <axis xyz="0 1 0"/>
286
+ <limit effort="28" lower="0.0" upper="2.443461" velocity="8"/>
287
+ </joint>
288
+ <link name="openarm_left_link5">
289
+ <visual name="openarm_left_link5_visual">
290
+ <origin rpy="0.0 0.0 0.0" xyz="-0.0 -0.0 -0.438"/>
291
+ <geometry>
292
+ <mesh filename="./meshes/arm/v10/visual/link5.stl" scale="0.001 -0.001 0.001"/>
293
+ </geometry>
294
+ <material name="dark_gray"/>
295
+ </visual>
296
+ <collision name="openarm_left_link5_collision">
297
+ <origin rpy="0.0 0.0 0.0" xyz="-0.0 -0.0 -0.438"/>
298
+ <geometry>
299
+
300
+
301
+ </geometry>
302
+ </collision>
303
+ <inertial>
304
+ <origin rpy="0.0 0.0 0.0" xyz="-0.003049665024221911 0.0008866902457326625 0.043079803024980934"/>
305
+ <mass value="0.5506588026168502"/>
306
+ <inertia ixx="0.000423" ixy="-8e-06" ixz="6e-06" iyy="0.000445" iyz="-6e-06" izz="0.000324"/>
307
+ </inertial>
308
+ </link>
309
+ <joint name="L_J5" type="revolute">
310
+ <origin rpy="0 0 0" xyz="0.0 -0.0315 0.0955"/>
311
+ <parent link="openarm_left_link4"/>
312
+ <child link="openarm_left_link5"/>
313
+ <axis xyz="0 0 1"/>
314
+ <limit effort="10" lower="-1.570796" upper="1.570796" velocity="30"/>
315
+ </joint>
316
+ <link name="openarm_left_link6">
317
+ <visual name="openarm_left_link6_visual">
318
+ <origin rpy="0.0 0.0 0.0" xyz="-0.0375 -0.0 -0.5585"/>
319
+ <geometry>
320
+ <mesh filename="./meshes/arm/v10/visual/link6.stl" scale="0.001 -0.001 0.001"/>
321
+ </geometry>
322
+ <material name="light_black"/>
323
+ </visual>
324
+ <collision name="openarm_left_link6_collision">
325
+ <origin rpy="0.0 0.0 0.0" xyz="-0.0375 -0.0 -0.5585"/>
326
+ <geometry>
327
+
328
+
329
+ </geometry>
330
+ </collision>
331
+ <inertial>
332
+ <origin rpy="0.0 0.0 0.0" xyz="-0.037136587005447405 0.00033230528343419053 -9.498374522309838e-05"/>
333
+ <mass value="0.3540202773187987"/>
334
+ <inertia ixx="0.000143" ixy="4e-06" ixz="0.0" iyy="0.000157" iyz="1e-06" izz="0.000159"/>
335
+ </inertial>
336
+ </link>
337
+ <joint name="L_J6" type="revolute">
338
+ <origin rpy="0 0 0" xyz="0.0375 0.0 0.1205"/>
339
+ <parent link="openarm_left_link5"/>
340
+ <child link="openarm_left_link6"/>
341
+ <axis xyz="1 0 0"/>
342
+ <limit effort="10" lower="-0.785398" upper="0.785398" velocity="30"/>
343
+ </joint>
344
+ <link name="openarm_left_link7">
345
+ <visual name="openarm_left_link7_visual">
346
+ <origin rpy="0.0 0.0 0.0" xyz="0.0 -0.0 -0.5585"/>
347
+ <geometry>
348
+ <mesh filename="./meshes/arm/v10/visual/link7.stl" scale="0.001 -0.001 0.001"/>
349
+ </geometry>
350
+ <material name="gray"/>
351
+ </visual>
352
+ <collision name="openarm_left_link7_collision">
353
+ <origin rpy="0.0 0.0 0.0" xyz="0.0 -0.0 -0.5585"/>
354
+ <geometry>
355
+
356
+
357
+ </geometry>
358
+ </collision>
359
+ <inertial>
360
+ <origin rpy="0.0 0.0 0.0" xyz="6.875510271106056e-05 -0.01766175250761268 0.06651945409987448"/>
361
+ <mass value="0.5499771327380578"/>
362
+ <inertia ixx="0.000639" ixy="0.0" ixz="-0.0" iyy="0.000497" iyz="8.9e-05" izz="0.000342"/>
363
+ </inertial>
364
+ </link>
365
+ <joint name="L_J7" type="revolute">
366
+ <origin rpy="0 0 0" xyz="-0.0375 0.0 0.0"/>
367
+ <parent link="openarm_left_link6"/>
368
+ <child link="openarm_left_link7"/>
369
+ <axis xyz="0 -1 0"/>
370
+ <limit effort="10" lower="-1.570796" upper="1.570796" velocity="30"/>
371
+ </joint>
372
+ <link name="openarm_left_link8"/>
373
+ <joint name="L_J8" type="fixed">
374
+ <origin rpy="0 0 0" xyz="1e-06 0.0205 0.0"/>
375
+ <parent link="openarm_left_link7"/>
376
+ <child link="openarm_left_link8"/>
377
+ </joint>
378
+ <!-- Define a property that defaults to 'arm_prefix_arm_type' concatenated with an underscore if 'no_prefix' is not set -->
379
+ <!-- <xacro:if value="${gazebo}">
380
+ <xacro:property name="connected_to" value="" />
381
+ </xacro:if> -->
382
+ <!-- <link name="${connected_to}">
383
+ </link> -->
384
+ <joint name="openarm_right_openarm_body_link0_joint" type="fixed">
385
+ <parent link="openarm_body_link0"/>
386
+ <child link="openarm_right_link0"/>
387
+ <origin rpy="1.5708 0 0" xyz="0.0 -0.031 0.698"/>
388
+ </joint>
389
+ <link name="openarm_right_link0">
390
+ <visual name="openarm_right_link0_visual">
391
+ <origin rpy="0.0 0.0 0.0" xyz="0.0 0.0 0.0"/>
392
+ <geometry>
393
+ <mesh filename="./meshes/arm/v10/visual/link0.stl" scale="0.001 0.001 0.001"/>
394
+ </geometry>
395
+ <material name="light_black"/>
396
+ </visual>
397
+ <collision name="openarm_right_link0_collision">
398
+ <origin rpy="0.0 0.0 0.0" xyz="0.0 0.0 0.0"/>
399
+ <geometry>
400
+
401
+
402
+ </geometry>
403
+ </collision>
404
+ <inertial>
405
+ <origin rpy="0.0 0.0 0.0" xyz="-0.0009483362816297526 0.0001580207020448382 0.03076860287587199"/>
406
+ <mass value="1.1432284943239561"/>
407
+ <inertia ixx="0.001128" ixy="-4e-06" ixz="-3.3e-05" iyy="0.000962" iyz="-7e-06" izz="0.00147"/>
408
+ </inertial>
409
+ </link>
410
+ <link name="openarm_right_link1">
411
+ <visual name="openarm_right_link1_visual">
412
+ <origin rpy="0.0 0.0 0.0" xyz="-0.0 0.0 -0.0625"/>
413
+ <geometry>
414
+ <mesh filename="./meshes/arm/v10/visual/link1.stl" scale="0.001 0.001 0.001"/>
415
+ </geometry>
416
+ <material name="light_black"/>
417
+ </visual>
418
+ <collision name="openarm_right_link1_collision">
419
+ <origin rpy="0.0 0.0 0.0" xyz="-0.0 0.0 -0.0625"/>
420
+ <geometry>
421
+
422
+
423
+ </geometry>
424
+ </collision>
425
+ <inertial>
426
+ <origin rpy="0.0 0.0 0.0" xyz="0.0011467657911800769 3.319987657026362e-05 0.05395284380736254"/>
427
+ <mass value="1.1416684646202298"/>
428
+ <inertia ixx="0.001567" ixy="-1e-06" ixz="-2.9e-05" iyy="0.001273" iyz="-0.0" izz="0.001016"/>
429
+ </inertial>
430
+ </link>
431
+ <joint name="R_J1" type="revolute">
432
+ <origin rpy="0 0 0" xyz="0.0 0.0 0.0625"/>
433
+ <parent link="openarm_right_link0"/>
434
+ <child link="openarm_right_link1"/>
435
+ <axis xyz="0 0 1"/>
436
+ <limit effort="54" lower="-1.396263" upper="3.490659" velocity="45"/>
437
+ </joint>
438
+ <link name="openarm_right_link2">
439
+ <visual name="openarm_right_link2_visual">
440
+ <origin rpy="0.0 0.0 0.0" xyz="0.0301 0.0 -0.1225"/>
441
+ <geometry>
442
+ <mesh filename="./meshes/arm/v10/visual/link2.stl" scale="0.001 0.001 0.001"/>
443
+ </geometry>
444
+ <material name="light_black"/>
445
+ </visual>
446
+ <collision name="openarm_right_link2_collision">
447
+ <origin rpy="0.0 0.0 0.0" xyz="0.0301 0.0 -0.1225"/>
448
+ <geometry>
449
+
450
+
451
+ </geometry>
452
+ </collision>
453
+ <inertial>
454
+ <origin rpy="0.0 0.0 0.0" xyz="0.00839629182351943 -2.0145102027597523e-08 0.03256649300522363"/>
455
+ <mass value="0.2775092746011571"/>
456
+ <inertia ixx="0.000359" ixy="-0.0" ixz="-0.000109" iyy="0.000376" iyz="0.0" izz="0.000232"/>
457
+ </inertial>
458
+ </link>
459
+ <joint name="R_J2" type="revolute">
460
+ <origin rpy="1.57079632679 0 0" xyz="-0.0301 0.0 0.06"/>
461
+ <parent link="openarm_right_link1"/>
462
+ <child link="openarm_right_link2"/>
463
+ <axis xyz="-1 0 0"/>
464
+ <limit effort="54" lower="-0.17453267320510335" upper="3.3161253267948965" velocity="45"/>
465
+ </joint>
466
+ <link name="openarm_right_link3">
467
+ <visual name="openarm_right_link3_visual">
468
+ <origin rpy="0.0 0.0 0.0" xyz="-0.0 -0.0 -0.18875"/>
469
+ <geometry>
470
+ <mesh filename="./meshes/arm/v10/visual/link3.stl" scale="0.001 0.001 0.001"/>
471
+ </geometry>
472
+ <material name="dark_gray"/>
473
+ </visual>
474
+ <collision name="openarm_right_link3_collision">
475
+ <origin rpy="0.0 0.0 0.0" xyz="-0.0 -0.0 -0.18875"/>
476
+ <geometry>
477
+
478
+
479
+ </geometry>
480
+ </collision>
481
+ <inertial>
482
+ <origin rpy="0.0 0.0 0.0" xyz="-0.002104752099628911 0.0005549085042607548 0.08847470545721961"/>
483
+ <mass value="1.073863338202347"/>
484
+ <inertia ixx="0.004372" ixy="-0.0" ixz="1.1e-05" iyy="0.004319" iyz="-3.6e-05" izz="0.000661"/>
485
+ </inertial>
486
+ </link>
487
+ <joint name="R_J3" type="revolute">
488
+ <origin rpy="0 0 0" xyz="0.0301 0.0 0.06625"/>
489
+ <parent link="openarm_right_link2"/>
490
+ <child link="openarm_right_link3"/>
491
+ <axis xyz="0 0 1"/>
492
+ <limit effort="28" lower="-1.570796" upper="1.570796" velocity="8"/>
493
+ </joint>
494
+ <link name="openarm_right_link4">
495
+ <visual name="openarm_right_link4_visual">
496
+ <origin rpy="0.0 0.0 0.0" xyz="0.0 -0.0315 -0.3425"/>
497
+ <geometry>
498
+ <mesh filename="./meshes/arm/v10/visual/link4.stl" scale="0.001 0.001 0.001"/>
499
+ </geometry>
500
+ <material name="gray"/>
501
+ </visual>
502
+ <collision name="openarm_right_link4_collision">
503
+ <origin rpy="0.0 0.0 0.0" xyz="0.0 -0.0315 -0.3425"/>
504
+ <geometry>
505
+
506
+
507
+ </geometry>
508
+ </collision>
509
+ <inertial>
510
+ <origin rpy="0.0 0.0 0.0" xyz="-0.0029006831074562967 -0.03030575826634669 0.06339637422196209"/>
511
+ <mass value="1.3699337287025453"/>
512
+ <inertia ixx="0.001577" ixy="-5e-06" ixz="-7.5e-05" iyy="0.001346" iyz="0.000108" izz="0.001104"/>
513
+ </inertial>
514
+ </link>
515
+ <joint name="R_J4" type="revolute">
516
+ <origin rpy="0 0 0" xyz="-0.0 0.0315 0.15375"/>
517
+ <parent link="openarm_right_link3"/>
518
+ <child link="openarm_right_link4"/>
519
+ <axis xyz="0 1 0"/>
520
+ <limit effort="28" lower="0.0" upper="2.443461" velocity="8"/>
521
+ </joint>
522
+ <link name="openarm_right_link5">
523
+ <visual name="openarm_right_link5_visual">
524
+ <origin rpy="0.0 0.0 0.0" xyz="-0.0 -0.0 -0.438"/>
525
+ <geometry>
526
+ <mesh filename="./meshes/arm/v10/visual/link5.stl" scale="0.001 0.001 0.001"/>
527
+ </geometry>
528
+ <material name="dark_gray"/>
529
+ </visual>
530
+ <collision name="openarm_right_link5_collision">
531
+ <origin rpy="0.0 0.0 0.0" xyz="-0.0 -0.0 -0.438"/>
532
+ <geometry>
533
+
534
+
535
+ </geometry>
536
+ </collision>
537
+ <inertial>
538
+ <origin rpy="0.0 0.0 0.0" xyz="-0.003049665024221911 0.0008866902457326625 0.043079803024980934"/>
539
+ <mass value="0.5506588026168502"/>
540
+ <inertia ixx="0.000423" ixy="-8e-06" ixz="6e-06" iyy="0.000445" iyz="-6e-06" izz="0.000324"/>
541
+ </inertial>
542
+ </link>
543
+ <joint name="R_J5" type="revolute">
544
+ <origin rpy="0 0 0" xyz="0.0 -0.0315 0.0955"/>
545
+ <parent link="openarm_right_link4"/>
546
+ <child link="openarm_right_link5"/>
547
+ <axis xyz="0 0 1"/>
548
+ <limit effort="10" lower="-1.570796" upper="1.570796" velocity="30"/>
549
+ </joint>
550
+ <link name="openarm_right_link6">
551
+ <visual name="openarm_right_link6_visual">
552
+ <origin rpy="0.0 0.0 0.0" xyz="-0.0375 -0.0 -0.5585"/>
553
+ <geometry>
554
+ <mesh filename="./meshes/arm/v10/visual/link6.stl" scale="0.001 0.001 0.001"/>
555
+ </geometry>
556
+ <material name="light_black"/>
557
+ </visual>
558
+ <collision name="openarm_right_link6_collision">
559
+ <origin rpy="0.0 0.0 0.0" xyz="-0.0375 -0.0 -0.5585"/>
560
+ <geometry>
561
+
562
+
563
+ </geometry>
564
+ </collision>
565
+ <inertial>
566
+ <origin rpy="0.0 0.0 0.0" xyz="-0.037136587005447405 0.00033230528343419053 -9.498374522309838e-05"/>
567
+ <mass value="0.3540202773187987"/>
568
+ <inertia ixx="0.000143" ixy="4e-06" ixz="0.0" iyy="0.000157" iyz="1e-06" izz="0.000159"/>
569
+ </inertial>
570
+ </link>
571
+ <joint name="R_J6" type="revolute">
572
+ <origin rpy="0 0 0" xyz="0.0375 0.0 0.1205"/>
573
+ <parent link="openarm_right_link5"/>
574
+ <child link="openarm_right_link6"/>
575
+ <axis xyz="1 0 0"/>
576
+ <limit effort="10" lower="-0.785398" upper="0.785398" velocity="30"/>
577
+ </joint>
578
+ <link name="openarm_right_link7">
579
+ <visual name="openarm_right_link7_visual">
580
+ <origin rpy="0.0 0.0 0.0" xyz="0.0 -0.0 -0.5585"/>
581
+ <geometry>
582
+ <mesh filename="./meshes/arm/v10/visual/link7.stl" scale="0.001 0.001 0.001"/>
583
+ </geometry>
584
+ <material name="gray"/>
585
+ </visual>
586
+ <collision name="openarm_right_link7_collision">
587
+ <origin rpy="0.0 0.0 0.0" xyz="0.0 -0.0 -0.5585"/>
588
+ <geometry>
589
+
590
+
591
+ </geometry>
592
+ </collision>
593
+ <inertial>
594
+ <origin rpy="0.0 0.0 0.0" xyz="6.875510271106056e-05 -0.01766175250761268 0.06651945409987448"/>
595
+ <mass value="0.5499771327380578"/>
596
+ <inertia ixx="0.000639" ixy="0.0" ixz="-0.0" iyy="0.000497" iyz="8.9e-05" izz="0.000342"/>
597
+ </inertial>
598
+ </link>
599
+ <joint name="R_J7" type="revolute">
600
+ <origin rpy="0 0 0" xyz="-0.0375 0.0 0.0"/>
601
+ <parent link="openarm_right_link6"/>
602
+ <child link="openarm_right_link7"/>
603
+ <axis xyz="0 1 0"/>
604
+ <limit effort="10" lower="-1.570796" upper="1.570796" velocity="30"/>
605
+ </joint>
606
+ <link name="openarm_right_link8"/>
607
+ <joint name="R_J8" type="fixed">
608
+ <origin rpy="0 0 0" xyz="1e-06 0.0205 0.0"/>
609
+ <parent link="openarm_right_link7"/>
610
+ <child link="openarm_right_link8"/>
611
+ </joint>
612
+ <link name="openarm_left_hand">
613
+ <visual name="openarm_left_hand_visual">
614
+ <origin rpy="0.0 0.0 0.0" xyz="0.0 0.005 -0.6585"/>
615
+ <geometry>
616
+ <mesh filename="./meshes/ee/openarm_hand/visual/hand.stl" scale="0.001 0.001 0.001"/>
617
+ </geometry>
618
+ <material name="light_gray"/>
619
+ </visual>
620
+ <collision name="openarm_left_hand_collision">
621
+ <origin rpy="0.0 0.0 0.0" xyz="0.0 0.005 -0.6585"/>
622
+ <geometry>
623
+
624
+ </geometry>
625
+ </collision>
626
+ <inertial>
627
+ <origin rpy="0 0 0" xyz="0.0 0.002 0.01"/>
628
+ <mass value="0.15"/>
629
+ <inertia ixx="0.0001" ixy="0" ixz="0" iyy="0.00025" iyz="0" izz="0.00017"/>
630
+ </inertial>
631
+ </link>
632
+ <!-- <link name="${ee_prefix}hand"/> -->
633
+ <!-- <joint name="${ee_prefix}hand_joint" type="fixed"> -->
634
+ <joint name="left_openarm_hand_joint" type="fixed">
635
+ <parent link="openarm_left_link8"/>
636
+ <child link="openarm_left_hand"/>
637
+ <origin rpy="0 0 0" xyz="0 -0.025 0.1001"/>
638
+ </joint>
639
+ <!-- Define the hand_tcp frame -->
640
+ <link name="openarm_left_hand_tcp"/>
641
+ <joint name="openarm_left_hand_tcp_joint" type="fixed">
642
+ <origin rpy="0 0 0" xyz="0 -0.0 0.08"/>
643
+ <parent link="openarm_left_hand"/>
644
+ <child link="openarm_left_hand_tcp"/>
645
+ </joint>
646
+ <link name="openarm_left_left_finger">
647
+ <visual name="openarm_left_left_finger_visual">
648
+ <origin rpy="0.0 0.0 0.0" xyz="0.0 -0.05 -0.673001"/>
649
+ <geometry>
650
+ <mesh filename="./meshes/ee/openarm_hand/visual/finger.stl" scale="0.001 0.001 0.001"/>
651
+ </geometry>
652
+ <material name="light_black"/>
653
+ </visual>
654
+ <collision name="openarm_left_left_finger_collision">
655
+ <origin rpy="0.0 0.0 0.0" xyz="0.0 -0.05 -0.673001"/>
656
+ <geometry>
657
+
658
+ </geometry>
659
+ </collision>
660
+ <inertial>
661
+ <origin rpy="0 0 0" xyz="0.0064528 0.01702 0.0219685"/>
662
+ <mass value="0.03602545343277134"/>
663
+ <inertia ixx="2.3749999999999997e-06" ixy="0" ixz="0" iyy="2.3749999999999997e-06" iyz="0" izz="7.5e-07"/>
664
+ </inertial>
665
+ </link>
666
+ <link name="openarm_left_right_finger">
667
+ <visual name="openarm_left_right_finger_visual">
668
+ <origin rpy="0.0 0.0 0.0" xyz="0.0 0.05 -0.673001"/>
669
+ <geometry>
670
+ <mesh filename="./meshes/ee/openarm_hand/visual/finger.stl" scale="0.001 -0.001 0.001"/>
671
+ </geometry>
672
+ <material name="light_black"/>
673
+ </visual>
674
+ <collision name="openarm_left_right_finger_collision">
675
+ <origin rpy="0.0 0.0 0.0" xyz="0.0 0.05 -0.673001"/>
676
+ <geometry>
677
+
678
+ </geometry>
679
+ </collision>
680
+ <inertial>
681
+ <origin rpy="0 0 0" xyz="0.0064528 -0.01702 0.0219685"/>
682
+ <mass value="0.03602545343277134"/>
683
+ <inertia ixx="2.3749999999999997e-06" ixy="0" ixz="0" iyy="2.3749999999999997e-06" iyz="0" izz="7.5e-07"/>
684
+ </inertial>
685
+ </link>
686
+ <joint name="L_EE" type="prismatic">
687
+ <parent link="openarm_left_hand"/>
688
+ <child link="openarm_left_right_finger"/>
689
+ <origin rpy="0 0 0" xyz="0 0.00 0.015"/>
690
+ <axis xyz="0 -1 0"/>
691
+ <limit effort="333" lower="0.0" upper="0.044" velocity="10.0"/>
692
+ </joint>
693
+ <joint name="L_EE2" type="prismatic">
694
+ <parent link="openarm_left_hand"/>
695
+ <child link="openarm_left_left_finger"/>
696
+ <origin rpy="0 0 0" xyz="0 0.012 0.015"/>
697
+ <axis xyz="0 1 0"/>
698
+ <limit effort="333" lower="0.0" upper="0.044" velocity="10.0"/>
699
+ <mimic joint="L_EE"/>
700
+ </joint>
701
+ <link name="openarm_right_hand">
702
+ <visual name="openarm_right_hand_visual">
703
+ <origin rpy="0.0 0.0 0.0" xyz="0.0 0.005 -0.6585"/>
704
+ <geometry>
705
+ <mesh filename="./meshes/ee/openarm_hand/visual/hand.stl" scale="0.001 0.001 0.001"/>
706
+ </geometry>
707
+ <material name="light_gray"/>
708
+ </visual>
709
+ <collision name="openarm_right_hand_collision">
710
+ <origin rpy="0.0 0.0 0.0" xyz="0.0 0.005 -0.6585"/>
711
+ <geometry>
712
+
713
+ </geometry>
714
+ </collision>
715
+ <inertial>
716
+ <origin rpy="0 0 0" xyz="0.0 0.002 0.01"/>
717
+ <mass value="0.15"/>
718
+ <inertia ixx="0.0001" ixy="0" ixz="0" iyy="0.00025" iyz="0" izz="0.00017"/>
719
+ </inertial>
720
+ </link>
721
+ <!-- <link name="${ee_prefix}hand"/> -->
722
+ <!-- <joint name="${ee_prefix}hand_joint" type="fixed"> -->
723
+ <joint name="right_openarm_hand_joint" type="fixed">
724
+ <parent link="openarm_right_link8"/>
725
+ <child link="openarm_right_hand"/>
726
+ <origin rpy="0 0 0" xyz="0 -0.025 0.1001"/>
727
+ </joint>
728
+ <!-- Define the hand_tcp frame -->
729
+ <link name="openarm_right_hand_tcp"/>
730
+ <joint name="openarm_right_hand_tcp_joint" type="fixed">
731
+ <origin rpy="0 0 0" xyz="0 -0.0 0.08"/>
732
+ <parent link="openarm_right_hand"/>
733
+ <child link="openarm_right_hand_tcp"/>
734
+ </joint>
735
+ <link name="openarm_right_left_finger">
736
+ <visual name="openarm_right_left_finger_visual">
737
+ <origin rpy="0.0 0.0 0.0" xyz="0.0 -0.05 -0.673001"/>
738
+ <geometry>
739
+ <mesh filename="./meshes/ee/openarm_hand/visual/finger.stl" scale="0.001 0.001 0.001"/>
740
+ </geometry>
741
+ <material name="light_black"/>
742
+ </visual>
743
+ <collision name="openarm_right_left_finger_collision">
744
+ <origin rpy="0.0 0.0 0.0" xyz="0.0 -0.05 -0.673001"/>
745
+ <geometry>
746
+
747
+ </geometry>
748
+ </collision>
749
+ <inertial>
750
+ <origin rpy="0 0 0" xyz="0.0064528 0.01702 0.0219685"/>
751
+ <mass value="0.03602545343277134"/>
752
+ <inertia ixx="2.3749999999999997e-06" ixy="0" ixz="0" iyy="2.3749999999999997e-06" iyz="0" izz="7.5e-07"/>
753
+ </inertial>
754
+ </link>
755
+ <link name="openarm_right_right_finger">
756
+ <visual name="openarm_right_right_finger_visual">
757
+ <origin rpy="0.0 0.0 0.0" xyz="0.0 0.05 -0.673001"/>
758
+ <geometry>
759
+ <mesh filename="./meshes/ee/openarm_hand/visual/finger.stl" scale="0.001 -0.001 0.001"/>
760
+ </geometry>
761
+ <material name="light_black"/>
762
+ </visual>
763
+ <collision name="openarm_right_right_finger_collision">
764
+ <origin rpy="0.0 0.0 0.0" xyz="0.0 0.05 -0.673001"/>
765
+ <geometry>
766
+
767
+ </geometry>
768
+ </collision>
769
+ <inertial>
770
+ <origin rpy="0 0 0" xyz="0.0064528 -0.01702 0.0219685"/>
771
+ <mass value="0.03602545343277134"/>
772
+ <inertia ixx="2.3749999999999997e-06" ixy="0" ixz="0" iyy="2.3749999999999997e-06" iyz="0" izz="7.5e-07"/>
773
+ </inertial>
774
+ </link>
775
+ <joint name="R_EE" type="prismatic">
776
+ <parent link="openarm_right_hand"/>
777
+ <child link="openarm_right_right_finger"/>
778
+ <origin rpy="0 0 0" xyz="0 0.00 0.015"/>
779
+ <axis xyz="0 -1 0"/>
780
+ <limit effort="333" lower="0.0" upper="0.044" velocity="10.0"/>
781
+ </joint>
782
+ <joint name="R_EE2" type="prismatic">
783
+ <parent link="openarm_right_hand"/>
784
+ <child link="openarm_right_left_finger"/>
785
+ <origin rpy="0 0 0" xyz="0 0.012 0.015"/>
786
+ <axis xyz="0 1 0"/>
787
+ <limit effort="333" lower="0.0" upper="0.044" velocity="10.0"/>
788
+ <mimic joint="R_EE"/>
789
+ </joint>
790
+ <!-- <xacro:if value="${gazebo}">
791
+ <xacro:if value="${parent != ''}">
792
+ <xacro:if value="${parent == 'world'}">
793
+ <link name="${parent}" />
794
+ </xacro:if>
795
+ <joint name="${parent}_joint" type="fixed">
796
+ <origin xyz="${xyz}" rpy="${rpy}" />
797
+ <parent link="${parent}" />
798
+ <child link="${arm_type}_link0" />
799
+ </joint>
800
+ </xacro:if> -->
801
+ <!-- <xacro:gazebo-joint joint="${arm_type}_joint1" transmission="hardware_interface/PositionJointInterface" />
802
+ <xacro:gazebo-joint joint="${arm_type}_joint2" transmission="hardware_interface/PositionJointInterface" />
803
+ <xacro:gazebo-joint joint="${arm_type}_joint3" transmission="hardware_interface/PositionJointInterface" />
804
+ <xacro:gazebo-joint joint="${arm_type}_joint4" transmission="hardware_interface/PositionJointInterface" />
805
+ <xacro:gazebo-joint joint="${arm_type}_joint5" transmission="hardware_interface/PositionJointInterface" />
806
+ <xacro:gazebo-joint joint="${arm_type}_joint6" transmission="hardware_interface/PositionJointInterface" />
807
+ <xacro:gazebo-joint joint="${arm_type}_joint7" transmission="hardware_interface/PositionJointInterface" />
808
+
809
+ <xacro:gazebo-joint joint="${arm_type}_joint1" transmission="hardware_interface/VelocityJointInterface" />
810
+ <xacro:gazebo-joint joint="${arm_type}_joint2" transmission="hardware_interface/VelocityJointInterface" />
811
+ <xacro:gazebo-joint joint="${arm_type}_joint3" transmission="hardware_interface/VelocityJointInterface" />
812
+ <xacro:gazebo-joint joint="${arm_type}_joint4" transmission="hardware_interface/VelocityJointInterface" />
813
+ <xacro:gazebo-joint joint="${arm_type}_joint5" transmission="hardware_interface/VelocityJointInterface" />
814
+ <xacro:gazebo-joint joint="${arm_type}_joint6" transmission="hardware_interface/VelocityJointInterface" />
815
+ <xacro:gazebo-joint joint="${arm_type}_joint7" transmission="hardware_interface/VelocityJointInterface" />
816
+
817
+ <xacro:gazebo-joint joint="${arm_type}_joint1" transmission="hardware_interface/EffortJointInterface" />
818
+ <xacro:gazebo-joint joint="${arm_type}_joint2" transmission="hardware_interface/EffortJointInterface" />
819
+ <xacro:gazebo-joint joint="${arm_type}_joint3" transmission="hardware_interface/EffortJointInterface" />
820
+ <xacro:gazebo-joint joint="${arm_type}_joint4" transmission="hardware_interface/EffortJointInterface" />
821
+ <xacro:gazebo-joint joint="${arm_type}_joint5" transmission="hardware_interface/EffortJointInterface" />
822
+ <xacro:gazebo-joint joint="${arm_type}_joint6" transmission="hardware_interface/EffortJointInterface" />
823
+ <xacro:gazebo-joint joint="${arm_type}_joint7" transmission="hardware_interface/EffortJointInterface" /> -->
824
+ <!-- <xacro:transmission-openarm-state arm_type="${arm_type}" />
825
+ <xacro:transmission-openarm-model arm_type="${arm_type}"
826
+ root="${arm_type}_joint1"
827
+ tip="${arm_type}_joint8"
828
+ /> -->
829
+ <!-- <xacro:if value="${ee_type == 'openarm_hand'}">
830
+ <xacro:gazebo-joint joint="${arm_type}_finger_joint1" transmission="hardware_interface/EffortJointInterface" />
831
+ <xacro:gazebo-joint joint="${arm_type}_finger_joint2" transmission="hardware_interface/EffortJointInterface" />
832
+ <xacro:gazebo-friction link="${arm_type}_leftfinger" mu="1.13" />
833
+ <xacro:gazebo-friction link="${arm_type}_rightfinger" mu="1.13" />
834
+ </xacro:if>
835
+ </xacro:if> -->
836
+ </robot>
assets/publish-IjwDLK4H.js ADDED
@@ -0,0 +1 @@
 
 
1
+ var y=Object.defineProperty;var k=(a,t,e)=>t in a?y(a,t,{enumerable:!0,configurable:!0,writable:!0,value:e}):a[t]=e;var r=(a,t,e)=>k(a,typeof t!="symbol"?t+"":t,e);import{c as E,B as v,f as T}from"./connect-DkGLCYAo.js";class B{constructor(t){r(this,"config");r(this,"connection",null);r(this,"broadcast",null);r(this,"abortController",null);r(this,"running",!1);r(this,"activeTrack",null);this.config={trackName:"serial",groupSize:1024,...t}}async start(){if(this.running)throw new Error("Publisher is already running");this.running=!0,this.abortController=new AbortController;const{serial:t,url:e,path:l,trackName:i,groupSize:n}=this.config;this.connection=await E(new URL(e)),this.broadcast=new v,this.connection.publish(T(l),this.broadcast),this.handleRequests(i),await this.readSerial(t,i,n)}async handleRequests(t){if(this.broadcast)try{for(;;){const e=await this.broadcast.requested();if(!e||!this.running)break;e.track.name===t?this.publishToTrack(e.track):e.track.close(new Error("track not found"))}}catch{}}publishToTrack(t){this.activeTrack=t}async readSerial(t,e,l){var f,m,p;const i=(f=t.readable)==null?void 0:f.getReader();if(!i)throw new Error("Serial port is not readable");let n=null,h=0;try{for(;this.running;){const{value:b,done:w}=await i.read();if(w||(m=this.abortController)!=null&&m.signal.aborted)break;b&&this.activeTrack&&((!n||h>=l)&&(n==null||n.close(),n=this.activeTrack.appendGroup(),h=0),n.writeFrame(b),h+=b.byteLength)}n==null||n.close(),(p=this.activeTrack)==null||p.close()}finally{i.releaseLock()}}async stop(){var t,e,l;this.running=!1,(t=this.abortController)==null||t.abort(),this.abortController=null,(e=this.broadcast)==null||e.close(),this.broadcast=null,await((l=this.connection)==null?void 0:l.close()),this.connection=null}}const g=document.getElementById("log"),d=document.getElementById("start"),u=document.getElementById("stop");let c=null,s=null;function o(a,t=!1){const e=document.createElement("div");e.textContent=`[${new Date().toLocaleTimeString()}] ${a}`,t&&(e.className="error"),g.appendChild(e),g.scrollTop=g.scrollHeight}d.addEventListener("click",async()=>{try{const a=document.getElementById("url").value,t=document.getElementById("path").value,e=parseInt(document.getElementById("baudRate").value);o("Requesting serial port..."),s=await navigator.serial.requestPort(),await s.open({baudRate:e}),o(`Opened serial port at ${e} baud`),c=new B({url:a,path:t,serial:s}),d.disabled=!0,u.disabled=!1,o(`Connecting to ${a}/${t}...`),await c.start(),o("Publisher stopped")}catch(a){o(`Error: ${a.message}`,!0)}finally{d.disabled=!1,u.disabled=!0}});u.addEventListener("click",async()=>{o("Stopping..."),await(c==null?void 0:c.stop()),await(s==null?void 0:s.close()),c=null,s=null,d.disabled=!1,u.disabled=!0});
assets/subscribe-Cz9tf8k2.js ADDED
@@ -0,0 +1 @@
 
 
1
+ import{c as g,f as m}from"./connect-DkGLCYAo.js";const d=document.getElementById("log"),r=document.getElementById("start"),c=document.getElementById("stop");let o=null,s=!1;const b=new TextDecoder;function e(t,n=""){const a=document.createElement("div");a.textContent=`[${new Date().toLocaleTimeString()}] ${t}`,n&&(a.className=n),d.appendChild(a),d.scrollTop=d.scrollHeight}r.addEventListener("click",async()=>{try{const t=document.getElementById("url").value,n=document.getElementById("path").value;r.disabled=!0,c.disabled=!1,s=!0,e(`Connecting to ${t}...`),o=await g(new URL(t)),e("Connected!"),e(`Subscribing to broadcast: ${n}`);const a=o.consume(m(n));e("Got broadcast handle"),e("Subscribing to track: serial");const u=a.subscribe("serial",0);for(e("Subscribed to track, waiting for data...");s;){e("Waiting for next group...");const l=await u.nextGroup();if(!l){e("No more groups");break}for(e(`Got group ${l.sequence}`);s;){const i=await l.readFrame();if(!i){e("End of group");break}e(`Data: ${b.decode(i)}`,"data")}}e("Loop ended")}catch(t){e(`Error: ${t.message}`,"error"),console.error(t)}finally{r.disabled=!1,c.disabled=!0}});c.addEventListener("click",async()=>{e("Stopping..."),s=!1,await(o==null?void 0:o.close()),o=null,r.disabled=!1,c.disabled=!0});
assets/urdf_viewer-trQNEAhR.js ADDED
@@ -0,0 +1,5 @@
 
 
 
 
 
 
1
+ import{c as V,B as he,f as K}from"./connect-DkGLCYAo.js";import{W as ye,S as ve,A as we,D as te,P as xe,O as be,G as Ee,a as Ie,l as Ce,U as Be,m as Se,V as Y}from"./URDFLoader-CL7UVBjw.js";const $=new URLSearchParams(location.search),Le="https://cdn.1ms.ai",je="anon/xoq-serial",$e="urdf/so101/so101.urdf",z=document.getElementById("urdfUrl"),ne=document.getElementById("relayUrl"),oe=document.getElementById("path"),R=document.getElementById("certHash");z.value=$.get("urdf")||$e;ne.value=$.get("relay")||Le;oe.value=$.get("path")||je;R.value=$.get("certHash")||localStorage.getItem("moq-cert-hash")||"";R.addEventListener("input",()=>localStorage.setItem("moq-cert-hash",R.value));const S=document.getElementById("log"),M=document.getElementById("startBtn"),G=document.getElementById("stopBtn"),g=document.getElementById("queryBtn"),Fe=document.getElementById("loadUrdfBtn"),Te=document.getElementById("statusText");let m=null,h=[];const D={};let F=null,T=null,j=null,v=null,P=!1,_=0,Q=0,H=0,X=performance.now(),x=null,k=!1;function r(e,n="info"){const t=document.createElement("div");t.className=`log-entry log-${n}`,t.textContent=`[${new Date().toLocaleTimeString()}] ${e}`,S.appendChild(t),S.children.length>200&&S.removeChild(S.firstChild),S.scrollTop=S.scrollHeight}function ke(e){return e<1024?`${e} B`:e<1024*1024?`${(e/1024).toFixed(1)} K`:`${(e/(1024*1024)).toFixed(1)} M`}function L(e){Te.textContent=e}const Re=2,se=56;function Ue(e){let n=0;for(let t=0;t<e.length;t++)n+=e[t];return~n&255}function ae(e,n,t){const o=new Uint8Array([e,4,Re,n,t]),s=Ue(o),a=new Uint8Array(2+o.length+1);return a[0]=255,a[1]=255,a.set(o,2),a[a.length-1]=s,a}function re(e){return(e-2048)*(Math.PI/2048)}const ce="urdf-viewer-joint-mapping";function Ne(){try{const e=localStorage.getItem(ce);if(e)return JSON.parse(e)}catch{}return ie()}function ie(){return{1:"1",2:"2",3:"3",4:"4",5:"5",6:"6"}}function O(e){localStorage.setItem(ce,JSON.stringify(e))}let d=Ne();const Z=document.getElementById("mappingRows"),Pe=document.getElementById("addMappingBtn"),Ae=document.getElementById("resetMappingBtn");function U(){Z.innerHTML="";for(const[e,n]of Object.entries(d)){const t=document.createElement("div");t.className="mapping-row";const o=document.createElement("input");o.type="text",o.value=e,o.title="Servo ID";const s=document.createElement("span");s.textContent="→",s.style.color="#666";const a=document.createElement("select"),c=document.createElement("option");c.value="",c.textContent="(none)",a.appendChild(c);for(const l of h){const y=document.createElement("option");y.value=l,y.textContent=l,l===n&&(y.selected=!0),a.appendChild(y)}if(h.length===0){const l=document.createElement("option");l.value=n,l.textContent=n,l.selected=!0,a.appendChild(l)}const f=document.createElement("button");f.className="remove-btn",f.textContent="×",f.addEventListener("click",()=>{delete d[e],O(d),U()});const w=()=>{const l=e,y=o.value.trim(),q=a.value;l!==y&&delete d[l],y&&(d[y]=q),O(d)};o.addEventListener("change",w),a.addEventListener("change",w),t.appendChild(o),t.appendChild(s),t.appendChild(a),t.appendChild(f),Z.appendChild(t)}}Pe.addEventListener("click",()=>{let e=1;for(;d[String(e)];)e++;d[String(e)]=h[0]||"",O(d),U()});Ae.addEventListener("click",()=>{d=ie(),O(d),U()});U();function Me(){const e=R.value.trim(),n={};if(e){const t=e.replace(/[^0-9a-fA-F]/g,""),o=new Uint8Array(t.length/2);for(let s=0;s<o.length;s++)o[s]=parseInt(t.substr(s*2,2),16);n.webtransport={serverCertificateHashes:[{algorithm:"sha-256",value:o.buffer}]},r(`Using cert hash: ${t.slice(0,16)}...`,"data")}return n}const J=document.getElementById("threeCanvas");let b;try{b=new ye({canvas:J,antialias:!0,preserveDrawingBuffer:!0}),b.setPixelRatio(window.devicePixelRatio),b.setClearColor(1710638)}catch(e){r(`WebGL not available: ${e.message}`,"error"),b=null}const E=new ve,De=new we(16777215,.6);E.add(De);const le=new te(16777215,.8);le.position.set(5,10,7);E.add(le);const de=new te(4491519,.3);de.position.set(-5,3,-5);E.add(de);const I=new xe(50,1,.01,100);I.position.set(.3,.3,.4);I.lookAt(0,.1,0);const C=new be(I,J);C.target.set(0,.1,0);C.enableDamping=!0;C.dampingFactor=.1;C.update();const ue=new Ee(1,20,3355477,2236996);E.add(ue);const He=new Ie(.1);E.add(He);const ee=document.getElementById("jointRows"),A={};function Oe(){ee.innerHTML="";const e=[16739125,16747586,16755021,16765286,448160,1149618,473932,8599788];h.forEach((n,t)=>{const o=e[t%e.length],s=document.createElement("div");s.className="joint-row",s.innerHTML=`
2
+ <span class="joint-label" style="color:#${o.toString(16).padStart(6,"0")}">${n}</span>
3
+ <span class="joint-angle" id="jangle-${t}">0.0&deg;</span>
4
+ <span class="joint-raw" id="jraw-${t}">-</span>
5
+ `,ee.appendChild(s),A[n]={angleEl:s.querySelector(`#jangle-${t}`),rawEl:s.querySelector(`#jraw-${t}`)}})}function qe(){if(!m)return;const e=new Se().setFromObject(m),n=e.getCenter(new Y),t=e.getSize(new Y),s=Math.max(t.x,t.y,t.z)*1.8;I.position.set(n.x+s*.7,n.y+s*.5,n.z+s*.7),I.lookAt(n),C.target.copy(n),C.update();const a=e.min.y;ue.position.y=a,r(`Loaded: bbox size=(${t.x.toFixed(3)}, ${t.y.toFixed(3)}, ${t.z.toFixed(3)})`,"data")}async function me(e){m&&(E.remove(m),m=null,h=[]),r(`Loading URDF: ${e}...`);const n=new Ce,t=new Be(n);return new Promise((o,s)=>{n.onLoad=()=>{r("All meshes loaded","success"),qe()},t.load(e,a=>{m=a,m.rotation.x=-Math.PI/2,E.add(m),h=[];for(const[c,f]of Object.entries(m.joints))(f.jointType==="revolute"||f.jointType==="continuous")&&h.push(c);h.sort((c,f)=>{const w=parseInt(c),l=parseInt(f);return!isNaN(w)&&!isNaN(l)?w-l:c.localeCompare(f)}),r(`Loaded ${m.robotName}: ${h.length} joints [${h.join(", ")}]`,"success"),Oe(),U(),o(m)},void 0,a=>{r(`URDF load error: ${a}`,"error"),s(a)})})}Fe.addEventListener("click",()=>{const e=z.value.trim();e&&me(e)});me(z.value.trim()).catch(()=>{});function ze(){if(m)for(const[e,n]of Object.entries(d)){if(!n||!D[e]||!m.joints[n])continue;const o=re(D[e].position);m.setJointValue(n,o)}}function Ge(){for(const[n,t]of Object.entries(d)){if(!t||!A[t])continue;const o=D[n];if(!o)continue;const s=(re(o.position)*180/Math.PI).toFixed(1);A[t].angleEl.innerHTML=`${s}&deg;`,A[t].rawEl.textContent=o.position}document.getElementById("frameCount").textContent=_,document.getElementById("bytesReceived").textContent=ke(Q);const e=performance.now();e-X>=1e3&&(document.getElementById("canFps").textContent=H,H=0,X=e),document.getElementById("lastUpdate").textContent=new Date().toLocaleTimeString().split(" ")[0]}function pe(){if(!b)return;const e=J.parentElement,n=e.clientWidth,t=e.clientHeight;b.setSize(n,t),I.aspect=n/t,I.updateProjectionMatrix()}window.addEventListener("resize",pe);requestAnimationFrame(pe);function fe(){requestAnimationFrame(fe),b&&(C.update(),ze(),b.render(E,I))}fe();let i=new Uint8Array(0);function _e(e){const n=new Uint8Array(i.length+e.length);n.set(i),n.set(e,i.length),i=n}function Qe(){for(;i.length>=6;){let e=-1;for(let c=0;c<i.length-1;c++)if(i[c]===255&&i[c+1]===255){e=c;break}if(e<0){i=new Uint8Array(0);return}if(e>0&&(i=i.slice(e)),i.length<4)return;const n=i[3],t=4+n;if(i.length<t)return;const o=i[2],s=i[4],a=i.slice(5,3+n);if(s===0&&a.length>=2){const c=a[0]|a[1]<<8;c>=0&&c<=4095&&(D[String(o)]={position:c,updated:!0},_++,H++)}Q+=t,i=i.slice(t)}}M.addEventListener("click",async()=>{try{const e=ne.value,n=oe.value,t=`${e}/${n}/s2c`,o=`${e}/${n}/c2s`;M.disabled=!0,G.disabled=!1,P=!0,_=0,Q=0,H=0,i=new Uint8Array(0),L("Connecting...");const s=Me();if(!R.value.trim())try{const u=`${e}/certificate.sha256`,p=await fetch(u);if(p.ok){const B=await p.text();r(`Relay cert hash: ${B.trim().slice(0,32)}...`,"data")}}catch(u){r(`Cert hash fetch failed: ${u.message}`,"error")}r(`Publishing commands to ${o}...`);const c=new Promise((u,p)=>setTimeout(()=>p(new Error("c2s connection timeout after 8s")),8e3));T=await Promise.race([V(new URL(o),s),c]),j=new he,T.publish(K(""),j),r("c2s broadcast published, waiting for serial server...","data");const f=new Promise((u,p)=>setTimeout(()=>p(new Error("No subscriber after 15s — is moq-serial-server running on this path?")),15e3)),w=await Promise.race([j.requested(),f]);if(!w)throw new Error("Command broadcast closed");v=w.track,r(`Command track "${v.name}" active`,"success"),r(`Subscribing to ${t}...`);const l=new Promise((u,p)=>setTimeout(()=>p(new Error("s2c connection timeout after 8s")),8e3));F=await Promise.race([V(new URL(t),s),l]);const q=F.consume(K("")).subscribe("data",0);r("Subscribed to s2c 'data' track","success");const N=Object.keys(d).map(Number).filter(u=>!isNaN(u)&&u>0);let W=0;for(x=setInterval(()=>{if(!v||N.length===0)return;const u=N[W%N.length],p=ae(u,se,2),B=v.appendGroup();B.writeFrame(p),B.close(),W++},15),k=!0,g.classList.add("active"),g.textContent="Stop Query",g.disabled=!1,r(`Querying servos [${N.join(",")}] at ~${Math.round(1e3/15)}Hz`,"success"),L("Streaming");P;){const u=await q.nextGroup();if(!u){r("Track ended");break}for(;P;){const p=await u.readFrame();if(!p)break;const B=new Uint8Array(p);_e(B),Qe()}}L("Ended")}catch(e){r(`Error: ${e.message}`,"error"),console.error(e),L("Error")}finally{ge()}});function ge(){if(x&&(clearInterval(x),x=null),k=!1,g.classList.remove("active"),g.textContent="Query Servos",g.disabled=!0,M.disabled=!1,G.disabled=!0,v){try{v.close()}catch{}v=null}if(j){try{j.close()}catch{}j=null}if(T){try{T.close()}catch{}T=null}}G.addEventListener("click",async()=>{if(P=!1,ge(),L("Stopping..."),F){try{F.close()}catch{}F=null}L("Disconnected"),r("Disconnected","success")});g.addEventListener("click",()=>{if(k)x&&(clearInterval(x),x=null),k=!1,g.classList.remove("active"),g.textContent="Query Servos",r("Query paused");else{const e=Object.keys(d).map(Number).filter(t=>!isNaN(t)&&t>0);let n=0;x=setInterval(()=>{if(!v||e.length===0)return;const t=e[n%e.length],o=ae(t,se,2),s=v.appendGroup();s.writeFrame(o),s.close(),n++},15),k=!0,g.classList.add("active"),g.textContent="Stop Query",r("Query resumed","success")}});setInterval(Ge,100);r("Ready. Load a URDF and connect to start.","info");($.has("relay")||$.has("path"))&&(r("Auto-connecting from query params...","info"),M.click());
assets/video_player-BJSMA0Bo.js ADDED
@@ -0,0 +1 @@
 
 
1
+ import{c as x,f as w}from"./connect-DkGLCYAo.js";const o=document.getElementById("video"),b=document.getElementById("log"),p=document.getElementById("startBtn"),y=document.getElementById("stopBtn"),C=document.getElementById("status"),I=document.getElementById("groupCount"),k=document.getElementById("bytesReceived"),R=document.getElementById("bufferLength");let l=null,m=!1,d=null,r=null,g=0,B=0,h=!1,v=[];function t(e,n="info"){const s=document.createElement("div");s.className=`log-entry log-${n}`,s.textContent=`[${new Date().toLocaleTimeString()}] ${e}`,b.appendChild(s),b.scrollTop=b.scrollHeight}function U(e){return e<1024?`${e} B`:e<1024*1024?`${(e/1024).toFixed(1)} KB`:`${(e/(1024*1024)).toFixed(2)} MB`}function $(){if(I.textContent=g,k.textContent=U(B),o.buffered.length>0){const e=o.buffered.end(0)-o.currentTime;R.textContent=`${Math.max(0,e).toFixed(1)}s`}}function i(e){C.textContent=e}function M(){if(v.length>0&&r&&!r.updating){const e=v.shift();try{r.appendBuffer(e)}catch(n){t(`Append error: ${n.message}`,"error")}}}async function T(e){if(!r||r.updating){v.push(e);return}try{r.appendBuffer(e)}catch(n){t(`Append error: ${n.message}`,"error")}}async function A(){return new Promise((e,n)=>{d=new MediaSource,o.src=URL.createObjectURL(d),d.addEventListener("sourceopen",()=>{t("MediaSource opened","success");const s=['video/mp4; codecs="avc1.640028"','video/mp4; codecs="avc1.64001f"','video/mp4; codecs="avc1.4d4028"','video/mp4; codecs="avc1.4d401f"','video/mp4; codecs="avc1.42e01f"','video/mp4; codecs="avc1.640029"'];let f=null;for(const a of s)if(MediaSource.isTypeSupported(a)){f=a;break}if(!f){t("No supported H.264 codec found","error"),n(new Error("No codec supported"));return}t(`Using codec: ${f}`,"success"),r=d.addSourceBuffer(f),r.mode="segments",r.addEventListener("updateend",()=>{M(),$(),o.paused&&o.buffered.length>0&&o.play().catch(()=>{})}),r.addEventListener("error",a=>{t(`SourceBuffer error: ${a.type}`,"error"),console.error("SourceBuffer error:",a)}),e()}),d.addEventListener("error",n)})}p.addEventListener("click",async()=>{try{const e=document.getElementById("relayUrl").value,n=document.getElementById("path").value,s=`${e}/${n}`;p.disabled=!0,y.disabled=!1,m=!0,g=0,B=0,h=!1,v=[],i("Connecting..."),t(`Connecting to ${s}...`),await A(),l=await x(new URL(e)),t("Connected!","success"),i("Subscribing...");const a=l.consume(w(n)).subscribe("video",0);for(t("Subscribed to video track","success"),i("Streaming");m;){const S=await a.nextGroup();if(!S){t("Track ended");break}for(;m;){const u=await S.readFrame();if(!u)break;g++,B+=u.byteLength;const c=new Uint8Array(u),L=Array.from(c.slice(0,8)).map(E=>E.toString(16).padStart(2,"0")).join(" ");if(!h)t(`Init segment: ${u.byteLength} bytes [${L}...]`,"data"),c[4]===102&&c[5]===116&&c[6]===121&&c[7]===112?t("Valid ftyp box detected","success"):t("WARNING: Init segment doesn't start with ftyp!","error"),h=!0;else{t(`Segment ${g-1}: ${u.byteLength} bytes [${L}...]`,"data");const E=String.fromCharCode(c[4],c[5],c[6],c[7]);t(`Box type: ${E}`,"info")}await T(u),$()}}i("Ended")}catch(e){t(`Error: ${e.message}`,"error"),i("Error")}finally{p.disabled=!1,y.disabled=!0}});y.addEventListener("click",async()=>{m=!1,i("Stopping...");try{await(l==null?void 0:l.close())}catch{}if(l=null,(d==null?void 0:d.readyState)==="open")try{d.endOfStream()}catch{}p.disabled=!1,y.disabled=!0,i("Disconnected"),t("Disconnected","success")});o.addEventListener("error",e=>{const n=o.error;t(`Video error: ${(n==null?void 0:n.message)||"unknown"} (code: ${n==null?void 0:n.code})`,"error")});o.addEventListener("loadedmetadata",()=>{t(`Video metadata loaded: ${o.videoWidth}x${o.videoHeight}`,"success")});o.addEventListener("canplay",()=>{t("Video can play!","success")});setInterval($,1e3);t("Ready. Enter relay URL and path, then click Connect.","info");
camera.html ADDED
@@ -0,0 +1,143 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>Camera CMAF Player - xoq</title>
7
+ <style>
8
+ * { box-sizing: border-box; }
9
+ body {
10
+ font-family: system-ui, -apple-system, sans-serif;
11
+ max-width: 900px;
12
+ margin: 0 auto;
13
+ padding: 1rem;
14
+ background: #1a1a2e;
15
+ color: #eee;
16
+ }
17
+ h1 { color: #00d4ff; margin-bottom: 0.5rem; }
18
+ .subtitle { color: #888; margin-bottom: 1.5rem; }
19
+
20
+ .controls {
21
+ display: flex;
22
+ gap: 0.5rem;
23
+ flex-wrap: wrap;
24
+ margin-bottom: 1rem;
25
+ align-items: center;
26
+ }
27
+ .controls label {
28
+ display: flex;
29
+ align-items: center;
30
+ gap: 0.5rem;
31
+ }
32
+ .controls input[type="text"] {
33
+ padding: 0.5rem;
34
+ border: 1px solid #444;
35
+ border-radius: 4px;
36
+ background: #2a2a4a;
37
+ color: #fff;
38
+ width: 300px;
39
+ }
40
+ button {
41
+ padding: 0.5rem 1rem;
42
+ border: none;
43
+ border-radius: 4px;
44
+ cursor: pointer;
45
+ font-size: 1rem;
46
+ transition: background 0.2s;
47
+ }
48
+ button:disabled { opacity: 0.5; cursor: not-allowed; }
49
+ #startBtn { background: #00d4ff; color: #000; }
50
+ #startBtn:hover:not(:disabled) { background: #00b8e6; }
51
+ #stopBtn { background: #ff4757; color: #fff; }
52
+ #stopBtn:hover:not(:disabled) { background: #ff3344; }
53
+
54
+ .video-container {
55
+ background: #000;
56
+ border-radius: 8px;
57
+ overflow: hidden;
58
+ margin-bottom: 1rem;
59
+ aspect-ratio: 16/9;
60
+ }
61
+ video { width: 100%; height: 100%; display: block; }
62
+
63
+ .stats {
64
+ display: grid;
65
+ grid-template-columns: repeat(auto-fit, minmax(120px, 1fr));
66
+ gap: 0.5rem;
67
+ margin-bottom: 1rem;
68
+ }
69
+ .stat {
70
+ background: #2a2a4a;
71
+ padding: 0.75rem;
72
+ border-radius: 8px;
73
+ text-align: center;
74
+ }
75
+ .stat-label { color: #888; font-size: 0.75rem; text-transform: uppercase; }
76
+ .stat-value { font-size: 1.2rem; font-weight: bold; color: #00d4ff; }
77
+
78
+ #log {
79
+ background: #0a0a1a;
80
+ border: 1px solid #333;
81
+ border-radius: 8px;
82
+ padding: 1rem;
83
+ height: 200px;
84
+ overflow-y: auto;
85
+ font-family: 'Monaco', 'Menlo', monospace;
86
+ font-size: 0.8rem;
87
+ }
88
+ .log-entry { margin: 0.2rem 0; }
89
+ .log-info { color: #888; }
90
+ .log-success { color: #2ed573; }
91
+ .log-error { color: #ff4757; }
92
+ .log-data { color: #00d4ff; }
93
+ </style>
94
+ <script type="module" crossorigin src="/assets/camera-M5W9d3UM.js"></script>
95
+ <link rel="modulepreload" crossorigin href="/assets/connect-DkGLCYAo.js">
96
+ </head>
97
+ <body>
98
+ <h1>Camera CMAF Player</h1>
99
+ <p class="subtitle">xoq MoQ Video Stream Client</p>
100
+
101
+ <div class="controls">
102
+ <label>
103
+ Relay:
104
+ <input type="text" id="relayUrl" />
105
+ </label>
106
+ <label>
107
+ Path:
108
+ <input type="text" id="path" />
109
+ </label>
110
+ </div>
111
+ <div class="controls">
112
+ <button id="startBtn">Connect</button>
113
+ <button id="stopBtn" disabled>Disconnect</button>
114
+ </div>
115
+
116
+ <div class="video-container">
117
+ <video id="video" autoplay muted playsinline></video>
118
+ </div>
119
+
120
+ <div class="stats">
121
+ <div class="stat">
122
+ <div class="stat-label">Status</div>
123
+ <div class="stat-value" id="status">Idle</div>
124
+ </div>
125
+ <div class="stat">
126
+ <div class="stat-label">Groups</div>
127
+ <div class="stat-value" id="groupCount">0</div>
128
+ </div>
129
+ <div class="stat">
130
+ <div class="stat-label">Received</div>
131
+ <div class="stat-value" id="bytesReceived">0 B</div>
132
+ </div>
133
+ <div class="stat">
134
+ <div class="stat-label">Buffer</div>
135
+ <div class="stat-value" id="bufferLength">0s</div>
136
+ </div>
137
+ </div>
138
+
139
+ <h3>Log</h3>
140
+ <div id="log"></div>
141
+
142
+ </body>
143
+ </html>
index.html CHANGED
@@ -1,19 +1,22 @@
1
- <!doctype html>
2
- <html>
3
- <head>
4
- <meta charset="utf-8" />
5
- <meta name="viewport" content="width=device-width" />
6
- <title>My static Space</title>
7
- <link rel="stylesheet" href="style.css" />
8
- </head>
9
- <body>
10
- <div class="card">
11
- <h1>Welcome to your static Space!</h1>
12
- <p>You can modify this app directly by editing <i>index.html</i> in the Files and versions tab.</p>
13
- <p>
14
- Also don't forget to check the
15
- <a href="https://huggingface.co/docs/hub/spaces" target="_blank">Spaces documentation</a>.
16
- </p>
17
- </div>
18
- </body>
 
 
 
19
  </html>
 
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>XoQ Examples</title>
7
+ <style>
8
+ body { font-family: system-ui, sans-serif; max-width: 600px; margin: 2rem auto; padding: 0 1rem; }
9
+ h1 { margin-bottom: 2rem; }
10
+ a { display: block; margin: 1rem 0; font-size: 1.2rem; }
11
+ </style>
12
+ </head>
13
+ <body>
14
+ <h1>XoQ Examples</h1>
15
+ <a href="openarm.html">OpenArm 3D Visualizer</a>
16
+ <a href="camera.html">Camera Viewer</a>
17
+ <a href="publish.html">Publisher (Serial &rarr; MoQ)</a>
18
+ <a href="subscribe.html">Subscriber (MoQ &rarr; Console)</a>
19
+ <a href="urdf_viewer.html">URDF Robot Viewer</a>
20
+ <a href="video_player.html">Video Player</a>
21
+ </body>
22
  </html>
openarm.html ADDED
@@ -0,0 +1,301 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>OpenArm 3D Visualizer - xoq</title>
7
+ <style>
8
+ * { box-sizing: border-box; margin: 0; padding: 0; }
9
+ body {
10
+ font-family: system-ui, -apple-system, sans-serif;
11
+ background: #1a1a2e;
12
+ color: #eee;
13
+ height: 100vh;
14
+ display: flex;
15
+ flex-direction: column;
16
+ overflow: hidden;
17
+ }
18
+
19
+ /* Top bar */
20
+ .top-bar {
21
+ padding: 0.5rem 1rem;
22
+ display: flex;
23
+ align-items: center;
24
+ gap: 0.75rem;
25
+ flex-wrap: wrap;
26
+ border-bottom: 1px solid #333;
27
+ background: #16162a;
28
+ }
29
+ .top-bar h1 { color: #00d4ff; font-size: 1.1rem; white-space: nowrap; }
30
+ .top-bar label {
31
+ display: flex;
32
+ align-items: center;
33
+ gap: 0.3rem;
34
+ font-size: 0.85rem;
35
+ color: #aaa;
36
+ }
37
+ .top-bar input[type="text"] {
38
+ padding: 0.35rem 0.5rem;
39
+ border: 1px solid #444;
40
+ border-radius: 4px;
41
+ background: #2a2a4a;
42
+ color: #fff;
43
+ font-size: 0.85rem;
44
+ width: 240px;
45
+ }
46
+ button {
47
+ padding: 0.35rem 0.75rem;
48
+ border: none;
49
+ border-radius: 4px;
50
+ cursor: pointer;
51
+ font-size: 0.85rem;
52
+ transition: background 0.2s;
53
+ }
54
+ button:disabled { opacity: 0.5; cursor: not-allowed; }
55
+ #startBtn { background: #00d4ff; color: #000; }
56
+ #startBtn:hover:not(:disabled) { background: #00b8e6; }
57
+ #stopBtn { background: #ff4757; color: #fff; }
58
+ #stopBtn:hover:not(:disabled) { background: #ff3344; }
59
+ #queryBtn { background: #2a2a4a; color: #888; border: 1px solid #444; }
60
+ #queryBtn.active { background: #2ed573; color: #000; border-color: #2ed573; }
61
+ #queryBtn:hover:not(:disabled) { background: #444; }
62
+ #queryBtn.active:hover:not(:disabled) { background: #26b860; }
63
+
64
+ /* Main layout */
65
+ .main {
66
+ flex: 1;
67
+ display: flex;
68
+ min-height: 0;
69
+ }
70
+
71
+ /* 3D canvas */
72
+ .canvas-container {
73
+ flex: 1;
74
+ position: relative;
75
+ min-width: 0;
76
+ }
77
+ #threeCanvas {
78
+ width: 100%;
79
+ height: 100%;
80
+ display: block;
81
+ }
82
+ .canvas-overlay {
83
+ position: absolute;
84
+ top: 0.5rem;
85
+ left: 0.5rem;
86
+ font-size: 0.7rem;
87
+ color: #888;
88
+ pointer-events: none;
89
+ }
90
+
91
+ /* Right panel */
92
+ .side-panel {
93
+ width: 280px;
94
+ background: #16162a;
95
+ border-left: 1px solid #333;
96
+ display: flex;
97
+ flex-direction: column;
98
+ overflow-y: auto;
99
+ }
100
+ .panel-section {
101
+ padding: 0.75rem;
102
+ border-bottom: 1px solid #2a2a4a;
103
+ }
104
+ .panel-section h3 {
105
+ font-size: 0.8rem;
106
+ color: #888;
107
+ text-transform: uppercase;
108
+ margin-bottom: 0.5rem;
109
+ }
110
+
111
+ /* Joint rows */
112
+ .joint-row {
113
+ display: grid;
114
+ grid-template-columns: 50px 1fr 50px 50px;
115
+ gap: 0.25rem;
116
+ align-items: center;
117
+ padding: 0.3rem 0;
118
+ font-size: 0.8rem;
119
+ border-bottom: 1px solid #1e1e3a;
120
+ }
121
+ .joint-row:last-child { border-bottom: none; }
122
+ .joint-label {
123
+ font-weight: bold;
124
+ white-space: nowrap;
125
+ }
126
+ .joint-angle {
127
+ font-family: 'Monaco', 'Menlo', monospace;
128
+ text-align: right;
129
+ font-size: 0.85rem;
130
+ }
131
+ .joint-vel, .joint-tau {
132
+ font-family: 'Monaco', 'Menlo', monospace;
133
+ text-align: right;
134
+ font-size: 0.7rem;
135
+ color: #888;
136
+ }
137
+
138
+ /* Stats */
139
+ .stats-grid {
140
+ display: grid;
141
+ grid-template-columns: 1fr 1fr;
142
+ gap: 0.4rem;
143
+ }
144
+ .stat {
145
+ background: #2a2a4a;
146
+ padding: 0.4rem;
147
+ border-radius: 4px;
148
+ text-align: center;
149
+ }
150
+ .stat-label { color: #888; font-size: 0.65rem; text-transform: uppercase; }
151
+ .stat-value { font-size: 0.9rem; font-weight: bold; color: #00d4ff; }
152
+
153
+ /* Log */
154
+ .log-panel {
155
+ height: 120px;
156
+ border-top: 1px solid #333;
157
+ background: #0a0a1a;
158
+ overflow-y: auto;
159
+ padding: 0.5rem;
160
+ font-family: 'Monaco', 'Menlo', monospace;
161
+ font-size: 0.7rem;
162
+ flex-shrink: 0;
163
+ }
164
+ .log-entry { margin: 0.15rem 0; }
165
+ .log-info { color: #888; }
166
+ .log-success { color: #2ed573; }
167
+ .log-error { color: #ff4757; }
168
+ .log-data { color: #00d4ff; }
169
+ </style>
170
+ <script type="module" crossorigin src="/assets/openarm-DqhZ0Caw.js"></script>
171
+ <link rel="modulepreload" crossorigin href="/assets/connect-DkGLCYAo.js">
172
+ <link rel="modulepreload" crossorigin href="/assets/URDFLoader-CL7UVBjw.js">
173
+ </head>
174
+ <body>
175
+ <div class="top-bar">
176
+ <h1>OpenArm 3D</h1>
177
+ <label>
178
+ Relay:
179
+ <input type="text" id="relayUrl" />
180
+ </label>
181
+ <label>
182
+ Left:
183
+ <input type="text" id="leftPath" style="width:200px;" />
184
+ </label>
185
+ <label>
186
+ Right:
187
+ <input type="text" id="rightPath" style="width:200px;" />
188
+ </label>
189
+ <label>
190
+ Depth:
191
+ <input type="text" id="depthPath" style="width:180px;" />
192
+ </label>
193
+ <label>
194
+ Cert hash:
195
+ <input type="text" id="certHash" placeholder="sha256 hex (optional)" style="width:140px;" />
196
+ </label>
197
+ <label>
198
+ Hz:
199
+ <input type="number" id="queryRate" value="100" min="10" max="1000" step="10" style="width:60px; padding:0.35rem 0.3rem; border:1px solid #444; border-radius:4px; background:#2a2a4a; color:#fff; font-size:0.85rem;" />
200
+ </label>
201
+ <button id="startBtn">Connect</button>
202
+ <button id="stopBtn" disabled>Disconnect</button>
203
+ <button id="queryBtn" disabled>Query Motors</button>
204
+ <span id="statusText" style="color:#888; font-size:0.8rem;">Idle</span>
205
+ <span style="border-left:1px solid #444; height:1.2rem;"></span>
206
+ <button id="viewToggle" style="background:#2a2a4a; color:#aaa; border:1px solid #444;">Camera</button>
207
+ <label style="font-size:0.75rem;">Pt size: <input type="range" id="ptSize" min="0.5" max="8" step="0.5" value="2" style="width:60px; vertical-align:middle;" /></label>
208
+ <span style="font-size:0.7rem; color:#666;">depth: 1mm</span>
209
+ <span style="border-left:1px solid #444; height:1.2rem;"></span>
210
+ <label style="font-size:0.75rem;">Cam X:<input type="number" id="camX" value="0" step="0.01" style="width:48px; padding:0.2rem; border:1px solid #444; border-radius:3px; background:#2a2a4a; color:#fff; font-size:0.75rem;" /></label>
211
+ <label style="font-size:0.75rem;">Y:<input type="number" id="camY" value="0" step="0.01" style="width:48px; padding:0.2rem; border:1px solid #444; border-radius:3px; background:#2a2a4a; color:#fff; font-size:0.75rem;" /></label>
212
+ <label style="font-size:0.75rem;">Z:<input type="number" id="camZ" value="0" step="0.01" style="width:48px; padding:0.2rem; border:1px solid #444; border-radius:3px; background:#2a2a4a; color:#fff; font-size:0.75rem;" /></label>
213
+ <label style="font-size:0.75rem;">R:<input type="number" id="camRoll" value="0" step="1" style="width:40px; padding:0.2rem; border:1px solid #444; border-radius:3px; background:#2a2a4a; color:#fff; font-size:0.75rem;" /></label>
214
+ <label style="font-size:0.75rem;">P:<input type="number" id="camPitch" value="0" step="1" style="width:40px; padding:0.2rem; border:1px solid #444; border-radius:3px; background:#2a2a4a; color:#fff; font-size:0.75rem;" /></label>
215
+ <label style="font-size:0.75rem;">Yw:<input type="number" id="camYaw" value="0" step="1" style="width:40px; padding:0.2rem; border:1px solid #444; border-radius:3px; background:#2a2a4a; color:#fff; font-size:0.75rem;" /></label>
216
+ </div>
217
+
218
+ <div class="main">
219
+ <div class="canvas-container" id="view3d">
220
+ <canvas id="threeCanvas"></canvas>
221
+ <div class="canvas-overlay">
222
+ <span>Drag to orbit / Scroll to zoom / Right-drag to pan</span>
223
+ </div>
224
+ </div>
225
+ <div id="viewCamera" style="display:none; flex:1; min-width:0; background:#000; position:relative;">
226
+ <div style="display:flex; height:100%; gap:2px; padding:2px;">
227
+ <div style="flex:1; display:flex; flex-direction:column; min-width:0;">
228
+ <div style="font-size:0.65rem; color:#666; padding:2px 4px;">Color</div>
229
+ <canvas id="colorFullCanvas" style="flex:1; width:100%; object-fit:contain; background:#111; border-radius:3px;"></canvas>
230
+ </div>
231
+ <div style="flex:1; display:flex; flex-direction:column; min-width:0;">
232
+ <div style="font-size:0.65rem; color:#666; padding:2px 4px;">Depth</div>
233
+ <canvas id="depthFullCanvas" style="flex:1; width:100%; object-fit:contain; background:#111; border-radius:3px;"></canvas>
234
+ </div>
235
+ </div>
236
+ </div>
237
+
238
+ <div class="side-panel">
239
+ <div class="panel-section">
240
+ <h3>Left Arm</h3>
241
+ <div class="joint-row" style="font-size:0.65rem; color:#666;">
242
+ <span>Joint</span><span style="text-align:right;">Angle</span><span style="text-align:right;">Vel</span><span style="text-align:right;">Tau</span>
243
+ </div>
244
+ <div id="leftJointRows"></div>
245
+ </div>
246
+
247
+ <div class="panel-section">
248
+ <h3>Right Arm</h3>
249
+ <div class="joint-row" style="font-size:0.65rem; color:#666;">
250
+ <span>Joint</span><span style="text-align:right;">Angle</span><span style="text-align:right;">Vel</span><span style="text-align:right;">Tau</span>
251
+ </div>
252
+ <div id="rightJointRows"></div>
253
+ </div>
254
+
255
+ <div class="panel-section">
256
+ <h3>Camera</h3>
257
+ <div style="display:flex; gap:4px;">
258
+ <div style="flex:1; text-align:center;">
259
+ <div style="font-size:0.65rem; color:#666; margin-bottom:2px;">Color</div>
260
+ <canvas id="colorPreview" width="128" height="96" style="width:100%; border-radius:3px; background:#000;"></canvas>
261
+ </div>
262
+ <div style="flex:1; text-align:center;">
263
+ <div style="font-size:0.65rem; color:#666; margin-bottom:2px;">Depth</div>
264
+ <canvas id="depthPreview" width="128" height="96" style="width:100%; border-radius:3px; background:#000;"></canvas>
265
+ </div>
266
+ </div>
267
+ <div style="font-size:0.7rem; color:#888; margin-top:4px;" id="pcStats">No depth stream</div>
268
+ </div>
269
+
270
+ <div class="panel-section">
271
+ <h3>Stats</h3>
272
+ <div class="stats-grid">
273
+ <div class="stat">
274
+ <div class="stat-label">Frames</div>
275
+ <div class="stat-value" id="frameCount">0</div>
276
+ </div>
277
+ <div class="stat">
278
+ <div class="stat-label">Bytes</div>
279
+ <div class="stat-value" id="bytesReceived">0 B</div>
280
+ </div>
281
+ <div class="stat">
282
+ <div class="stat-label">FPS</div>
283
+ <div class="stat-value" id="canFps">0</div>
284
+ </div>
285
+ <div class="stat">
286
+ <div class="stat-label">Last</div>
287
+ <div class="stat-value" id="lastUpdate">-</div>
288
+ </div>
289
+ </div>
290
+ </div>
291
+ </div>
292
+ </div>
293
+
294
+ <div class="log-panel" id="log"></div>
295
+
296
+ <div style="position:fixed; top:-9999px;">
297
+ <video id="colorVideo" autoplay muted playsinline></video>
298
+ </div>
299
+
300
+ </body>
301
+ </html>
publish.html ADDED
@@ -0,0 +1,33 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>xoq publisher</title>
7
+ <style>
8
+ body { font-family: system-ui, sans-serif; max-width: 600px; margin: 2rem auto; padding: 0 1rem; }
9
+ button { font-size: 1rem; padding: 0.5rem 1rem; margin: 0.5rem 0; cursor: pointer; }
10
+ #log { background: #1a1a1a; color: #0f0; padding: 1rem; height: 300px; overflow-y: auto; font-family: monospace; font-size: 0.9rem; }
11
+ .error { color: #f00; }
12
+ </style>
13
+ <script type="module" crossorigin src="/assets/publish-IjwDLK4H.js"></script>
14
+ <link rel="modulepreload" crossorigin href="/assets/connect-DkGLCYAo.js">
15
+ </head>
16
+ <body>
17
+ <h1>xoq publisher</h1>
18
+ <div>
19
+ <label>URL: <input type="text" id="url" value="https://cdn.moq.dev/anon" /></label>
20
+ </div>
21
+ <div>
22
+ <label>Path: <input type="text" id="path" value="xoq-duplex" /></label>
23
+ </div>
24
+ <div>
25
+ <label>Baud rate: <input type="number" id="baudRate" value="1000000" /></label>
26
+ </div>
27
+ <button id="start">Select Port & Start</button>
28
+ <button id="stop" disabled>Stop</button>
29
+ <h3>Log</h3>
30
+ <div id="log"></div>
31
+
32
+ </body>
33
+ </html>
style.css DELETED
@@ -1,28 +0,0 @@
1
- body {
2
- padding: 2rem;
3
- font-family: -apple-system, BlinkMacSystemFont, "Arial", sans-serif;
4
- }
5
-
6
- h1 {
7
- font-size: 16px;
8
- margin-top: 0;
9
- }
10
-
11
- p {
12
- color: rgb(107, 114, 128);
13
- font-size: 15px;
14
- margin-bottom: 10px;
15
- margin-top: 5px;
16
- }
17
-
18
- .card {
19
- max-width: 620px;
20
- margin: 0 auto;
21
- padding: 16px;
22
- border: 1px solid lightgray;
23
- border-radius: 16px;
24
- }
25
-
26
- .card p:last-child {
27
- margin-bottom: 0;
28
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
subscribe.html ADDED
@@ -0,0 +1,31 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>xoq subscriber</title>
7
+ <style>
8
+ body { font-family: system-ui, sans-serif; max-width: 600px; margin: 2rem auto; padding: 0 1rem; }
9
+ button { font-size: 1rem; padding: 0.5rem 1rem; margin: 0.5rem 0; cursor: pointer; }
10
+ #log { background: #1a1a1a; color: #0f0; padding: 1rem; height: 300px; overflow-y: auto; font-family: monospace; font-size: 0.9rem; }
11
+ .error { color: #f00; }
12
+ .data { color: #0ff; }
13
+ </style>
14
+ <script type="module" crossorigin src="/assets/subscribe-Cz9tf8k2.js"></script>
15
+ <link rel="modulepreload" crossorigin href="/assets/connect-DkGLCYAo.js">
16
+ </head>
17
+ <body>
18
+ <h1>xoq subscriber</h1>
19
+ <div>
20
+ <label>URL: <input type="text" id="url" value="https://cdn.moq.dev/anon" /></label>
21
+ </div>
22
+ <div>
23
+ <label>Path: <input type="text" id="path" value="xoq-duplex" /></label>
24
+ </div>
25
+ <button id="start">Start</button>
26
+ <button id="stop" disabled>Stop</button>
27
+ <h3>Log</h3>
28
+ <div id="log"></div>
29
+
30
+ </body>
31
+ </html>
urdf/so101/assets/base_motor_holder_so101_v1.stl ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:8cd2f241037ea377af1191fffe0dd9d9006beea6dcc48543660ed41647072424
3
+ size 1877084
urdf/so101/assets/base_so101_v2.stl ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:bb12b7026575e1f70ccc7240051f9d943553bf34e5128537de6cd86fae33924d
3
+ size 471584
urdf/so101/assets/motor_holder_so101_base_v1.stl ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:31242ae6fb59d8b15c66617b88ad8e9bded62d57c35d11c0c43a70d2f4caa95b
3
+ size 1129384
urdf/so101/assets/motor_holder_so101_wrist_v1.stl ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:887f92e6013cb64ea3a1ab8675e92da1e0beacfd5e001f972523540545e08011
3
+ size 1052184
urdf/so101/assets/moving_jaw_so101_v1.stl ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:785a9dded2f474bc1d869e0d3dae398a3dcd9c0c345640040472210d2861fa9d
3
+ size 1413584
urdf/so101/assets/rotation_pitch_so101_v1.stl ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:9be900cc2a2bf718102841ef82ef8d2873842427648092c8ed2ca1e2ef4ffa34
3
+ size 883684
urdf/so101/assets/sts3215_03a_no_horn_v1.stl ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:75ef3781b752e4065891aea855e34dc161a38a549549cd0970cedd07eae6f887
3
+ size 865884
urdf/so101/assets/sts3215_03a_v1.stl ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:a37c871fb502483ab96c256baf457d36f2e97afc9205313d9c5ab275ef941cd0
3
+ size 954084
urdf/so101/assets/under_arm_so101_v1.stl ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:d01d1f2de365651dcad9d6669e94ff87ff7652b5bb2d10752a66a456a86dbc71
3
+ size 1975884
urdf/so101/assets/upper_arm_so101_v1.stl ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:475056e03a17e71919b82fd88ab9a0b898ab50164f2a7943652a6b2941bb2d4f
3
+ size 1303484
urdf/so101/assets/waveshare_mounting_plate_so101_v2.stl ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:e197e24005a07d01bbc06a8c42311664eaeda415bf859f68fa247884d0f1a6e9
3
+ size 62784
urdf/so101/assets/wrist_roll_follower_so101_v1.stl ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:4b17b410a12d64ec39554abc3e8054d8a97384b2dc4a8d95a5ecb2a93670f5f4
3
+ size 1439884
urdf/so101/assets/wrist_roll_pitch_so101_v2.stl ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:6c7ec5525b4d8b9e397a30ab4bb0037156a5d5f38a4adf2c7d943d6c56eda5ae
3
+ size 2699784
urdf/so101/so101.urdf ADDED
@@ -0,0 +1,411 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?xml version="1.0" ?>
2
+ <!-- Generated using onshape-to-robot -->
3
+ <!-- Onshape https://cad.onshape.com/documents/7715cc284bb430fe6dab4ffd/w/4fd0791b683777b02f8d975a/e/826c553ede3b7592eb9ca800 -->
4
+ <robot name="so100">
5
+ <!-- Link base -->
6
+ <link name="base">
7
+ <inertial>
8
+ <origin xyz="-0.14932 -0.16812 0.065966" rpy="0 0 0"/>
9
+ <mass value="0.147"/>
10
+ <inertia ixx="0.000114686" ixy="-4.59787e-07" ixz="4.97151e-06" iyy="0.000136117" iyz="9.75275e-08" izz="0.000130364"/>
11
+ </inertial>
12
+ <!-- Part base_motor_holder_so101_v1 -->
13
+ <visual>
14
+ <origin xyz="-0.169402 -0.168167 0.0300817" rpy="1.5708 -1.67685e-15 1.5708"/>
15
+ <geometry>
16
+ <mesh filename="assets/base_motor_holder_so101_v1.stl"/>
17
+ </geometry>
18
+ <material name="base_motor_holder_so101_v1_material">
19
+ <color rgba="0.964706 0.964706 0.952941 1.0"/>
20
+ </material>
21
+ </visual>
22
+ <collision>
23
+ <origin xyz="-0.169402 -0.168167 0.0300817" rpy="1.5708 -1.67685e-15 1.5708"/>
24
+ <geometry>
25
+ <mesh filename="assets/base_motor_holder_so101_v1.stl"/>
26
+ </geometry>
27
+ </collision>
28
+ <!-- Part base_so101_v2 -->
29
+ <visual>
30
+ <origin xyz="-0.169402 -0.168068 0.0300817" rpy="1.5708 -1.6144e-15 1.5708"/>
31
+ <geometry>
32
+ <mesh filename="assets/base_so101_v2.stl"/>
33
+ </geometry>
34
+ <material name="base_so101_v2_material">
35
+ <color rgba="0.964706 0.964706 0.952941 1.0"/>
36
+ </material>
37
+ </visual>
38
+ <collision>
39
+ <origin xyz="-0.169402 -0.168068 0.0300817" rpy="1.5708 -1.6144e-15 1.5708"/>
40
+ <geometry>
41
+ <mesh filename="assets/base_so101_v2.stl"/>
42
+ </geometry>
43
+ </collision>
44
+ <!-- Part sts3215_03a_v1 -->
45
+ <visual>
46
+ <origin xyz="-0.136702 -0.168068 0.0761817" rpy="-8.21148e-16 7.84513e-18 1.249e-15"/>
47
+ <geometry>
48
+ <mesh filename="assets/sts3215_03a_v1.stl"/>
49
+ </geometry>
50
+ <material name="sts3215_03a_v1_material">
51
+ <color rgba="0.627451 0.627451 0.627451 1.0"/>
52
+ </material>
53
+ </visual>
54
+ <collision>
55
+ <origin xyz="-0.136702 -0.168068 0.0761817" rpy="-8.21148e-16 7.84513e-18 1.249e-15"/>
56
+ <geometry>
57
+ <mesh filename="assets/sts3215_03a_v1.stl"/>
58
+ </geometry>
59
+ </collision>
60
+ <!-- Part waveshare_mounting_plate_so101_v2 -->
61
+ <visual>
62
+ <origin xyz="-0.19402 -0.168267 0.0798817" rpy="1.5708 -1.35493e-14 1.5708"/>
63
+ <geometry>
64
+ <mesh filename="assets/waveshare_mounting_plate_so101_v2.stl"/>
65
+ </geometry>
66
+ <material name="waveshare_mounting_plate_so101_v2_material">
67
+ <color rgba="0.964706 0.964706 0.952941 1.0"/>
68
+ </material>
69
+ </visual>
70
+ <collision>
71
+ <origin xyz="-0.19402 -0.168267 0.0798817" rpy="1.5708 -1.35493e-14 1.5708"/>
72
+ <geometry>
73
+ <mesh filename="assets/waveshare_mounting_plate_so101_v2.stl"/>
74
+ </geometry>
75
+ </collision>
76
+ </link>
77
+ <!-- Frame baseframe (dummy link + fixed joint) -->
78
+ <link name="baseframe">
79
+ <origin xyz="0 0 0" rpy="0 -0 0"/>
80
+ <inertial>
81
+ <origin xyz="0 0 0" rpy="0 0 0"/>
82
+ <mass value="1e-9"/>
83
+ <inertia ixx="0" ixy="0" ixz="0" iyy="0" iyz="0" izz="0"/>
84
+ </inertial>
85
+ </link>
86
+ <joint name="baseframe_frame" type="fixed">
87
+ <origin xyz="-0.163038 -0.168068 0.0324817" rpy="1.6144e-15 7.84513e-18 1.33799e-15"/>
88
+ <parent link="base"/>
89
+ <child link="baseframe"/>
90
+ <axis xyz="0 0 0"/>
91
+ </joint>
92
+ <!-- Link shoulder -->
93
+ <link name="shoulder">
94
+ <inertial>
95
+ <origin xyz="-0.0307604 -1.66727e-05 -0.0252713" rpy="0 0 0"/>
96
+ <mass value="0.100006"/>
97
+ <inertia ixx="8.3759e-05" ixy="7.55525e-08" ixz="-1.16342e-06" iyy="8.10403e-05" iyz="1.54663e-07" izz="2.39783e-05"/>
98
+ </inertial>
99
+ <!-- Part sts3215_03a_v1_2 -->
100
+ <visual>
101
+ <origin xyz="-0.0303992 0.000422241 -0.0417" rpy="1.5708 1.5708 0"/>
102
+ <geometry>
103
+ <mesh filename="assets/sts3215_03a_v1.stl"/>
104
+ </geometry>
105
+ <material name="sts3215_03a_v1_2_material">
106
+ <color rgba="0.627451 0.627451 0.627451 1.0"/>
107
+ </material>
108
+ </visual>
109
+ <collision>
110
+ <origin xyz="-0.0303992 0.000422241 -0.0417" rpy="1.5708 1.5708 0"/>
111
+ <geometry>
112
+ <mesh filename="assets/sts3215_03a_v1.stl"/>
113
+ </geometry>
114
+ </collision>
115
+ <!-- Part motor_holder_so101_base_v1 -->
116
+ <visual>
117
+ <origin xyz="-0.0675992 -0.000177759 0.0158499" rpy="1.5708 -1.5708 0"/>
118
+ <geometry>
119
+ <mesh filename="assets/motor_holder_so101_base_v1.stl"/>
120
+ </geometry>
121
+ <material name="motor_holder_so101_base_v1_material">
122
+ <color rgba="0.964706 0.964706 0.952941 1.0"/>
123
+ </material>
124
+ </visual>
125
+ <collision>
126
+ <origin xyz="-0.0675992 -0.000177759 0.0158499" rpy="1.5708 -1.5708 0"/>
127
+ <geometry>
128
+ <mesh filename="assets/motor_holder_so101_base_v1.stl"/>
129
+ </geometry>
130
+ </collision>
131
+ <!-- Part rotation_pitch_so101_v1 -->
132
+ <visual>
133
+ <origin xyz="0.0122008 2.22413e-05 0.0464" rpy="-1.5708 2.35221e-33 0"/>
134
+ <geometry>
135
+ <mesh filename="assets/rotation_pitch_so101_v1.stl"/>
136
+ </geometry>
137
+ <material name="rotation_pitch_so101_v1_material">
138
+ <color rgba="0.964706 0.964706 0.952941 1.0"/>
139
+ </material>
140
+ </visual>
141
+ <collision>
142
+ <origin xyz="0.0122008 2.22413e-05 0.0464" rpy="-1.5708 2.35221e-33 0"/>
143
+ <geometry>
144
+ <mesh filename="assets/rotation_pitch_so101_v1.stl"/>
145
+ </geometry>
146
+ </collision>
147
+ </link>
148
+ <!-- Link upper_arm -->
149
+ <link name="upper_arm">
150
+ <inertial>
151
+ <origin xyz="-0.0898471 -0.00838224 0.0184089" rpy="0 0 0"/>
152
+ <mass value="0.103"/>
153
+ <inertia ixx="4.08002e-05" ixy="-1.97819e-05" ixz="-4.03016e-08" iyy="0.000147318" iyz="8.97326e-09" izz="0.000142487"/>
154
+ </inertial>
155
+ <!-- Part sts3215_03a_v1_3 -->
156
+ <visual>
157
+ <origin xyz="-0.11257 -0.0155 0.0187" rpy="-3.14159 -5.27356e-16 -1.5708"/>
158
+ <geometry>
159
+ <mesh filename="assets/sts3215_03a_v1.stl"/>
160
+ </geometry>
161
+ <material name="sts3215_03a_v1_3_material">
162
+ <color rgba="0.627451 0.627451 0.627451 1.0"/>
163
+ </material>
164
+ </visual>
165
+ <collision>
166
+ <origin xyz="-0.11257 -0.0155 0.0187" rpy="-3.14159 -5.27356e-16 -1.5708"/>
167
+ <geometry>
168
+ <mesh filename="assets/sts3215_03a_v1.stl"/>
169
+ </geometry>
170
+ </collision>
171
+ <!-- Part upper_arm_so101_v1 -->
172
+ <visual>
173
+ <origin xyz="-0.065085 0.012 0.0182" rpy="3.14159 -0 -1.30911e-30"/>
174
+ <geometry>
175
+ <mesh filename="assets/upper_arm_so101_v1.stl"/>
176
+ </geometry>
177
+ <material name="upper_arm_so101_v1_material">
178
+ <color rgba="0.964706 0.964706 0.952941 1.0"/>
179
+ </material>
180
+ </visual>
181
+ <collision>
182
+ <origin xyz="-0.065085 0.012 0.0182" rpy="3.14159 -0 -1.30911e-30"/>
183
+ <geometry>
184
+ <mesh filename="assets/upper_arm_so101_v1.stl"/>
185
+ </geometry>
186
+ </collision>
187
+ </link>
188
+ <!-- Link lower_arm -->
189
+ <link name="lower_arm">
190
+ <inertial>
191
+ <origin xyz="-0.0980701 0.00324376 0.0182831" rpy="0 0 0"/>
192
+ <mass value="0.104"/>
193
+ <inertia ixx="2.87438e-05" ixy="7.41152e-06" ixz="1.26409e-06" iyy="0.000159844" iyz="-4.90188e-08" izz="0.00014529"/>
194
+ </inertial>
195
+ <!-- Part under_arm_so101_v1 -->
196
+ <visual>
197
+ <origin xyz="-0.0648499 -0.032 0.0182" rpy="3.14159 -0 6.67202e-31"/>
198
+ <geometry>
199
+ <mesh filename="assets/under_arm_so101_v1.stl"/>
200
+ </geometry>
201
+ <material name="under_arm_so101_v1_material">
202
+ <color rgba="0.964706 0.964706 0.952941 1.0"/>
203
+ </material>
204
+ </visual>
205
+ <collision>
206
+ <origin xyz="-0.0648499 -0.032 0.0182" rpy="3.14159 -0 6.67202e-31"/>
207
+ <geometry>
208
+ <mesh filename="assets/under_arm_so101_v1.stl"/>
209
+ </geometry>
210
+ </collision>
211
+ <!-- Part motor_holder_so101_wrist_v1 -->
212
+ <visual>
213
+ <origin xyz="-0.0648499 -0.032 0.018" rpy="-3.14159 -2.55351e-15 -2.56146e-31"/>
214
+ <geometry>
215
+ <mesh filename="assets/motor_holder_so101_wrist_v1.stl"/>
216
+ </geometry>
217
+ <material name="motor_holder_so101_wrist_v1_material">
218
+ <color rgba="0.964706 0.964706 0.952941 1.0"/>
219
+ </material>
220
+ </visual>
221
+ <collision>
222
+ <origin xyz="-0.0648499 -0.032 0.018" rpy="-3.14159 -2.55351e-15 -2.56146e-31"/>
223
+ <geometry>
224
+ <mesh filename="assets/motor_holder_so101_wrist_v1.stl"/>
225
+ </geometry>
226
+ </collision>
227
+ <!-- Part sts3215_03a_v1_4 -->
228
+ <visual>
229
+ <origin xyz="-0.1224 0.0052 0.0187" rpy="-3.14159 -7.88861e-31 -3.14159"/>
230
+ <geometry>
231
+ <mesh filename="assets/sts3215_03a_v1.stl"/>
232
+ </geometry>
233
+ <material name="sts3215_03a_v1_4_material">
234
+ <color rgba="0.627451 0.627451 0.627451 1.0"/>
235
+ </material>
236
+ </visual>
237
+ <collision>
238
+ <origin xyz="-0.1224 0.0052 0.0187" rpy="-3.14159 -7.88861e-31 -3.14159"/>
239
+ <geometry>
240
+ <mesh filename="assets/sts3215_03a_v1.stl"/>
241
+ </geometry>
242
+ </collision>
243
+ </link>
244
+ <!-- Link wrist -->
245
+ <link name="wrist">
246
+ <inertial>
247
+ <origin xyz="-0.000103312 -0.0386143 0.0281156" rpy="0 0 0"/>
248
+ <mass value="0.079"/>
249
+ <inertia ixx="3.68263e-05" ixy="1.7893e-08" ixz="-5.28128e-08" iyy="2.5391e-05" iyz="3.6412e-06" izz="2.1e-05"/>
250
+ </inertial>
251
+ <!-- Part sts3215_03a_no_horn_v1 -->
252
+ <visual>
253
+ <origin xyz="5.55112e-17 -0.0424 0.0306" rpy="1.5708 1.5708 0"/>
254
+ <geometry>
255
+ <mesh filename="assets/sts3215_03a_no_horn_v1.stl"/>
256
+ </geometry>
257
+ <material name="sts3215_03a_no_horn_v1_material">
258
+ <color rgba="0.627451 0.627451 0.627451 1.0"/>
259
+ </material>
260
+ </visual>
261
+ <collision>
262
+ <origin xyz="5.55112e-17 -0.0424 0.0306" rpy="1.5708 1.5708 0"/>
263
+ <geometry>
264
+ <mesh filename="assets/sts3215_03a_no_horn_v1.stl"/>
265
+ </geometry>
266
+ </collision>
267
+ <!-- Part wrist_roll_pitch_so101_v2 -->
268
+ <visual>
269
+ <origin xyz="0 -0.028 0.0181" rpy="-1.5708 -1.5708 0"/>
270
+ <geometry>
271
+ <mesh filename="assets/wrist_roll_pitch_so101_v2.stl"/>
272
+ </geometry>
273
+ <material name="wrist_roll_pitch_so101_v2_material">
274
+ <color rgba="0.964706 0.964706 0.952941 1.0"/>
275
+ </material>
276
+ </visual>
277
+ <collision>
278
+ <origin xyz="0 -0.028 0.0181" rpy="-1.5708 -1.5708 0"/>
279
+ <geometry>
280
+ <mesh filename="assets/wrist_roll_pitch_so101_v2.stl"/>
281
+ </geometry>
282
+ </collision>
283
+ </link>
284
+ <!-- Link gripper -->
285
+ <link name="gripper">
286
+ <inertial>
287
+ <origin xyz="0.000213627 0.000245138 -0.025187" rpy="0 0 0"/>
288
+ <mass value="0.087"/>
289
+ <inertia ixx="2.75087e-05" ixy="-3.35241e-07" ixz="-5.7352e-06" iyy="4.33657e-05" iyz="-5.17847e-08" izz="3.45059e-05"/>
290
+ </inertial>
291
+ <!-- Part sts3215_03a_v1_5 -->
292
+ <visual>
293
+ <origin xyz="0.0077 0.0001 -0.0234" rpy="-1.5708 -5.19179e-17 -1.66533e-16"/>
294
+ <geometry>
295
+ <mesh filename="assets/sts3215_03a_v1.stl"/>
296
+ </geometry>
297
+ <material name="sts3215_03a_v1_5_material">
298
+ <color rgba="0.627451 0.627451 0.627451 1.0"/>
299
+ </material>
300
+ </visual>
301
+ <collision>
302
+ <origin xyz="0.0077 0.0001 -0.0234" rpy="-1.5708 -5.19179e-17 -1.66533e-16"/>
303
+ <geometry>
304
+ <mesh filename="assets/sts3215_03a_v1.stl"/>
305
+ </geometry>
306
+ </collision>
307
+ <!-- Part wrist_roll_follower_so101_v1 -->
308
+ <visual>
309
+ <origin xyz="0 -0.000218214 0.000949706" rpy="-3.14159 -5.55112e-17 0"/>
310
+ <geometry>
311
+ <mesh filename="assets/wrist_roll_follower_so101_v1.stl"/>
312
+ </geometry>
313
+ <material name="wrist_roll_follower_so101_v1_material">
314
+ <color rgba="0.964706 0.964706 0.952941 1.0"/>
315
+ </material>
316
+ </visual>
317
+ <collision>
318
+ <origin xyz="0 -0.000218214 0.000949706" rpy="-3.14159 -5.55112e-17 0"/>
319
+ <geometry>
320
+ <mesh filename="assets/wrist_roll_follower_so101_v1.stl"/>
321
+ </geometry>
322
+ </collision>
323
+ </link>
324
+ <!-- Frame gripperframe (dummy link + fixed joint) -->
325
+ <link name="gripperframe">
326
+ <origin xyz="0 0 0" rpy="0 -0 0"/>
327
+ <inertial>
328
+ <origin xyz="0 0 0" rpy="0 0 0"/>
329
+ <mass value="1e-9"/>
330
+ <inertia ixx="0" ixy="0" ixz="0" iyy="0" iyz="0" izz="0"/>
331
+ </inertial>
332
+ </link>
333
+ <joint name="gripperframe_frame" type="fixed">
334
+ <origin xyz="-0.0079 -0.000218121 -0.0981274" rpy="-0 1.5708 0"/>
335
+ <parent link="gripper"/>
336
+ <child link="gripperframe"/>
337
+ <axis xyz="0 0 0"/>
338
+ </joint>
339
+ <!-- Link moving_jaw_so101_v1 -->
340
+ <link name="moving_jaw_so101_v1">
341
+ <inertial>
342
+ <origin xyz="-0.00157495 -0.0300244 0.0192755" rpy="0 0 0"/>
343
+ <mass value="0.012"/>
344
+ <inertia ixx="6.61427e-06" ixy="-3.19807e-07" ixz="-5.90717e-09" iyy="1.89032e-06" iyz="-1.09945e-07" izz="5.28738e-06"/>
345
+ </inertial>
346
+ <!-- Part moving_jaw_so101_v1 -->
347
+ <visual>
348
+ <origin xyz="-5.55112e-17 0 0.0189" rpy="9.53145e-17 6.93889e-18 1.24077e-24"/>
349
+ <geometry>
350
+ <mesh filename="assets/moving_jaw_so101_v1.stl"/>
351
+ </geometry>
352
+ <material name="moving_jaw_so101_v1_material">
353
+ <color rgba="0.964706 0.964706 0.952941 1.0"/>
354
+ </material>
355
+ </visual>
356
+ <collision>
357
+ <origin xyz="-5.55112e-17 0 0.0189" rpy="9.53145e-17 6.93889e-18 1.24077e-24"/>
358
+ <geometry>
359
+ <mesh filename="assets/moving_jaw_so101_v1.stl"/>
360
+ </geometry>
361
+ </collision>
362
+ </link>
363
+ <!-- Joint from gripper to moving_jaw_so101_v1 -->
364
+ <joint name="6" type="revolute">
365
+ <origin xyz="0.0202 0.0188 -0.0234" rpy="1.5708 -5.24284e-08 -1.41553e-15"/>
366
+ <parent link="gripper"/>
367
+ <child link="moving_jaw_so101_v1"/>
368
+ <axis xyz="0 0 1"/>
369
+ <limit effort="10" velocity="10" lower="-0.174533" upper="1.74533"/>
370
+ </joint>
371
+ <!-- Joint from wrist to gripper -->
372
+ <joint name="5" type="revolute">
373
+ <origin xyz="2.77556e-16 -0.0611 0.0181" rpy="1.5708 0.0486795 3.14159"/>
374
+ <parent link="wrist"/>
375
+ <child link="gripper"/>
376
+ <axis xyz="0 0 1"/>
377
+ <limit effort="10" velocity="10" lower="-2.74385" upper="2.84121"/>
378
+ </joint>
379
+ <!-- Joint from lower_arm to wrist -->
380
+ <joint name="4" type="revolute">
381
+ <origin xyz="-0.1349 0.0052 8.44651e-17" rpy="4.02456e-15 8.67362e-16 -1.5708"/>
382
+ <parent link="lower_arm"/>
383
+ <child link="wrist"/>
384
+ <axis xyz="0 0 1"/>
385
+ <limit effort="10" velocity="10" lower="-1.65806" upper="1.65806"/>
386
+ </joint>
387
+ <!-- Joint from upper_arm to lower_arm -->
388
+ <joint name="3" type="revolute">
389
+ <origin xyz="-0.11257 -0.028 2.09886e-16" rpy="-3.63608e-16 8.74301e-16 1.5708"/>
390
+ <parent link="upper_arm"/>
391
+ <child link="lower_arm"/>
392
+ <axis xyz="0 0 1"/>
393
+ <limit effort="10" velocity="10" lower="-1.74533" upper="1.5708"/>
394
+ </joint>
395
+ <!-- Joint from shoulder to upper_arm -->
396
+ <joint name="2" type="revolute">
397
+ <origin xyz="-0.0303992 -0.0182778 -0.0542" rpy="-1.5708 -1.5708 0"/>
398
+ <parent link="shoulder"/>
399
+ <child link="upper_arm"/>
400
+ <axis xyz="0 0 1"/>
401
+ <limit effort="10" velocity="10" lower="-1.74533" upper="1.74533"/>
402
+ </joint>
403
+ <!-- Joint from base to shoulder -->
404
+ <joint name="1" type="revolute">
405
+ <origin xyz="-0.124202 -0.168068 0.0948817" rpy="3.14159 4.18253e-17 -3.14159"/>
406
+ <parent link="base"/>
407
+ <child link="shoulder"/>
408
+ <axis xyz="0 0 1"/>
409
+ <limit effort="10" velocity="10" lower="-1.91986" upper="1.91986"/>
410
+ </joint>
411
+ </robot>
urdf_viewer.html ADDED
@@ -0,0 +1,305 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>URDF Robot Viewer - xoq</title>
7
+ <style>
8
+ * { box-sizing: border-box; margin: 0; padding: 0; }
9
+ body {
10
+ font-family: system-ui, -apple-system, sans-serif;
11
+ background: #1a1a2e;
12
+ color: #eee;
13
+ height: 100vh;
14
+ display: flex;
15
+ flex-direction: column;
16
+ overflow: hidden;
17
+ }
18
+
19
+ /* Top bar */
20
+ .top-bar {
21
+ padding: 0.5rem 1rem;
22
+ display: flex;
23
+ align-items: center;
24
+ gap: 0.75rem;
25
+ flex-wrap: wrap;
26
+ border-bottom: 1px solid #333;
27
+ background: #16162a;
28
+ }
29
+ .top-bar h1 { color: #00d4ff; font-size: 1.1rem; white-space: nowrap; }
30
+ .top-bar label {
31
+ display: flex;
32
+ align-items: center;
33
+ gap: 0.3rem;
34
+ font-size: 0.85rem;
35
+ color: #aaa;
36
+ }
37
+ .top-bar input[type="text"] {
38
+ padding: 0.35rem 0.5rem;
39
+ border: 1px solid #444;
40
+ border-radius: 4px;
41
+ background: #2a2a4a;
42
+ color: #fff;
43
+ font-size: 0.85rem;
44
+ width: 240px;
45
+ }
46
+ button {
47
+ padding: 0.35rem 0.75rem;
48
+ border: none;
49
+ border-radius: 4px;
50
+ cursor: pointer;
51
+ font-size: 0.85rem;
52
+ transition: background 0.2s;
53
+ }
54
+ button:disabled { opacity: 0.5; cursor: not-allowed; }
55
+ #loadUrdfBtn { background: #a855f7; color: #fff; }
56
+ #loadUrdfBtn:hover:not(:disabled) { background: #9333ea; }
57
+ #startBtn { background: #00d4ff; color: #000; }
58
+ #startBtn:hover:not(:disabled) { background: #00b8e6; }
59
+ #stopBtn { background: #ff4757; color: #fff; }
60
+ #stopBtn:hover:not(:disabled) { background: #ff3344; }
61
+ #queryBtn { background: #2a2a4a; color: #888; border: 1px solid #444; }
62
+ #queryBtn.active { background: #2ed573; color: #000; border-color: #2ed573; }
63
+ #queryBtn:hover:not(:disabled) { background: #444; }
64
+ #queryBtn.active:hover:not(:disabled) { background: #26b860; }
65
+
66
+ /* Main layout */
67
+ .main {
68
+ flex: 1;
69
+ display: flex;
70
+ min-height: 0;
71
+ }
72
+
73
+ /* 3D canvas */
74
+ .canvas-container {
75
+ flex: 1;
76
+ position: relative;
77
+ min-width: 0;
78
+ }
79
+ #threeCanvas {
80
+ width: 100%;
81
+ height: 100%;
82
+ display: block;
83
+ }
84
+ .canvas-overlay {
85
+ position: absolute;
86
+ top: 0.5rem;
87
+ left: 0.5rem;
88
+ font-size: 0.7rem;
89
+ color: #888;
90
+ pointer-events: none;
91
+ }
92
+
93
+ /* Right panel */
94
+ .side-panel {
95
+ width: 300px;
96
+ background: #16162a;
97
+ border-left: 1px solid #333;
98
+ display: flex;
99
+ flex-direction: column;
100
+ overflow-y: auto;
101
+ }
102
+ .panel-section {
103
+ padding: 0.75rem;
104
+ border-bottom: 1px solid #2a2a4a;
105
+ }
106
+ .panel-section h3 {
107
+ font-size: 0.8rem;
108
+ color: #888;
109
+ text-transform: uppercase;
110
+ margin-bottom: 0.5rem;
111
+ }
112
+
113
+ /* Joint rows */
114
+ .joint-row {
115
+ display: grid;
116
+ grid-template-columns: 70px 1fr 50px;
117
+ gap: 0.25rem;
118
+ align-items: center;
119
+ padding: 0.3rem 0;
120
+ font-size: 0.8rem;
121
+ border-bottom: 1px solid #1e1e3a;
122
+ }
123
+ .joint-row:last-child { border-bottom: none; }
124
+ .joint-label {
125
+ font-weight: bold;
126
+ white-space: nowrap;
127
+ overflow: hidden;
128
+ text-overflow: ellipsis;
129
+ }
130
+ .joint-angle {
131
+ font-family: 'Monaco', 'Menlo', monospace;
132
+ text-align: right;
133
+ font-size: 0.85rem;
134
+ }
135
+ .joint-raw {
136
+ font-family: 'Monaco', 'Menlo', monospace;
137
+ text-align: right;
138
+ font-size: 0.7rem;
139
+ color: #888;
140
+ }
141
+
142
+ /* Mapping rows */
143
+ .mapping-row {
144
+ display: flex;
145
+ align-items: center;
146
+ gap: 0.3rem;
147
+ padding: 0.25rem 0;
148
+ font-size: 0.8rem;
149
+ }
150
+ .mapping-row input {
151
+ width: 40px;
152
+ padding: 0.2rem 0.3rem;
153
+ border: 1px solid #444;
154
+ border-radius: 3px;
155
+ background: #2a2a4a;
156
+ color: #fff;
157
+ font-size: 0.8rem;
158
+ text-align: center;
159
+ }
160
+ .mapping-row select {
161
+ flex: 1;
162
+ padding: 0.2rem 0.3rem;
163
+ border: 1px solid #444;
164
+ border-radius: 3px;
165
+ background: #2a2a4a;
166
+ color: #fff;
167
+ font-size: 0.8rem;
168
+ }
169
+ .mapping-row .remove-btn {
170
+ padding: 0.1rem 0.4rem;
171
+ background: #ff475733;
172
+ color: #ff4757;
173
+ border: 1px solid #ff475744;
174
+ font-size: 0.7rem;
175
+ }
176
+ .mapping-actions {
177
+ display: flex;
178
+ gap: 0.4rem;
179
+ margin-top: 0.4rem;
180
+ }
181
+ .mapping-actions button {
182
+ font-size: 0.7rem;
183
+ padding: 0.2rem 0.5rem;
184
+ background: #2a2a4a;
185
+ color: #aaa;
186
+ border: 1px solid #444;
187
+ }
188
+
189
+ /* Stats */
190
+ .stats-grid {
191
+ display: grid;
192
+ grid-template-columns: 1fr 1fr;
193
+ gap: 0.4rem;
194
+ }
195
+ .stat {
196
+ background: #2a2a4a;
197
+ padding: 0.4rem;
198
+ border-radius: 4px;
199
+ text-align: center;
200
+ }
201
+ .stat-label { color: #888; font-size: 0.65rem; text-transform: uppercase; }
202
+ .stat-value { font-size: 0.9rem; font-weight: bold; color: #00d4ff; }
203
+
204
+ /* Log */
205
+ .log-panel {
206
+ height: 120px;
207
+ border-top: 1px solid #333;
208
+ background: #0a0a1a;
209
+ overflow-y: auto;
210
+ padding: 0.5rem;
211
+ font-family: 'Monaco', 'Menlo', monospace;
212
+ font-size: 0.7rem;
213
+ flex-shrink: 0;
214
+ }
215
+ .log-entry { margin: 0.15rem 0; }
216
+ .log-info { color: #888; }
217
+ .log-success { color: #2ed573; }
218
+ .log-error { color: #ff4757; }
219
+ .log-data { color: #00d4ff; }
220
+ </style>
221
+ <script type="module" crossorigin src="/assets/urdf_viewer-trQNEAhR.js"></script>
222
+ <link rel="modulepreload" crossorigin href="/assets/connect-DkGLCYAo.js">
223
+ <link rel="modulepreload" crossorigin href="/assets/URDFLoader-CL7UVBjw.js">
224
+ </head>
225
+ <body>
226
+ <div class="top-bar">
227
+ <h1>URDF Viewer</h1>
228
+ <label>
229
+ URDF:
230
+ <input type="text" id="urdfUrl" style="width:300px;" />
231
+ </label>
232
+ <button id="loadUrdfBtn">Load</button>
233
+ <span style="color:#444;">|</span>
234
+ <label>
235
+ Relay:
236
+ <input type="text" id="relayUrl" />
237
+ </label>
238
+ <label>
239
+ Path:
240
+ <input type="text" id="path" />
241
+ </label>
242
+ <label>
243
+ Cert hash:
244
+ <input type="text" id="certHash" placeholder="sha256 hex (optional)" style="width:180px;" />
245
+ </label>
246
+ <button id="startBtn">Connect</button>
247
+ <button id="stopBtn" disabled>Disconnect</button>
248
+ <button id="queryBtn" disabled>Query Servos</button>
249
+ <span id="statusText" style="color:#888; font-size:0.8rem;">Idle</span>
250
+ </div>
251
+
252
+ <div class="main">
253
+ <div class="canvas-container">
254
+ <canvas id="threeCanvas"></canvas>
255
+ <div class="canvas-overlay">
256
+ <span>Drag to orbit / Scroll to zoom / Right-drag to pan</span>
257
+ </div>
258
+ </div>
259
+
260
+ <div class="side-panel">
261
+ <div class="panel-section">
262
+ <h3>Joint Angles</h3>
263
+ <div class="joint-row" style="font-size:0.65rem; color:#666;">
264
+ <span>Joint</span><span style="text-align:right;">Angle</span><span style="text-align:right;">Raw</span>
265
+ </div>
266
+ <div id="jointRows"><span style="color:#666; font-size:0.75rem;">Load a URDF to see joints</span></div>
267
+ </div>
268
+
269
+ <div class="panel-section">
270
+ <h3>Joint Mapping (Servo ID &rarr; Joint)</h3>
271
+ <div id="mappingRows"></div>
272
+ <div class="mapping-actions">
273
+ <button id="addMappingBtn">+ Add</button>
274
+ <button id="resetMappingBtn">Reset</button>
275
+ </div>
276
+ </div>
277
+
278
+ <div class="panel-section">
279
+ <h3>Stats</h3>
280
+ <div class="stats-grid">
281
+ <div class="stat">
282
+ <div class="stat-label">Frames</div>
283
+ <div class="stat-value" id="frameCount">0</div>
284
+ </div>
285
+ <div class="stat">
286
+ <div class="stat-label">Bytes</div>
287
+ <div class="stat-value" id="bytesReceived">0 B</div>
288
+ </div>
289
+ <div class="stat">
290
+ <div class="stat-label">FPS</div>
291
+ <div class="stat-value" id="canFps">0</div>
292
+ </div>
293
+ <div class="stat">
294
+ <div class="stat-label">Last</div>
295
+ <div class="stat-value" id="lastUpdate">-</div>
296
+ </div>
297
+ </div>
298
+ </div>
299
+ </div>
300
+ </div>
301
+
302
+ <div class="log-panel" id="log"></div>
303
+
304
+ </body>
305
+ </html>
video_player.html ADDED
@@ -0,0 +1,176 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>Camera CMAF Player - xoq</title>
7
+
8
+ <style>
9
+ * { box-sizing: border-box; }
10
+ body {
11
+ font-family: system-ui, -apple-system, sans-serif;
12
+ max-width: 900px;
13
+ margin: 0 auto;
14
+ padding: 1rem;
15
+ background: #1a1a2e;
16
+ color: #eee;
17
+ }
18
+ h1 { color: #00d4ff; margin-bottom: 0.5rem; }
19
+ .subtitle { color: #888; margin-bottom: 1.5rem; }
20
+
21
+ .controls {
22
+ display: flex;
23
+ gap: 0.5rem;
24
+ flex-wrap: wrap;
25
+ margin-bottom: 1rem;
26
+ align-items: center;
27
+ }
28
+ .controls label {
29
+ display: flex;
30
+ align-items: center;
31
+ gap: 0.5rem;
32
+ }
33
+ .controls input[type="text"] {
34
+ padding: 0.5rem;
35
+ border: 1px solid #444;
36
+ border-radius: 4px;
37
+ background: #2a2a4a;
38
+ color: #fff;
39
+ width: 300px;
40
+ }
41
+ button {
42
+ padding: 0.5rem 1rem;
43
+ border: none;
44
+ border-radius: 4px;
45
+ cursor: pointer;
46
+ font-size: 1rem;
47
+ transition: background 0.2s;
48
+ }
49
+ button:disabled { opacity: 0.5; cursor: not-allowed; }
50
+ #startBtn { background: #00d4ff; color: #000; }
51
+ #startBtn:hover:not(:disabled) { background: #00b8e6; }
52
+ #stopBtn { background: #ff4757; color: #fff; }
53
+ #stopBtn:hover:not(:disabled) { background: #ff3344; }
54
+
55
+ .video-container {
56
+ background: #000;
57
+ border-radius: 8px;
58
+ overflow: hidden;
59
+ margin-bottom: 1rem;
60
+ aspect-ratio: 16/9;
61
+ }
62
+ video { width: 100%; height: 100%; display: block; }
63
+
64
+ .stats {
65
+ display: grid;
66
+ grid-template-columns: repeat(auto-fit, minmax(120px, 1fr));
67
+ gap: 0.5rem;
68
+ margin-bottom: 1rem;
69
+ }
70
+ .stat {
71
+ background: #2a2a4a;
72
+ padding: 0.75rem;
73
+ border-radius: 8px;
74
+ text-align: center;
75
+ }
76
+ .stat-label { color: #888; font-size: 0.75rem; text-transform: uppercase; }
77
+ .stat-value { font-size: 1.2rem; font-weight: bold; color: #00d4ff; }
78
+
79
+ .info-box {
80
+ background: #2a2a4a;
81
+ padding: 1rem;
82
+ border-radius: 8px;
83
+ margin-bottom: 1rem;
84
+ }
85
+ .info-box h3 { margin-top: 0; color: #00d4ff; }
86
+ .info-box pre {
87
+ background: #1a1a2e;
88
+ padding: 1rem;
89
+ border-radius: 4px;
90
+ overflow-x: auto;
91
+ margin: 0.5rem 0;
92
+ }
93
+
94
+ #log {
95
+ background: #0a0a1a;
96
+ border: 1px solid #333;
97
+ border-radius: 8px;
98
+ padding: 1rem;
99
+ height: 200px;
100
+ overflow-y: auto;
101
+ font-family: 'Monaco', 'Menlo', monospace;
102
+ font-size: 0.8rem;
103
+ }
104
+ .log-entry { margin: 0.2rem 0; }
105
+ .log-info { color: #888; }
106
+ .log-success { color: #2ed573; }
107
+ .log-error { color: #ff4757; }
108
+ .log-data { color: #00d4ff; }
109
+ </style>
110
+ <script type="importmap">
111
+ {
112
+ "imports": {
113
+ "@moq/lite": "https://esm.sh/@moq/lite@0.1.0"
114
+ }
115
+ }
116
+ </script>
117
+ <script type="module" crossorigin src="/assets/video_player-BJSMA0Bo.js"></script>
118
+ <link rel="modulepreload" crossorigin href="/assets/connect-DkGLCYAo.js">
119
+ </head>
120
+ <body>
121
+ <h1>Camera CMAF Player</h1>
122
+ <p class="subtitle">xoq MoQ Video Stream Client</p>
123
+
124
+ <div class="controls">
125
+ <label>
126
+ URL:
127
+ <input type="text" id="relayUrl" value="https://cdn.moq.dev/anon" />
128
+ </label>
129
+ <label>
130
+ Path:
131
+ <input type="text" id="path" value="camera" />
132
+ </label>
133
+ </div>
134
+ <div class="controls">
135
+ <button id="startBtn">Connect</button>
136
+ <button id="stopBtn" disabled>Disconnect</button>
137
+ </div>
138
+
139
+ <div class="video-container">
140
+ <video id="video" autoplay muted playsinline></video>
141
+ </div>
142
+
143
+ <div class="stats">
144
+ <div class="stat">
145
+ <div class="stat-label">Status</div>
146
+ <div class="stat-value" id="status">Idle</div>
147
+ </div>
148
+ <div class="stat">
149
+ <div class="stat-label">Groups</div>
150
+ <div class="stat-value" id="groupCount">0</div>
151
+ </div>
152
+ <div class="stat">
153
+ <div class="stat-label">Received</div>
154
+ <div class="stat-value" id="bytesReceived">0 B</div>
155
+ </div>
156
+ <div class="stat">
157
+ <div class="stat-label">Buffer</div>
158
+ <div class="stat-value" id="bufferLength">0s</div>
159
+ </div>
160
+ </div>
161
+
162
+ <h3>Log</h3>
163
+ <div id="log"></div>
164
+
165
+ <div class="info-box">
166
+ <h3>How to Run</h3>
167
+ <p>This player requires running from the xoq JS dev server:</p>
168
+ <pre>cd ../wser/js
169
+ npm install
170
+ npm run examples</pre>
171
+ <p>Or start the camera stream with:</p>
172
+ <pre>cargo run --example camera_xoq_stream --features xoq</pre>
173
+ </div>
174
+
175
+ </body>
176
+ </html>