Overview
Frog is built on top of Hono (a fast & lightweight Web Framework), extended with a first-class API for Farcaster Frames.
If you are familiar with other Web Frameworks such as Express, Koa, or Fastify, then the Frog (and Hono) API should seem familiar to you.
At a high-level, the most basic Frog application looks like this:
import { Button, Frog } from 'frog'
export const app = new Frog({ title: 'Frog Frame' })
app.frame('/', (c) => {
const { buttonValue, status } = c
return c.res({
image: (
<div style={{ color: 'white', display: 'flex', fontSize: 60 }}>
{status === 'initial' ? (
'Select your fruit!'
) : (
`Selected: ${buttonValue}`
)}
</div>
),
intents: [
<Button value="apple">Apple</Button>,
<Button value="banana">Banana</Button>,
<Button value="mango">Mango</Button>
]
})
})
Below, we will break down high-level concepts of the above example.
Imports
Before we can instantiate an application, we need to import the Frog
class.
import { Button, Frog } from 'frog'
export const app = new Frog({ title: 'Frog Frame' })
// ...
Instantiation
We instantiate a new Frog application by calling the Frog
class.
import { Button, Frog } from 'frog'
export const app = new Frog({ title: 'Frog Frame' })
app.frame('/', (c) => {
const { buttonValue, status } = c
// ...
You can pass optional constructor parameters to new Frog({ title: 'Frog Frame' })
to:
- Set a Base Path for your application,
- Set a Redirect URL if the user is coming from a browser,
- Set a custom Hub,
- Set custom Hono Options,
- Set Initial State for your frame,
- Specify whether or not frames should be verified.
Routing
Similar to .post
, .get
, .put
, etc in other Web Frameworks, Frog uses .frame
to define a new frame route.
Internally, the frame route automatically handles GET
and POST
requests sent by Farcaster clients such as Warpcast to
get frame metadata.
export const app = new Frog({ title: 'Frog Frame' })
app.frame('/', (c) => {
return c.res({/* ... */})
})
You can also define multiple routes by specifying alternative paths.
export const app = new Frog({ title: 'Frog Frame' })
app.frame('/', (c) => {
return c.res({/* ... */})
})
app.frame('/foo', (c) => {
return c.res({/* ... */})
})
app.frame('/bar', (c) => {
return c.res({/* ... */})
})
You can also define GET
, POST
, etc routes via the Hono instance.
export const app = new Frog({ title: 'Frog Frame' })
app.frame('/', (c) => {
return c.res({/* ... */})
})
app.hono.get('/healthcheck', (c) => {
return c.text('ribbit')
})
This only scratches the surface of Routing in Frog. For more advanced routing, check out the Routing section.
Context
The c
parameter in the frame route contains properties about the frame, such as:
- The frame data (ie.
trustedData
/untrustedData
), - The button index/value or input value that was interacted with,
- A function to derive and set state,
- The initial/start path of the frame,
- The current URL of the frame,
- and more.
export const app = new Frog({ title: 'Frog Frame' })
app.frame('/', (c) => {
const { buttonValue, inputText, status, verified } = c
return c.res({/* ... */})
})
Images & Intents
Farcaster Frames have two main UI components: an Image, and a set of Intents:
We can represent this in the Frog API via the image
and intents
properties of the frame route:
app.frame('/', (c) => {
const { buttonValue, status } = c
return c.res({
image: (
<div style={{ color: 'white', display: 'flex', fontSize: 60 }}>
{status === 'initial' ? (
'Select your fruit!'
) : (
`Selected: ${buttonValue}`
)}
</div>
),
intents: [
<Button value="apple">Apple</Button>,
<Button value="banana">Banana</Button>,
<Button value="mango">Mango</Button>
]
})
})
Read more on Images & Intents.
Dev Server & Devtools
To get a live preview of our frames, we can attach the Frog Devtools to our app.
import { devtools } from 'frog/dev'
import { serveStatic } from 'frog/serve-static'
export const app = new Frog({ title: 'Frog Frame' })
app.frame('/', (c) => { ... })
devtools(app, { serveStatic })
Then, spin up a local dev server using the frog dev
command:
frog dev
This will start a dev server at http://localhost:5173
.
Then you can head to the /dev
route (http://localhost:5173/dev
) to see a live preview (with live reloading) of your frame.