# ⚔️ Intro to Frames <!-- Need to move overview content that is not event specific here --> ## Hack-a-thons - [⚔️ Hacking Frames](https://hackmd.io/G3msHBgKR6yAXmmD8mS1hw?view) (Hack One) - [⚔️ Frame Hack Deux](https://hackmd.io/ZIOAnYnhT2Sc6Dj6Kr-EHg?view) ## Workshops - [On-Chain Basic Base Frames Workshop](https://hackmd.io/So0bAr3eSVqJQU7LHi6DAA?both) ## ⚔️ Tools - [frog](https://frog.fm/) [`/frogfm`](https://warpcast.com/~/channel/frogfm) - [OG Image Playground](https://og-playground.vercel.app/) - [Neynar](https://neynar.com/) - [Pinata](https://docs.pinata.cloud/farcaster/introduction) - [Airstack](https://www.airstack.xyz/) - [with Airstack 🐸 Frog Middleware it's now 🫰 to fetch anything onchain about Frames users](https://warpcast.com/betashop.eth/0xbadd8c6a) - [Airstack Frog Recipes & Middleware](https://docs.airstack.xyz/airstack-docs-and-faqs/guides/airstack-frog-recipes-and-middleware) - [frames.js](https://framesjs.org/) - [Frame Validator](https://warpcast.com/~/developers/frames) - [Developers: Embeds](https://warpcast.com/~/developers/embeds) ## Resources - [The Open Graph protocol](https://ogp.me/) - [Open Graph (OG) Image Generation](https://vercel.com/docs/functions/og-image-generation) - [Frames Docs](https://docs.farcaster.xyz/learn/what-is-farcaster/frames) - [Frame Specification](https://docs.farcaster.xyz/reference/frames/spec) - [Getting started with frog.fm](https://frog.fm/getting-started) - [Frame Transactions [Public]](https://www.notion.so/warpcast/Frame-Transactions-Public-9d9f9f4f527249519a41bd8d16165f73) - [RainbowKit](https://www.rainbowkit.com/docs/introduction) (Warpcast Web) - [Mobile Wallet Protocol](https://mobilewalletprotocol.github.io/wallet-mobile-sdk/docs/spec/) ([wallet-mobile-sdk](https://github.com/MobileWalletProtocol/wallet-mobile-sdk/)) (Warpcast Mobile) - [Farcaster Frames Transactions](https://dune.com/jhackworth/frames) Dune Dashboard ## WTF are Frames? Frames are a new design pattern. A way of interacting with dynamic content. Developers can build a multi-view experience in the feed. The app has user context. The user is able to send data to the server. It allows developers to embed parts of their app in the feed and link users to specifc parts of your app. Frames extend the OpenGraph standard and turn static embeds into interactive experiences. - [Farcaster Frames](https://docs.farcaster.xyz/learn/what-is-farcaster/frames) - [The Open Graph protocol](https://ogp.me/) Frames are simple af! They are essentially just dynamic images that are interacted with intents. ![image](https://hackmd.io/_uploads/rkq8Yg_pa.png) All they are really doing is generating meta tags in HTML. ```html <meta property="fc:frame" content="vNext" /> ``` ### [Required Properties](https://docs.farcaster.xyz/reference/frames/spec#required-properties) - `fc:frame` - `fc:frame:image` - `og:image` ### [Optional Properties](https://docs.farcaster.xyz/reference/frames/spec#optional-properties) - `fc:frame:button:$idx` - `fc:frame:post_url` - `fc:frame:button:$idx:action` - `fc:frame:button:$idx:target` - `fc:frame:input:text` - `fc:frame:image:aspect_ratio` - `fc:frame:state` Don't know why but I am kinda obsessed with meta data. Probably cause it is easy for my smooth brain to understand. Sam has called me, "The unfurl guy." I had also been looking into [htmx](https://htmx.org/) so some things just clicked and I kinda geeked out as soon this stuff was released. Here is the simple first [Yeet](https://warpcast.com/earth2travis/0x79d08f72) frame I made: ![image](https://hackmd.io/_uploads/r1BPMXd6T.png) That one did not even have any dynamic image ish. It just updated the metadata with a different `.png` based on what button was pushed. ```html <meta property="fc:frame" content="vNext" /> <meta property="fc:frame:image" content="${NEW_IMAGE_URLimage}" /> <meta property="fc:frame:button:1" content="YEET" /> <meta property="fc:frame:button:2" content="YEET" /> <meta property="fc:frame:button:3" content="YEET" /> <meta property="fc:frame:button:4" content="YEET" /> <meta property="fc:frame:post_url" content="${POST_URL}" /> ``` - [page.tsx](https://github.com/earth2travis/frames/blob/main/src/app/page.tsx) - [route.ts](https://github.com/earth2travis/frames/blob/main/src/app/api/frame/route.ts) The only real PITA was that it is a full Next.js app that had to be deployed to Vercel and checked in the [Frame Validator](https://warpcast.com/~/developers/frames) to test every small change. Being able to do most of that locally in a sexy console was one of the things that got me so excited about frog. ![image](https://hackmd.io/_uploads/BJInY7uaT.png) Vanilla made the [first RaidGuild frame](https://warpcast.com/vani11a/0x534e495d): ![image](https://hackmd.io/_uploads/rJNCA4u6p.png) ### Image ![image](https://hackmd.io/_uploads/SkB6Bm_6T.png) The image is `1200x630` which is a aspect ratio of `1.91:1`. If you use `1:1` you still need the `og:image` fallback for clients that do not support frames. ### Intents ```tsx import { TextInput, Button, Frog } from 'frog'; ``` - [Button](https://frog.fm/intents/button#button) - [Button.Link](https://frog.fm/intents/button-link#buttonlink) - [Button.Mint](https://frog.fm/intents/button-mint#buttonmint) - [Button.Redirect](https://frog.fm/intents/button-redirect#buttonredirect) - [Button.Reset](https://frog.fm/intents/button-reset#buttonreset) - [Button.Transaction](https://frog.fm/intents/button-transaction#buttontransaction) - [TextInput](https://frog.fm/intents/textinput#textinput) ## Where is this going? While this fuel has been poured on Farcaster `frames.js` is enabling [Display Frames](https://framesjs.org/guides/display-frames) in any site or app and pushing for [Open Frames Spec [Draft v0.0.2]](https://github.com/open-frames/standard) to become a standard. [Frames in CharmVerse](https://warpcast.com/ccarella.eth/0xde011da7) jaymehoffman.eth wrote a good article about [Framing Frames](https://paragraph.xyz/@jayme/framing-frames?referrer=0xBC5b552641e5d203f0a6C230aA9dC14DA7450053 ) on Paragraph. **Six Mental Models to Help You Think about Farcaster Frames** 1. Frames: [OG+] 2. Billboarding with frames 3. Headless marketplaces 4. Many-to-many mini apps 5. Bring your product into frames 6. Small Apps, Growing Protocols ## Features ![image](https://hackmd.io/_uploads/BJsXkB_T6.png) In just over a month we have gone from meta tags to transactions - [input](https://warpcast.com/horsefacts.eth/0x3b404256) - [state](https://warpcast.com/horsefacts.eth/0xaa0254dd) - [transactions](https://warpcast.com/v/0xc5e99831) ## Vision Comms are critical to coordination. Farcaster is a new standard for social communication. And it appear to be the first real demand for DAOs. PFP projects and memecoins are bringing communities together fast. There is governace of: - Coins - NFTs Frames can already hold tokens and I assume there will be governance over frames themselves. This community is actually asking for DAO tools. Let's sneak the Moloch pill into a hotdog and get the baseheads doing real onchain shit. Nouns is active on Warpcast and if we wait too long we may lose governance of the culture layer like we missed governance of defi protocols with Compound. ## Examples There are some good examples in this thread: [Since Frames launched, we’ve announced four rounds of grants for builders creating /frames on Base](https://warpcast.com/base/0x0d1c73e2) - [Testnet Faucet](https://warpcast.com/haardikkk/0x28f4237d) - [Vitalik's Survey](https://warpcast.com/vitalik.eth/0x940d8535) - [Base Quest](https://warpcast.com/seangeng/0xedb2a886) - [Yoink!](https://warpcast.com/horsefacts.eth/0x3a0bc387) - [Wanna play??](https://warpcast.com/popwonder/0xff5a1960) - [frameme](https://frameme.xyz/frameme) - [Are you a Farcoder?](https://warpcast.com/polluterofminds/0x276b4b45) - [@boombox](https://warpcast.com/coopahtroopa.eth/0x76cd1af4) - [Send the gift of Farcaster storage to someone with the Storage Fairy.](https://warpcast.com/v/0x9b8f5abb) - [Randomly generate @custompunks](https://warpcast.com/falcon/0x96c92599) ### Frames ### Repos #### [storage-fairy](https://github.com/horsefacts/storage-fairy) (frog.fm) ```json "dependencies": { "@neynar/nodejs-sdk": "^1.11.0", "frog": "latest", "hono": "^4", "viem": "^2.7.19" }, "devDependencies": { "tsx": "^4.7.1", "typescript": "^5.3.3", "vercel": "^32.4.1" } ``` #### [adventure_frame](https://github.com/thebreadcat/adventure_frame) #### [stateful-counter-frog-demo](https://github.com/horsefacts/stateful-counter-frog-demo) #### [yoink](https://github.com/horsefacts/yoink) ## Tips ### Routes Unsure of best practices but think most of these are intended to be a single file. But if you create multiple pages: - `view.tsx` - `vote.tsx` Just add them in the `src` directory and import them into `index.tsx` ```index.tsx import { app as view } from './view'; import { app as vote } from './vote'; app.frame('/', c => {}); app.route('/view', view); app.route('/vote', vote); ``` ### Design The `css-in-js` is pretty simple. But you can also use images for more detailed designs. [FrogUI](https://frog.fm/ui) is :fire: horsefacts said [Satori](https://github.com/vercel/satori) might be the way to include fonts without React. Tailwind is not necessary. But... - [Access to custom Tailwind config through ImageResponse #503](https://github.com/vercel/satori/issues/503) - [Vladyslav Dalechyn](https://warpcast.com/dalechyn.eth/0xe1747083) ## Building Farcaster Frames with Frog <iframe width="560" height="315" src="https://www.youtube.com/embed/dngMrWsmHBM?si=y25jxoEfQunQ84dP" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen></iframe>