File size: 6,842 Bytes
82d282f
 
ee6161a
82d282f
 
 
 
ee6161a
 
82d282f
 
 
b9b34d4
 
82d282f
 
 
 
 
 
 
 
 
 
 
 
 
ee6161a
82d282f
ee6161a
82d282f
 
 
 
 
 
 
 
 
 
 
 
ee6161a
82d282f
 
 
 
 
 
 
 
 
ee6161a
82d282f
 
 
 
b9b34d4
82d282f
ee6161a
82d282f
 
 
 
b9b34d4
82d282f
ee6161a
82d282f
ee6161a
82d282f
 
 
 
 
 
 
 
40f243c
 
82d282f
 
 
 
b9b34d4
82d282f
 
ee6161a
 
82d282f
 
 
 
 
 
 
 
 
 
 
 
 
036cb16
82d282f
 
 
 
036cb16
82d282f
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
036cb16
82d282f
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
036cb16
 
82d282f
 
 
 
 
 
 
 
 
 
 
 
 
036cb16
82d282f
 
 
036cb16
 
 
 
b9b34d4
036cb16
82d282f
 
 
 
036cb16
 
 
 
 
 
82d282f
 
 
 
 
 
 
 
 
 
 
 
 
ee6161a
dd86ab1
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
<!doctype html>
<html>
<head>
  <meta charset="utf-8" />
  <meta name="viewport" content="width=device-width" />
  <title>RMScript App</title>
  <link rel="stylesheet" href="style.css" />
</head>
<body>
  <div class="hero">
    <div class="hero-content">
      <div class="app-icon">πŸ“πŸ€–</div>
      <h1>Reachy Mini Script App</h1>
      <p class="tagline">Web app for programming Reachy Mini movements</p>
    </div>
  </div>

  <div class="container">
    <div class="main-card">
      <div class="app-preview">
        <div class="preview-image">
          <div class="camera-feed">πŸ’»</div>
          <pre class="code-preview">"Wave hello"
look left
antenna both up
wait 1s
look right</pre>
        </div>
      </div>

      <div class="app-details">
        <h2>About RMScript</h2>
        <div class="template-info">
          <div class="info-box">
            <h3>Kid-Friendly Language</h3>
            <p>Write scripts using natural language commands like <code>look left</code>, <code>turn right</code>, and <code>antenna up</code>.</p>
          </div>
          <div class="info-box">
            <h3>Real-Time Execution</h3>
            <p>Execute scripts directly on your robot with proper timing and smooth movements.</p>
          </div>
        </div>

        <div class="how-to-use">
          <h3>Features</h3>
          <div class="steps">
            <div class="step">
              <div class="step-number">1</div>
              <div>
                <h4>Syntax Highlighting</h4>
                <p>Real-time verification and error detection as you type</p>
              </div>
            </div>
            <div class="step">
              <div class="step-number">2</div>
              <div>
                <h4>Live Compilation</h4>
                <p>Instant compilation to robot commands with visual intermediate representation preview</p>
              </div>
            </div>
            <div class="step">
              <div class="step-number">3</div>
              <div>
                <h4>Movements & Sounds</h4>
                <p>Support for head movements, antennas, waits, (sounds and pictures TBD !) </p>
              </div>
            </div>
          </div>
        </div>
      </div>
    </div>
  </div>

  <div class="download-section">
    <div class="download-card">
      <h2>Install This App</h2>
      <div class="dashboard-config">
        <label for="dashboardUrl">Your Reachy Dashboard URL (when using the desktop Reachy Mini app):</label>
        <input type="url" id="dashboardUrl" value="http://localhost:8042"
          placeholder="http://your-reachy-ip:8000" />
      </div>
      <button id="installBtn" class="install-btn primary">
        <span class="btn-icon">πŸ“₯</span>
        Install Reachy Mini Script App to Reachy Mini
      </button>
      <div id="installStatus" class="install-status"></div>

    </div>
  </div>

  <div class="footer">
    <p>
      πŸ“ RMScript App β€’
      <a href="https://github.com/pollen-robotics" target="_blank">Pollen Robotics</a> β€’
      <a href="https://huggingface.co/spaces/pollen-robotics/Reachy_Mini_Apps" target="_blank">Browse More Apps</a>
    </p>
  </div>

  <script>
    function getCurrentSpaceUrl() {
      const url = window.location.href;
      // Match huggingface.co/spaces/user/repo format
      const match = url.match(/https:\/\/huggingface\.co\/spaces\/([^\/]+\/[^\/]+)/);
      if (match) {
        return `https://huggingface.co/spaces/${match[1]}`;
      }
      // Match user-repo.hf.space format
      if (url.includes('.hf.space')) {
        const hostMatch = url.match(/https?:\/\/([^\.]+)\.hf\.space/);
        if (hostMatch) {
          const spaceName = hostMatch[1].replace(/-/g, '/');
          return `https://huggingface.co/spaces/${spaceName}`;
        }
      }
      return url;
    }

    async function parseTomlProjectName(tomlContent) {
      const nameMatch = tomlContent.match(/^name\s*=\s*["']([^"']+)["']/m);
      return nameMatch ? nameMatch[1] : null;
    }

    async function getAppNameFromCurrentSpace() {
      try {
        const spaceUrl = getCurrentSpaceUrl();
        const tomlUrl = spaceUrl + '/raw/main/pyproject.toml';
        const response = await fetch(tomlUrl);
        if (response.ok) {
          const tomlContent = await response.text();
          return await parseTomlProjectName(tomlContent);
        }
      } catch (e) {
        console.error('Error fetching app name:', e);
      }
      return 'rmscript-app';
    }

    function showStatus(type, message) {
      const statusEl = document.getElementById('installStatus');
      statusEl.className = `install-status ${type}`;
      statusEl.textContent = message;
      statusEl.style.display = 'block';
    }

    async function installToReachy() {
      const btn = document.getElementById('installBtn');
      const dashboardUrl = document.getElementById('dashboardUrl').value.replace(/\/$/, '');

      btn.disabled = true;
      showStatus('loading', 'Connecting to Reachy dashboard...');

      try {
        // Test connection using the correct endpoint
        const testResponse = await fetch(`${dashboardUrl}/api/apps/list-available`, {
          method: 'GET',
          mode: 'cors',
        });

        if (!testResponse.ok) {
          throw new Error('Cannot connect to dashboard');
        }

        showStatus('loading', 'Installing app...');

        const spaceUrl = getCurrentSpaceUrl();
        const appName = await getAppNameFromCurrentSpace();

        // Use correct API format: AppInfo schema with name, source_kind, url
        const installResponse = await fetch(`${dashboardUrl}/api/apps/install`, {
          method: 'POST',
          headers: { 'Content-Type': 'application/json' },
          body: JSON.stringify({
            name: appName || 'rmscript-app',
            source_kind: 'hf_space',
            url: spaceUrl,
            description: 'Web app for programming Reachy Mini with RMScript language',
          }),
          mode: 'cors',
        });

        if (installResponse.ok) {
          const result = await installResponse.json();
          if (result.job_id) {
            showStatus('success', `Installation started! Job ID: ${result.job_id}. Check the dashboard for progress.`);
          } else {
            showStatus('success', `Successfully installed! Open the dashboard to run ${appName}.`);
          }
        } else {
          const error = await installResponse.text();
          throw new Error(error || 'Installation failed');
        }
      } catch (e) {
        showStatus('error', `Error: ${e.message}. Make sure the Reachy daemon is running.`);
      } finally {
        btn.disabled = false;
      }
    }

    document.getElementById('installBtn').addEventListener('click', installToReachy);
  </script>
</body>
</html>