TutorialJan 9, 2026

Building Your First Game on Midnight

Develop privacy-preserving blockchain games with zero-knowledge proofs. Build a Rock-Paper-Scissors game where moves stay hidden until revelation.

Summary

This comprehensive developer guide introduces Midnight, a privacy-focused blockchain platform designed for creating decentralized games with built-in data protection through zero-knowledge proofs.

Key Concepts

Midnight Platform Features

  • Privacy by Default: All contract state can be kept private using ZK proofs
  • Supports both shielded (private) and unshielded (public) assets
  • Uses the Compact language for smart contract development
  • Includes full-stack dApp support with React integration

Why Games Benefit from Midnight

The platform solves traditional blockchain gaming problems like visible game state, front-running attacks, and strategy exposure by enabling private computations that prove validity without revealing sensitive information.

Technical Architecture

The stack includes:

  • Frontend: React with Lace wallet integration
  • Smart Contracts: Written in Compact language, compiling to WebAssembly
  • Blockchain Layer: Public ledger combined with private state storage
  • Proof Generation: Server-side zero-knowledge proof creation

Practical Implementation

The tutorial provides:

  • Setup instructions including Git LFS, Compact compiler, and Lace wallet installation
  • Project structure overview covering contract files, CLI tools, and React frontend
  • Rock-Paper-Scissors game example demonstrating commit-reveal mechanics
  • Testing frameworks using Vitest for contract validation
  • Deployment guidance for local development and Preview Network testnet

Rock-Paper-Scissors Implementation

The game demonstrates core privacy patterns:

compact
pragma language_version >= 0.19;
import CompactStandardLibrary;

enum Choice { rock, paper, scissors }
enum GameState { waiting, committed, revealed, finished }

export ledger gameState: GameState;
export ledger player1Commitment: Bytes<32>;
export ledger player2Commitment: Bytes<32>;

witness get_secret(): Bytes<32>;

circuit commit_move(choice: Choice): Bytes<32> {
  const secret = get_secret();
  return persistentHash<Vector<2, Field>>([

choice as Field,

secret as Field

]);

}

export circuit player1_commit(commitment: Bytes<32>): [] { assert(gameState == GameState.waiting, "Invalid state");

player1Commitment = commitment;

}

export circuit player1_reveal(choice: Choice, secret: Bytes<32>): [] { const expected = persistentHash<Vector<2, Field>>([

choice as Field,

secret as Field

]);

assert(expected == player1Commitment, "Invalid reveal"); "hl-comment">// Continue with game logic...

}

Advanced Patterns

Includes techniques for:

  • Multi-player game state management: Coordinate turns and actions between players
  • Commit-reveal schemes: Hide moves until all players have committed
  • Time-locked actions: Enforce deadlines for player responses
  • Token staking mechanisms: Add economic incentives to games

Testing Your Game

typescript
class="hl-keyword">import { describe, it, expect } class="hl-keyword">from class="hl-string">'vitest';
class="hl-keyword">import { GameSimulator } class="hl-keyword">from class="hl-string">'./simulator';

describe(class="hl-string">'Rock Paper Scissors', () => {

it(class="hl-string">'should allow player to commit move', class="hl-keyword">async () => {

class="hl-keyword">const sim = new GameSimulator(); class="hl-keyword">const commitment = class="hl-keyword">await sim.commitMove(class="hl-string">'rock', class="hl-string">'secret123');

expect(commitment).toBeDefined();

});

it(class="hl-string">'should correctly determine winner', class="hl-keyword">async () => {

class="hl-keyword">const sim = new GameSimulator(); class="hl-keyword">await sim.player1Commit(class="hl-string">'rock'); class="hl-keyword">await sim.player2Commit(class="hl-string">'scissors'); class="hl-keyword">await sim.revealMoves();

expect(sim.getWinner()).toBe(class="hl-string">'player1');

});

});

Deployment Checklist

  • Install Compact compiler v0.27.0
  • Run all tests locally
  • Set up Lace wallet with testnet tokens
  • Configure environment variables
  • Deploy to Preview Network
  • Verify contract on explorer

Best Practices

The guide emphasizes:

  • Minimizing circuit complexity for faster proof generation
  • Appropriate state visibility (public vs private)
  • Graceful error handling with clear messages
  • Comprehensive edge-case testing
  • Gas optimization for complex games

Resources

  • Midnight Documentation: https://docs.midnight.network
  • Compact Language Guide: https://docs.midnight.network/develop/reference/compact
  • Lace Wallet: https://www.lace.io
  • Discord Community: Join for developer support