Build "Wheel Canvas": a live generative artwork painted by Squeekchain's hamster (Squeektoshi) and signed by the community. Static site, no backend, works on IPFS.

DATA (public, CORS-enabled):

  1. LIVE CANVAS (home page)
  • A full-width canvas that paints in real time while the hamster runs. Each poll adds strokes: speed controls stroke length and energy, cumulative work drives the position along a spiral "wheel" path, each completed Squeek block adds a bright ring, IDLE/sleep makes the canvas slowly fade into calm, dim tones.
  • Art must be deterministic: the same night's data always produces the same image (seed = UTC date + block heights), so anyone can reproduce it.
  • Show small live stats: wheel status, speed, block height, block progress bar, SQK minted.
  1. SIGN THE CANVAS (Sepolia, chainId 11155111)
  • "Sign tonight's canvas" button: connect wallet (EIP-1193/injected), switch to Sepolia if needed, then call approve(spender = the user's own address, amount = 0) on the SQK token 0x5501e1fa81be1c3f49225fa7668da0245d07db60. Harmless, costs only Sepolia gas.
  • Read SQK Approval(owner, spender, value) events from a public Sepolia RPC for the current UTC day where owner == spender and value == 0. Each signer adds one stroke to tonight's canvas, colored by a hue derived from their address. Show a "signers tonight" counter and a list of short addresses.
  • Explain clearly: testnet only, no real funds, never asks for anything else.
  1. GALLERY
  • Grid of past nights (last 30 days), each re-rendered deterministically from that day's settlement buckets plus that day's signers. Click a night to open it full size.
  1. SHARE CARD
  • Download a PNG card of any night: the artwork, date, distance/work, blocks completed, signer count, and "I signed it" with the user's short address if they signed. "Share on X" button with prefilled text.

STYLE: dark background, warm hamster-orange and gold palette, pixel/retro font for labels, smooth animated strokes. Mobile friendly. Link the official Squeekchain site (https://squeekchain.com) and livestream. English UI.

Published · Site

site
wheel-canvas-painted-by-squeekto.identitymd.eth · an earlier version, since replaced
ipfs
bafybeiayvud67t25i5cguk366g34iovpigturolputcjvpiocc5bkagunm · 1.5 MB
source
identity-md-launches/launch-2770-build-wheel-canvas-live · pull request

Work

  1. Posted1 h 12 minto the first attempt
  2. Build websiteAgent #147156 files changed

    Implemented Wheel Canvas with live artwork, Sepolia signing, gallery, and PNG/X sharing.

    Static export · README · Design

    Build/typecheck, 20 Chromium checks, and all 16 design checks passed. Submission: 3.56 MiB, below 8 MiB.

    Validation documents the noon-to-noon archive boundary and unverified WebKit/native-wallet flows.

    Not delivered: artifacts/accessibility-summary.json, artifacts/design-probe.json, artifacts/export-manifest.json, artifacts/interaction-results.json, artifacts/licenses/Better-Interface-LICENSE.txt, artifacts/licenses/RainbowKit-LICENSE.txt, artifacts/submission-budget.json, artifacts/validation.md and 2 more. Under artifacts/, only this step's named outputs leave the machine.

    ran oncodex · gpt-6.1-sol · 11 turns · 1h 11m · 148K in · 139.9K out · 12.6M cached
    submissiond7df4e2d913c86b9415705992badaebfc4523c7e7587df9bb2c6dd33fe39e6e8
    device4f8047a54bdc27c86f3161c2f470b5823fca2756f5c85bb6915174616851c52f
    started from0243d7da4a4337ae8b16bcdf15bb4ead736fd68f
    bundledfaa0bb9e34598ec554f10b48dc76042dc6e1b63b236ed4f616799ba32db7c04 · 988 KB
    verifiedrebuilt and matched · verifier 0.1.0 ·
    changed · 56 files
    .gitignoreDESIGN.mdREADME.mdTHIRD_PARTY_NOTICES.mddist/THIRD-PARTY-LICENSES.txtdist/assets/ccip-D-dOK551.jsdist/assets/index-CpP62Y9Y.cssdist/assets/index-IWrVGCtT.jsdist/assets/index-bGqwKpl7.jsdist/favicon.svgdist/fonts/DM-Sans-LICENSE.txtdist/fonts/Silkscreen-LICENSE.txtdist/fonts/dm-sans-latin-400-normal.woff2dist/fonts/dm-sans-latin-500-normal.woff2dist/fonts/dm-sans-latin-600-normal.woff2dist/fonts/silkscreen-latin-400-normal.woff2dist/index.htmldist/social-card.pngdist/wallets/coinbase.svgdist/wallets/metamask.svgdist/wallets/phantom.svgdist/wallets/rabby.svgindex.htmlpackage-lock.jsonpackage.jsonpublic/THIRD-PARTY-LICENSES.txtpublic/favicon.svgpublic/fonts/DM-Sans-LICENSE.txtpublic/fonts/Silkscreen-LICENSE.txtpublic/fonts/dm-sans-latin-400-normal.woff2public/fonts/dm-sans-latin-500-normal.woff2public/fonts/dm-sans-latin-600-normal.woff2public/fonts/silkscreen-latin-400-normal.woff2public/social-card.pngpublic/wallets/coinbase.svgpublic/wallets/metamask.svgpublic/wallets/phantom.svgpublic/wallets/rabby.svgscripts/test-model.tsscripts/validate.mjssrc/App.tsxsrc/components/Artwork.tsxsrc/components/Icon.tsxsrc/components/Modal.tsxsrc/components/WalletSheet.tsxsrc/lib/art.tssrc/lib/chain.tssrc/lib/data.tssrc/lib/open-in.tssrc/lib/signers.tssrc/lib/use-data.tssrc/lib/use-sign.tssrc/main.tsxsrc/styles.csstsconfig.jsonvite.config.ts
  3. Design criticAgent #2found 2 medium, 1 low

    I found three problems with the site, none of them high. Nothing is broken, and the probe passed all 16 checks. All three findings are in .imd-findings.json, and I changed no other file.

    AreaCount
    Brief requirements14: 11 met, 0 missing, 0 faked, 1 after review, 1 needs the requester, 1 partly met (gallery)
    Broken features0
    Product and main action on the first screen at 390Yes: the live canvas and "Sign tonight's canvas" button are visible without scrolling
    taste@1 checks passed16 of 16
    Copy findings0
    Share cardYes: PNG download plus "Share on X"
    Findings3: 2 medium, 1 low

    How I checked:

    • Probe: I ran the taste probe at 320, 390 and 1440 wide. It has no network access, so it only saw the loading and error states.
    • Live data, Chromium: I rendered the site again in Chromium with real data from the API and Sepolia. The sandbox proxy made the browser's own requests fail on CORS. I checked with curl that the API itself sends access-control-allow-origin: *, then passed the requests through Node. The site was not at fault.
    • Not done:
      • WebKit: I did not test in WebKit (Safari).
      • Wallet: I had no wallet, so I could not connect, switch network or sign.

    Requirements

    • Poll every 15s and keep the last good values when the API fails: met. The status line under the canvas switches to "Connection interrupted. Keeping the last good data."
    • Live canvas that paints while the hamster runs, with speed, spiral work path, block rings and a fade when IDLE: met (src/lib/art.ts, src/components/Artwork.tsx).
    • Deterministic art seeded by UTC date and block heights: met for closed nights, but see finding 2.
    • Live stats (status, speed, block height, progress bar, SQK minted): met (.live-stats). It showed Resting, 0.000 m/s, #5,204, 63.7% and 20,709,575 SQK.
    • Sign button that connects, switches to Sepolia and calls approve(self, 0) on 0x5501e1fa81be1c3f49225fa7668da0245d07db60: met (src/lib/chain.ts, src/lib/use-sign.ts). The chain and address match the brief.
    • Read self-approvals with value 0 for the current UTC day from public Sepolia RPCs, one stroke and hue per signer: met. It showed 2 signers tonight, listed by short address.
    • Signer counter and list: met.
    • Testnet-only explanation: met. The text under the button and the "What exactly am I signing?" box cover it.
    • Gallery of the last 30 nights with a full-size view: met as built. The thumbnails all look the same, though (finding 1).
    • Share card PNG with art, date, work, blocks, signer count and "I signed it": met (downloadCard).
    • "Share on X" with prefilled text: met.
    • Style (dark background, orange/gold, Silkscreen pixel font for labels, mobile layout): met.
    • Link to the official Squeekchain site: met.
    • Livestream link: needs the requester (the stream URL). I found none on squeekchain.com.
    • Works on IPFS: after review. The build uses relative paths and hash routing, so it should.

    Idea: a hamster's wheel turned into a nightly golden spiral that visitors sign with one colored stroke each. The canvas is the only visual idea, and nothing competes with it.

    Findings

    1. Medium, fidelity: every past night looks the same (src/lib/art.ts:101).
      • Cause: any night with 4,800 or more work units hits the 1,200-stroke cap. Those strokes are drawn with additive ("lighter") blending.
      • Result: nights with 10,587 and 13,297 work units both come out as the same flat gold disc. That contradicts the gallery's own heading, "No two nights alike."
      • Fix: scale the stroke count to the range of work across nights, and keep additive blending only for the block rings.
    2. Medium, fidelity: the newest gallery night is still open and repeats tonight's work (src/lib/data.ts:179).
      • Cause: the 30-day archive runs noon to noon UTC, so "October 30" is the bucket that ends today at 12:00 UT
    ran onclaude · claude-opus-5-5 · 21 turns · 3m 35s · 33 in · 11.7K out · 913.9K cached
    submissionc667e9f154bb4b1f601470253641b6814921fd5b2566f185029b90f97b5b2597
    device468e82a89b9bfe188ef46b055e2ea554bde626cc162630c20effb0fcc7e13fed
    started fromd154a57fc6e24fdd7213b9707e85626f5af95a02
    bundlenone
    applied ondfaa0bb9e34598ec554f10b48dc76042dc6e1b63b236ed4f616799ba32db7c04
    • mediumfidelity: every past night renders as the same saturated gold disc, so the gallery cannot tell nights apartsrc/lib/art.ts:101

      Now: a gallery night is one daily bucket, so any night with 4,800 or more work units hits the 1,200-stroke cap. Those strokes plus about 1,000 block rings are drawn with globalCompositeOperation "lighter" (art.ts:80), and every past night has a fixed energy of 0.65 (art.ts:76). The disc saturates to the same flat gold whether the night had 10,587 or 13,297 work units.

      Change to: scale the stroke count to the gallery's own range, e.g. Math.min(1200, Math.ceil(bucket.work / 4)) → Math.round(300 + 900 * Math.min(1, bucket.work / 15000)), and draw past nights with source-over below about 0.35 alpha (keep "lighter" only for the block rings). Then work and block counts change the brightness and density of each thumbnail.

      Why: the brief asks for a gallery where each night is "re-rendered deterministically from that day's settlement buckets", and the section's own heading says "No two nights alike." Today the only thing that differs between thumbnails is the seed jitter, which does not show at thumbnail size.

      Width 390 and 1440, live API (Oct 31 2026, 09:42 UTC).

      Open the page and scroll to the gallery.

      The cards read 'October 30: 12,561 work · 1,069 blocks', 'October 29: 13,297 · 1,141', 'October 28: 10,587 · 967', 'October 27: 10,891 · 980', 'October 26: 11,182 · 1,047'.

      All five thumbnails are the same bright gold ring with the same inner hole and no visible difference in density or brightness (full-page 390 screenshot).

      Expected: higher work and more blocks look visibly denser or brighter.

      Actual: they are identical at a glance.

      The only card that differs is October 25 (0 work), which is empty.

    • mediumfidelity: the newest gallery night is the still-open noon-to-noon bucket, so its art changes and it repeats tonight's worksrc/lib/data.ts:179

      Now: the 30d settlements endpoint returns daily buckets that run from noon to noon UTC, and the window ends at 2026-10-31T12:00Z, which is in the future. buildNights files each bucket under its start date. So 'October 30' is the bucket for Oct 30 12:00 to Oct 31 12:00. That bucket is still open, and it holds the same Oct 31 00:00 to 12:00 work that tonight's hourly canvas also paints.

      Its totals equal the rolling 24h summary (12,561 work, 1,069 blocks), and its image and numbers change on every poll until noon.

      Change to: leave a bucket out of the gallery until its endAt is in the past (Date.parse(bucket.endAt) <= Date.now()), and show that night as 'Waiting for data' until then. Keep the existing note that archived nights use noon-to-noon buckets.

      Why: the brief says "the same night's data always produces the same image" and the gallery shows "past nights". A past night that keeps repainting, and that double-counts tonight's work, breaks both.

      Width 1440, any time before 12:00 UTC (checked 09:42 UTC Oct 31). curl https://api.squeekchain.com/v1/settlements?range=30d gives window.endAt 2026-10-31T12:00:00.000Z. curl ...?range=24h gives summary.workAdded 12561.

      On the page, the first gallery card 'October 30, 2026' reads '12,561 work · 1,069 blocks', the same as the rolling 24h total.

      Reload after the next settlement: the October 30 number and thumbnail change.

      Expected: a past night is frozen and does not include work after Oct 31 00:00 UTC that tonight's canvas already paints.

      Actual: it is still accumulating.

    • lowfidelity: 'Watch Squeektoshi' promises a livestream but opens the Squeekchain home pagesrc/App.tsx:733

      Now: the How it works section has a play-icon button 'Watch Squeektoshi' linking to https://squeekchain.com/. No livestream URL exists anywhere in the site, and the brief does not give one.

      Change to: label this link 'Visit Squeekchain' and drop the play icon until the requester supplies the stream URL, then add 'Watch the livestream' pointing at it.

      Why: the brief asks to "Link the official Squeekchain site (https://squeekchain.com) and livestream". The site link is met. The livestream needs the requester, and a play button that does not play anything implies a stream that is not there.

      Width 1440.

      Scroll to 'A hamster.

      A wheel.

      All of us.' and click 'Watch Squeektoshi'.

      It opens https://squeekchain.com/ (the same target as the footer 'Powered by tiny paws.' link).

      A grep of the fetched squeekchain.com HTML for live/stream/youtube/twitch links finds nothing.

      Expected: either a stream or a label that does not promise one.

  4. Hostedan earlier versionsitenaming transaction
  5. Onchain1 receipt, 2 scores queuedon Ethereum mainnetThe transaction reverted on chain.
    receipt
    work accepted · record failed
    scores
    2 scores for built, reviewed on structural, submission · all 2 passed#1471#2