🎥 Videography & Film · visual concepting

Moodboard Mint

Create NFT-backed moodboards to validate and share artistic vision securely with collaborators.

NFT provenance mint· onchain authorship
Section · Onchain

The primitive.

full primer →

Videographers mint each visual concepting as an ERC-721 token on 0G Galileo pointing at a 0G Storage root hash, so authorship and timestamp are provable from a single Chainscan link.

Why this primitiveNFT provenance anchors moodboard IPFS CIDs to creators, enabling trusted sharing.

Kernel
an ERC-721 / ERC-7857 contract on 0G Galileo that mints a creator-owned token pointing at a 0G Storage root hash
Drives the UI as
a 'mint to claim authorship' button that returns the tokenId, owner address, and 0G Chainscan link
Appendix · Secrets

Required keys.

METAMASK_PRIVATE_KEY
Exported from MetaMask. Fund on 0G Galileo via the faucet (0.1 OG/day).
open ↗
PRIVY_APP_ID
Enables Google sign-in and an embedded wallet on 0G Galileo. User signs their own tx and pays gas in OG (faucet: 0.1 OG/day).
open ↗
LOVABLE_API_KEY
Auto-provisioned by Lovable for AI calls via Lovable AI Gateway — nothing to paste. Default model: google/gemini-3-flash-preview.
open ↗

Add these three in your Lovable project under Settings → Secrets before pasting the prompt below. 0G's public RPC (https://evmrpc-testnet.0g.ai) is hardcoded — no RPC key needed.

Appendix · Mega-prompt

The build prompt.

Paste into a fresh Lovable project. Make sure all five secrets above are set first. read the build strategy →

Build "Moodboard Mint" in ONE Lovable message. Single-page demo.

CONCEPT
Create NFT-backed moodboards to validate and share artistic vision securely with collaborators.
Discipline: Videography & Film (visual concepting).
Onchain primitive: NFT provenance mint. Why this primitive: NFT provenance anchors moodboard IPFS CIDs to creators, enabling trusted sharing.

