Preparing Your Next.js Game
Next.js is a powerful React framework that can be used to build interactive web games. Our platform supports both static exports and server-side rendered Next.js applications.
Set Up Your Next.js Project
If you haven't already, create a new Next.js project:
Note: We recommend using yarn as your package manager for Next.js projects.
Configure Your Project
Update your next.config.js
file based on your deployment strategy:
For Static Export (Recommended)
For Server-Side Rendering
Important: Static export is recommended for most games as it's simpler to deploy and has better performance for client-side interactive applications.
Build Your Game
Run the build command to create a production-ready version of your game:
For Static Export
This will create an out
folder containing your static export with the following structure:
For Server-Side Rendering
This will create a .next
folder containing your server-side application with the following structure:
Test Your Build Locally
Before uploading, test your built game to ensure everything works correctly:
For Static Export
For Server-Side Rendering
Check that all game features, assets, and interactions work as expected.
Zip Your Build
Compress your build folder into a ZIP file:
For Static Export
For Server-Side Rendering
Important: For static exports, make sure to zip the contents of the out folder, not the out folder itself.
Common Issues and Solutions
Image Optimization
If you're using Next.js Image component and having issues:
- Set
unoptimized: true
in your next.config.js for static exports - Use regular
<img>
tags for static assets - Place images in the
public
folder for direct access
API Routes in Static Exports
API routes don't work in static exports. Instead:
- Use client-side API calls to external services
- Consider using serverless functions (like Vercel Edge Functions) for dynamic functionality
- Pre-compute data at build time using
getStaticProps
Routing Issues
If you're experiencing routing problems:
- Set
trailingSlash: true
in your next.config.js - Use
Link
components for internal navigation - Ensure all links use relative paths
Implementing Game Session Tracking
All games uploaded to our platform must implement session tracking functionality. This allows us to track player sessions and maintain leaderboards for your game.
Important: Your game bundle must include API calls to our session tracking endpoints. Our validation system will check for these calls during the upload process. Games without proper session tracking implementation will be rejected.
Option 1: Use Our SDK (Recommended)
The easiest way to implement session tracking is to use our JavaScript SDK. You can download the SDK here or view an example implementation.
In your Next.js project, you can add it in a few different ways:
Method A: Using Script Component
// In your _app.js or a game component import Script from 'next/script'; import { useEffect, useState } from 'react'; export default function Game() { const [tracker, setTracker] = useState(null); useEffect(() => { // Initialize tracker when the SDK is loaded if (window.GameSessionTracker) { setTracker(new window.GameSessionTracker()); } }, []); return ( <div> <Script src="/sdk/game-session-tracker.js" strategy="afterInteractive" onLoad="() => { setTracker(new window.GameSessionTracker()); }" /> <!-- Your game UI --> </div> ); }
Method B: Using Custom Document
// In pages/_document.js import { Html, Head, Main, NextScript } from 'next/document'; export default function Document() { return ( <Html> <Head /> <body> <Main /> <NextScript /> <script src="/sdk/game-session-tracker.js"></script> </body> </Html> ); }
Then use the tracker in your game component:
import { useEffect, useState } from 'react'; export default function GameComponent() { const [tracker, setTracker] = useState(null); useEffect(() => { // Wait for the SDK to load const initTracker = () => { if (window.GameSessionTracker) { // The SDK will automatically detect the subdomain setTracker(new window.GameSessionTracker()); } else { // If not loaded yet, try again in a moment setTimeout(initTracker, 100); } }; initTracker(); }, []); // Function to call when game ends const handleGameOver = (score) => { if (tracker) { tracker.endSession(score) .then(response => { console.log("Session recorded successfully", response); }) .catch(error => { console.error("Failed to record session", error); }); } }; // Function to display leaderboard const showLeaderboard = () => { if (tracker) { tracker.getLeaderboard(10) .then(response => { const leaderboard = response.data.leaderboard; // Display leaderboard in your UI }) .catch(error => { console.error("Failed to fetch leaderboard", error); }); } }; return ( <div> <!-- Your game UI --> <button onClick="() => handleGameOver(1500)">End Game</button> <button onClick="showLeaderboard">Show Leaderboard</button> </div> ); }
Option 2: Custom Implementation
If you prefer to implement session tracking yourself, follow these steps:
1. Create a session tracking service:
// services/sessionTracker.js export default class SessionTracker { constructor() { this.token = null; this.appVersion = null; this.language = null; this.sessionStartTime = null; this.initialized = false; // Initialize on creation this.initialize(); } initialize() { if (typeof window === 'undefined') return; // Skip on server-side const urlParams = new URLSearchParams(window.location.search); this.token = urlParams.get('token') || this.generateRandomToken(); this.appVersion = urlParams.get('appVersion') || '1.0.0'; this.language = urlParams.get('language') || 'en'; this.sessionStartTime = new Date(); this.initialized = true; } generateRandomToken() { return 'player-' + Math.random().toString(36).substring(2, 15); } async endSession(score) { if (!this.initialized) { console.error('Session tracker not initialized'); return; } const sessionEndTime = new Date(); const payload = { token: this.token, session_start_time: this.sessionStartTime.toISOString(), session_end_time: sessionEndTime.toISOString(), score: score, app_version: this.appVersion, language: this.language }; // Get the subdomain from the current hostname const hostname = window.location.hostname; const parts = hostname.split('.'); const subdomain = parts.length > 2 ? parts[0] : ''; // REQUIRED: This exact endpoint must be called when a game session ends try { const response = await fetch(`/api/v1/games/${subdomain}/session-ended`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(payload) }); return await response.json(); } catch (error) { console.error('Failed to record session', error); throw error; } } async getLeaderboard(limit = 10) { // Get the subdomain from the current hostname const hostname = window.location.hostname; const parts = hostname.split('.'); const subdomain = parts.length > 2 ? parts[0] : ''; try { const response = await fetch(`/api/v1/games/${subdomain}/leaderboard?limit=${limit}`); return await response.json(); } catch (error) { console.error('Failed to fetch leaderboard', error); throw error; } } }
2. Use the service in your game component:
// components/Game.js import { useEffect, useState } from 'react'; import SessionTracker from '../services/sessionTracker'; export default function Game() { const [tracker, setTracker] = useState(null); useEffect(() => { // Initialize the tracker on client-side only if (typeof window !== 'undefined') { // The tracker will automatically detect the subdomain setTracker(new SessionTracker()); } }, []); const handleGameOver = async (score) => { if (tracker) { try { const result = await tracker.endSession(score); console.log('Session recorded successfully', result); } catch (error) { console.error('Error recording session', error); } } }; return ( <div> <!-- Your game UI --> <button onClick="() => handleGameOver(1500)">End Game</button> </div> ); }
Testing Your Implementation
Before uploading, test your session tracking implementation:
- Run your Next.js app locally with
yarn dev
- Add URL parameters to your local development URL (e.g.,
http://localhost:3000/?token=test123&appVersion=1.0.0&language=en
) - Use browser developer tools to verify network requests are being made correctly
In browser developer tools, check that the POST request to /api/v1/games/:subdomain/session-ended
is being made with all required parameters.
Uploading to Jiran Games
Log in to Your Account
Sign in to your Jiran Games developer account.
Create a New Game
Click on "Add New Game" and fill in the required information:
- Game Name
- Description
- Game Logo (recommended size: 512x512px)
- Tags (to help users find your game)
- Subdomain (this will be your game's URL: yourgame.jiran.games)
Upload Your Game Bundle
Select the ZIP file containing your Next.js build and upload it.
Note: Our system will automatically detect your Next.js build structure (static or server) and serve it correctly.
Submit for Review
After uploading, your game will be marked as "pending_review". Our team will review it to ensure it meets our guidelines.
The review process typically takes 1-2 business days.