frames.js is a TypeScript library and framework for writing and testing Farcaster Frames.
- β‘οΈ Local frames debugger
- π₯³ Write Frames using React
- π Batteries included framework
- π΄ Tree-shakeable & Lightweight
- π Library with all the functions
Look at our documentation to learn more about frames.js.
npm install frames.js
yarn add frames.js
Run to clone the starter into a new folder called framesjs-starter
npx degit github:framesjs/frames.js/examples/framesjs-starter#main framesjs-starter
yarn add frames.js
Create a frames directory in your Next.js app and add the following files:
import { createFrames } from "frames.js/next"; export const frames = createFrames({ basePath: "/frames", });
/* eslint-disable react/jsx-key */ import { Button } from "frames.js/next"; import { frames } from "./frames"; const handleRequest = frames(async (ctx) => { return { image: ( <span> {ctx.pressedButton ? `I clicked ${ctx.searchParams.value}` : `Click some button`} </span> ), buttons: [ <Button action="post" target={{ query: { value: "Yes" } }}> Say Yes </Button>, <Button action="post" target={{ query: { value: "No" } }}> Say No </Button>, ], }; }); export const GET = handleRequest; export const POST = handleRequest;
import { fetchMetadata } from "frames.js/next"; export async function generateMetadata() { return { title: "My Page", // ... other: { // ... ...(await fetchMetadata( // provide a full URL to your /frames endpoint new URL( "/frames", process.env.VERCEL_URL ? `https://${process.env.VERCEL_URL}` : "http://localhost:3000" ) )), }, }; } export default function Page() { return <span>My existing page</span>; }
// page that renders a frame // ./app/page.tsx import { Frame, getFrameFlattened } from "frames.js"; import type { Metadata } from "next"; // Declare the frame const initialFrame: Frame = { image: "https://picsum.photos/seed/frames.js/1146/600", version: "vNext", buttons: [ { label: "Random image", }, ], postUrl: `${process.env.NEXT_PUBLIC_HOST}/frames`, }; // Export Next.js metadata export const metadata: Metadata = { title: "Random Image Frame", description: "This is an example of a simple frame using frames.js", openGraph: { images: [ { url: "https://picsum.photos/seed/frames.js/600", }, ], }, other: getFrameFlattened(initialFrame), };
// handle frame actions // ./app/frames/route.ts import { getFrameHtml, validateFrameMessage } from "frames.js"; import { NextRequest } from "next/server"; export async function POST(request: NextRequest) { const body = await request.json(); // Parse and validate the frame message const { isValid, message } = await validateFrameMessage(body); if (!isValid || !message) { return new Response("Invalid message", { status: 400 }); } const randomInt = Math.floor(Math.random() * 100); const imageUrlBase = `https://picsum.photos/seed/${randomInt}`; // Use the frame message to build the frame const frame = { version: "vNext", image: `${imageUrlBase}/1146/600`, buttons: [ { label: `Next (pressed by ${message.data.fid})`, }, ], ogImage: `${imageUrlBase}/600`, postUrl: `${process.env.NEXT_PUBLIC_HOST}/frames`, }; // Return the frame as HTML const html = getFrameHtml(frame); return new Response(html, { headers: { "Content-Type": "text/html", }, status: 200, }); }
Distributed under an MIT License. See LICENSE for more information.
Check out the following places for more Frames-related content:
- Join the /frames-dev channel on Farcaster to ask questions
- Follow Frames.js & team (@df and @stephancill) on Farcaster for updates
- Star frames.js on GitHub to show your support and keep track of updates
- Browse the awesome-frames list of awesome Frames projects and resources