Documentation
⚡ Vite

⚡ Vite

🚧

W.I.P

This guide provides a step-by-step walkthrough for integrating Gamba into your Vite.js application.

Installation

First, ensure you have the necessary Gamba packages installed in your project:

npm install gamba-core-v2 gamba-react-v2 gamba-react-ui-v2

Create a .env for rpc url

NEXT_PUBLIC_RPC_ENDPOINT=<HELIUS API KEY>

Setting Up Gamba Providers

In your Vite.js project, update the src/main.tsx file to include the GambaProvider and GambaPlatformProvider. Replace <YOUR_PLATFORM_CREATOR_ADDRESS_HERE> with your actual creator address.

// src/main.tsx
import "@solana/wallet-adapter-react-ui/styles.css";
import React from "react";
import ReactDOM from "react-dom";
import { GambaPlatformProvider } from "gamba-react-ui-v2";
import { GambaProvider } from "gamba-react-v2";
import { GAMES } from "./games";
import {
  ConnectionProvider,
  WalletProvider,
} from "@solana/wallet-adapter-react";
import { WalletModalProvider } from "@solana/wallet-adapter-react-ui";
import { makeHeliusTokenFetcher } from "gamba-react-ui-v2";
 
import App from "./App";
 
const PLATFORM_CREATOR_ADDRESS = "<YOUR_PLATFORM_CREATOR_ADDRESS_HERE>";
const PLATFORM_CREATOR_FEE = "0.005"; // 5% (5/100 = 0.05)
const PLATFORM_JACKPOT_FEE = "0.01"; // 1% (1/100 = 0.01)
 
const RPC_ENDPOINT =
  import.meta.env.NEXT_PUBLIC_RPC_ENDPOINT ??
  "https://api.mainnet-beta.solana.com";
 
ReactDOM.render(
  <ConnectionProvider
    endpoint={RPC_ENDPOINT}
    config={{ commitment: "processed" }}
  >
    <WalletProvider autoConnect wallets={[]}>
      <WalletModalProvider>
        <GambaProvider>
          <GambaPlatformProvider
            creator={PLATFORM_CREATOR_ADDRESS}
            games={GAMES}
            defaultCreatorFee={PLATFORM_CREATOR_FEE}
            defaultJackpotFee={PLATFORM_JACKPOT_FEE}
          >
            <TokenMetaProvider
              // Method that the useTokenMeta will use to fetch token metadata
              fetcher={makeHeliusTokenFetcher(RPC_ENDPOINT)}
              // List of known tokens that useTokenMeta will fallback to
              tokens={[
                {
                  mint: "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v",
                  symbol: "USDC",
                  name: "USD Coin",
                  image: "/faketoken.png",
                  decimals: 6,
                  baseWager: 1e6,
                },
                {
                  mint: "So11111111111111111111111111111111111111112",
                  symbol: "SOL",
                  name: "Solana",
                  decimals: 9,
                  baseWager: 0.01e9,
                },
              ]}
            />
            <App />
          </GambaPlatformProvider>
        </GambaProvider>
      </WalletModalProvider>
    </WalletProvider>
  </ConnectionProvider>,
  document.getElementById("app")
);

Custom Renderer

Implementing Gamba UI Portals:

The CustomRenderer is where the bulk of dynamic content management takes place. It utilizes PortalTarget to render content defined by Portal, allowing for flexible UI updates in response to various triggers.

Errors and alerts are a critical part of any gaming experience. Implement custom error handling using Gamba UI's Portal to define error messages that can be dynamically placed across the UI with PortalTarget.

import { GambaUi, useGambaAudioStore } from "gamba-react-ui-v2";
import React, { useState } from "react";
import { useGamba } from "gamba-react-v2";
 
export function CustomError() {
  return (
    <GambaUi.Portal target="error">
      <div>
        <h1>😭 Oh no!</h1>
        <p>Something went wrong</p>
      </div>
    </GambaUi.Portal>
  );
}
 
