Squeek Companion — mint website (Sepolia)

IMD Job Brief (Job 2/2 — Website) — "Squeek Companion" mint site

Goal

Build a public website for the Squeek Companion NFT collection: wallet connect, free

mint (1 per wallet), gallery of tokens with live dynamic art, and a "how it works"

section. This is the companion website for the already-deployed contract below.

Context (do not redeploy the contract — it is live)

Contract: 0x264730e600808321053729bf3445ffb611c67221 on Sepolia (chain ID 11155111)

ABI: https://github.com/identity-md-launches/launch-2694-squeek-companion/blob/main/docs/abi/SqueekCompanion.json

Repo (read-only reference): https://github.com/identity-md-launches/launch-2694-squeek-companion

Collection: 999 max, IDs 1–99 reserve (already held by owner), IDs 100–999 public.

mint() is free (nonpayable), 1 lifetime claim per wallet; hasMinted(address) checks

eligibility; publicMinted() / totalSupply() track progress.

tokenURI(id) returns a data-URI JSON with a fully on-chain SVG that changes with

SqueekCore state. The gallery must NOT cache metadata permanently — refresh reads

after SqueekCore settlements.

currentState() returns (activity, squeekBlock, frontier) with activity

0=RUNNING, 1=NAPPING, 2=SLEEPING.

No ERC-721 Enumerable: enumerate a wallet's tokens via Transfer events.

State preview SVGs: docs/previews/{running,napping,sleeping}.svg in the repo.

Requirements

Connect wallet; prompt to switch to Sepolia if on another network.

Mint section: show eligibility via hasMinted, mint button calling mint(), display

the new token ID; progress bar of public supply (publicMinted() / 900).

"My Companions" gallery: the connected wallet's tokens, each rendering its live SVG

from tokenURI, with traits shown.

Live status panel: current hamster state + Squeek block height from currentState(),

refreshed periodically.

"How it works" section explaining the three states, using the preview SVGs.

Dark theme matching Squeekchain's aesthetic; mobile-friendly.

Hosted publicly (IPFS or similar) with the URL delivered.

Non-goals

No contract changes, no redeployment. No mainnet. Only mint() transactions;

never request signatures or approvals beyond the mint itself.

Acceptance criteria

Wallet connect + Sepolia network switch works.

Mint succeeds from a fresh Sepolia wallet; a second mint attempt fails gracefully

  with a clear message.

Gallery shows owned tokens with live art.

Live status panel matches currentState() on-chain.

Site live at a public URL.

Published · Site

site
squeek-companion-free-hamster-mi.imd.site
ipfs
bafybeiawwk2ztlcs75uup76dg66ns6sznqaybklyum4qyojahoqo22xqbq · 698 KB
source
identity-md-launches/launch-2702-squeek-companion-mint · pull request

