From f02fdd99c455cad8cba2f6f289a224e32708d7bc Mon Sep 17 00:00:00 2001
From: Minggang Wang
Date: Wed, 6 May 2026 13:43:18 +0800
Subject: [PATCH 1/2] Consolidate all demos under demo/ + add rosocket demo
---
.npmignore | 1 +
README.md | 8 +-
{electron_demo => demo/electron}/README.md | 0
.../electron}/car/README.md | 0
.../electron}/car/car-control-electron.gif | Bin
.../electron}/car/index.html | 0
{electron_demo => demo/electron}/car/main.js | 0
.../electron}/car/package.json | 0
.../electron}/car/renderer.js | 0
.../electron}/manipulator/README.md | 2 +-
.../electron}/manipulator/index.html | 0
.../electron}/manipulator/main.js | 0
.../manipulator/manipulator-demo.gif | Bin
.../manipulator/manipulator-demo.png | Bin
.../electron}/manipulator/package.json | 0
.../electron}/manipulator/renderer.js | 0
.../electron}/topics/README.md | 2 +-
.../electron}/topics/electron-demo.gif | Bin
.../electron}/topics/index.html | 0
.../electron}/topics/main.js | 0
.../electron}/topics/package.json | 0
.../electron}/topics/renderer.js | 0
.../electron}/turtle_tf2/README.md | 2 +-
.../electron}/turtle_tf2/index.html | 0
.../electron}/turtle_tf2/main.js | 0
.../electron}/turtle_tf2/orbit-controls.js | 0
.../electron}/turtle_tf2/package.json | 0
.../electron}/turtle_tf2/renderer.js | 0
.../electron}/turtle_tf2/turtle-tf2-demo.gif | Bin
.../electron}/turtle_tf2/turtle-tf2-demo.png | Bin
demo/rosocket/README.md | 93 ++++++++
demo/rosocket/index.html | 212 ++++++++++++++++++
demo/rosocket/server.js | 76 +++++++
{ts_demo => demo/typescript}/README.md | 4 +-
.../typescript}/actions/README.md | 4 +-
.../typescript}/actions/package.json | 0
.../typescript}/actions/src/client.ts | 0
.../typescript}/actions/src/server.ts | 0
.../typescript}/actions/tsconfig.json | 0
.../typescript}/services/README.md | 2 +-
.../typescript}/services/package.json | 0
.../typescript}/services/src/client.ts | 0
.../typescript}/services/src/server.ts | 0
.../typescript}/services/tsconfig.json | 0
{ts_demo => demo/typescript}/topics/README.md | 6 +-
.../typescript}/topics/package.json | 0
.../typescript}/topics/src/publisher.ts | 0
.../typescript}/topics/src/subscriber.ts | 0
.../typescript}/topics/tsconfig.json | 0
eslint.config.mjs | 2 +-
scripts/npmjs-readme.md | 5 +-
51 files changed, 401 insertions(+), 18 deletions(-)
rename {electron_demo => demo/electron}/README.md (100%)
rename {electron_demo => demo/electron}/car/README.md (100%)
rename {electron_demo => demo/electron}/car/car-control-electron.gif (100%)
rename {electron_demo => demo/electron}/car/index.html (100%)
rename {electron_demo => demo/electron}/car/main.js (100%)
rename {electron_demo => demo/electron}/car/package.json (100%)
rename {electron_demo => demo/electron}/car/renderer.js (100%)
rename {electron_demo => demo/electron}/manipulator/README.md (99%)
rename {electron_demo => demo/electron}/manipulator/index.html (100%)
rename {electron_demo => demo/electron}/manipulator/main.js (100%)
rename {electron_demo => demo/electron}/manipulator/manipulator-demo.gif (100%)
rename {electron_demo => demo/electron}/manipulator/manipulator-demo.png (100%)
rename {electron_demo => demo/electron}/manipulator/package.json (100%)
rename {electron_demo => demo/electron}/manipulator/renderer.js (100%)
rename {electron_demo => demo/electron}/topics/README.md (99%)
rename {electron_demo => demo/electron}/topics/electron-demo.gif (100%)
rename {electron_demo => demo/electron}/topics/index.html (100%)
rename {electron_demo => demo/electron}/topics/main.js (100%)
rename {electron_demo => demo/electron}/topics/package.json (100%)
rename {electron_demo => demo/electron}/topics/renderer.js (100%)
rename {electron_demo => demo/electron}/turtle_tf2/README.md (99%)
rename {electron_demo => demo/electron}/turtle_tf2/index.html (100%)
rename {electron_demo => demo/electron}/turtle_tf2/main.js (100%)
rename {electron_demo => demo/electron}/turtle_tf2/orbit-controls.js (100%)
rename {electron_demo => demo/electron}/turtle_tf2/package.json (100%)
rename {electron_demo => demo/electron}/turtle_tf2/renderer.js (100%)
rename {electron_demo => demo/electron}/turtle_tf2/turtle-tf2-demo.gif (100%)
rename {electron_demo => demo/electron}/turtle_tf2/turtle-tf2-demo.png (100%)
create mode 100644 demo/rosocket/README.md
create mode 100644 demo/rosocket/index.html
create mode 100644 demo/rosocket/server.js
rename {ts_demo => demo/typescript}/README.md (94%)
rename {ts_demo => demo/typescript}/actions/README.md (99%)
rename {ts_demo => demo/typescript}/actions/package.json (100%)
rename {ts_demo => demo/typescript}/actions/src/client.ts (100%)
rename {ts_demo => demo/typescript}/actions/src/server.ts (100%)
rename {ts_demo => demo/typescript}/actions/tsconfig.json (100%)
rename {ts_demo => demo/typescript}/services/README.md (99%)
rename {ts_demo => demo/typescript}/services/package.json (100%)
rename {ts_demo => demo/typescript}/services/src/client.ts (100%)
rename {ts_demo => demo/typescript}/services/src/server.ts (100%)
rename {ts_demo => demo/typescript}/services/tsconfig.json (100%)
rename {ts_demo => demo/typescript}/topics/README.md (99%)
rename {ts_demo => demo/typescript}/topics/package.json (100%)
rename {ts_demo => demo/typescript}/topics/src/publisher.ts (100%)
rename {ts_demo => demo/typescript}/topics/src/subscriber.ts (100%)
rename {ts_demo => demo/typescript}/topics/tsconfig.json (100%)
diff --git a/.npmignore b/.npmignore
index 947bfcd51..d24e04c8f 100644
--- a/.npmignore
+++ b/.npmignore
@@ -26,6 +26,7 @@ tutorials/
electron_demo/
ts_demo/
tools/
+demo/
.github/
.nyc_output/
.vscode/
diff --git a/README.md b/README.md
index 6dc9f07ad..8735f0621 100644
--- a/README.md
+++ b/README.md
@@ -144,10 +144,10 @@ Create rich, interactive desktop applications using Electron and web technologie
| Demo | Description | Screenshot |
| :-----------------------------------------------: | :-----------------------------------------------------------------------------------------------------------------------------------: | :--------------------------------------------------------------: |
-| **🐢 [turtle_tf2](./electron_demo/turtle_tf2)** | Real-time coordinate frame visualization with turtle control. Features TF2 transforms, keyboard control, and dynamic frame updates. |  |
-| **🦾 [manipulator](./electron_demo/manipulator)** | Interactive two-joint robotic arm simulation. Features 3D joint visualization, manual/automatic control, and visual movement markers. |  |
+| **🐢 [turtle_tf2](./demo/electron/turtle_tf2)** | Real-time coordinate frame visualization with turtle control. Features TF2 transforms, keyboard control, and dynamic frame updates. |  |
+| **🦾 [manipulator](./demo/electron/manipulator)** | Interactive two-joint robotic arm simulation. Features 3D joint visualization, manual/automatic control, and visual movement markers. |  |
-Explore more examples in [electron_demo](https://github.com/RobotWebTools/rclnodejs/tree/develop/electron_demo).
+Explore more examples in [demo/electron](https://github.com/RobotWebTools/rclnodejs/tree/develop/demo/electron).
## Using rclnodejs with TypeScript
@@ -175,7 +175,7 @@ rclnodejs.init().then(() => {
});
```
-See [TypeScript demos](https://github.com/RobotWebTools/rclnodejs/tree/develop/ts_demo) for more examples.
+See [TypeScript demos](https://github.com/RobotWebTools/rclnodejs/tree/develop/demo/typescript) for more examples.
## Observable Subscriptions
diff --git a/electron_demo/README.md b/demo/electron/README.md
similarity index 100%
rename from electron_demo/README.md
rename to demo/electron/README.md
diff --git a/electron_demo/car/README.md b/demo/electron/car/README.md
similarity index 100%
rename from electron_demo/car/README.md
rename to demo/electron/car/README.md
diff --git a/electron_demo/car/car-control-electron.gif b/demo/electron/car/car-control-electron.gif
similarity index 100%
rename from electron_demo/car/car-control-electron.gif
rename to demo/electron/car/car-control-electron.gif
diff --git a/electron_demo/car/index.html b/demo/electron/car/index.html
similarity index 100%
rename from electron_demo/car/index.html
rename to demo/electron/car/index.html
diff --git a/electron_demo/car/main.js b/demo/electron/car/main.js
similarity index 100%
rename from electron_demo/car/main.js
rename to demo/electron/car/main.js
diff --git a/electron_demo/car/package.json b/demo/electron/car/package.json
similarity index 100%
rename from electron_demo/car/package.json
rename to demo/electron/car/package.json
diff --git a/electron_demo/car/renderer.js b/demo/electron/car/renderer.js
similarity index 100%
rename from electron_demo/car/renderer.js
rename to demo/electron/car/renderer.js
diff --git a/electron_demo/manipulator/README.md b/demo/electron/manipulator/README.md
similarity index 99%
rename from electron_demo/manipulator/README.md
rename to demo/electron/manipulator/README.md
index 76c3497d5..616769367 100644
--- a/electron_demo/manipulator/README.md
+++ b/demo/electron/manipulator/README.md
@@ -25,7 +25,7 @@ An interactive Electron application demonstrating a two-joint robotic manipulato
1. **Navigate to the demo directory**:
```bash
- cd rclnodejs/electron_demo/manipulator
+ cd rclnodejs/demo/electron/manipulator
```
2. **Install dependencies**:
diff --git a/electron_demo/manipulator/index.html b/demo/electron/manipulator/index.html
similarity index 100%
rename from electron_demo/manipulator/index.html
rename to demo/electron/manipulator/index.html
diff --git a/electron_demo/manipulator/main.js b/demo/electron/manipulator/main.js
similarity index 100%
rename from electron_demo/manipulator/main.js
rename to demo/electron/manipulator/main.js
diff --git a/electron_demo/manipulator/manipulator-demo.gif b/demo/electron/manipulator/manipulator-demo.gif
similarity index 100%
rename from electron_demo/manipulator/manipulator-demo.gif
rename to demo/electron/manipulator/manipulator-demo.gif
diff --git a/electron_demo/manipulator/manipulator-demo.png b/demo/electron/manipulator/manipulator-demo.png
similarity index 100%
rename from electron_demo/manipulator/manipulator-demo.png
rename to demo/electron/manipulator/manipulator-demo.png
diff --git a/electron_demo/manipulator/package.json b/demo/electron/manipulator/package.json
similarity index 100%
rename from electron_demo/manipulator/package.json
rename to demo/electron/manipulator/package.json
diff --git a/electron_demo/manipulator/renderer.js b/demo/electron/manipulator/renderer.js
similarity index 100%
rename from electron_demo/manipulator/renderer.js
rename to demo/electron/manipulator/renderer.js
diff --git a/electron_demo/topics/README.md b/demo/electron/topics/README.md
similarity index 99%
rename from electron_demo/topics/README.md
rename to demo/electron/topics/README.md
index e06a3a03b..20f2f504e 100644
--- a/electron_demo/topics/README.md
+++ b/demo/electron/topics/README.md
@@ -30,7 +30,7 @@ A minimal Electron application demonstrating basic ROS2 topic communication usin
1. **Navigate to the demo directory**:
```bash
- cd rclnodejs/electron_demo/topics
+ cd rclnodejs/demo/electron/topics
```
2. **Source your ROS 2 environment**:
diff --git a/electron_demo/topics/electron-demo.gif b/demo/electron/topics/electron-demo.gif
similarity index 100%
rename from electron_demo/topics/electron-demo.gif
rename to demo/electron/topics/electron-demo.gif
diff --git a/electron_demo/topics/index.html b/demo/electron/topics/index.html
similarity index 100%
rename from electron_demo/topics/index.html
rename to demo/electron/topics/index.html
diff --git a/electron_demo/topics/main.js b/demo/electron/topics/main.js
similarity index 100%
rename from electron_demo/topics/main.js
rename to demo/electron/topics/main.js
diff --git a/electron_demo/topics/package.json b/demo/electron/topics/package.json
similarity index 100%
rename from electron_demo/topics/package.json
rename to demo/electron/topics/package.json
diff --git a/electron_demo/topics/renderer.js b/demo/electron/topics/renderer.js
similarity index 100%
rename from electron_demo/topics/renderer.js
rename to demo/electron/topics/renderer.js
diff --git a/electron_demo/turtle_tf2/README.md b/demo/electron/turtle_tf2/README.md
similarity index 99%
rename from electron_demo/turtle_tf2/README.md
rename to demo/electron/turtle_tf2/README.md
index 89ad595ed..33ae9a002 100644
--- a/electron_demo/turtle_tf2/README.md
+++ b/demo/electron/turtle_tf2/README.md
@@ -77,7 +77,7 @@ The demo uses the following key dependencies:
1. **Navigate to the demo directory**:
```bash
- cd electron_demo/turtle_tf2
+ cd demo/electron/turtle_tf2
```
2. **Install dependencies**:
diff --git a/electron_demo/turtle_tf2/index.html b/demo/electron/turtle_tf2/index.html
similarity index 100%
rename from electron_demo/turtle_tf2/index.html
rename to demo/electron/turtle_tf2/index.html
diff --git a/electron_demo/turtle_tf2/main.js b/demo/electron/turtle_tf2/main.js
similarity index 100%
rename from electron_demo/turtle_tf2/main.js
rename to demo/electron/turtle_tf2/main.js
diff --git a/electron_demo/turtle_tf2/orbit-controls.js b/demo/electron/turtle_tf2/orbit-controls.js
similarity index 100%
rename from electron_demo/turtle_tf2/orbit-controls.js
rename to demo/electron/turtle_tf2/orbit-controls.js
diff --git a/electron_demo/turtle_tf2/package.json b/demo/electron/turtle_tf2/package.json
similarity index 100%
rename from electron_demo/turtle_tf2/package.json
rename to demo/electron/turtle_tf2/package.json
diff --git a/electron_demo/turtle_tf2/renderer.js b/demo/electron/turtle_tf2/renderer.js
similarity index 100%
rename from electron_demo/turtle_tf2/renderer.js
rename to demo/electron/turtle_tf2/renderer.js
diff --git a/electron_demo/turtle_tf2/turtle-tf2-demo.gif b/demo/electron/turtle_tf2/turtle-tf2-demo.gif
similarity index 100%
rename from electron_demo/turtle_tf2/turtle-tf2-demo.gif
rename to demo/electron/turtle_tf2/turtle-tf2-demo.gif
diff --git a/electron_demo/turtle_tf2/turtle-tf2-demo.png b/demo/electron/turtle_tf2/turtle-tf2-demo.png
similarity index 100%
rename from electron_demo/turtle_tf2/turtle-tf2-demo.png
rename to demo/electron/turtle_tf2/turtle-tf2-demo.png
diff --git a/demo/rosocket/README.md b/demo/rosocket/README.md
new file mode 100644
index 000000000..830d5cd44
--- /dev/null
+++ b/demo/rosocket/README.md
@@ -0,0 +1,93 @@
+# rosocket demo (browser ↔ ROS 2)
+
+A minimal end-to-end example of the
+[`rosocket`](../../rosocket/README.md) WebSocket bridge added in
+commit `3176aca`. The Node server runs anywhere ROS 2 is sourced;
+the HTML page runs in any modern browser and talks to it over plain
+`WebSocket` — no client library required.
+
+## What it shows
+
+- Subscribe to and publish on `/chatter` (`std_msgs/msg/String`).
+- Call `/add_two_ints` (`example_interfaces/srv/AddTwoInts`) — the
+ service implementation lives in
+ [`example/services/service/service-example.js`](../../example/services/service/service-example.js)
+ and is launched in a second terminal.
+
+## Layout
+
+- `server.js` — `rclnodejs` node + `startRosocket` bridge only.
+- `index.html` — single-file browser client using only built-in
+ `WebSocket` and `JSON`.
+
+## Run the bridge
+
+```bash
+# 1. Source your ROS 2 distro (humble / jazzy / kilted / lyrical / rolling)
+source /opt/ros/$ROS_DISTRO/setup.bash
+
+# 2. Terminal A — start the WebSocket bridge
+node demo/rosocket/server.js
+# [rosocket-demo] listening on ws://localhost:9000 (bind=0.0.0.0)
+
+# 3. Terminal B — start the AddTwoInts service so the browser has
+# something to call
+node example/services/service/service-example.js
+```
+
+The server binds to `0.0.0.0:9000` so it is reachable from any host
+that can route to the machine running it.
+
+## Open the page
+
+Open `demo/rosocket/index.html` in any modern browser (double-click,
+or `File > Open`). Leave the bridge field as `ws://localhost:9000`
+when the browser and the bridge run on the same machine, and click
+**Subscribe**, then **Publish**, then **Call**.
+
+If the browser is on a different machine than the bridge (remote ROS
+box, container, VM, WSL → host browser, etc.), change the bridge
+field to point at the bridge host, e.g. `ws://192.0.2.10:9000` or
+`ws://my-ros-host.local:9000`, and reconnect.
+
+> WSL note: WSL2 normally forwards `localhost` to Windows, so
+> `ws://localhost:9000` works as-is. On WSL1 or with custom/mirrored
+> networking, use the WSL IP (`hostname -I | awk '{print $1}'`)
+> instead.
+
+### Verify from the ROS 2 side (optional)
+
+```bash
+# Always works (explicit type), even before any browser tab is connected:
+ros2 topic echo /chatter std_msgs/msg/String
+
+# Auto-discovery form — only works after a browser tab is connected to
+# ws://.../topic/chatter (the bridge creates the subscription on demand)
+# and after a publisher exists on the topic (browser Publish, or the
+# `ros2 topic pub` command below):
+ros2 topic echo /chatter
+
+ros2 topic pub /chatter std_msgs/msg/String "{data: 'hi from ros2'}"
+ros2 service call /add_two_ints example_interfaces/srv/AddTwoInts "{a: 7, b: 5}"
+```
+
+> If you see `WARNING: topic [/chatter] does not appear to be published yet
+> / Could not determine the type for the passed topic`, it just means no
+> publisher exists on `/chatter` yet — use the explicit-type form above,
+> or click **Subscribe** + **Publish** in the browser first.
+
+Anything you publish from the browser shows up in `ros2 topic echo`,
+and any `ros2 topic pub` to `/chatter` shows up in the browser
+subscription log.
+
+## URL scheme reminder
+
+```
+ws://:/topic/?type=/msg/
+ws://:/service/?type=/srv/
+```
+
+This demo pre-declares both types server-side via `topicTypes` /
+`serviceTypes`, so the browser can omit `?type=`. See
+[`rosocket/README.md`](../../rosocket/README.md) for the full
+protocol reference.
diff --git a/demo/rosocket/index.html b/demo/rosocket/index.html
new file mode 100644
index 000000000..89e4aa872
--- /dev/null
+++ b/demo/rosocket/index.html
@@ -0,0 +1,212 @@
+
+
+
+
+
+ rosocket demo
+
+
+
+ rosocket demo
+
+ Browser ↔ ROS 2 over plain WebSocket. Adjust the bridge URL if your WSL
+ IP differs from localhost.
+
+
+ Bridge:
+
+
+
+ Topic: /chatter (std_msgs/msg/String)
+
+
+
+
+
+
+
+
+
+
+
+
+
// Subscribe — every published message arrives as onmessage.
+const sub = new WebSocket('ws://localhost:9000/topic/chatter');
+sub.onmessage = (ev) => console.log('recv:', ev.data);
+// e.g. {"data":"hi"}
+
+// Publish — open, send JSON, close.
+const ws = new WebSocket('ws://localhost:9000/topic/chatter');
+ws.onopen = () => {
+ ws.send(JSON.stringify({ data: 'hello from browser' }));
+ setTimeout(() => ws.close(), 200); // let it flush
+};
+
+
+ Service: /add_two_ints (example_interfaces/srv/AddTwoInts)
+
+
+
// Service call — send {id, request}, await one response, close.
+const ws = new WebSocket('ws://localhost:9000/service/add_two_ints');
+ws.onopen = () => ws.send(JSON.stringify({
+ id: 1,
+ request: { a: '2n', b: '3n' }, // int64 → "Nn" string
+}));
+ws.onmessage = (ev) => {
+ console.log('resp:', ev.data);
+ // {"id":1,"response":{"sum":"5n"}}
+ ws.close();
+};
+
+
+
+
+
diff --git a/demo/rosocket/server.js b/demo/rosocket/server.js
new file mode 100644
index 000000000..8e1d7061f
--- /dev/null
+++ b/demo/rosocket/server.js
@@ -0,0 +1,76 @@
+// Copyright (c) 2026 RobotWebTools Contributors. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+
+'use strict';
+
+// rosocket demo server.
+//
+// Bridges two ROS 2 endpoints to plain WebSocket URLs so a browser can
+// drive them with built-in `WebSocket` + `JSON`, no client library:
+//
+// ws://:9000/topic/chatter std_msgs/msg/String
+// ws://:9000/service/add_two_ints example_interfaces/srv/AddTwoInts
+//
+// Run inside WSL (where ROS 2 is sourced):
+// node demo/rosocket/server.js
+//
+// To exercise the service, start the existing AddTwoInts example in a
+// second terminal (it implements `/add_two_ints`):
+// node example/services/service/service-example.js
+//
+// Then open demo/rosocket/index.html on the Windows host browser. WSL2
+// forwards localhost so `ws://localhost:9000` works as-is. See README.md
+// for fallback instructions.
+
+const rclnodejs = require('../../index.js');
+const { startRosocket } = require('../../rosocket');
+
+const PORT = Number(process.env.PORT) || 9000;
+const HOST = process.env.HOST || '0.0.0.0';
+
+async function main() {
+ await rclnodejs.init();
+ const node = rclnodejs.createNode('rosocket_demo_node');
+ rclnodejs.spin(node);
+
+ const bridge = await startRosocket({
+ node,
+ port: PORT,
+ host: HOST,
+ topicTypes: {
+ '/chatter': 'std_msgs/msg/String',
+ },
+ serviceTypes: {
+ '/add_two_ints': 'example_interfaces/srv/AddTwoInts',
+ },
+ });
+
+ console.log(
+ `[rosocket-demo] listening on ws://localhost:${bridge.port} (bind=${HOST})`
+ );
+ console.log('[rosocket-demo] endpoints:');
+ console.log(' ws://localhost:9000/topic/chatter');
+ console.log(' ws://localhost:9000/service/add_two_ints');
+ console.log('Open demo/rosocket/index.html in the host browser to try it.');
+
+ const shutdown = () => {
+ bridge.close().finally(() => {
+ try {
+ rclnodejs.shutdown();
+ } catch (_) {}
+ process.exit(0);
+ });
+ };
+ process.on('SIGINT', shutdown);
+ process.on('SIGTERM', shutdown);
+}
+
+main().catch((e) => {
+ console.error(e.stack || e.message);
+ process.exit(1);
+});
diff --git a/ts_demo/README.md b/demo/typescript/README.md
similarity index 94%
rename from ts_demo/README.md
rename to demo/typescript/README.md
index 9619ade74..3ce710873 100644
--- a/ts_demo/README.md
+++ b/demo/typescript/README.md
@@ -59,7 +59,7 @@ Asynchronous actions with progress feedback and cancellation
## 🔗 Related Resources
-- [rclnodejs Tutorials](../tutorials/) - Comprehensive API documentation
-- [Electron Demos](../electron_demo/) - GUI applications with rclnodejs
+- [rclnodejs Tutorials](../../tutorials/) - Comprehensive API documentation
+- [Electron Demos](../electron/) - GUI applications with rclnodejs
- [TypeScript Handbook](https://www.typescriptlang.org/docs/) - Language reference
- [ROS2 Documentation](https://docs.ros.org/) - Official ROS2 concepts
diff --git a/ts_demo/actions/README.md b/demo/typescript/actions/README.md
similarity index 99%
rename from ts_demo/actions/README.md
rename to demo/typescript/actions/README.md
index 015d9f3c9..447e28b94 100644
--- a/ts_demo/actions/README.md
+++ b/demo/typescript/actions/README.md
@@ -32,7 +32,7 @@ This demo implements a Fibonacci sequence calculator using ROS2 actions:
## Project Structure
```
-ts_demo/actions/
+demo/typescript/actions/
├── src/
│ ├── client.ts # Action client implementation
│ └── server.ts # Action server implementation
@@ -74,7 +74,7 @@ Before running this demo, ensure you have:
3. **Navigate to the demo directory**:
```bash
- cd ts_demo/actions
+ cd demo/typescript/actions
```
4. **Install dependencies**:
diff --git a/ts_demo/actions/package.json b/demo/typescript/actions/package.json
similarity index 100%
rename from ts_demo/actions/package.json
rename to demo/typescript/actions/package.json
diff --git a/ts_demo/actions/src/client.ts b/demo/typescript/actions/src/client.ts
similarity index 100%
rename from ts_demo/actions/src/client.ts
rename to demo/typescript/actions/src/client.ts
diff --git a/ts_demo/actions/src/server.ts b/demo/typescript/actions/src/server.ts
similarity index 100%
rename from ts_demo/actions/src/server.ts
rename to demo/typescript/actions/src/server.ts
diff --git a/ts_demo/actions/tsconfig.json b/demo/typescript/actions/tsconfig.json
similarity index 100%
rename from ts_demo/actions/tsconfig.json
rename to demo/typescript/actions/tsconfig.json
diff --git a/ts_demo/services/README.md b/demo/typescript/services/README.md
similarity index 99%
rename from ts_demo/services/README.md
rename to demo/typescript/services/README.md
index df754bba8..26280c126 100644
--- a/ts_demo/services/README.md
+++ b/demo/typescript/services/README.md
@@ -48,7 +48,7 @@ npm run build
Navigate to this demo directory and install dependencies:
```bash
-cd ts_demo/services
+cd demo/typescript/services
npm install
```
diff --git a/ts_demo/services/package.json b/demo/typescript/services/package.json
similarity index 100%
rename from ts_demo/services/package.json
rename to demo/typescript/services/package.json
diff --git a/ts_demo/services/src/client.ts b/demo/typescript/services/src/client.ts
similarity index 100%
rename from ts_demo/services/src/client.ts
rename to demo/typescript/services/src/client.ts
diff --git a/ts_demo/services/src/server.ts b/demo/typescript/services/src/server.ts
similarity index 100%
rename from ts_demo/services/src/server.ts
rename to demo/typescript/services/src/server.ts
diff --git a/ts_demo/services/tsconfig.json b/demo/typescript/services/tsconfig.json
similarity index 100%
rename from ts_demo/services/tsconfig.json
rename to demo/typescript/services/tsconfig.json
diff --git a/ts_demo/topics/README.md b/demo/typescript/topics/README.md
similarity index 99%
rename from ts_demo/topics/README.md
rename to demo/typescript/topics/README.md
index ee158beb9..928ec2f98 100644
--- a/ts_demo/topics/README.md
+++ b/demo/typescript/topics/README.md
@@ -47,7 +47,7 @@ npm run build
Navigate to this demo directory and install dependencies:
```bash
-cd ts_demo/topics
+cd demo/typescript/topics
npm install
```
@@ -162,7 +162,7 @@ Starting TypeScript Subscriber Demo...
## Project Structure
```
-ts_demo/topics/
+demo/typescript/topics/
├── package.json # Project dependencies and scripts
├── tsconfig.json # TypeScript configuration
├── README.md # This file
@@ -239,7 +239,7 @@ This demo showcases several TypeScript advantages:
**Solution**: Ensure you're in the correct directory and rclnodejs is properly linked:
```bash
- cd ts_demo/topics
+ cd demo/typescript/topics
npm install
```
diff --git a/ts_demo/topics/package.json b/demo/typescript/topics/package.json
similarity index 100%
rename from ts_demo/topics/package.json
rename to demo/typescript/topics/package.json
diff --git a/ts_demo/topics/src/publisher.ts b/demo/typescript/topics/src/publisher.ts
similarity index 100%
rename from ts_demo/topics/src/publisher.ts
rename to demo/typescript/topics/src/publisher.ts
diff --git a/ts_demo/topics/src/subscriber.ts b/demo/typescript/topics/src/subscriber.ts
similarity index 100%
rename from ts_demo/topics/src/subscriber.ts
rename to demo/typescript/topics/src/subscriber.ts
diff --git a/ts_demo/topics/tsconfig.json b/demo/typescript/topics/tsconfig.json
similarity index 100%
rename from ts_demo/topics/tsconfig.json
rename to demo/typescript/topics/tsconfig.json
diff --git a/eslint.config.mjs b/eslint.config.mjs
index a40fdcaab..75f596d21 100644
--- a/eslint.config.mjs
+++ b/eslint.config.mjs
@@ -15,7 +15,7 @@ export default [
"**/scripts/",
"**/benchmark/",
"**/docs/",
- "**/electron_demo/",
+ "**/demo/electron/",
],
},
{
diff --git a/scripts/npmjs-readme.md b/scripts/npmjs-readme.md
index 5d1cca269..73fc37543 100644
--- a/scripts/npmjs-readme.md
+++ b/scripts/npmjs-readme.md
@@ -68,8 +68,9 @@ npm install rclnodejs
- API documentation: [robotwebtools.github.io/rclnodejs/docs](https://robotwebtools.github.io/rclnodejs/docs/index.html)
- Tutorials: [tutorials/](https://github.com/RobotWebTools/rclnodejs/tree/develop/tutorials)
- JavaScript examples: [example/](https://github.com/RobotWebTools/rclnodejs/tree/develop/example)
-- TypeScript demos: [ts_demo/](https://github.com/RobotWebTools/rclnodejs/tree/develop/ts_demo)
-- Electron demos: [electron_demo/](https://github.com/RobotWebTools/rclnodejs/tree/develop/electron_demo)
+- TypeScript demos: [demo/typescript/](https://github.com/RobotWebTools/rclnodejs/tree/develop/demo/typescript)
+- Electron demos: [demo/electron/](https://github.com/RobotWebTools/rclnodejs/tree/develop/demo/electron)
+- WebSocket bridge demo: [demo/rosocket/](https://github.com/RobotWebTools/rclnodejs/tree/develop/demo/rosocket)
- Companion CLI: [rclnodejs-cli](https://github.com/RobotWebTools/rclnodejs-cli/)
## Message Generation
From 459a0f71debb50aff7d01c8bf0910937881a9133 Mon Sep 17 00:00:00 2001
From: Minggang Wang
Date: Wed, 6 May 2026 18:05:15 +0800
Subject: [PATCH 2/2] Address comments
---
demo/rosocket/README.md | 8 ++++----
demo/rosocket/index.html | 12 ++++++++++--
demo/rosocket/server.js | 8 +++++---
3 files changed, 19 insertions(+), 9 deletions(-)
diff --git a/demo/rosocket/README.md b/demo/rosocket/README.md
index 830d5cd44..6e35b96ae 100644
--- a/demo/rosocket/README.md
+++ b/demo/rosocket/README.md
@@ -1,10 +1,10 @@
# rosocket demo (browser ↔ ROS 2)
A minimal end-to-end example of the
-[`rosocket`](../../rosocket/README.md) WebSocket bridge added in
-commit `3176aca`. The Node server runs anywhere ROS 2 is sourced;
-the HTML page runs in any modern browser and talks to it over plain
-`WebSocket` — no client library required.
+[`rosocket`](../../rosocket/README.md) WebSocket bridge. The Node
+server runs anywhere ROS 2 is sourced; the HTML page runs in any
+modern browser and talks to it over plain `WebSocket` — no client
+library required.
## What it shows
diff --git a/demo/rosocket/index.html b/demo/rosocket/index.html
index 89e4aa872..aba379cc4 100644
--- a/demo/rosocket/index.html
+++ b/demo/rosocket/index.html
@@ -37,6 +37,14 @@
overflow: auto;
white-space: pre-wrap;
}
+ .log {
+ background: #f4f4f4;
+ padding: 0.5em;
+ max-height: 12em;
+ overflow: auto;
+ font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
+ font-size: 0.9em;
+ }
.demo {
display: grid;
grid-template-columns: 1fr 1fr;
@@ -102,7 +110,7 @@ Topic: /chatter (std_msgs/msg/String)
-
+
// Subscribe — every published message arrives as onmessage.
const sub = new WebSocket('ws://localhost:9000/topic/chatter');
@@ -125,7 +133,7 @@ Service: /add_two_ints (example_interfaces/srv/AddTwoInts)
-
+
// Service call — send {id, request}, await one response, close.
const ws = new WebSocket('ws://localhost:9000/service/add_two_ints');
diff --git a/demo/rosocket/server.js b/demo/rosocket/server.js
index 8e1d7061f..5f5898d1f 100644
--- a/demo/rosocket/server.js
+++ b/demo/rosocket/server.js
@@ -50,12 +50,14 @@ async function main() {
},
});
+ const displayHost = HOST === '0.0.0.0' || HOST === '::' ? 'localhost' : HOST;
+ const baseUrl = `ws://${displayHost}:${bridge.port}`;
console.log(
- `[rosocket-demo] listening on ws://localhost:${bridge.port} (bind=${HOST})`
+ `[rosocket-demo] listening on ${baseUrl} (bind=${HOST}:${bridge.port})`
);
console.log('[rosocket-demo] endpoints:');
- console.log(' ws://localhost:9000/topic/chatter');
- console.log(' ws://localhost:9000/service/add_two_ints');
+ console.log(` ${baseUrl}/topic/chatter`);
+ console.log(` ${baseUrl}/service/add_two_ints`);
console.log('Open demo/rosocket/index.html in the host browser to try it.');
const shutdown = () => {