export default function CustomRenderer() {
  const gamba = useGamba();
  const audioStore = useGambaAudioStore();
 
  return (
    <>
      <div className="game-container">
        <GambaUi.PortalTarget target="error" />
        <GambaUi.PortalTarget target="screen" />
        <div className="absolute left-0 bottom-0 p-1 flex gap-2">
          <button
            onClick={() =>
              audioStore.set((audioStore.masterGain + 0.25) % 1.25)
            }
          >
            Volume: {audioStore.masterGain * 100}%
          </button>
        </div>
      </div>
      <div className="controls-container">
        <div className="flex-grow flex items-center justify-start gap-2">
          <GambaUi.PortalTarget target="controls" />
          <GambaUi.PortalTarget target="play" />
        </div>
      </div>
    </>
  );
}

Setting Up the Game Component

The game component leverages Gamba UI's Portals we created in the custom renderer as well as several hooks and components from Gamba UI. The main focus is on handling user wagers and initiating the game.

import { GambaUi, useWagerInput } from "gamba-react-ui-v2";
import React from "react";
 
export default function ExampleGame() {
  const _hue = React.useRef(0);
  const [wager, setWager] = useWagerInput();
  const game = GambaUi.useGame();
 
  const click = () => {
    _hue.current = (_hue.current + 30) % 360;
  };
 
  const play = async () => {
    await game.play({
      wager,
      bet: [2, 0],
    });
    const result = await game.result();
    console.log(result);
    // Do something with result
  };
 
  return (
    <>
      <GambaUi.Portal target="screen">
        <GambaUi.Canvas
          render={({ ctx, size }, clock) => {
            const scale = 3 + Math.cos(clock.time) * 0.5;
            const hue = _hue.current;
 
            ctx.fillStyle = "hsla(" + hue + ", 50%, 3%, 1)";
            ctx.fillRect(0, 0, size.width, size.height);
 
            ctx.save();
            ctx.translate(size.width / 2, size.height / 2);
 
            for (let i = 0; i < 5; i++) {
              ctx.save();
              ctx.scale(scale * (1 + i), scale * (1 + i));
              ctx.fillStyle = "hsla(" + hue + ", 75%, 60%, .2)";
              ctx.beginPath();
              ctx.arc(0, 0, 10, 0, Math.PI * 2);
              ctx.fill();
              ctx.restore();
            }
 
            ctx.fillStyle = "hsla(" + hue + ", 75%, 60%, 1)";
            ctx.beginPath();
            ctx.arc(0, 0, 8, 0, Math.PI * 2);
            ctx.fill();
 
            ctx.textAlign = "center";
            ctx.textBaseline = "middle";
            ctx.font = "32px Arial";
 
            ctx.fillStyle = "hsla(" + hue + ", 75%, 90%, 1)";
            ctx.fillText("HELLO", 0, 0);
 
            ctx.restore();
          }}
        />
      </GambaUi.Portal>
      <GambaUi.Portal target="controls">
        <GambaUi.WagerInput value={wager} onChange={setWager} />
        <GambaUi.Button onClick={click}>Useless button</GambaUi.Button>
        <GambaUi.PlayButton onClick={play}>
          Double or Nothing
        </GambaUi.PlayButton>
      </GambaUi.Portal>
    </>
  );
}

Create Your Games Configuration

Next, set up your games configuration in src/games/index.tsx. Here's an example setup for a dice game:

// src/games/index.tsx
 
import { GameBundle } from "gamba-react-ui-v2";
import dynamic from "next/dynamic";
 
export const GAMES: GameBundle[] = [
  {
    id: "example",
    meta: {
      background: "#ff6490",
      name: "Example",
      image: "/games/logo.png",
      description: `This is a example.`,
    },
    app: dynamic(() => import("./Example")),
  },
  // MORE GAMES
];

For further customization and advanced usage, refer to Gamba UI's documentation and explore how you can extend these concepts to fit your specific game development needs.