A static web app (pure HTML/CSS/JS, no frameworks) that lets users upload a certificate image and mint it as an NFT on Polygon. Dark theme, cool modern UI. Deployed via GitHub Pages.
- URL: https://github.com/alfredang/certifynft.git
- Owner: alfredang
- Local path:
/home/orin_nano/.openclaw/workspace/projects/certifynft
- ✅ Pure HTML/CSS/JavaScript only — NO React, NO Next.js, NO Vue, NO build tools, NO bundlers
- ✅ Dark theme — modern, premium feel (glassmorphism, neon accents, smooth gradients)
- ✅ Cool UI — not plain bootstrap. Think: Vercel-style, linear.app-style, or crypto-dapp aesthetic
- ✅ GitHub Pages deployment via GitHub Actions workflow
- ✅ Ethers.js v6 via CDN (no npm install)
- ✅ Mobile responsive
- Land on page — hero with "Mint Your Certificate" CTA
- Click "Connect Wallet" → MetaMask popup → connect
- Auto-prompt to switch to Polygon Amoy testnet (chain ID 80002) if not on it
- Upload certificate image (PNG/JPG, drag-drop or click)
- Client-side compresses image to ~50KB JPEG (canvas API)
- Fill metadata form:
- Certificate Title (e.g., "Certificate of Completion")
- Recipient Name
- Issuer (e.g., "Tertiary Infotech Academy")
- Description
- Issue Date (defaults to today)
- Live preview of the certificate card with metadata
- Click "Mint NFT" → MetaMask signs transaction
- Success screen: tx hash, link to PolygonScan, link to view on OpenSea testnet
- "View My Certificates" section shows all NFTs minted by connected wallet
- No IPFS dependency (no API keys to leak)
- Metadata JSON encoded as
data:application/json;base64,...and passed astokenURI - Image embedded as
data:image/jpeg;base64,...inside the metadata - Image is compressed client-side to keep gas reasonable (target <50KB base64)
Simple ERC-721 with public mint:
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
import "@openzeppelin/contracts/token/ERC721/ERC721.sol";
import "@openzeppelin/contracts/token/ERC721/extensions/ERC721URIStorage.sol";
contract CertifyNFT is ERC721, ERC721URIStorage {
uint256 private _nextTokenId;
constructor() ERC721("CertifyNFT", "CERT") {}
function mint(address to, string memory uri) public returns (uint256) {
uint256 tokenId = _nextTokenId++;
_safeMint(to, tokenId);
_setTokenURI(tokenId, uri);
return tokenId;
}
function tokenURI(uint256 tokenId)
public view override(ERC721, ERC721URIStorage)
returns (string memory) {
return super.tokenURI(tokenId);
}
function supportsInterface(bytes4 interfaceId)
public view override(ERC721, ERC721URIStorage)
returns (bool) {
return super.supportsInterface(interfaceId);
}
}- Pre-deployed to Polygon Amoy testnet (or instructions for user to deploy via Remix in README)
config.jsexportsCONTRACT_ADDRESS+CHAIN_ID- If not deployed yet: placeholder
0x0000...0000with README instructions
const POLYGON_AMOY = {
chainId: '0x13882', // 80002
chainName: 'Polygon Amoy Testnet',
nativeCurrency: { name: 'MATIC', symbol: 'MATIC', decimals: 18 },
rpcUrls: ['https://rpc-amoy.polygon.technology'],
blockExplorerUrls: ['https://amoy.polygonscan.com']
};certifynft/
├── index.html # Main single-page app
├── styles.css # Dark theme, glassmorphism, animations
├── app.js # Wallet, image processing, minting
├── config.js # Contract address, network config
├── contracts/
│ └── CertifyNFT.sol # Smart contract source
├── assets/
│ ├── favicon.svg
│ └── logo.svg
├── .github/
│ └── workflows/
│ └── deploy.yml # GitHub Pages deploy
├── README.md # Full documentation
└── LICENSE # MIT
- Background: deep dark (#0a0a0f or #000000) with subtle animated gradient
- Accent colors: neon purple (#a855f7) + cyan (#06b6d4) or neon pink
- Cards: glassmorphism (backdrop-filter: blur, semi-transparent border)
- Typography: Inter or similar sans-serif via Google Fonts
- Animations: subtle hover lifts, smooth fade-ins, shimmer on buttons
- Icons: inline SVG (no external icon lib)
- Nav bar: Logo (left), "Connect Wallet" button (right), network indicator
- Hero: Big title "Mint Your Certificate", subtitle, animated glow
- Mint form card (glassmorphism): upload zone → metadata fields → preview → mint button
- Gallery section: "Your Certificates" grid below
- Footer: "How it works" + links + credit
- Drag-and-drop upload zone with hover state
- Live certificate preview card (shows image + metadata as it would appear)
- Transaction status modal (pending → success/error)
- Toast notifications for errors
.github/workflows/deploy.yml:
name: Deploy to GitHub Pages
on:
push:
branches: [main]
workflow_dispatch:
permissions:
contents: read
pages: write
id-token: write
concurrency:
group: "pages"
cancel-in-progress: false
jobs:
deploy:
environment:
name: github-pages
url: ${{ steps.deployment.outputs.page_url }}
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/configure-pages@v4
- uses: actions/upload-pages-artifact@v3
with:
path: '.'
- id: deployment
uses: actions/deploy-pages@v4- What it is / why
- Live demo URL (github.io link once deployed)
- How to use (user flow)
- How to get testnet MATIC (Polygon faucet)
- How to deploy the contract (Remix instructions, step-by-step)
- How to update
config.jsafter deploying contract - Local dev: just open
index.htmlin browser - License: MIT
- Working code in
/home/orin_nano/.openclaw/workspace/projects/certifynft/ - Git initialized, initial commit
- Attempt push to
https://github.com/alfredang/certifynft.git— if auth fails, document manual push commands - GitHub Actions workflow file ready (triggers on push to main)
- README with clear instructions
- ❌ PDF upload (images only for v1)
- ❌ User authentication (wallet is the auth)
- ❌ Backend/database
- ❌ Multi-chain support (Polygon only)
- ❌ Royalties / secondary sales
- ❌ Batch minting
- Opens in browser with dark cool UI
- Connect MetaMask works
- Auto-switches to Polygon Amoy
- Image upload + compression works
- Preview renders correctly
- Mint button calls contract (or shows proper error if contract not deployed)
- Gallery shows owned tokens
- Mobile responsive
- GitHub Actions workflow deploys on push
- README is clear for first-time users