chore: drop liveblocks dependency

Remove @liveblocks/client and @liveblocks/zustand; add ws and a
server npm script. Update README (fork attribution preserved, WS
backend usage), .env.example (VITE_RT_URL), and pin the /blocs-pro/
base in vite.config.
This commit is contained in:
L'électron rare
2026-06-13 18:04:28 +02:00
parent 8a34b1d333
commit c8dff33836
5 changed files with 72 additions and 82 deletions
+3 -1
View File
@@ -1 +1,3 @@
VITE_LIVEBLOCKS_API_KEY=YOU_LIVEBLOCKS_API_KEY
# Realtime WebSocket backend URL. Optional.
# If unset: dev -> ws://localhost:8090 ; prod (https) -> wss://<host>/blocs-rt
VITE_RT_URL=ws://localhost:8090
+37 -29
View File
@@ -1,15 +1,17 @@
# 3D Lego-like Brick Builder Web App
Build and collaborate in real-time on 3D models using rectangular bricks. This multi-user application allows users to create intricate designs in a 3D space using Lego-like bricks.
Build and collaborate in real-time on 3D models using rectangular bricks. This multi-user application lets several people create designs together in a shared 3D space using Lego-like bricks.
![App Screenshot](/public/Screenshot.png)
> Fork of [bhushan6/lego-builder](https://github.com/bhushan6/lego-builder) (MIT — see `LICENSE`, attribution preserved). The original used the **Liveblocks** SaaS for real-time collaboration; this fork replaces it with a **self-hosted, sovereign WebSocket backend** (`server/index.js`) — no third-party SaaS, no API key.
## Features
- **3D Rendering**: Utilizes `three.js` and `react-three-fiber` for efficient and smooth 3D rendering.
- **Real-time Collaboration**: Integrated with `liveblocks` to enable users to collaborate in real-time.
- **Intuitive UI**: Built with `radix ui` to provide a seamless user experience.
- **State Management**: `Zustand` is being used as state management solution.
- **Real-time Collaboration**: Self-hosted WebSocket relay (`server/index.js`) synchronizes the shared build (`bricks`, `cursorColors`) and per-user presence/cursors across everyone in a room.
- **Intuitive UI**: Built with `radix ui`.
- **State Management**: `Zustand`, with a custom `roomSync` middleware (`src/store/roomSync.js`) that exposes the same store surface the components expect.
## Technologies Used
@@ -17,64 +19,70 @@ Build and collaborate in real-time on 3D models using rectangular bricks. This m
- [three.js](https://threejs.org/)
- [react-three-fiber](https://github.com/pmndrs/react-three-fiber)
- [radix ui](https://www.radix-ui.com/)
- [liveblocks](https://liveblocks.io/)
- [zustand](https://docs.pmnd.rs/zustand/getting-started/introduction)
- [ws](https://github.com/websockets/ws) — WebSocket server for the real-time backend
- [Vite](https://vitejs.dev/)
## Live Demo
## Real-time architecture
Experience the app live [here](<[your_live_project_link](https://lego-builder.vercel.app/)>).
- **`server/index.js`** — a standalone Node WebSocket relay (uses `ws`, no build step). One server hosts many rooms; per room it keeps the current shared storage snapshot (`{ bricks, cursorColors }`) plus the connected clients. Clients connect with `ws(s)://HOST/?room=<id>`. JSON protocol:
- server → client: `init`, `join`, `leave`, `presence`, `storage`, `event`
- client → server: `presence`, `storage` (last-writer-wins), `event` (ephemeral cursors, relayed to others only, never persisted)
- **`src/store/roomSync.js`** — a Zustand middleware that drops in for `@liveblocks/zustand`. It exposes `state.liveblocks.{enterRoom, leaveRoom, status, others, room}` where `room` has `broadcastEvent`, `subscribe("event", cb)` and no-op `history.undo/redo` stubs — so the existing components work unchanged.
## Local Development
### Prerequisites
- [Node.js](https://nodejs.org/)
- [Yarn](https://yarnpkg.com/) or [npm](https://www.npmjs.com/)
- [Node.js](https://nodejs.org/) (18+; tested on Node 26)
- [npm](https://www.npmjs.com/)
### Setup
1. Clone the repository:
```bash
git clone https://github.com/bhushan6/lego-builder.git
```
2. Navigate to the project directory:
```bash
git clone https://git.saillant.cc/electron-rare/lego-builder.git
cd lego-builder
```
3. Install the dependencies:
```bash
yarn install
```
or
2. Install dependencies:
```bash
npm install
```
4. Create a .env file in the root directory and add your Liveblocks public API key:
3. (Optional) point the client at a specific realtime server. Create `.env`:
```bash
echo "VITE_LIVEBLOCKS_API_KEY=your_liveblocks_public_api_key" > .env
echo "VITE_RT_URL=ws://localhost:8090" > .env
```
Replace your_liveblocks_public_api_key with your actual Liveblocks public API key.
If unset, the client falls back to `ws://localhost:8090` in dev, or
`wss://<your-host>/blocs-rt` when served over HTTPS in production (that path
is routed to the relay by the deployment infra).
4. Start the realtime server (in one terminal):
5. Start the development server:
```bash
yarn dev
npm run server # listens on $PORT (default 8090)
```
or
5. Start the dev server (in another terminal):
```bash
npm run dev
```
6. Open your browser and navigate to http://127.0.0.1:5173/ (or the port you've configured).
6. Open the app at the URL Vite prints (note the `/blocs-pro/` base path,
e.g. http://localhost:5173/blocs-pro/). Open it in two browsers/tabs and
join the **same Room ID** to collaborate.
### Build
```bash
npm run build # outputs dist/, served under base /blocs-pro/
```
## Contribution
+28 -49
View File
@@ -8,8 +8,6 @@
"name": "lego-builder",
"version": "0.0.0",
"dependencies": {
"@liveblocks/client": "^1.2.2",
"@liveblocks/zustand": "^1.2.2",
"@radix-ui/colors": "^2.0.1",
"@radix-ui/react-checkbox": "^1.0.4",
"@radix-ui/react-dialog": "^1.0.4",
@@ -29,6 +27,7 @@
"react-dom": "^18.2.0",
"three": "^0.155.0",
"use-keyboard-shortcut": "^1.1.6",
"ws": "^8.18.0",
"zustand": "^4.4.1"
},
"devDependencies": {
@@ -984,31 +983,6 @@
"@jridgewell/sourcemap-codec": "^1.4.14"
}
},
"node_modules/@liveblocks/client": {
"version": "1.2.2",
"resolved": "https://registry.npmjs.org/@liveblocks/client/-/client-1.2.2.tgz",
"integrity": "sha512-cav7NIoZNGmOC07p/spaCiNwLL/eeKKTAscLb2wN5myXG+xWlf6sj6zIxMOSA1eTDcDDvDMsnkLUviUUK0QGWA==",
"dependencies": {
"@liveblocks/core": "1.2.2"
}
},
"node_modules/@liveblocks/core": {
"version": "1.2.2",
"resolved": "https://registry.npmjs.org/@liveblocks/core/-/core-1.2.2.tgz",
"integrity": "sha512-1WALetZ600EN3D4VaSpXse2Plp5+7os78B1kAANlOmf/NtiQKIoEBE40xYBVd4QAJgX6YIYGjOsQQja0CUqs7g=="
},
"node_modules/@liveblocks/zustand": {
"version": "1.2.2",
"resolved": "https://registry.npmjs.org/@liveblocks/zustand/-/zustand-1.2.2.tgz",
"integrity": "sha512-F8xTtR3yE2SJ5FYHMpdAu6mheSBubjc4AekNaoePg2uV8BfZljNT1VrU+1SKCCEddV1e96OOYQqP+iBJcryYhg==",
"dependencies": {
"@liveblocks/client": "1.2.2",
"@liveblocks/core": "1.2.2"
},
"peerDependencies": {
"zustand": "^4.1.3"
}
},
"node_modules/@mediapipe/tasks-vision": {
"version": "0.10.2",
"resolved": "https://registry.npmjs.org/@mediapipe/tasks-vision/-/tasks-vision-0.10.2.tgz",
@@ -5283,6 +5257,27 @@
"integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==",
"dev": true
},
"node_modules/ws": {
"version": "8.21.0",
"resolved": "https://registry.npmjs.org/ws/-/ws-8.21.0.tgz",
"integrity": "sha512-Vsp28b7DRcimFQvrqu2Wek3z1iYxDCWqHYB8Qsnk/S4RfaCQzPGPyBNuVjJV3cd6UiKtUtp6sNM77gWvzcCH+g==",
"license": "MIT",
"engines": {
"node": ">=10.0.0"
},
"peerDependencies": {
"bufferutil": "^4.0.1",
"utf-8-validate": ">=5.0.2"
},
"peerDependenciesMeta": {
"bufferutil": {
"optional": true
},
"utf-8-validate": {
"optional": true
}
}
},
"node_modules/yallist": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz",
@@ -5937,28 +5932,6 @@
"@jridgewell/sourcemap-codec": "^1.4.14"
}
},
"@liveblocks/client": {
"version": "1.2.2",
"resolved": "https://registry.npmjs.org/@liveblocks/client/-/client-1.2.2.tgz",
"integrity": "sha512-cav7NIoZNGmOC07p/spaCiNwLL/eeKKTAscLb2wN5myXG+xWlf6sj6zIxMOSA1eTDcDDvDMsnkLUviUUK0QGWA==",
"requires": {
"@liveblocks/core": "1.2.2"
}
},
"@liveblocks/core": {
"version": "1.2.2",
"resolved": "https://registry.npmjs.org/@liveblocks/core/-/core-1.2.2.tgz",
"integrity": "sha512-1WALetZ600EN3D4VaSpXse2Plp5+7os78B1kAANlOmf/NtiQKIoEBE40xYBVd4QAJgX6YIYGjOsQQja0CUqs7g=="
},
"@liveblocks/zustand": {
"version": "1.2.2",
"resolved": "https://registry.npmjs.org/@liveblocks/zustand/-/zustand-1.2.2.tgz",
"integrity": "sha512-F8xTtR3yE2SJ5FYHMpdAu6mheSBubjc4AekNaoePg2uV8BfZljNT1VrU+1SKCCEddV1e96OOYQqP+iBJcryYhg==",
"requires": {
"@liveblocks/client": "1.2.2",
"@liveblocks/core": "1.2.2"
}
},
"@mediapipe/tasks-vision": {
"version": "0.10.2",
"resolved": "https://registry.npmjs.org/@mediapipe/tasks-vision/-/tasks-vision-0.10.2.tgz",
@@ -8827,6 +8800,12 @@
"integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==",
"dev": true
},
"ws": {
"version": "8.21.0",
"resolved": "https://registry.npmjs.org/ws/-/ws-8.21.0.tgz",
"integrity": "sha512-Vsp28b7DRcimFQvrqu2Wek3z1iYxDCWqHYB8Qsnk/S4RfaCQzPGPyBNuVjJV3cd6UiKtUtp6sNM77gWvzcCH+g==",
"requires": {}
},
"yallist": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz",
+3 -3
View File
@@ -7,11 +7,10 @@
"dev": "vite",
"build": "vite build",
"lint": "eslint . --ext js,jsx --report-unused-disable-directives --max-warnings 0",
"preview": "vite preview"
"preview": "vite preview",
"server": "node server/index.js"
},
"dependencies": {
"@liveblocks/client": "^1.2.2",
"@liveblocks/zustand": "^1.2.2",
"@radix-ui/colors": "^2.0.1",
"@radix-ui/react-checkbox": "^1.0.4",
"@radix-ui/react-dialog": "^1.0.4",
@@ -31,6 +30,7 @@
"react-dom": "^18.2.0",
"three": "^0.155.0",
"use-keyboard-shortcut": "^1.1.6",
"ws": "^8.18.0",
"zustand": "^4.4.1"
},
"devDependencies": {
+1
View File
@@ -3,5 +3,6 @@ import react from '@vitejs/plugin-react'
// https://vitejs.dev/config/
export default defineConfig({
base: '/blocs-pro/',
plugins: [react()],
})