Co-Chuck: WebChucK IDE with Multi-User Collaboration and Synchronized ChucK Shreds
Co-Chuck is an enhanced version of the WebChuck IDE that enables multi-user collaboration, concurrent code editing, and project file synchronization. It also synchronizes ChucK Shred playback across distributed devices, allowing users to collaboratively write and execute ChucK code directly in their browsers—just like Google Docs, but for music/audio programming!
This project builds upon ccrma/webchuck-ide
v2.1.4. Explore the links below to learn more about the projects that inspired and provided the foundation for Co-Chuck:
- Full WebChuck IDE: Co-Chuck retains all the functionality of the original WebChuck IDE, a web-based integrated development environment (IDE) for real-time sound synthesis and music creation with ChucK.
- Session Management: Create, join, and close Co-Chuck sessions. Each session serves as a virtual "room" for up to 16 users to collaborate on a ChucK project. All you need is a username and a session ID.
- File Synchronization: Keep files synchronized across users in the same session. Actions such as creating, deleting, exploring, or modifying files (including adding examples) are instantly reflected for everyone. Files actively edited by another user are protected from deletion.
- Real-Time Editor Sync: Collaborate on a single file simultaneously. Co-Chuck uses Myers's Difference Algorithm and custom server-client mechanisms to perform conflict resolution in real-time.
- File and Cursor Location Sync: View the list of active users in the session, the file they are working on, and their current cursor position—similar to Google Docs.
- Synchronized Shred Playback: Play/stop synchronized ChucK Shreds across devices with a single button click. Co-Chuck implements a custom clock-synchronization mechanism to ensure precise playback timing (starts 1.5 seconds after the button is clicked).
- Production-ready full-stack deployment with NginX, Uvicorn, FastAPI, and Docker. The above diagram shows the overall service architecture.
- File, text, and user location synchronization through HTTP polling.
- Session state management, clock synchronization, and real-time user activity tracking with WebSocket.
- Automatic session clean-up, removing inactive users and sessions with no users.
- Custom network clock synchronization using WebSocket for synchronized Shred playback across multiple devices over the internet.
- FastAPI endpoints for creating, joining, and synchronizing sessions, adding, removing, and downloading files, managing projects, and broadcasting ChucK Shreds.
- In-memory session state management for fast sync (future plans to migrate to an external in-memory key-value store like Redis).
- New
SessionManager
andSessionSystem
classes for session handling (located insrc/components/session
).
Sample screenshot of Co-Chuck
Here are a few usage examples of Co-Chuck.
- Create a New Session: Start a new session and obtain a session ID to share with collaborators.
- Join an Existing Session: Enter a session ID to join a collaboration room.
- Close Current Session: End your session when collaboration is complete. Your project files will be retained in your browser.
- View Session Information: Check session details, including session ID and active users.
- Add/Remove Files (Synchronized): Create, edit, and delete files with real-time synchronization across all users. This also works with adding ChucK examples.
- Edit Files Together: Collaboratively work on files with real-time synchronization and conflict resolution.
- View Active Users: See a list of users in the session along with their names.
- Cursor Tracking: Monitor where other collaborators are editing within the file.
- Broadcast Shreds: Play or stop synchronized Shreds across all participants with precise timing.
The frontend was developed using Node.js v20.11.0.
-
Clone the repository:
git clone https://github.com/stuartsul/co-chuck cd webchuck-ide
-
Install dependencies:
npm install
-
Run the development server:
npm run dev
This starts a local development server.
-
Generate optimized static files for production in the
/dist
folder:npm run build
The backend is developed using Python 3.12 and FastAPI.
-
Create and activate a Python virtual environment of your choice (e.g., Conda,
venv
). -
Install dependencies:
cd api pip install -r requirements.txt
-
Run the FastAPI server in development using Uvicorn:
cd api uvicorn app.main:app --reload
Now the server should be accessible at
http://localhost:8000
For production deployment, read the next section.
It is recommended to set up TLS to enable HTTPS and WSS connections. To do this, I highly encourage using Let's Encrypt, which is free and easy-to-use. The following steps assume an Ubuntu environment.
-
SSH into your host machine:
ssh user@your-host
-
Install system dependencies:
sudo apt-get remove certbot # remove existing certbot installation sudo apt update sudo apt upgrade -y sudo apt install python3 python3-venv libaugeas0
-
Set up a Python virtual environment:
sudo python3 -m venv /opt/certbot/ sudo /opt/certbot/bin/pip install --upgrade pip
-
Install Certbot on the virtual environment:
sudo /opt/certbot/bin/pip install certbot
-
Create a command alias (for convenience):
sudo ln -s /opt/certbot/bin/certbot /usr/bin/certbot
-
Issue a TLS certificate:
sudo certbot certonly --standalone
After running this command, your TLS certificates should be located at
/etc/letsencrypt/live/<YOUR_DOMAIN>
directory. The certificate files will be namedfullchain.pem
(including both your domain's certificate and CA certificate), and the TLS private key will be namedprivkey.pem
. -
Integrate TLS with Your Web Server.
Almost all of web servers out there have support for TLS. Uvicorn, for example, can be set up with:
uvicorn main:app --host 0.0.0.0 --port 443 --ssl-keyfile /path/to/privkey.pem --ssl-certfile /path/to/fullchain.pem
-
(Optional) Set up automatic certificate renewal:
echo "0 0,12 * * * root /opt/certbot/bin/python -c 'import random; import time; time.sleep(random.random() * 3600)' && sudo certbot renew -q" | sudo tee -a /etc/crontab > /dev/null
-
Verify your setup by visiting your website with
https://...
-
Make sure to update certbot every month:
sudo /opt/certbot/bin/pip install --upgrade certbot
It is recommended to deploy the Co-Chuck backend API as a Docker container using the provided Dockerfile in the /api directory. The following steps assume an Ubuntu environment.
-
Add Docker's
apt
repository:sudo apt-get update sudo apt-get install ca-certificates curl sudo install -m 0755 -d /etc/apt/keyrings sudo curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc sudo chmod a+r /etc/apt/keyrings/docker.asc echo \ "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/ubuntu \ $(. /etc/os-release && echo "$VERSION_CODENAME") stable" | \ sudo tee /etc/apt/sources.list.d/docker.list > /dev/null sudo apt-get update
-
Install Docker:
sudo apt-get install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
-
(Optional) Set up permissions so that you can use Docker in the host without sudo permissions:
sudo groupadd docker sudo usermod -aG docker $USER
-
Verify that Docker service is running:
sudo docker run --rm hello-world systemctl status docker
-
Build and run Co-Chuck API:
cd api docker build -t cochuck-api . docker run -d \ --name cochuck-api \ --restart always \ -p 9435:9435 \ cochuck-api
Note that this runs the server without any TLS encryption. We will worry about that in the next section. Specifically, we will not expose this server directly, but run it behind a TLS termination proxy.
The final step is to put everything together with NginX. It will serve the static frontend files, and route requests to /api/...
to our FastAPI backend API server running inside a Docker container. The NginX itself, of course, will be run inside a Docker container as well.
-
Place your frontend build files in
/usr/share/nginx/html
. Ensure index.html is present at/usr/share/nginx/html/index.html
. If you don't want this, update theroot
configuration in the next step. -
Create an NginX configuration file. Save the following configuration to /etc/nginx/conf.d/default.conf. Replace <YOUR_DOMAIN> with your domain name:
server { listen 443 ssl; server_name <YOUR_DOMAIN>; # Set maximum file size to 10 MB globally client_max_body_size 10M; # TLS Certificates ssl_certificate /etc/letsencrypt/live/<YOUR_DOMAIN>/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/<YOUR_DOMAIN>/privkey.pem; # SSL settings ssl_protocols TLSv1.2 TLSv1.3; ssl_ciphers HIGH:!aNULL:!MD5; # Serve static frontend build files location / { root /usr/share/nginx/html; index index.html; try_files $uri /index.html; # SPA fallback to index.html } # Proxy API requests to the FastAPI backend location /api/ { proxy_pass http://cochuck-api:9435/; # Ensure this matches the container name rewrite ^/api(/.*)$ $1 break; # Strip off `/api` from the path proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; # Websocket support proxy_set_header Connection "upgrade"; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; } } # Redirect HTTP to HTTPS server { listen 80; server_name <YOUR_DOMAIN>; return 301 https://$host$request_uri; }
-
Create a Docker network. Because NginX container and the FastAPI container must be able to communicate over a network, we should define a custom network that they can use.
docker network create cochuck-network
-
Re-start the FastAPI container using this network. Note that unlike in the previous section, port-forwarding is no longer required.
cd api docker build -t cochuck-api . docker run -d \ --name cochuck-api \ --restart always \ --network cochuck-network \ cochuck-api
-
Run NginX using the same network.
# This assumes that you have issued certificates using Let's Encrypt docker run -d \ --name cochuck \ --restart always \ --network cochuck-network \ -p 80:80 \ -p 443:443 \ -v /etc/nginx/conf.d/default.conf:/etc/nginx/conf.d/default.conf:ro \ -v /usr/share/nginx/html:/usr/share/nginx/html:ro \ -v /etc/letsencrypt:/etc/letsencrypt:ro \ nginx:alpine
-
Ensure ports 80 and 443 are open for incoming connections in your firewall settings.
- Class Comments and Docstrings: Add detailed comments and docstrings for all new classes and functions.
- State Persistence: Implement an external in-memory database (e.g., Redis) to enable persistent state storage and session-agnostic connections.
- Sync Optimization: Optimize synchronization processes to minimize data transfer and reduce interference with the main JavaScript thread (e.g., improve
Editor.updateEditorCode
function). - Minor Glitch Fixes: Resolve occasional synchronization glitches, such as the editor cursor moving one character ahead of its intended position.
Contributions are welcome! Please report issues and open PRs freely in this repository.
Note: You will need to run npm run lint
and npm run format
to pass build checks.