Building a Buzzfeed-Style Quiz App with Next.js and OnchainKit

Building a Buzzfeed-Style Quiz App with Next.js and OnchainKit

This tutorial walks you through a the code for a Warpcast frame that implements a Buzzfeed-style quiz using Coinbase's OnchainKit, dynamic Open Graph (OG) images, and robust API routes.

The code for the frame can be found in this github repository

Prerequisites

  • Familiarity with Next.js and React.

  • Basic understanding of APIs and server-side rendering.

  • Installed dependencies:

    • @coinbase/onchainkit

    • sharp


Step 1: Page Setup (/app/page.tsx)

The app starts with a simple page containing metadata and a title.

Key Features:

  1. Dynamic Metadata: Uses getFrameMetadata from OnchainKit to set up Open Graph data for sharing and buttons for user interaction.

  2. Page Content: Displays a heading with the quiz title.

import { getFrameMetadata } from '@coinbase/onchainkit/frame';
import type { Metadata } from 'next';
import { NEXT_PUBLIC_URL } from './config';

const frameMetadata = getFrameMetadata({
  buttons: [{ label: 'Start Quiz' }],
  image: { src: `${NEXT_PUBLIC_URL}/image.jpg`, aspectRatio: '1:1' },
  postUrl: `${NEXT_PUBLIC_URL}/api/frame`,
});

export const metadata: Metadata = {
  title: 'Project Buidl On Base Buzzfeed Quiz Frame',
  description: 'LFG',
  openGraph: { title: 'Project Buidl On Base Buzzfeed Quiz Frame', images: [`${NEXT_PUBLIC_URL}/image.jpg`] },
  other: { ...frameMetadata },
};

export default function Page() {
  return (
    <>
      <h1>Project Buidl On Base Buzzfeed Quiz Frame</h1>
    </>
  );
}

Step 2: Layout (/app/layout.tsx)

Defines the root layout for the app, including viewport settings and a container for child components.

export const viewport = { width: 'device-width', initialScale: 1.0 };

export default function RootLayout({ children }: { children: React.ReactNode }) {
  return (
    <html lang="en">
      <body>{children}</body>
    </html>
  );
}

Step 3: API for Quiz Logic (/app/api/frame/route.ts)

Handles the core quiz logic through a POST request. It processes user input, tracks quiz state, and serves dynamic responses.

Key Features:

  1. State Management:

    • Tracks the questionIndex and answers via untrustedData.
  2. Dynamic Responses:

    • If the quiz is complete, generates a results frame.

    • Otherwise, serves the next question with dynamically generated options.

  3. Error Handling:

    • Returns a "Try Again" button for errors.
import { FrameRequest, getFrameHtmlResponse } from '@coinbase/onchainkit/frame';
import { NextRequest, NextResponse } from 'next/server';

const questions = [...]; // Array of quiz questions and options.

async function getResponse(req: NextRequest): Promise<NextResponse> {
  // Logic to handle quiz progress and generate frames
}

export async function POST(req: NextRequest): Promise<Response> {
  return getResponse(req);
}

export const dynamic = 'force-dynamic';

Step 4: Open Graph for Quiz Questions (/api/og/question/route.ts)

Generates a dynamic image for each quiz question.

Key Features:

  1. Dynamic Text Rendering:

    • Overlays the question text on a background image using sharp.
  2. Error Handling:

    • Returns a 500 status and logs errors if image generation fails.
import sharp from 'sharp';

export async function GET(req: NextRequest): Promise<NextResponse> {
  // Parse question index and generate image using sharp.
}

Step 5: Open Graph for Quiz Results (/api/og/results/route.ts)

Generates an OG image displaying the user's quiz result.

Key Features:

  1. Result Calculation:

    • Calculates a stablecoin personality based on the answers.
  2. Dynamic Image Rendering:

    • Uses sharp to overlay the result text on a background image.
function calculateResult(answers: number[]): string {
  // Logic to determine the quiz result.
}

export async function GET(req: NextRequest): Promise<NextResponse> {
  // Parse answers, calculate result, and generate image using sharp.
}

Step 6: Error Handling (/api/og/error/route.ts)

Handles errors by serving a static error image.

Key Features:

  1. Edge Runtime:

    • Uses the edge runtime for optimized performance.
  2. Simple JSX Rendering:

    • Renders a friendly error message as an Open Graph image.
import { ImageResponse } from 'next/og';

export const runtime = 'edge';

export async function GET(req: NextRequest) {
  return new ImageResponse(
    (
      <div style={{ display: 'flex', flexDirection: 'column', alignItems: 'center' }}>
        <h1>Something went wrong!</h1>
        <p>Please try again</p>
      </div>
    ),
    { width: 1200, height: 630 }
  );
}

To test the frame, go the web version of Warpcast on your computer and navigate to this link
https://warpcast.com/~/developers/frames-legacy

Using this tutorial, you should be able to create your own Buzzfeed style quiz frame!