Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update Frame Tutorials for current state of OnchainKit #625

Merged
merged 8 commits into from
Jul 12, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file modified apps/base-docs/assets/images/frames/updated-100-lines.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,6 @@ displayed_sidebar: null

To share your [Frames] on [Farcaster], you must first deploy them to the web. Farcaster reads the metadata from your site to build the Frame as it initially appears to the user. In this tutorial, we'll show you how to deploy the frame in the example - [a-frame-in-100-lines]

:::caution

Frames are brand new and tools are evolving quickly. Check the links above for changelogs!

:::

---

## Objectives
Expand Down Expand Up @@ -56,13 +50,39 @@ You must have a [Farcaster] account with a connected wallet. Check out the [Base

## Setup and Testing the Template

Start by creating a fork of the [a-frame-in-100-lines].
Start by creating a new repo using [a-frame-in-100-lines] as a template.
briandoyle81CB marked this conversation as resolved.
Show resolved Hide resolved

Run `yarn install`, then `yarn dev`.

In the browser, open `http://localhost:3000/`. All you'll see is a heading with _Zizzamia.xyz_. This is expected!

Open `page.tsx`. Here, you'll find the initial setup of the metadata that Farcaster reads to create the frame, as well as the simple page you just viewed. Change the `<h1>` to be your name. Change the `label` of the first button in `buttons` to be something you'll recognize as well. This can be your name, your pet's, or anything you like!
Open `app/page.tsx`. Here, you'll find the initial setup of the metadata that Farcaster reads to create the frame, as well as the simple page you just viewed. Change the `<h1>` to be your name.

```tsx
export default function Page() {
return (
<>
<h1>YOUR NAME HERE</h1>
</>
);
}
```

Change the `label` of the first button in `buttons` to be something you'll recognize as well. This can be your name, your pet's, or anything you like!

```tsx
buttons: [
{
label: 'YOUR NAME HERE',
},
{
action: 'tx',
label: 'Send Base Sepolia',
target: `${NEXT_PUBLIC_URL}/api/tx`,
postUrl: `${NEXT_PUBLIC_URL}/api/tx-success`,
},
],
```

## Setting up Vercel

Expand All @@ -74,7 +94,7 @@ You should see something like this:

Click the `Install` button to install the Vercel app in your Github organization. You'll need to select the appropriate choice for your organization between `All repositories` and `Only selected repositories`.

All is more convenient, but riskier. For this tutorial, we're assuming that you've chosen to go with minimum necessary access. Click the `Select repositories` dropdown, and pick the repo for your Frame.
All is more convenient, but gives a (well respected) third party more access than is required. For this tutorial, we're assuming that you've chosen to go with minimum necessary access. Click the `Select repositories` dropdown, and pick the repo for your Frame.

Click `Install`.

Expand All @@ -94,7 +114,7 @@ Click the button, then configure your project. The [a-frame-in-100-lines] exampl

:::caution

You won't have been the first person to name a project `a-frame-in-100-lines`, so Vercel will adjust the name for you for the file path. Don't be confused when your changes don't show up at `a-frame-in-100-lines.vercel, app`, that one isn't yours!
You won't have been the first person to name a project `a-frame-in-100-lines`, so Vercel will adjust the name for you for the file path, if you gave your template copy the same name. Don't be confused when your changes don't show up at `a-frame-in-100-lines.vercel, app`, that one isn't yours!

:::

Expand Down Expand Up @@ -130,19 +150,19 @@ If you want, you can disable CI/CD and set up manual deploys. One convenient way

## Testing the Cast

Open the [Frame Validator] and paste in your link. You may need to add junk data to your url with `?1234` to bypass caching of previous versions.
Open the [Frame Validator] and paste in your link. Viewing a frame from the validator will re-cache it for **future** casts, but it **will not** change any existing casts of the frame.

Click `Load`. You should see:

![Example](../../assets/images/frames/100-lines-frame.png)

Except it should have the text that you edited!
Except it will have the text that you edited!

---

## Conclusion

In this tutorial, you learned how to set up [Vercel]
In this tutorial, you learned how to deploy a frame with [Vercel] and take advantage of CI/CD.

---

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,7 @@ hide_table_of_contents: false
displayed_sidebar: null
---

As [Frames] on [Farcaster] grow in popularity, developers are building more complex interactions to meet the community's expectation for new and exciting things to do. [OnchainKit], and our [a-frame-in-100-lines] demo give you a number of tools to build complex interactions within a frame.

:::caution

Frames are brand new and tools are evolving quickly. Check the links above for changelogs!

:::
You can build complex and exciting [Frames] on [Farcaster] that meet the community's expectation for new and exciting things to do. [OnchainKit], and our [a-frame-in-100-lines] demo give you a number of tools to build complex interactions within a frame.

---

Expand Down Expand Up @@ -53,123 +47,87 @@ You should be comfortable with the basics of creating Farcaster [Frames]. If you

## Setting Up a Copy of A Frame in 100 Lines

If you've been working in the early days of Frames, you may have an existing fork of [a-frame-in-100-lines] that you don't want to alter because it contains live frames.

You can create a copy that is not a fork to take advantage of the newest developments without risking prior work. Note that this copy will not behave as a fork.
Create a new repo using [a-frame-in-100-lines] as a template.

First, create a bare clone of the template:
Add your new repo to Vercel and deploy. If you need a refresher, check out [deploying with Vercel]. Open the [Frame Validator] and test the current version of the template.

```bash
git clone --bare [email protected]:Zizzamia/a-frame-in-100-lines.git new-frames-project
```

Create a new, empty repo on GitHub, then mirror-push to that repo.

```bash
cd new-frames-project
git push --mirror [email protected]:<YOUR_NAME_HERE>/new-frames-project.git
```

Delete the `new-frames-project` folder, then clone as normal from the repo on GitHub.

Now you've got a fresh copy to work with!

## Deploy and Test

Add your new repo to Vercel and deploy. If you need a refresher, check out [deploying with Vercel]. Open the [Frame Validator] and test the current version of the template. Remember, this may have changed since the time of writing! We're moving fast!
![100 Lines](../../assets/images/frames/updated-100-lines.png)

## A Quick Overview of Features
The demo has examples of most of the features available for your frames.

![100 Lines](../../assets/images/frames/updated-100-lines.png)
### Buttons and Images

The demo now has examples of text entry and redirects.
The core functionality of a frame is an image and at least 1 button. Buttons can do a number of things, including requesting a new frame to replace the current one, opening a transaction for the user to consider approving, or opening a link to a website.

### Text Entry

The frame now has a text entry field. Try it out! When you click the `Story Time!` button, the text will be preserved, and will appear in the button on the next frame.
Optionally, frames can include a text entry field. Try it out! When you click the `Story Time!` button, the text will be preserved, and will appear in the button on the next frame.

![Story Time](../../assets/images/frames/story-time.png)

The text input field is created by adding the `input` property to `getFrameMetadata`.

In this example, it's in `app/page.tsx` on line 24:

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

const frameMetadata = getFrameMetadata({
buttons: [
{
label: 'Story time!',
label: 'Story time',
},
{
action: 'link',
label: 'Link to Google',
target: 'https://www.google.com',
},
{
label: 'Redirect to pictures',
action: 'post_redirect',
action: 'tx',
label: 'Send Base Sepolia',
target: `${NEXT_PUBLIC_URL}/api/tx`,
postUrl: `${NEXT_PUBLIC_URL}/api/tx-success`,
},
],
image: {
src: `${NEXT_PUBLIC_URL}/park-3.png`,
aspectRatio: '1:1',
},
input: {
text: 'Tell me a boat story',
text: 'Tell me a story',
},
postUrl: `${NEXT_PUBLIC_URL}/api/frame`,
});
```

When the user enters the text, it gets included in the frame message. You can see how it is retrieved in `api/frame/route.ts`. the `getFrameMessageBody` extracts the frame message from the request, and validates it. The returned `message` contains a number of useful properties that can be seen where it is defined in [OnchainKit], in `src/core/types.ts`:
When the user enters the text, it gets included in the frame message. You can see how it is retrieved in `api/frame/route.ts`. The `getFrameMessageBody` function extracts the frame message from the request, and validates it. The returned `message` contains a number of useful properties that can be seen where it is defined in [OnchainKit], in `src/frame/types.ts`:

```tsx
export interface FrameValidationData {
address: string | null; // The connected wallet address of the interacting user.
button: number; // Number of the button clicked
following: boolean; // Indicates if the viewer clicking the frame follows the cast author
input: string; // Text input from the viewer typing in the frame
interactor: {
fid: number; // Viewer Farcaster ID
custody_address: string; // Viewer custody address
verified_accounts: string[]; // Viewer account addresses
verified_addresses: {
eth_addresses: string[] | null;
sol_addresses: string[] | null;
};
};
liked: boolean; // Indicates if the viewer clicking the frame liked the cast
raw: NeynarFrameValidationInternalModel;
recasted: boolean; // Indicates if the viewer clicking the frame recasted the cast
state: {
serialized: string; // Serialized state (e.g. JSON) passed to the frame server
};
transaction: {
hash: string;
} | null;
valid: boolean; // Indicates if the frame is valid
}
```

The demo makes use of the `input` property to add the story text to the button in the next frame:
The demo doesn't make use of the `input` property, but it does extract the text:

```tsx
//api/frames/route.ts

// Extract the input:
if (message?.input) {
text = message.input;
}

// Other code

// Return a new frame, with the story `text`
return new NextResponse(
getFrameHtmlResponse({
buttons: [
{
label: `🌲☀️ ${text} 🌲🌲`,
},
],
image: {
src: `${NEXT_PUBLIC_URL}/park-1.png`,
},
postUrl: `${NEXT_PUBLIC_URL}/api/frame`,
}),
);
const text = message.input || '';
```

### Link Button
Expand All @@ -186,15 +144,17 @@ You can now add outbound links to buttons. To do this with [OnchainKit], simply

### Redirect Button

The third button contains a `Redirect to pictures ↗`. The way it works is a little tricky. Start with the `buttons` defined in the original frame in `page.tsx`. The third button is a `post_redirect`:
You can also do a redirect with a button. The example has one on the second frame - `Dog pictures ↗`:

briandoyle81CB marked this conversation as resolved.
Show resolved Hide resolved
```tsx
{
label: 'Redirect to pictures',
action: 'post_redirect',
label: 'Dog pictures',
},
```

The way it works is a little tricky.

Clicking this button hits the `postUrl`, with the requirement that you return a `redirect` response with a status of 302, and a link. You can see that in `route.ts`:

```tsx
Expand Down Expand Up @@ -244,42 +204,46 @@ if (message?.button === 3 && message.liked) {
getFrameHtmlResponse({
buttons: [
{
label: 'Story time!',
label: `State: ${state?.page || 0}`,
},
{
action: 'link',
label: 'Link to Google',
target: 'https://www.google.com',
label: 'OnchainKit',
target: 'https://onchainkit.xyz',
},
{
label: 'Redirect to pictures',
action: 'post_redirect',
label: 'Like to see doggos!',
},
],
image: {
src: `${NEXT_PUBLIC_URL}/park-3.png`,
aspectRatio: '1:1',
},
input: {
text: 'Tell me a boat story',
src: `${NEXT_PUBLIC_URL}/park-1.png`,
},
postUrl: `${NEXT_PUBLIC_URL}/api/frame`,
state: {
page: state?.page + 1,
time: new Date().toISOString(),
},
}),
);
}
briandoyle81CB marked this conversation as resolved.
Show resolved Hide resolved
```

Note that we're returning a `getFrameHtmlResponse` here, **not** a `getFrameMetadata`!

To test this, you'll need to actually cast the Frame. It won't work in the developer tool!
Note that we're returning a `getFrameHtmlResponse` here, **not** a `getFrameMetadata`. That's only used for the initial frame created from a page!

### Follow and Recast Gates

On your own, try changing the "like" gate to require the user to follow you, recast, or all three!

:::info

**Hint:** Take a close look at the `FrameValidationData` properties. [OnchainKit] makes this easy!

:::

## Conclusion

In this tutorial, you learned how to use the newest features of Frames - text input, link buttons, and redirects. You also learned how to use new features in [OnchainKit] to require your users to perform certain actions to unlock features in your Frame. Finally, you learned how to create a loop in your Frame's behavior, which can be used to create very complicated Frames!
In this tutorial, you learned how to use the main features of Frames - text input, link buttons, and redirects. You also learned how to use new features in [OnchainKit] to require your users to perform certain actions to unlock features in your Frame. Finally, you learned how to create a loop in your Frame's behavior, which can be used to create very complicated Frames!

---

Expand Down
Loading
Loading