5-CREDIT BUDGET (HARD LIMIT):
- ONE single-page app. No router, no Lovable Cloud, no database, no auth flows beyond Privy drop-in.
- ONE Solidity contract, <=80 lines, deployed to 0G Galileo testnet, source uploaded to Chainscan-Galileo.
- Privy is always the auth + embedded-wallet layer (Google login, chainId 16602). Privy does NOT sponsor gas on 0G — the user signs every tx and pays in OG (top up from https://faucet.0g.ai, 0.1 OG/day).
- 0G Storage SDK (`@0glabs/0g-ts-sdk`) only if the idea genuinely needs to store a file.
- At most ONE AI call per user action via Lovable AI Gateway (LOVABLE_API_KEY, auto-provisioned) from a server route / server function. Default model: google/gemini-3-flash-preview.
- Skip tests, skip CI, skip docs pages. Ship the demo, nothing else.

0G GALILEO TESTNET (hardcode — no RPC secret needed):
  chainId:      16602            (0x40DA)
  name:         "0G Galileo Testnet"
  nativeCurrency: { name: "0G", symbol: "OG", decimals: 18 }
  rpcUrl:       "https://evmrpc-testnet.0g.ai"
  explorer:     "https://chainscan-galileo.0g.ai"
  storageExplorer: "https://storagescan-galileo.0g.ai"
  storageIndexer:  "https://indexer-storage-testnet-turbo.0g.ai"

STACK
- React + Vite single page (the index route).
- Privy embedded wallet wraps `<App />` in src/main.tsx:
    <PrivyProvider appId={import.meta.env.VITE_PRIVY_APP_ID}
      config={{ loginMethods:['google'], embeddedWallets:{createOnLogin:'users-without-wallets'},
                defaultChain:{ id: 16602, name:'0G Galileo Testnet',
                  nativeCurrency:{ name:'0G', symbol:'OG', decimals:18 },
                  rpcUrls:{ default:{ http:['https://evmrpc-testnet.0g.ai'] } },
                  blockExplorers:{ default:{ name:'Chainscan', url:'https://chainscan-galileo.0g.ai' } } } }}>
- All txs via Privy `useSendTransaction` with `chainId: 16602`. Privy does NOT sponsor gas on 0G — the user signs and pays in OG from their embedded wallet. Surface a "Top up at https://faucet.0g.ai" hint when balance is 0.
- src/lib/zerog-storage.ts uses the 0G TypeScript SDK:
    import { Indexer, ZgFile } from '@0glabs/0g-ts-sdk';
    import { ethers } from 'ethers';
    const RPC = 'https://evmrpc-testnet.0g.ai';
    const INDEXER = 'https://indexer-storage-testnet-turbo.0g.ai';
    export async function uploadToZeroG(file: File): Promise<string> {
      const signer = new ethers.Wallet(import.meta.env.VITE_METAMASK_PRIVATE_KEY,
        new ethers.JsonRpcProvider(RPC));
      const zg = await ZgFile.fromBlob(file);
      const [tree] = await zg.merkleTree();
      const rootHash = tree!.rootHash()!;
      const indexer = new Indexer(INDEXER);
      const [, err] = await indexer.upload(zg, RPC, signer);
      if (err) throw err;
      await zg.close();
      return rootHash; // the CID written onchain
    }
- Hardhat in /contracts (kept outside the Vite bundle). Install `@nomicfoundation/hardhat-toolbox`.
- hardhat.config.cjs (no Etherscan plugin — 0G uses Chainscan's web UI for verification):
    require("@nomicfoundation/hardhat-toolbox");
    module.exports = {
      solidity: { version: "0.8.28", settings: { optimizer: { enabled: false }, evmVersion: "paris" } },
      networks: { galileo: {
        url: "https://evmrpc-testnet.0g.ai",
        accounts: [process.env.METAMASK_PRIVATE_KEY.startsWith("0x")
          ? process.env.METAMASK_PRIVATE_KEY : "0x" + process.env.METAMASK_PRIVATE_KEY],
        chainId: 16602,
      } },
    };
- Deploy: `npx hardhat run scripts/deploy.cjs --network galileo`.
- VERIFY on 0G Chainscan (manual, web UI — there is no Etherscan-compatible API):
    1. Open `https://chainscan-galileo.0g.ai/address/<deployedAddress>` and click "Contract" -> "Verify and Publish".
    2. Compiler: solc 0.8.28, optimization OFF, evmVersion: paris. These exact settings are required for Chainscan-Galileo to match bytecode — do not deviate.
    3. Paste the flattened source (`npx hardhat flatten contracts/X.sol > flat.sol`, strip duplicate SPDX/pragma lines).
    4. Submit. On success the source becomes readable at `https://chainscan-galileo.0g.ai/address/<address>#code`.
    If verification fails with a bytecode mismatch, the cause is almost always optimizer ON or a different evmVersion — redeploy with the settings above rather than fighting the verifier.
- Frontend reads use viem with the hardcoded 0G RPC:
    import { defineChain, createPublicClient, http } from 'viem';
    export const galileo = defineChain({
      id: 16602, name: '0G Galileo Testnet',
      nativeCurrency: { name: '0G', symbol: 'OG', decimals: 18 },
      rpcUrls: { default: { http: ['https://evmrpc-testnet.0g.ai'] } },
      blockExplorers: { default: { name: 'Chainscan', url: 'https://chainscan-galileo.0g.ai' } },
    });
    const client = createPublicClient({ chain: galileo, transport: http() });
- Write the deployed address to `src/data/contract.json` so the UI links to
  `https://chainscan-galileo.0g.ai/address/<address>`.

CONTRACT (contracts/MoodboardMint.sol):
```solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;
import "@openzeppelin/contracts/token/ERC721/ERC721.sol";
/// @title MoodboardMint
/// @notice ERC-721 provenance for: Create NFT-backed moodboards to validate and share artistic vision securely with collaborators.
/// @notice Built during the Creative AI & Quantum Hackathon organised by StreetKode Fam during Indian Krump Festival 14
contract MoodboardMint is ERC721 {
    uint256 public nextId;
    mapping(uint256 => string) public cidOf;
    constructor() ERC721("MoodboardMint", "MOODBO") {}
    /// @notice Built during the Creative AI & Quantum Hackathon organised by StreetKode Fam during Indian Krump Festival 14
    function mint(string calldata cid) external returns (uint256 id) {
        id = ++nextId; cidOf[id] = cid; _safeMint(msg.sender, id);
    }
    function tokenURI(uint256 id) public view override returns (string memory) {
        return string(abi.encodePacked("0g://", cidOf[id]));
    }
}
```

USER FLOW
1. Land on page -> 'Sign in with Google' (Privy) -> embedded wallet auto-provisioned on 0G Galileo (chainId 16602).
2. After the user creates a visual concepting artefact, upload the file to 0G Storage via the 0G SDK (returns a root-hash CID), then call `mint(cid)` on the deployed contract via the Privy embedded wallet (`useSendTransaction`, `chainId: 16602`). User signs and pays gas in OG from the embedded wallet. Show tokenId, the Storagescan-Galileo preview (`https://storagescan-galileo.0g.ai/tx/<rootHash>`), and the Chainscan-Galileo mint-tx link.
3. Footer renders: "Built during the Creative AI & Quantum Hackathon organised by StreetKode Fam during Indian Krump Festival 14"

REQUIRED SECRETS (Lovable -> Project Settings -> Secrets):
- METAMASK_PRIVATE_KEY  0G Galileo deployer key. Fund it: https://faucet.0g.ai (0.1 OG/day) or https://hub.0g.ai/faucet?network=testnet
- PRIVY_APP_ID          Google sign-in + embedded wallet on 0G Galileo (user signs their own tx). Docs: https://docs.privy.io/llms-full.txt

AI calls (if the idea uses AI) go through Lovable AI Gateway via the auto-provisioned LOVABLE_API_KEY — no secret to add.
  Base URL: https://ai.gateway.lovable.dev/v1   Header: Lovable-API-Key: $LOVABLE_API_KEY
  Default model: google/gemini-3-flash-preview. Call from a server route / server function only; never expose the key client-side.

No SEPOLIA_RPC_URL, no ETHERSCAN_API_KEY, no PINATA_JWT, no AISA_API_KEY. 0G's public RPC is hardcoded
(https://evmrpc-testnet.0g.ai), verification happens on Chainscan-Galileo's web UI,
and blobs go through the 0G Storage SDK signed by the deployer key.

CREDIT (must appear in UI footer AND as NatSpec on every deployed contract):
Built during the Creative AI & Quantum Hackathon organised by StreetKode Fam during Indian Krump Festival 14
Appendix · Market

Market sizing.

TAM
$1.1B
creative asset management sector
SAM
$120M
video directors and concept artists
SOM
$7M
small teams using NFT for creative validation

Indicative figures for hackathon pitches — refine with your own research before raising.

See also

Adjacent entries.