Skip to content

mdotstrange/myetherspace

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

547 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

My Ether Space

A virtual world where every Ethereum wallet address gets its own unique house. Explore, customize, and socialize in a retro-styled pixelverse.

My Ether Space

What Is This?

My Ether Space is a multiplayer 2D world built entirely with vanilla JavaScript — no frameworks, no build system. Players connect their Ethereum wallet and are dropped into BlockSpace, a shared top-down world where they can walk around, visit other players' houses, chat, draw, make music, and send encrypted postcards.

Every Ethereum address automatically gets a house. You can customize your house inside and out using the built-in level editor, and visitors can interact with your space through guest books, drawing canvases, and more.

Authentication is handled entirely through Ethereum wallet signatures — no passwords, no accounts, no email. Messages between houses are end-to-end encrypted using wallet-derived keys.

Features

BlockSpace (Multiplayer World with 50 user max limit)

  • Real-time 2D multiplayer world with animated GIF sprites
  • Walk around and see other players in a shared space
  • Visit any house by walking up to its door
  • BlockTalk — real-time chat zone near the watercooler
  • Graffeth — collaborative drawing panel for the whole server
  • Live Ethereum block display and block-time daily limits
  • Captain system — super user elected using Speaketh Thy Mindeth

Personal Houses

  • Every Ethereum address gets a unique house
  • Full level editor for customizing exterior and interior
  • Custom house sprites, wallpaper, rugs, flowers, furniture, ambient sounds
  • Upload custom head sprites (115x115 GIF) and body sprites
  • Point-and-click for interactive room navigation
  • Occupancy tracking — see who's visiting whose house in real-time

Social & Creative Tools

  • gEth Book — Guest book where visitors leave encrypted messages
  • skEth Book — Drawing canvas for visitors to sketch in your house
  • MEth Drop — Piano/composition tool to record and share music
  • 8-Track Player — Play and share NSF (NES Sound Format) music files
  • Postcard Mailbox — Send/receive encrypted illustrated postcards between houses
  • NotEth Book — Private encrypted notebook (owner only)
  • EthOS — Retro Mac OS 6-style desktop with apps (LogEth, EthMail, NotEth, MyData, Manual)
  • Proof of Humanity — Community voting system to verify house ownership authenticity

Security & Privacy

  • Ethereum wallet authentication via MetaMask or Rabby (no passwords)
  • End-to-end encryption for messages, notes, and postcards (NaCl/TweetNaCl)
  • Content Security Policy headers on all pages
  • CORS restrictions on all APIs
  • Blocklist system for content moderation
  • Address validation and HTML escaping for XSS prevention

Architecture

