Spaces:
Running
Running
feat: added syntax highlighting; updated the docs
Browse files
examples/cyberpunk-standalone/src/components/docs-section.tsx
CHANGED
@@ -1,30 +1,57 @@
|
|
1 |
-
"use client"
|
2 |
|
3 |
-
import type React from "react"
|
4 |
-
import { Book, Code2, Terminal, Copy, Check } from "lucide-react"
|
5 |
-
import { Button } from "@/components/ui/button"
|
6 |
-
import { useState } from "react"
|
|
|
|
|
7 |
|
8 |
-
const CodeBlock = ({
|
9 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
10 |
|
11 |
const copyToClipboard = async (text: string) => {
|
12 |
try {
|
13 |
-
await navigator.clipboard.writeText(text)
|
14 |
-
setCopied(true)
|
15 |
-
setTimeout(() => setCopied(false), 2000)
|
16 |
} catch (err) {
|
17 |
-
console.error("Failed to copy:", err)
|
18 |
}
|
19 |
-
}
|
20 |
|
21 |
-
const codeText =
|
|
|
22 |
|
23 |
return (
|
24 |
<div className="bg-muted/50 dark:bg-black/40 border border-border dark:border-white/10 rounded-md overflow-hidden my-4 relative">
|
25 |
-
<
|
26 |
-
|
27 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
28 |
<Button
|
29 |
variant="outline"
|
30 |
size="sm"
|
@@ -34,8 +61,8 @@ const CodeBlock = ({ children }: { children: React.ReactNode }) => {
|
|
34 |
{copied ? <Check className="w-3 h-3" /> : <Copy className="w-3 h-3" />}
|
35 |
</Button>
|
36 |
</div>
|
37 |
-
)
|
38 |
-
}
|
39 |
|
40 |
export function DocsSection() {
|
41 |
return (
|
@@ -45,7 +72,9 @@ export function DocsSection() {
|
|
45 |
<Book className="w-6 h-6" />
|
46 |
Docs
|
47 |
</h2>
|
48 |
-
<p className="text-sm text-muted-foreground">
|
|
|
|
|
49 |
</div>
|
50 |
|
51 |
<div className="bg-muted/40 dark:bg-black/30 border-l-4 border-cyan-500 dark:border-accent-cyan p-6 md:p-8 rounded-r-lg space-y-8">
|
@@ -56,22 +85,60 @@ export function DocsSection() {
|
|
56 |
Getting Started
|
57 |
</h3>
|
58 |
<p className="text-muted-foreground text-sm mt-2 mb-4">
|
59 |
-
|
60 |
</p>
|
61 |
<CodeBlock>
|
62 |
-
{`import {
|
63 |
-
|
64 |
-
|
65 |
-
|
66 |
-
|
67 |
-
|
68 |
-
|
69 |
-
|
70 |
-
|
71 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
72 |
</CodeBlock>
|
73 |
</div>
|
74 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
75 |
{/* API Reference */}
|
76 |
<div>
|
77 |
<h3 className="text-xl font-bold text-cyan-600 dark:text-accent-cyan tracking-wider uppercase flex items-center gap-2">
|
@@ -81,70 +148,122 @@ async function connectToRobot() {
|
|
81 |
<div className="space-y-6 mt-4">
|
82 |
{/* findPort */}
|
83 |
<div>
|
84 |
-
<h4 className="font-bold text-primary">
|
85 |
-
<p className="text-muted-foreground text-sm mt-1">
|
|
|
|
|
86 |
<CodeBlock>
|
87 |
-
{`//
|
88 |
-
|
89 |
-
|
90 |
-
onMessage?: (msg: string) => void // Callback for status updates
|
91 |
-
}
|
92 |
|
93 |
-
//
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
94 |
{
|
95 |
-
result: Promise<RobotConnection[]
|
|
|
96 |
}`}
|
97 |
</CodeBlock>
|
98 |
</div>
|
99 |
|
100 |
{/* calibrate */}
|
101 |
<div>
|
102 |
-
<h4 className="font-bold text-primary">
|
103 |
-
<p className="text-muted-foreground text-sm mt-1">
|
|
|
|
|
104 |
<CodeBlock>
|
105 |
-
{
|
106 |
-
robot
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
107 |
|
108 |
-
//
|
109 |
-
|
110 |
-
|
111 |
-
onProgress: (msg: string) => void // Callback for status messages
|
112 |
-
}
|
113 |
|
114 |
-
// Returns
|
115 |
{
|
116 |
-
result: Promise<WebCalibrationResults>, //
|
117 |
-
stop
|
118 |
}`}
|
119 |
</CodeBlock>
|
120 |
</div>
|
121 |
|
122 |
{/* teleoperate */}
|
123 |
<div>
|
124 |
-
<h4 className="font-bold text-primary">
|
125 |
-
<p className="text-muted-foreground text-sm mt-1">
|
|
|
|
|
126 |
<CodeBlock>
|
127 |
-
{`//
|
128 |
-
|
129 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
130 |
|
131 |
-
//
|
132 |
-
{
|
133 |
-
|
134 |
-
|
|
|
|
|
135 |
|
136 |
-
// Returns
|
137 |
{
|
138 |
-
start
|
139 |
-
stop
|
140 |
-
|
141 |
-
|
|
|
142 |
}`}
|
143 |
</CodeBlock>
|
144 |
</div>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
145 |
</div>
|
146 |
</div>
|
147 |
</div>
|
148 |
</div>
|
149 |
-
)
|
150 |
}
|
|
|
1 |
+
"use client";
|
2 |
|
3 |
+
import type React from "react";
|
4 |
+
import { Book, Code2, Terminal, Copy, Check } from "lucide-react";
|
5 |
+
import { Button } from "@/components/ui/button";
|
6 |
+
import { useState } from "react";
|
7 |
+
import { Prism as SyntaxHighlighter } from "react-syntax-highlighter";
|
8 |
+
import { oneDark } from "react-syntax-highlighter/dist/esm/styles/prism";
|
9 |
|
10 |
+
const CodeBlock = ({
|
11 |
+
children,
|
12 |
+
language = "typescript",
|
13 |
+
}: {
|
14 |
+
children: React.ReactNode;
|
15 |
+
language?: string;
|
16 |
+
}) => {
|
17 |
+
const [copied, setCopied] = useState(false);
|
18 |
|
19 |
const copyToClipboard = async (text: string) => {
|
20 |
try {
|
21 |
+
await navigator.clipboard.writeText(text);
|
22 |
+
setCopied(true);
|
23 |
+
setTimeout(() => setCopied(false), 2000);
|
24 |
} catch (err) {
|
25 |
+
console.error("Failed to copy:", err);
|
26 |
}
|
27 |
+
};
|
28 |
|
29 |
+
const codeText =
|
30 |
+
typeof children === "string" ? children : children?.toString() || "";
|
31 |
|
32 |
return (
|
33 |
<div className="bg-muted/50 dark:bg-black/40 border border-border dark:border-white/10 rounded-md overflow-hidden my-4 relative">
|
34 |
+
<SyntaxHighlighter
|
35 |
+
language={language}
|
36 |
+
style={oneDark}
|
37 |
+
customStyle={{
|
38 |
+
margin: 0,
|
39 |
+
padding: "1rem",
|
40 |
+
fontSize: "0.875rem",
|
41 |
+
background: "transparent",
|
42 |
+
backgroundColor: "transparent",
|
43 |
+
}}
|
44 |
+
wrapLines={true}
|
45 |
+
wrapLongLines={true}
|
46 |
+
codeTagProps={{
|
47 |
+
style: {
|
48 |
+
background: "transparent",
|
49 |
+
backgroundColor: "transparent",
|
50 |
+
},
|
51 |
+
}}
|
52 |
+
>
|
53 |
+
{codeText}
|
54 |
+
</SyntaxHighlighter>
|
55 |
<Button
|
56 |
variant="outline"
|
57 |
size="sm"
|
|
|
61 |
{copied ? <Check className="w-3 h-3" /> : <Copy className="w-3 h-3" />}
|
62 |
</Button>
|
63 |
</div>
|
64 |
+
);
|
65 |
+
};
|
66 |
|
67 |
export function DocsSection() {
|
68 |
return (
|
|
|
72 |
<Book className="w-6 h-6" />
|
73 |
Docs
|
74 |
</h2>
|
75 |
+
<p className="text-sm text-muted-foreground">
|
76 |
+
Complete API reference for @lerobot/web robotics library.
|
77 |
+
</p>
|
78 |
</div>
|
79 |
|
80 |
<div className="bg-muted/40 dark:bg-black/30 border-l-4 border-cyan-500 dark:border-accent-cyan p-6 md:p-8 rounded-r-lg space-y-8">
|
|
|
85 |
Getting Started
|
86 |
</h3>
|
87 |
<p className="text-muted-foreground text-sm mt-2 mb-4">
|
88 |
+
Complete workflow from discovery to teleoperation.
|
89 |
</p>
|
90 |
<CodeBlock>
|
91 |
+
{`import { findPort, releaseMotors, calibrate, teleoperate } from "@lerobot/web";
|
92 |
+
|
93 |
+
// 1. find and connect to hardware like a robot arm
|
94 |
+
const findProcess = await findPort();
|
95 |
+
const robots = await findProcess.result;
|
96 |
+
const robot = robots[0];
|
97 |
+
|
98 |
+
// 2. release the motors and put them into the homing position
|
99 |
+
await releaseMotors(robot);
|
100 |
+
|
101 |
+
// 3. calibrate the motors by moving each motor through its full range of motion
|
102 |
+
const calibrationProcess = await calibrate({
|
103 |
+
robot,
|
104 |
+
onProgress: (message) => console.log(message),
|
105 |
+
onLiveUpdate: (data) => console.log("Live positions:", data),
|
106 |
+
});
|
107 |
+
|
108 |
+
// when done, stop calibration and get the min/max ranges for each motor
|
109 |
+
calibrationProcess.stop();
|
110 |
+
const calibrationData = await calibrationProcess.result;
|
111 |
+
|
112 |
+
// 4. start controlling the robot arm with your keyboard
|
113 |
+
const teleop = await teleoperate({
|
114 |
+
robot,
|
115 |
+
calibrationData,
|
116 |
+
teleop: { type: "keyboard" },
|
117 |
+
});
|
118 |
+
teleop.start();`}
|
119 |
</CodeBlock>
|
120 |
</div>
|
121 |
|
122 |
+
{/* Browser Requirements */}
|
123 |
+
<div>
|
124 |
+
<h3 className="text-xl font-bold text-cyan-600 dark:text-accent-cyan tracking-wider uppercase">
|
125 |
+
Browser Requirements
|
126 |
+
</h3>
|
127 |
+
<div className="mt-4 space-y-2 text-sm">
|
128 |
+
<div>
|
129 |
+
• <strong>Chromium 89+</strong> with WebSerial and WebUSB API
|
130 |
+
support
|
131 |
+
</div>
|
132 |
+
<div>
|
133 |
+
• <strong>HTTPS or localhost</strong>
|
134 |
+
</div>
|
135 |
+
<div>
|
136 |
+
• <strong>User gesture</strong> required for initial port
|
137 |
+
selection
|
138 |
+
</div>
|
139 |
+
</div>
|
140 |
+
</div>
|
141 |
+
|
142 |
{/* API Reference */}
|
143 |
<div>
|
144 |
<h3 className="text-xl font-bold text-cyan-600 dark:text-accent-cyan tracking-wider uppercase flex items-center gap-2">
|
|
|
148 |
<div className="space-y-6 mt-4">
|
149 |
{/* findPort */}
|
150 |
<div>
|
151 |
+
<h4 className="font-bold text-primary">findPort(config?)</h4>
|
152 |
+
<p className="text-muted-foreground text-sm mt-1">
|
153 |
+
Discovers and connects to robotics hardware using WebSerial API.
|
154 |
+
</p>
|
155 |
<CodeBlock>
|
156 |
+
{`// Interactive Mode (Default) - Shows port dialog
|
157 |
+
const findProcess = await findPort();
|
158 |
+
const robots = await findProcess.result; // RobotConnection[]
|
|
|
|
|
159 |
|
160 |
+
// Auto-Connect Mode - Reconnects to known robots
|
161 |
+
const findProcess = await findPort({
|
162 |
+
robotConfigs: [
|
163 |
+
{ robotType: "so100_follower", robotId: "left_arm", serialNumber: "USB123" }
|
164 |
+
],
|
165 |
+
onMessage: (msg) => console.log(msg),
|
166 |
+
});
|
167 |
+
|
168 |
+
// Returns: FindPortProcess
|
169 |
{
|
170 |
+
result: Promise<RobotConnection[]>, // Array of robot connections
|
171 |
+
stop(): void // Cancel discovery process
|
172 |
}`}
|
173 |
</CodeBlock>
|
174 |
</div>
|
175 |
|
176 |
{/* calibrate */}
|
177 |
<div>
|
178 |
+
<h4 className="font-bold text-primary">calibrate(config)</h4>
|
179 |
+
<p className="text-muted-foreground text-sm mt-1">
|
180 |
+
Calibrates motor homing offsets and records range of motion.
|
181 |
+
</p>
|
182 |
<CodeBlock>
|
183 |
+
{`const calibrationProcess = await calibrate({
|
184 |
+
robot,
|
185 |
+
onProgress: (message) => {
|
186 |
+
console.log(message); // "⚙️ Setting motor homing offsets"
|
187 |
+
},
|
188 |
+
onLiveUpdate: (data) => {
|
189 |
+
// Real-time motor positions during range recording
|
190 |
+
Object.entries(data).forEach(([motor, info]) => {
|
191 |
+
console.log(\`\${motor}: \${info.current} (range: \${info.range})\`);
|
192 |
+
});
|
193 |
+
},
|
194 |
+
});
|
195 |
|
196 |
+
// Move robot through full range of motion...
|
197 |
+
calibrationProcess.stop(); // Stop range recording
|
198 |
+
const calibrationData = await calibrationProcess.result;
|
|
|
|
|
199 |
|
200 |
+
// Returns: CalibrationProcess
|
201 |
{
|
202 |
+
result: Promise<WebCalibrationResults>, // Python-compatible format
|
203 |
+
stop(): void // Stop calibration process
|
204 |
}`}
|
205 |
</CodeBlock>
|
206 |
</div>
|
207 |
|
208 |
{/* teleoperate */}
|
209 |
<div>
|
210 |
+
<h4 className="font-bold text-primary">teleoperate(config)</h4>
|
211 |
+
<p className="text-muted-foreground text-sm mt-1">
|
212 |
+
Enables real-time robot control with extensible input devices.
|
213 |
+
</p>
|
214 |
<CodeBlock>
|
215 |
+
{`// Keyboard Teleoperation
|
216 |
+
const keyboardTeleop = await teleoperate({
|
217 |
+
robot,
|
218 |
+
calibrationData: savedCalibrationData,
|
219 |
+
teleop: { type: "keyboard" },
|
220 |
+
onStateUpdate: (state) => {
|
221 |
+
console.log(\`Active: \${state.isActive}\`);
|
222 |
+
console.log(\`Motors:\`, state.motorConfigs);
|
223 |
+
},
|
224 |
+
});
|
225 |
|
226 |
+
// Direct Teleoperation
|
227 |
+
const directTeleop = await teleoperate({
|
228 |
+
robot,
|
229 |
+
calibrationData: savedCalibrationData,
|
230 |
+
teleop: { type: "direct" },
|
231 |
+
});
|
232 |
|
233 |
+
// Returns: TeleoperationProcess
|
234 |
{
|
235 |
+
start(): void, // Begin teleoperation
|
236 |
+
stop(): void, // Stop teleoperation and clear states
|
237 |
+
getState(): TeleoperationState, // Current state and motor positions
|
238 |
+
teleoperator: BaseWebTeleoperator, // Access teleoperator-specific methods
|
239 |
+
disconnect(): Promise<void> // Stop and disconnect
|
240 |
}`}
|
241 |
</CodeBlock>
|
242 |
</div>
|
243 |
+
|
244 |
+
{/* releaseMotors */}
|
245 |
+
<div>
|
246 |
+
<h4 className="font-bold text-primary">
|
247 |
+
releaseMotors(robot, motorIds?)
|
248 |
+
</h4>
|
249 |
+
<p className="text-muted-foreground text-sm mt-1">
|
250 |
+
Releases motor torque so robot can be moved freely by hand.
|
251 |
+
</p>
|
252 |
+
<CodeBlock>
|
253 |
+
{`// Release all motors for calibration
|
254 |
+
await releaseMotors(robot);
|
255 |
+
|
256 |
+
// Release specific motors only
|
257 |
+
await releaseMotors(robot, [1, 2, 3]);
|
258 |
+
|
259 |
+
// Parameters
|
260 |
+
robot: RobotConnection // Connected robot
|
261 |
+
motorIds?: number[] // Specific motor IDs (default: all motors for robot type)`}
|
262 |
+
</CodeBlock>
|
263 |
+
</div>
|
264 |
</div>
|
265 |
</div>
|
266 |
</div>
|
267 |
</div>
|
268 |
+
);
|
269 |
}
|