Farcaster Frames in less than 100 lines, and ready to be deployed to Vercel.
To test a Frame, use: https://warpcast.com/~/developers/frames.
And let us know what you build by either mentioning @zizzamia on Warpcast or X.
Have fun! ⛵️
- app/
- api/
- frame/
import { getFrameMetadata } from '@coinbase/onchainkit';
import type { Metadata } from 'next';
import { NEXT_PUBLIC_URL } from './config';
const frameMetadata = getFrameMetadata({
buttons: [
{
label: 'Story time!',
},
{
action: 'link',
label: 'Link to Google',
target: 'https://www.google.com',
},
{
label: 'Redirect to pictures',
action: 'post_redirect',
},
],
image: {
src: `${NEXT_PUBLIC_URL}/park-3.png`,
aspectRatio: '1:1',
},
input: {
text: 'Tell me a boat story',
},
postUrl: `${NEXT_PUBLIC_URL}/api/frame`,
});
export const metadata: Metadata = {
title: 'zizzamia.xyz',
description: 'LFG',
openGraph: {
title: 'zizzamia.xyz',
description: 'LFG',
images: [`${NEXT_PUBLIC_URL}/park-1.png`],
},
other: {
...frameMetadata,
},
};
export default function Page() {
return (
<>
<h1>zizzamia.xyz</h1>
</>
);
}
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>
);
}
export const NEXT_PUBLIC_URL = 'https://zizzamia.xyz';
import { FrameRequest, getFrameMessage, getFrameHtmlResponse } from '@coinbase/onchainkit';
import { NextRequest, NextResponse } from 'next/server';
import { NEXT_PUBLIC_URL } from '../../config';
async function getResponse(req: NextRequest): Promise<NextResponse> {
let accountAddress: string | undefined = '';
let text: string | undefined = '';
const body: FrameRequest = await req.json();
const { isValid, message } = await getFrameMessage(body, { neynarApiKey: 'NEYNAR_ONCHAIN_KIT' });
if (isValid) {
accountAddress = message.interactor.verified_accounts[0];
}
if (message?.input) {
text = message.input;
}
if (message?.button === 3) {
return NextResponse.redirect(
'https://www.google.com/search?q=cute+dog+pictures&tbm=isch&source=lnms',
{ status: 302 },
);
}
return new NextResponse(
getFrameHtmlResponse({
buttons: [
{
label: `🌲 ${text} 🌲`,
},
],
image: {
src: `${NEXT_PUBLIC_URL}/park-1.png`,
},
postUrl: `${NEXT_PUBLIC_URL}/api/frame`,
}),
);
}
export async function POST(req: NextRequest): Promise<Response> {
return getResponse(req);
}
export const dynamic = 'force-dynamic';
- Official Farcaster Frames documentation
- Official Farcaster Frame specification
- OnchainKit documentation
A Farcaster Frame in 100 Lines is all about community. If you have any questions, feel free to reach out to the core maintainers on Twitter or through Farcaster.
Leonardo Zizzamia |
Chris Nascone |
Rob Polak |
This project is licensed under the MIT License - see the LICENSE.md file for details