RISE Logo-Light

Implementation

Build the game with realtime Shreds integration

Game Implementation

The complete Shred Ninja implementation can be found in the GitHub repository. We'll cover the key concepts here.

Key Implementation Concepts

Shreds Subscription:

const client = createPublicClient({
  chain: riseTestnet,
  transport: webSocket('wss://testnet.riselabs.xyz/ws'),
}).extend(shredActions)

const unwatch = client.watchShreds({
  includeStateChanges: false,
  onShred: (shred) => {
    // Process realtime events
  },
})

Event Filtering:

  • Filter logs by Transfer event signature
  • Match against USDC and USDT contract addresses
  • Extract and process only relevant transfers
  • Deduplicate using transaction hash + log index

Progressive Difficulty:

// Show fewer events at low scores
if (currentScore < 25) {
  shouldSpawn = eventCounter % 3 === 0; // Every 3rd event
} else if (currentScore < 50) {
  shouldSpawn = eventCounter % 2 === 0; // Every 2nd event
} else {
  shouldSpawn = true; // Every event
}

Audio Synthesis:

const playTone = (frequency: number, duration: number) => {
  const audioContext = new AudioContext();
  const oscillator = audioContext.createOscillator();
  oscillator.frequency.value = frequency;
  oscillator.type = "sine";
  oscillator.start();
  oscillator.stop(audioContext.currentTime + duration);
};

sounds.tap = () => {
  playTone(523, 0.1); // C5
  playTone(659, 0.1, 0.05); // E5
};

Framer Motion Animation:

<motion.div
  initial={{ y: -80, x: token.x }}
  animate={{ y: window.innerHeight + 80 }}
  exit={{ scale: 0, opacity: 0 }}
  transition={{ duration: 5, ease: "linear" }}
  onClick={() => handleTap(token)}
>
  {token.type === "USDC" ? "C" : "T"}
</motion.div>

Complete Source Code

For the full implementation including:

  • Complete Shreds subscription setup
  • Game state management
  • Audio synthesis functions
  • Progressive difficulty system
  • Token animation and collision detection

Visit: https://github.com/awesamarth/shred-ninja


Running and Testing

Start the Development Server

Run the App

npm run dev
yarn dev
pnpm dev
bun run dev

Open http://localhost:3000 in your browser.

How to Play

  • Green tokens (USDC transfers) = TAP THEM
  • Red tokens (USDT transfers) = AVOID THEM
  • Miss 10 green tokens = Game over
  • Tap a red token = Game over
  • Difficulty increases with your score

Understanding What You See

Every token represents a real blockchain transfer happening on RISE Testnet at that moment. The 3-5ms latency makes it feel like a traditional web app, not blockchain!

When running, the game should look like this:

Shred Ninja Gameplay


How It Works

Event Flow Timeline

  1. Tx execution: 0ms
  2. Shred delivered: 3-5ms
  3. Token spawns: 5-10ms (including React render)
  4. Player sees token: 10-15ms after blockchain event

This demonstrates RISE's capability: events arrive fast enough for interactive gaming!

Deduplication Strategy

const processedTokens = new Set<string>();

// Create unique ID
const tokenId = `${tx.hash}-${log.logIndex}`;
if (processedTokens.has(tokenId)) return;
processedTokens.add(tokenId);

Prevents the same transfer from spawning multiple tokens if delivered in multiple shreds.

Miss Detection

// Set timeout when token spawns
const missTimeout = setTimeout(() => {
  if (tokenType === "USDC") {
    setMisses((m) => {
      const newMisses = m + 1;
      if (newMisses >= 10) {
        sounds.gameOver();
        setStatus("gameOver");
      }
      return newMisses;
    });
  }
  setTokens((prev) => prev.filter((t) => t.id !== tokenId));
}, 4500); // Match animation duration

Tapping clears the timeout; reaching bottom increments miss counter.


Customization Ideas

Adjust Difficulty

Modify the difficulty thresholds:

if (currentScore < 10) {
  shouldSpawn = eventCounter % 4 === 0; // Easier
} else if (currentScore < 30) {
  shouldSpawn = eventCounter % 2 === 0;
} else {
  shouldSpawn = true; // Harder
}

Add More Token Types

Monitor additional ERC20 contracts:

const USDC_ADDRESS = "0x...";
const USDT_ADDRESS = "0x...";
const DAI_ADDRESS = "0x..."; // New token

// In onShred callback
const tokenType =
  log.address.toLowerCase() === USDC_ADDRESS ? "USDC" :
  log.address.toLowerCase() === USDT_ADDRESS ? "USDT" :
  log.address.toLowerCase() === DAI_ADDRESS ? "DAI" : null;

Change Animation Speed

Adjust the falling speed:

<motion.div
  transition={{ duration: 3, ease: "linear" }} // Faster
>

Remember to match the timeout duration!


Next Steps

Congratulations! You've built a realtime blockchain game. You now understand how to:

  • Establish WebSocket connections to RISE Testnet
  • Subscribe to blockchain events with watchShreds
  • Filter and process ERC20 transfer events
  • Handle event deduplication
  • Build realtime UIs powered by blockchain data

Ideas to Extend

  1. Leaderboards: Record high scores with player addresses
  2. Multiplayer: Show other players' scores in realtime
  3. NFT Rewards: Mint achievement NFTs for milestones
  4. Custom Tokens: Let users choose which tokens to monitor
  5. Sound Effects: Add unique sounds for different token types

Resources