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
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:

How It Works
Event Flow Timeline
- Tx execution: 0ms
- Shred delivered: 3-5ms
- Token spawns: 5-10ms (including React render)
- 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 durationTapping 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
- Leaderboards: Record high scores with player addresses
- Multiplayer: Show other players' scores in realtime
- NFT Rewards: Mint achievement NFTs for milestones
- Custom Tokens: Let users choose which tokens to monitor
- Sound Effects: Add unique sounds for different token types
Related Tutorials
- Reaction Time Game - 3ms transaction confirmations
- RISE Wallet Demo - Wallet integration patterns
- RISEx Telegram Bot - AI trading bot
Resources
- GitHub Repository - Complete source code
- Shreds Documentation - Complete API reference
- Shreds Quickstart - Quick intro
- Viem Documentation - Ethereum library
- Framer Motion Docs - Animation library
- RISE Testnet Details - Network info