https://github.com/usini/bete
Mindmap pense-bete pixel art - site statique
https://github.com/usini/bete
Last synced: 1 day ago
JSON representation
Mindmap pense-bete pixel art - site statique
- Host: GitHub
- URL: https://github.com/usini/bete
- Owner: usini
- Created: 2026-06-23T17:29:27.000Z (11 days ago)
- Default Branch: main
- Last Pushed: 2026-07-01T15:50:18.000Z (3 days ago)
- Last Synced: 2026-07-01T17:28:09.442Z (3 days ago)
- Language: JavaScript
- Homepage: https://usini.github.io/bete/
- Size: 634 KB
- Stars: 0
- Watchers: 0
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
Awesome Lists containing this project
README
# Bete
Pixel-art mindmap. 100% static site, zero dependencies, zero build step.
## Run locally
ES modules don't work over `file://`, so you need a small server:
```bash
python -m http.server 8000
# then open http://localhost:8000
```
## Deploy to GitHub Pages
1. Push the repo to GitHub.
2. `Settings → Pages → Build and deployment → Source: Deploy from a branch`.
3. Branch `main`, folder `/ (root)`. The site is served as-is.
For a custom domain: `Settings → Pages → Custom domain`, and a `CNAME` file
(containing your domain) appears at the repo root — replace it or delete it
if you fork the project to host it under a different domain.
## Language
The app is available in French and English. It guesses the language from
the browser on first visit; your choice in Settings → Language is then
remembered and always takes priority. Adding a new language is a small,
self-contained change in `js/i18n.js` (one dictionary object + one list
entry) — see the comments there.
## Usage
- **Right-click**: radial menu (create rectangle/sign/circle/hexagon/liaison, color, text, delete, export/import).
- **Sign**: a larger rectangle with a wood texture, for titles/panels.
- **Deleting** an object makes it **explode into pieces** (animation, synced with clients).
- **Wheel**: zoom · **drag the background**: pan the view.
- **Drag a rectangle**: elastic movement.
- **Drag a circle/hexagon's edge**: resize · **drag its inside**: move it.
- **Double-click**: edit the text (Escape to confirm). On an **image rectangle**: opens the image full-size.
- **Drag-and-drop an image** (or **Ctrl-V** an image from the clipboard): onto a rectangle to put it inside, onto empty space to create an image rectangle ("Remove image" to take it out). The image is always shown **in full**; the rectangle keeps a roughly constant size.
- **Link** (radial menu on a rectangle): attaches a URL; an ↗ badge appears and a **click** opens the link in a new tab.
- **Delete**: erases the selected element.
- **Ctrl-C / Ctrl-V**: copy-paste the selected element (pasted at the mouse position).
- A rectangle whose center is inside a circle/hexagon takes its color.
### Hexagons & links
A **hexagon** (e.g. "Today") aggregates **links** to rectangles stored elsewhere.
Drag a rectangle (from a circle) into a hexagon: a **link** (dashed border) is
created, the original goes back to its place. The link keeps the **source
circle's color** and mirrors its text/image; renaming or deleting the source
updates (or removes) the link. Links can be freely placed inside the hexagon.
### Sync across devices (P2P)
To copy your board from one device to another (e.g. desktop → phone):
1. On the **source** device (HOST): radial menu → **"+ Liaison"**. A QR code block appears.
2. On the other device (CLIENT): **scan the QR** (or open the link — clicking the block copies it).
3. Once connected, the client's board is replaced by the host's, then both stay **synced live, in both directions**, as long as the host's window stays open.
**Synced**: the content (text, image, color, description, links, creations/deletions) and the **objects' positions** — but the latter only **on drop** (not during the drag), and the other screen **animates** it. **The camera stays independent**: each screen keeps its own zoom/framing (e.g. one screen zoomed out, another zoomed into a circle). If the same element is edited simultaneously, **the host wins**.
**Encrypted P2P connection** (WebRTC via PeerJS); only connection identifiers go through the signaling broker, the content travels directly between the two browsers. The PeerJS / QR libs are loaded on demand (CDN), the app stays dependency-free at rest. Images and voice memos are stored locally (IndexedDB) and only transit once per peer, never through the broker.
**Permanent host (optional)**: to keep sync available even with all browsers closed, you can run a small Node server on a Raspberry Pi that acts as a permanent host — see [`server/`](server/README.md). The app doesn't need any modification: devices connect to it via `?peer=`.
The liaison id is **stable** (remembered): refreshing the host's page and recreating the liaison gives back **the same link/QR**. On a network drop, the host automatically reconnects to the broker (same id) and clients retry the connection — no need to rescan. If the link leaks, **"New link"** (liaison block menu) regenerates an id: the old URL becomes invalid, the board is preserved.
Privacy-wise: content travels over encrypted WebRTC (DTLS), directly between peers in the normal case; if a direct connection isn't possible, it's relayed (encrypted) by PeerJS's TURN servers. The broker only ever sees connection identifiers.
### Mobile / touch
- **Interaction locked by default** (so a block isn't accidentally moved): only panning (1 finger) and zooming (pinch) work. **Long-press** then only offers **"Enable"**. Once enabled, the standard radial menu comes back (with **"Lock"** to re-lock it).
- **1 finger**: drags the background (pan) or, once enabled, moves an element.
- **2 fingers**: pinch to zoom.
- **Long-press**: radial menu · **double-tap**: edit / view the image (interaction enabled).
Automatic save in the browser (localStorage). JSON export/import via the radial menu.
## Open a board from a URL
Adding `?file=` to the address loads that JSON instead of localStorage, without overwriting your personal board:
```
https://your-instance.example/?file=https://example.com/board.json
```
The file must be accessible over CORS (same origin, raw.githubusercontent.com, gist…). A relative path also works: `?file=boards/demo.json`.