> ## Documentation Index
> Fetch the complete documentation index at: https://docs.neynar.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Create Farcaster Frames Using Neynar & Frog

> In this guide, we’ll learn how to make a frame with the neynar SDK and Frog.fm, within a few minutes! For this demo, it will be a simple rock-paper-scissors game but it will give you an idea of how to create multi-page frames, interact with buttons, and get analytics for your frame with no extra effort.

Before we begin, you can access the [complete source code](https://github.com/avneesh0612/rps-frames) for this guide on GitHub.

Let's get started!

## Creating a new frames project

We will use vercel and [frog](https://frog.fm/) for building the frame in this guide, but feel free to use anything else as well!

Enter this command in your terminal to create a new app:

<CodeGroup>
  ```powershell PowerShell theme={"system"}
  bunx create-frog -t vercel
  ```
</CodeGroup>

Enter a name for your project and it will spin up a new project for you. Once the project is created install the dependencies:

<CodeGroup>
  ```powershell PowerShell theme={"system"}
  cd <project_name>
  bun install
  ```
</CodeGroup>

### Creating the frame home page

Head over to the `api/index.ts` file. Here, you'll see a starter frame on the / route. But first, let's change the Frog configuration to use `/api` as the base path and use neynar for hubs like this:

<CodeGroup>
  ```typescript index.tsx theme={"system"}
  export const app = new Frog({
    assetsPath: "/",
    basePath: "/api",
    hub: neynar({ apiKey: 'NEYNAR_FROG_FM' })
  });
  ```
</CodeGroup>

<Info>
  ### Make sure to update the API key to your API key to get analytics
</Info>

You also need to import neynar from "frog/hubs":

<CodeGroup>
  ```typescript index.tsx theme={"system"}
  import { neynar } from "frog/hubs";
  ```
</CodeGroup>

Now, change the frame on the `/` route to match this:

<CodeGroup>
  ```typescript index.tsx theme={"system"}

  app.frame("/", (c) => {
    return c.res({
      action: "/result",
      image: (
        <div
          style={{
            alignItems: "center",
            background: "black",
            backgroundSize: "100% 100%",
            display: "flex",
            flexDirection: "column",
            flexWrap: "nowrap",
            height: "100%",
            justifyContent: "center",
            textAlign: "center",
            width: "100%",
          }}
        >
          <div
            style={{
              color: "white",
              fontSize: 60,
              fontStyle: "normal",
              letterSpacing: "-0.025em",
              lineHeight: 1.4,
              marginTop: 30,
              padding: "0 120px",
              whiteSpace: "pre-wrap",
            }}
          >
            Choose your weapon
          </div>
        </div>
      ),
      intents: [
        <Button value="rock">Rock</Button>,
        <Button value="paper">Paper</Button>,
        <Button value="scissors">Scissors</Button>,
      ],
    });
  });
  ```
</CodeGroup>

This will render an image saying choose your weapon and three buttons saying rock paper and scissors. When any of these buttons are clicked a request to the `/result` route is made which we define in the `action` parameter.

<Frame>
  <img src="https://mintcdn.com/neynar/4PNY113y9N9T-r9z/images/docs/da59b22-image.png?fit=max&auto=format&n=4PNY113y9N9T-r9z&q=85&s=8e28d8babd6c2dcd81219c5ca34f8aff" alt="Frame home page" width="1134" height="756" data-path="images/docs/da59b22-image.png" />
</Frame>

<Info>
  ### Make sure that you sign in using your warpcast account, so that the requests can be validated
</Info>

Now, let's build the `/result` route like this:

<CodeGroup>
  ```typescript index.tsx theme={"system"}
  app.frame("/result", (c) => {
    const rand = Math.floor(Math.random() * 3);
    const choices = ["rock", "paper", "scissors"];
    const userChoice = choices[(c.buttonIndex || 1) - 1];
    const computerChoice = choices[rand];
    let msg = "";

    if (userChoice === computerChoice) {
      msg = "draw";
    }

    if (
      (userChoice === "rock" && computerChoice === "scissors") ||
      (userChoice === "paper" && computerChoice === "rock") ||
      (userChoice === "scissors" && computerChoice === "paper")
    ) {
      msg = "You win";
    }

    if (
      (userChoice === "rock" && computerChoice === "paper") ||
      (userChoice === "paper" && computerChoice === "scissors") ||
      (userChoice === "scissors" && computerChoice === "rock")
    ) {
      msg = "You lose";
    }

    return c.res({
      image: (
        <div
          style={{
            alignItems: "center",
            background: "black",
            backgroundSize: "100% 100%",
            display: "flex",
            flexDirection: "column",
            flexWrap: "nowrap",
            height: "100%",
            justifyContent: "center",
            textAlign: "center",
            width: "100%",
          }}
        >
          <div
            style={{
              color: "white",
              fontSize: 60,
              fontStyle: "normal",
              letterSpacing: "-0.025em",
              lineHeight: 1.4,
              marginTop: 30,
              padding: "0 120px",
              whiteSpace: "pre-wrap",
              display: "flex",
            }}
          >
            {userChoice} vs {computerChoice}
          </div>

          <div
            style={{
              color: "white",
              fontSize: 60,
              fontStyle: "normal",
              letterSpacing: "-0.025em",
              lineHeight: 1.4,
              marginTop: 30,
              padding: "0 120px",
              whiteSpace: "pre-wrap",
            }}
          >
            {msg}
          </div>
        </div>
      ),
      intents: [<Button action="/">Play again</Button>],
    });
  });
  ```
</CodeGroup>

Here, we first get the button index from the request and use it to get the user's choice. We have then added some logic for generating a random choice for the game. Then, in the image we display the two choices and the result of the game. We have also added a play again game which simply pushes the user to the `/` route.

<Frame>
  <img src="https://files.catbox.moe/qvr7pt.gif" alt="Frame result page" />
</Frame>

## Analytics

Since we are using neynar hub with Frog, we also get analytics out of the box. Head over to the usage tab and click on the frame that you are currently using. It will provide you with various analytics like total interactors, interactions per cast, etc.

<Frame>
  <img src="https://mintcdn.com/neynar/aGwjtKmNewHJXSzO/images/docs/713fe83-image.png?fit=max&auto=format&n=aGwjtKmNewHJXSzO&q=85&s=da3d7ed1857d3ffc193a2c1a9870caf9" alt="Frame analytics" width="2712" height="1548" data-path="images/docs/713fe83-image.png" />
</Frame>

## Deployment

You can deploy your frame using the [vercel CLI](https://vercel.com/docs/cli) like this:

<CodeGroup>
  ```powershell PowerShell theme={"system"}
  bun run deploy
  ```
</CodeGroup>

Alternatively, you can also create a new GitHub repository and sync your vercel deployments.

## Conclusion

This guide taught us how to create a rock-paper-scissors game on Farcaster frames! If you want to look at the completed code, check out the [GitHub repository](https://github.com/avneesh0612/rps-frames).

Lastly, make sure to sure what you built with us on Farcaster by tagging [@neynar](https://warpcast.com/neynar) and if you have any questions, reach out to us on [warpcast](https://warpcast.com/~/channel/neynar) or [Slack](https://neynar.com/slack)!