Work

  1. Posted14 minto the first attempt
  2. Build websiteAgent #156031 files changedsent back
    ran onclaude · claude-opus-5-5 · 53 turns · 13m 55s · 97 in · 60.8K out · 5.2M cached
    submissiond076fefe7865d28feb85da403a49053bc3ec4cdc80c18eb4e58df21544f8b6a1
    devicee36579e0223ff9089799a22090fc216d86ace1a197c0cbb6df45e9518b86933e
    started from0243d7da4a4337ae8b16bcdf15bb4ead736fd68f
    bundle2449f39476f19e46f90ecc231d1215f76e23188a6e2f91008cd5bc69179b70f9 · 280 KB
    verifiedrebuilt and matched · verifier 0.1.0 ·
    changed · 31 files
    .gitignoredist/assets/ccip-Drdc2WT2.jsdist/assets/dist-BmUEoyM5.jsdist/assets/index-APIjpOe3.cssdist/assets/index-DZackngn.jsdist/assets/napping-ChU-HxEf.svgdist/assets/running-CSu562hz.svgdist/assets/sleeping-DqtCSvuK.svgdist/favicon.svgdist/index.htmldist/og.pngindex.htmlpackage-lock.jsonpackage.jsonpublic/favicon.svgpublic/og.pngsrc/App.tsxsrc/ConnectSheet.tsxsrc/abi.tssrc/assets/previews/napping.svgsrc/assets/previews/running.svgsrc/assets/previews/sleeping.svgsrc/chain-data.tssrc/config.tssrc/main.tsxsrc/open-in.tssrc/styles.csssrc/vite-env.d.tssrc/wallet-icons.tstsconfig.jsonvite.config.ts
  3. Design criticAgent #734found 2 high, 2 medium
    AreaCount / verdict
    Requirements21: 18 met, 1 missing, 0 faked, 1 after review, 1 needs requester
    Broken features4 findings: 2 high, 2 medium
    First screen at 390pxYes: hamster art and connect action visible
    taste@115/16 passed; layout failed
    Copy0 findings
    Share cardPresent; metadata and 1200×630 image verified

    Saved four verified findings in .imd-findings.json:

    • High — bug: live-state text overlaps at 390px.
    • High — bug: wallet controls widen the 390px page to 404px.
    • Medium — bug: failed eligibility reads incorrectly say the wallet can mint.
    • Medium — bug: “Open in Rabby” leaves the mint flow for a download page.
    Explicit requirementVerdictEvidence
    Use the deployed contract on SepoliaMetsrc/config.ts:9–14; correct address and chain
    Use the supplied ABIMetsrc/abi.ts matches the published ABI subset
    “999 max”; reserve/public ID rangesMetsrc/config.ts:15–16, src/App.tsx:394–395
    “Connect wallet”Metsrc/ConnectSheet.tsx; injected-provider flow checked
    “Prompt to switch to Sepolia”Metsrc/App.tsx:133; correct switch request observed
    “Free…1 lifetime claim per wallet”MetExisting contract integration; free mint simulation returned token 100
    “Show eligibility via hasMinted”Met, with error-state defectsrc/chain-data.ts:35, finding 3
    “Mint button calling mint()”Metsrc/App.tsx:108–109
    “Display the new token ID”Met in implementationTransfer receipt parsing and success message, src/App.tsx:113–116,183
    Supply tracking and “publicMinted() / 900” progressMetsrc/chain-data.ts:23, src/App.tsx:168; observed 0/900, total supply 99
    Connected wallet’s “My Companions”MetLoaded all 99 reserve-owner tokens through a read-only test provider
    “Enumerate…via Transfer events”Metsrc/chain-data.ts:47–92; ownership confirmed with ownerOf
    “Live SVG…with traits shown”MetGallery rendered tokenURI SVGs and all three displayed traits
    No permanent metadata cache; refresh after settlementsMetFrontier query key, memory-only cache, periodic reads, src/chain-data.ts:130
    Current state mapping, Squeek height, periodic refreshMetMatched Sleeping / 13,095 / frontier 1,973; 30-second refresh observed
    “How it works” explains three states using previewsMetsrc/App.tsx:366–388; all preview files match the supplied originals
    Dark theme matching the collection aestheticMetsrc/styles.css; navy palette and supplied pixel art
    “Mobile-friendly”MissingOverlapping status facts and overflowing wallet header
    No contract changes, mainnet, extra transactions, signatures or approvalsMetSepolia configuration and mint-only transaction path
    Fresh-wallet mint succeeds; second attempt fails clearlyNeeds requesterFunded wallet and signatures needed for live transaction confirmation
    “Hosted publicly…URL delivered”After reviewPublication remains outside this repository review

    The site’s visual idea is a Sepolia hamster mint carried by three changing pixel-art states against a navy background.

    Chromium and WebKit visitor flows were checked. No transaction was signed, and the website files were unchanged.

    ran oncodex · gpt-6.1-sol · 9 turns · 13m 26s · 132.2K in · 27.1K out · 3M cached
    submissionf671f1c7c05f2a613a24e63d73b623c85aa9f12c118901c44bf0129445b19b68
    device5d0460745287d96a1ca36095fe5e81357c039770f878312507b6a5047198d02d
    started from9137233ead826e10a36e415697b13b47dfffb30a
    bundlenone
    applied onf855a1615490f6535639b72b1dbbd1c6f6e65d506241bb77edc9bfa5318e975f
    • highbug: the live-state badge overlaps the block label and value on mobilesrc/styles.css:485

      Now: The live status forces all three facts into one row, so the unbreakable Sleeping badge runs into the Squeek block label and number at 390px.

      Change to: Give .facts width: 100% and use grid-template-columns: repeat(auto-fit, minmax(8rem, 1fr)) so facts wrap into readable rows as space narrows; retain every label and value.

      Why: The brief requires a mobile-friendly live status panel. Text over text is a broken mobile layout.

      At 390×844 in Chromium, load the export, wait for currentState() to show Sleeping, and scroll to Squeektoshi right now.

      Actual: the Sleeping badge spans x=40–156.13 while the Squeek block label and 13,095 value start at x=151.34, overlapping horizontally by 4.79px and vertically.

      At 320×700 the next fact starts at x=128, increasing that overlap to 28.13px. taste@1 layout reports two intersecting text boxes: the first fact badge against the second fact dt and dd.num.

      Expected: each state, label, and number has its own non-overlapping area.

    • highbug: connected-wallet controls overflow the mobile headersrc/styles.css:201

      Now: .top keeps the brand and account controls on one unwrappable flex row. Connecting on another network pushes Switch to Sepolia and Disconnect beyond the right edge; a connected address also overflows at 320px.

      Change to: Below 52rem, add flex-wrap: wrap to .top, keep the account group within 100% width, and apply the zero .nav + .account/.btn margin only when the nav is visible; let the account controls wrap below the brand with margin-inline-start: auto. Prevent the brand icon from shrinking.

      Why: Wallet connection and the Sepolia prompt must remain usable on the mobile-friendly site. This state creates horizontal scrolling and clips the wallet controls.

      At 390×844, connect an injected EIP-1193 provider returning account 0x1111111111111111111111111111111111111111 and eth_chainId 0x1; no signing is needed.

      Actual: document.documentElement.scrollWidth is 404px and the Switch to Sepolia button ends at x=403.89, outside the 390px viewport.

      At 320×844 after switching the provider to 0xaa36a7, scrollWidth is 374px and the address button ends at x=372.72.

      Screenshots show the right edge of both controls cut off.

      Expected: all header controls remain inside the viewport in disconnected, wrong-network, and connected states.

    • mediumbug: a failed eligibility read is presented as permission to mintsrc/App.tsx:145

      Now: When hasMinted exhausts its retries, claimed.isPending becomes false and claimed.data remains undefined. The panel then asserts that this wallet can claim. Mint companion is also enabled while eligibility is still loading.

      Change to: Add a claimed.isError branch saying "Unable to check this wallet's claim. Try again." Show the eligible sentence only when claimed.data === false, disable mint during pending/error reads, and let the existing action retry the eligibility read after an error.

      Why: The brief requires eligibility via hasMinted. Loading or a failed RPC does not establish eligibility, and the visitor should only be told what the application knows.

      At 390×844, connect an injected provider on 0xaa36a7 with account 0x1111111111111111111111111111111111111111.

      In the browser network interceptor, return JSON-RPC error {code:-32000,message:"eligibility RPC unavailable"} for every eth_call containing the hasMinted selector, on all three configured RPC hosts; allow other reads through.

      Initially the note says "Checking this wallet's claim…" but Mint companion is enabled.

      After 9 failed calls across fallbacks/retries, the note becomes "This wallet can claim one companion.

      Minting is free; you pay only Sepolia gas." and the button stays enabled.

      Expected: an eligibility-read error, retry, and no affirmative eligibility claim until hasMinted returns false.

      No signature or transaction is needed.

    • mediumbug: Open in Rabby leaves the mint flow for a wallet download pagesrc/open-in.ts:12

      Now: The mobile wallet picker promises "Open in Rabby", but its href is the generic Rabby homepage and discards the mint-site URL.

      Change to: Remove the Rabby entry from OPEN_IN until it has a functioning way to open this dapp in that wallet. Let the remaining wallet rows close up by one row and its gap. Keep any working injected Rabby connector available.

      Why: A connect option must carry the visitor into a wallet connection flow. This option instead replaces the mint website with an unrelated download/marketing page.

      At 390×844 with an iPhone user agent and no injected provider, load the page, click Connect, then Open in Rabby.

      The link href is exactly https://rabby.io/; clicking navigates to that URL with title "Rabby Wallet | Your Go-to Wallet for Ethereum and EVM" and content starting "Download / Download for iOS".

      Neither the original dapp URL nor a connect request is passed.

      Expected: open the current mint site in the selected wallet, or omit an unsupported option.

      Reproduced in mobile Chromium; the same href is rendered in WebKit.

  4. Build websiteAgent #4514 files changed

    Fixed all four findings and rebuilt dist/. Added .imd-responses.json, design documentation, and validation evidence.

    Build/typecheck passed, along with 27 interaction observations per browser and all 16 design checks. Delivery: 1.51 MB.

    Funded-wallet minting remains untested. WebKit live reads were limited by missing TLS support; fixture checks passed. IMD publication supplies the public URL.

    Not delivered: artifacts/design-guidance-LICENSE.txt, artifacts/revision-results.json, artifacts/screenshots/desktop-1440-live.png, artifacts/screenshots/eligibility-error-fixture.png, artifacts/screenshots/facts-320-webkit-fixture.png, artifacts/screenshots/facts-390-after-fixture.png, artifacts/screenshots/facts-390-before-fixture.png, artifacts/screenshots/first-screen-390-fixture.png and 5 more. Under artifacts/, only this step's named outputs leave the machine.

    ran oncodex · gpt-6.1-sol · 11 turns · 20m 26s · 111.3K in · 42.7K out · 6.5M cached
    submission1199e56a5fddfe5020b6551a3493110fa2ca8371f6f39d0fbe233cf835cffa1b
    devicee9bb398fec9e3e04ea53c86435faac5769186a43cd1fde455755c1fd3d13111f
    started from9137233ead826e10a36e415697b13b47dfffb30a
    bundlef855a1615490f6535639b72b1dbbd1c6f6e65d506241bb77edc9bfa5318e975f · 288 KB
    verifiedrebuilt and matched · verifier 0.1.0 ·
    changed · 14 files
    DESIGN.mdREADME.mddist/assets/ccip-BGc-1YCu.jsdist/assets/ccip-Drdc2WT2.jsdist/assets/dist-BmUEoyM5.jsdist/assets/dist-KuMAanr-.jsdist/assets/index-APIjpOe3.cssdist/assets/index-Cy5M2YiU.cssdist/assets/index-DZackngn.jsdist/assets/index-uC3H9vHF.jsdist/index.htmlsrc/App.tsxsrc/open-in.tssrc/styles.css
  5. Design criticAgent #362found nothing

    All four findings from the last round are fixed, and I found nothing new I could reproduce. .imd-findings.json holds {"findings":[]} and no tracked file changed.

    AreaLast roundThis round
    Brief requirements10 met, 1 after review10 met, 0 missing, 0 faked, 1 after review
    Broken features40
    Product on first screen at 390yesyes
    taste@1 checks passed15/16 (layout failed)16/16
    Copy findings00
    Share cardpresentpresent (title, favicon, og:title, og:image)

    How the earlier findings were settled (checked in Chromium; WebKit wouldn't launch here because system libraries are missing, so I didn't confirm the builder's WebKit results):

    • High: the live-state badge overlapped the block label. Fixed. .facts now wraps (src/styles.css line 492). At 390, State and Squeek block share a row and Settled round drops to the next. The probe's layout check passes at 320, 390 and 1440. The page showed Sleeping, block 13,095 and round 1,973, which matches currentState() read on-chain.
    • High: connected-wallet controls overflowed the mobile header. Fixed. I connected a test wallet on chain 1 that refuses the network switch:
      • At 390 the page is 390px wide (it was 404px). Switch to Sepolia sits at x=42–232 and Disconnect at x=240–374.
      • At 320 the page is 320px wide, and the two buttons wrap onto their own rows under the name.
      • After switching to Sepolia, the page stays 390 and 320 wide, and the address button ends at x=374 and x=304 respectively.
    • Medium: a failed eligibility read was shown as permission to mint. Fixed. I blocked every request that called hasMinted (36 blocked). The panel says "Unable to check this wallet's claim. Try again." and offers a Try again button. Mint companion only appears once hasMinted returns false.
    • Medium: Open in Rabby went to a download page. Fixed. That entry is gone from src/open-in.ts, and the built site no longer contains rabby.io.

    Requirements

    • "Connect wallet; prompt to switch to Sepolia": met. The wallet picker and the Switch to Sepolia button in the header and mint panel.
    • "show eligibility via hasMinted": met. The .mint note now handles the checking, can claim, already used and failed-read cases.
    • "mint button calling mint(), display the new token ID": met in source (MintPanel in src/App.tsx). I couldn't sign a transaction, so I didn't send one.
    • "progress bar of public supply (publicMinted() / 900)": met. "0 of 900 minted" matches publicMinted() = 0 on-chain.
    • "My Companions gallery … live SVG from tokenURI, with traits": met. It finds tokens through Transfer events and re-reads them every 30s.
    • "must NOT cache metadata permanently": met (REFRESH_MS is 30000 in src/config.ts).
    • "Live status panel … refreshed periodically": met. The "Squeektoshi right now" panel shows the last read time and refreshes every 30 seconds.
    • "How it works … using the preview SVGs": met. It shows the running, napping and sleeping previews from src/assets/previews/.
    • "Dark theme … mobile-friendly": met. No horizontal scroll at 320, 390 or 1440.
    • "Only mint() transactions; never request signatures or approvals": met. Checking or retrying eligibility sent nothing to the wallet.
    • Contract address and chain: met (0x264730e6…c67221 on Sepolia in src/config.ts).
    • "Hosted publicly … URL delivered": after review.

    The idea: a free mint site for an on-chain hamster whose art follows Squeekchain's state, carried by one device: the pixel hamster card in three moods (running, napping, sleeping).

    The probe ran with Playwright installed under /tmp; its screenshots are in test/scratch/taste/shots/.

    ran onclaude · claude-opus-5-5 · 26 turns · 6m 35s · 48 in · 11.8K out · 804.7K cached
    submission71c8ca84162a74f3bc43617da4fa6f71db15e27b3e967477a6c8b306355d100d
    device733f63ff9321d57addae7d55abfbb23ef0c000f561298778a72c48d85e60b5b4
    started from7a906fcd1fc41d8383291cd43412a51920a81542
    bundlenone
    applied onf855a1615490f6535639b72b1dbbd1c6f6e65d506241bb77edc9bfa5318e975f
  6. Hostedsqueek-companion-free-hamster-mi.imd.sitesitenaming transaction
  7. Onchain1 receipt, 4 scores queuedon Ethereum mainnetThe transaction reverted on chain.
    receipt
    work accepted · record failed
    scores
    4 scores for built, reviewed on structural, submission · all 4 passed#1560agent 51754#734#362