┌─────────────────────┐     ┌──────────────────────┐     ┌──────────────────┐
│   Static Frontend   │     │  WebSocket Server     │     │  Cloudflare R2   │
│  (Cloudflare Pages) │────▶│  (Fly.io)             │────▶│  (S3-compatible  │
│                     │     │  Multiplayer, storage  │     │   storage)       │
└─────────────────────┘     └──────────────────────┘     └──────────────────┘
                                      │
                            ┌─────────┴──────────┐
                            │                    │
                   ┌────────▼──────┐   ┌─────────▼────────┐
                   │  Cloudflare   │   │  Image Gen API   │
                   │  Durable      │   │  (Runware or     │
                   │  Objects      │   │   ImageRouter)   │
                   │  (occupancy)  │   │  (optional)      │
                   └───────────────┘   └──────────────────┘
  • Frontend: Static HTML/CSS/JS served from Cloudflare Pages (or any static host)
  • WebSocket Server: Node.js on Fly.io handles multiplayer sync, R2 storage operations, image generation
  • Cloudflare R2: S3-compatible object storage for house data (houses/{address}.json), custom assets, and uploads
  • Cloudflare Durable Objects: Atomic house occupancy tracking (prevents race conditions for who's visiting)
  • Runware / ImageRouter: Optional AI image generation for the Graffeth collaborative drawing tool, Newsmaker, and Speaketh Thy Mindeth(first message only)

Deploy Your Own

Prerequisites

  • A Cloudflare account (for R2 storage, Pages hosting, and Durable Objects)
  • A Fly.io account (for the WebSocket server)
  • Node.js installed locally
  • Wrangler CLI (npm install -g wrangler)
  • Fly CLI (curl -L https://fly.io/install.sh | sh)
  • Optional: A Runware or ImageRouter API key for AI image generation

Step 1: Clone and Install

git clone https://github.com/yourusername/my-ether-space.git
cd my-ether-space
npm install

Step 2: Set Up Cloudflare R2

R2 is the storage backend for all house data, custom assets, and uploads.

wrangler login
wrangler r2 bucket create my-ether-space

Then create R2 API tokens from your Cloudflare dashboard:

  1. Go to R2 > Manage R2 API Tokens
  2. Create a token with Object Read & Write permissions
  3. Save the Access Key ID and Secret Access Key
  4. Note your Account ID from the Cloudflare dashboard URL
  5. Enable public access on your bucket and note the public URL (it will look like https://pub-xxxxx.r2.dev)

Step 3: Deploy the WebSocket Server to Fly.io

The WebSocket server handles multiplayer, storage operations, and image generation. All API keys are stored as Fly.io secrets (never in code).

cd ws-server
npm install

# Create the Fly app
flyctl launch

# Set your R2 credentials as secrets
flyctl secrets set R2_ACCOUNT_ID=your_account_id
flyctl secrets set R2_ACCESS_KEY_ID=your_access_key_id
flyctl secrets set R2_SECRET_ACCESS_KEY=your_secret_access_key
flyctl secrets set R2_BUCKET_NAME=my-ether-space
flyctl secrets set R2_PUBLIC_URL=https://pub-your-bucket-id.r2.dev

# Optional: AI image generation
flyctl secrets set RUNWARE_API_KEY=your_runware_api_key
# OR
flyctl secrets set IMAGEROUTER_API_KEY=your_imagerouter_api_key

# Deploy
flyctl deploy

Note your Fly.io app URL (e.g., wss://your-app-name.fly.dev).

Step 4: Deploy the Cloudflare Durable Objects Worker

This handles atomic occupancy tracking — ensuring only one visitor is in a house at a time.

cd cloudflare-worker

# Edit wrangler.toml and set your app name
# Then deploy:
wrangler publish

Note your worker URL (e.g., https://your-worker-name.your-subdomain.workers.dev).

Step 5: Update Frontend Configuration

Update the URLs to point to your own infrastructure:

js/config.js — Set your R2 CDN and occupancy worker URLs:

export const R2_CDN = 'https://pub-your-bucket-id.r2.dev';
export const OCCUPANCY_SERVICE_URL = 'https://your-worker.your-subdomain.workers.dev';

index.html, blockspace.html, mobile.html — Update the Content Security Policy meta tag to allow your URLs:

<meta http-equiv="Content-Security-Policy" content="...
  connect-src 'self' wss://your-app.fly.dev https://your-worker.workers.dev https://pub-your-bucket.r2.dev https://your-account-id.r2.cloudflarestorage.com;
  img-src 'self' data: blob: https://pub-your-bucket.r2.dev;
  media-src 'self' blob: data: https://pub-your-bucket.r2.dev;
...">

blockspace.html and js/main.js — Update the WebSocket URL:

const WS_URL = 'wss://your-app.fly.dev';

cloudflare-worker/house-occupancy.js — Update CORS origins:

const allowedOrigins = [
    'https://yourdomain.com',
    'https://www.yourdomain.com'
];

Step 6: Deploy the Frontend

The frontend is entirely static — no build step needed.

Cloudflare Pages:

  1. Push your code to GitHub
  2. Go to Cloudflare Pages > Create Project > Connect to Git
  3. Set build command to empty (no build needed)
  4. Set output directory to / (root)
  5. Deploy

Or use Netlify/Vercel — same process, just point it at the repo root with no build command.

Step 7: Custom Domain (Optional)

  1. Add a CNAME record pointing to your Cloudflare Pages URL
  2. Update the CORS origins in cloudflare-worker/house-occupancy.js
  3. Update the CSP headers in the HTML files

Environment Variables Reference

All secrets are stored in Fly.io — never in the codebase:

Variable Where Required Description
R2_ACCOUNT_ID Fly.io Yes Your Cloudflare account ID
R2_ACCESS_KEY_ID Fly.io Yes R2 API token access key
R2_SECRET_ACCESS_KEY Fly.io Yes R2 API token secret
R2_BUCKET_NAME Fly.io Yes R2 bucket name
R2_PUBLIC_URL Fly.io Yes R2 public CDN URL
RUNWARE_API_KEY Fly.io No Runware API key for AI image gen
IMAGEROUTER_API_KEY Fly.io No ImageRouter API key (alternative)

Files You Need to Customize

File What to Change
js/config.js R2 CDN URL, occupancy service URL
index.html CSP meta tag, WebSocket URL
blockspace.html CSP meta tag, WebSocket URL
mobile.html CSP meta tag
js/main.js WebSocket URL (search for WS_SERVER_URL)
js/mobile-app.js WebSocket URL
cloudflare-worker/house-occupancy.js CORS allowed origins
ws-server/admin.txt Your admin Ethereum addresses
ws-server/addressBlocklist.txt Blocked addresses (if any)

Project Structure

myetherspace/
├── index.html                  # Main page (wallet connect, house visit)
├── blockspace.html             # Multiplayer 2D world
├── mobile.html                 # Mobile-optimized version
├── mobilelanding.html          # Mobile redirect landing
├── _headers                    # Cache config (Netlify/Cloudflare)
│
├── js/                         # ES6 modules (no build system)
│   ├── main.js                 # Main app controller
│   ├── blockspace.js           # Multiplayer world engine (13,000+ lines)
│   ├── ipfs.js                 # R2 storage manager
│   ├── point-and-click.js      # Canvas game engine
│   ├── wallet.js               # Ethereum wallet connection
│   ├── encryption.js           # End-to-end encryption (NaCl)
│   ├── config.js               # URL configuration
│   ├── level-editor.js         # House customization
│   ├── geth-book.js            # Guest book
│   ├── sketh-book.js           # Sketch book
│   ├── meth-drop.js            # Music composition
│   ├── eight-track-player.js   # NSF music player
│   ├── noteth-book.js          # Encrypted notes
│   ├── ethos.js                # Retro OS desktop
│   ├── proof-of-humanity.js    # Humanity verification
│   ├── occupancy.js            # House occupancy tracking
│   └── ...                     # Additional modules
│
├── css/                        # Stylesheets
├── images/                     # Sprites and assets
├── playerGifs/                 # Player animation GIFs
├── levelEditorAssets/          # Level editor sprites
├── Audio_Ambience/             # Ambient sounds
├── libgme/                     # NES music player (WebAssembly)
│
├── ws-server/                  # WebSocket server (Fly.io)
│   ├── index.js                # Main server
│   ├── storage.js              # R2 storage + caching layer
│   ├── image-gen.js            # Runware/ImageRouter integration
│   ├── fly.toml                # Fly.io deployment config
│   ├── Dockerfile              # Container build
│   └── package.json            # Server dependencies
│
├── cloudflare-worker/          # Durable Objects worker
│   ├── house-occupancy.js      # Occupancy logic
│   └── wrangler.toml           # Wrangler deployment config
│
└── docs/                       # Additional documentation

How It Works

Storage: House data is stored as JSON in Cloudflare R2 at houses/{address}.json. Each house has a FIFO limit of 100 items per category (messages, sketches, recordings, notes, emails, postcards). Custom assets are content-addressed and deduplicated.

Multiplayer: The Fly.io WebSocket server syncs player positions, handles house state changes, and manages sessions. Players have a daily block-time limit (111 Ethereum blocks, roughly 27 minutes) tracked per address.

Encryption: Messages and notes use NaCl box encryption (x25519-xsalsa20-poly1305). Public keys are derived from wallet encryption keys via eth_getEncryptionPublicKey. Decryption requires wallet approval via eth_decrypt.

Occupancy: Cloudflare Durable Objects provide strongly consistent, atomic occupancy claims. Only one visitor can be in a house at a time. Visits auto-expire after 5 minutes; owners never expire.

Future Vision

IPFS Decentralization

My Ether Space was originally envisioned to run on IPFS for fully decentralized storage. The name ipfs.js for the storage manager reflects this original intent. The current architecture uses Cloudflare R2 as a practical alternative, but the vision remains:

  • Decentralized house data — Houses stored as IPFS CIDs instead of centralized R2
  • User-controlled pinning — Built-in pinning interface so users can pin their own house data, or choose to pin all data to help keep the network alive
  • Content addressing — Immutable references to assets via content hashes (the content-hash deduplication in the current codebase is a step toward this)
  • No single point of failure — Anyone could run a node and keep the world alive

I'd love to see this implemented. The storage layer in ipfs.js was designed with this migration in mind.

Smart Contract Integration

Since the site already uses Ethereum wallets for authentication and encryption, the natural next step is on-chain functionality:

  • House tipping — Send ETH directly to another house's address
  • In-house games with real stakes — Use smart contracts to hold funds for house-based games
  • On-chain reputation — Store Proof of Humanity scores on-chain
  • NFT display — Show owned NFTs inside houses
  • House economy — A contract that manages house balances, enabling in-world commerce

The wallet integration is already built — it just needs a contract to talk to.

Local Development

npm start
# Opens http://localhost:8080

Or just open index.html in a browser. Without a WebSocket server configured, the multiplayer features won't work, but you can still explore the single-player house experience with localStorage.

Tech Stack

  • Frontend: Vanilla JavaScript (ES6 modules), no framework, no build system
  • Styling: Custom CSS with NES-style retro components, Press Start 2P pixel font
  • Multiplayer: WebSocket (ws library on Node.js)
  • Storage: Cloudflare R2 (S3-compatible)
  • Occupancy: Cloudflare Durable Objects
  • Encryption: TweetNaCl (NaCl box)
  • Web3: ethers.js 5.7+
  • Music: libgme (WebAssembly NES/NSF player)
  • Hosting: Cloudflare Pages / Fly.io

Contributing

Contributions are welcome. Some areas that could use help:

  • IPFS integration (see Future Vision above)
  • Smart contract development
  • Mobile experience improvements
  • Accessibility improvements
  • New house items and sprites
  • Performance optimization for large BlockSpace instances

To contribute:

  1. Fork the repository
  2. Create a feature branch
  3. Make your changes
  4. Test thoroughly
  5. Submit a pull request

License

GPLv3 — see LICENSE file for details.

Security

If you find a security vulnerability, please open an issue or contact the maintainer directly. See SECURITY_AUDIT.md for the full security review.

Donations

Donations Eth 0x8ebA166Eb2898a7E14afc6687fB4692F8EE0adF5

Donations Btc bc1qu7dxsstve8l93xwcfpaklyhsh7gvagjplnqzkg

Donations Sol 6pLqZt93M5PCEVHpkRKoTHidLFdhMuqLwUYwnJjKFuJH

About

MyEtherSpace- a web1b toy site made by an Uberector and Claude Code.

Topics

Resources

License

Stars

Watchers

Forks

Contributors