A collaborative pixel canvas where every pixel is a micro-economy. Buy pixels, earn from future purchases, and watch the canvas evolve.
This was completely vibecoded, yes, even this readme.
Each pixel has its own independent price based on how many times it's been purchased:
Linear Phase (Purchases 1-10):
$0.01 → $0.02 → $0.03 → ... → $0.10
Exponential Phase (Purchases 11+):
$0.10 × 1.1^(n-10)
So purchase 11 costs $0.11, purchase 12 costs $0.121, and so on.
When someone buys a pixel, the payment is split:
| Recipient | Share |
|---|---|
| Protocol | 0.5% |
| Founders (first 5 buyers) | 5% (1% each) |
| Recent Buyers (last 10) | 94.5% (split evenly) |
The first 5 buyers of any pixel become permanent "founders" and earn 1% of all future purchases forever. The last 10 buyers share 94.5% of each new purchase.
Both purchasePixel and purchasePixels require a maxPrice parameter. If someone frontruns your transaction and the price increases, your transaction reverts instead of paying more than expected.
// Single pixel: reverts if price > maxPrice
function purchasePixel(uint256 x, uint256 y, uint8 color, uint256 maxPrice) external;
// Batch: reverts if total > maxTotalPrice
function purchasePixels(uint256[] xs, uint256[] ys, uint8[] colors, uint256 maxTotalPrice) external;The frontend defaults to 0% slippage (exact price), so users are fully protected from MEV attacks.
# Install dependencies
forge install
# Build
forge build
# Test
forge test
# Test with verbosity
forge test -vvvPlace.sol- Main contract handling pixel purchases, pricing, and payment distribution- Uses USDC for payments (6 decimals)
- Canvas size is expandable by owner
- Bitmap storage for efficient onchain pixel data reads
The contract is intentionally designed so the frontend can read everything directly onchain - no backend or indexer needed:
getPixel(x, y)- Get pixel color, purchase count, founders, and recent ownersgetPixelPrice(x, y)- Get current price for any pixelgetPixelsPrice(xs, ys)- Get total price for a batch of pixelsgetPlayerStats(address)- Get how much a user has invested and earnedgetStats()- Get global stats (total players, pixel volume, USDC volume)getAllPixelData()/getPixelDataChunk()- Bulk read all pixel colors and purchase counts via bitmap