๐ฎ Snippi NFTs: The interactive NFT collection for frontend developers
An NFT collection and frontend code playground to mint code snippets as NFTs
What are Snippi NFTs
Snippi NTFs is an NFT collection and frontend code playground to mint code snippets as NFTs. It's a custom web app built with Next.js that integrates a frontend code playground where you can build interactive NFTs. The generated HTML file then gets minted to the blockchain of Polygon Network and is rendered in the web app using iframes.
๐ You can try Snippi NFTs here
๐ Get some free MATIC for your wallet from Polygon's Faucet
** NFTs are being mintent to Polygon's Testnet: Mumbai, connect your wallet to that network.
๐ผ Screenshoots
Homepage
NFT details page
Code playground
NFT mint
๐ฅ Problem
Most NFTs we see are made by artists, but to create an NFTs you not only need to know about the technical part, but you also need to have knowledge about illustration tools, photoshop, blender or whatever it requires to create your NFT asset.
In the other hand, frontends can also create impressive stuff with just code, there are many 3D rendering engines, animation libraries, and more to build complex or easy art elements for websites. With Snippi NFTs frontend artists can easily create an NFT out of their code snippet, it's an easy form to onboard them to NFTs.
๐ The Solution
To create an NFT collection and code playground to let frontend developers easily create and mint code snippets as NFTs. While most NFTs are static or video assets, making code snippets as NFTs also allows to create NFTs users can interact with.
๐ Tech Stack
The tech stack used for this app was:
Thirdweb SDK
We've heard of Web3 these days right. It was a new world for me, to be honest I am not that expert in Web3. Hopefully, if you know JavaScript or Python, you can start building Web3 Apps thanks to Thirdweb SDK.
Thirdweb is a platform with all the tools needed to build Web3 apps, you can build NFTs, marketplaces, tokens, packs, drops, and splits from their dashboard without the need to write code, or using its powerful SDK to develop your own code as needed.
๐ The Making Of
Once I had the idea, I usually create an unstyled version of the app before writing the whole codebase. While exploring options for the main feature which is the code playground, I found some React packages to integrate CodeMirror as the editor. I had built a code playground in the past, but never made it with React so I finally went with this package.
Once I validate that I can create the app and the requirements of it, I made some simple designs on a figma file
The code is saved in the app state and in localStorage
so code is kept safe in case the app crashes. When state changes, the code is passed to a function that generates a HTML document string and then it's injected into the rendering iframe.
// @utils/generateSnippet.ts
import type { Snippet } from '@stores/playground';
const generateSnippet = (title: string, code: Snippet) => {
return `<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>${title}</title>
<style>
${code.css}
</style>
</head>
<body style="min-width: 100vw; min-height: 100vh;">
${code.html}
<script>
${code.js}
</script>
</body>`;
};
export { generateSnippet };
Thirdweb's code examples were a great resource to find specific examples on how to interact with the SDK. From there I copied and adapted the examples for mint, and getAllWithOwner.
For the minting function I created an api function that receives the NFT data such as the wallet address, the code snippet, the name, and description. The HTML file is generated using a Buffer from the code snippet and then it gets passed to the mint function which utilizes my own MetaMask private key to mint it to my collection.
Initially an image of the NFTs was being generated with a node package that utilizes puppeteer in the hood, but after deploying it to Vercel found that this package does not work so I removed that option for now.
// @pages/api/mint.ts
import type { NextApiRequest, NextApiResponse } from 'next';
import { nftCollection } from '@utils/thirdweb';
import { generateSnippet } from '@utils/generateSnippet';
const handler = async (req: NextApiRequest, res: NextApiResponse) => {
if (req.method !== 'POST') {
res.status(405).end(`Method ${req.method} Not Allowed`);
return;
}
const { address, name, description, code } = req.body;
if (!address) {
res.status(400).end('Missing Address');
return;
}
const snippet = generateSnippet(name, code);
const file = Buffer.from(snippet);
/**
* ToDo: find a way to convert the html string to image
* vercel and netlify don't support puppeter so librearies are useless
*/
// import nodeHtmlToImage from 'node-html-to-image';
// const image = await nodeHtmlToImage({
// html: snippet,
// });
return new Promise<void>((resolve) => {
nftCollection
.mintTo(address, {
name,
description,
// image,
file,
})
.then((data) => {
res.status(200).json(data);
console.log('New NFT data ->', data);
resolve();
});
});
};
export default handler;
Finally, the code is deployed to Vercel on every git push so you know how the rest works.
๐ค Known Caveats
- NFTs does not include an image resource: initially it was included, a preview image of your html was being rendered using
node-html-to-image
, but because of Vercel platform limitations I had trouble with puppeteer, so I temporary removed this option. Anyways if you clone the repository, you can still make it work in local by installing the library and uncommenting the respective lines inpages/api/mint.ts
path. - Vercel functions cold start issues: when you try to mint your NFT, you may see the loader in the "MINT" button and then it will enable again, if you don't get the confirmation alert navigate back to your user page or the "explore" page to see if your NFT was minted (it was). Unless you get that confirmation message all your code is saved in
localStorage
, so don't worry for losing it. (Update: it is more of a code size issue, if your snippet does not have thousands of lines of code, it should be working fine) - Some performance issues: as it loads a lot of frames, it gets slow. (Update: I've added browser based lazy loading for iframes and dns preconnection to ipfs.io)
๐ฝ GitHub repository and demo
You can find all the code in the GitHub repository and the live demo website here; also, the collection is available on OpenSea.
Cheers! โจ