Skip to content

Latest commit

History

158 Commits

Folders and files

NameName
Last commit message
Last commit date

Repository files navigation

GeneratedArt — Platform

Code-based generative art, owned by the people who write it. A community-run platform and on-chain marketplace for hand-written p5.js, three.js, WebGL and GLSL. Spiritual successor to fxhash and Art Blocks, with a physical-digital bridge through the Geneva gallery.

What's shipped (v0.1.0-hackathon)

SurfacePathBacked by
Wallet sign-in/connect/Hono Worker + SIWE + KV sessions
Repo-as-project/dashboard/GitHub PAT (central) + D1 projects
Sketch Studio/studio/CodeMirror 6 + sandboxed p5 iframe + R2
Profile + follow/@{handle}/D1 users / follows + static _authors
Mint on Base/mint/{id}GAProject + GAProjectFactory (Base Sep.)
Briefs board/briefs/D1 briefs + KV rate limit

Architecture

graph LR
subgraph "Static site (Cloudflare Pages)"
Jekyll[Jekyll<br/>generatedart.com]
Authors["_authors/{handle}.md"]
Studio[/studio/]
Briefs[/briefs/]
end
subgraph "Worker (Cloudflare)"
API[Hono · api.generatedart.com]
KV[(KV<br/>sessions + rate limit)]
D1[(D1<br/>users / projects / briefs / ...)]
R2[(R2<br/>canvas captures)]
end
subgraph "GitHub"
Org[GeneratedArt-artists org<br/>per-project repos]
PAT[Central PAT in Wrangler secrets]
end
subgraph "Base L2"
Factory[GAProjectFactory<br/>EIP-1167 clones]
Project[GAProject ERC-721<br/>EIP-2981 royalties]
end
Browser((Wallet)) -- SIWE --> API
Jekyll -- "/v1/* fetch" --> API
API <--> KV
API <--> D1
API -- "captures/* PUTs/GETs" --> R2
API -- "create / commit" --> Org
PAT -.-> API
Browser -- "deploy / mint tx" --> Factory
Factory -- "clones" --> Project
Project -- "tokenURI = ipfs://{cid}/?seed=" --> IPFS[(IPFS<br/>frozen source)]
Loading

§2 of the platform brief in long form. Highlights:

  • One static target, one dynamic service. Cloudflare Pages serves the Jekyll site; everything dynamic is one Hono Worker. No AWS, Vercel, Firebase, Supabase, Mongo, or Stripe-as-primary-rails.
  • Wallet does every transaction. The Worker only returns calldata for deploy / lockCID / mint and verifies receipts; no platform key holds funds.
  • Source is the asset.tokenURI resolves to a frozen IPFS CID that contains the exact repo state at mint time, plus a deterministic ?seed= param.

Layout

platform/
├── _config.yml, _layouts/, _includes/, _data/, _posts/ Jekyll site (root)
├── _authors/ /@{handle}/ static front-matter
├── briefs/, mint/, p/, studio/, dashboard/, @/ Surface pages (Jekyll)
├── assets/{css,js,img,images}/ Brand CSS + bundled TS
├── workers/
│ └── api/ Hono Worker — auth, projects, profiles, mint, briefs
│ ├── src/ index.ts + auth/ + projects/ + users/ + briefs/ + db/ + lib/
│ ├── client/ Vanilla TS bundles (esbuild → assets/js/ga-*.js)
│ └── migrations/ D1 schema (0001..0006) + demo seed (0004)
└── contracts/ Foundry — GAProject, GAProjectFactory (Base L2)

Quickstart

# 1. Static site (Jekyll, port 5000)
bundle install
bundle exec jekyll serve --host 0.0.0.0 --port 5000
# 2. API Worker (Hono, port 8787)cd workers/api
npm install
cp .dev.vars.example .dev.vars # then set JWT_SECRET (openssl rand -hex 32)
npx wrangler d1 migrations apply DB --local # one-time + after every new migration
npm run dev
# 3. Bundle changes
npm run build:all # rebuilds every assets/js/ga-*.js

The Replit Start application workflow runs the Jekyll command above.

Verifying the API

cd workers/api
npm run typecheck # tsc --noEmit over src/
npm test# unit + bundler-determinism regressions, no Worker needed
npm run smoke # 90+ end-to-end HTTP checks against a running `npm run dev`

npm run smoke signs in with throwaway wallets over real SIWE and walks the whole surface — projects, studio commits, captures, freeze → activate → mint guard, galleries, social graph, briefs, discovery, OG — plus ownership, traversal, cursor-validation and replay abuse cases. It exits non-zero on the first failure, so it works as a pre-deploy gate.

The mock/optional switches in .dev.vars.example decide how far it gets:

VarUnsetSet
GITHUB_MOCK=1project create/commit call the real GitHub API (needs GITHUB_PAT)stubbed repo + file responses
PINNING_MOCK=1POST /freeze returns 503 pinning_unconfiguredfull freeze → activate → mint-guard chain runs locally
GA_FACTORY_ADDRESSmint endpoints return 503 mint_unconfiguredmint calldata is issued against the configured chain
ADMIN_HANDLES/v1/internal/* returns 403 admin_unconfiguredlisted handles reach the stats surface

Every one of these fails closed: an unset secret produces an explicit 503, never a silently degraded write.

Vendored runtimes

workers/api/vendor/{p5,three}.min.js are committed on purpose — the freeze bundler inlines them into the IPFS-pinned artifact, and bundle_hash covers the runtime source, so a version bump has to be an explicit commit. The Worker does not build without them. Refresh with npm run vendor:sync; see workers/api/vendor/README.md.

Cloudflare Pages setup

The static site is hosted on Cloudflare Pages. Use these settings in the Cloudflare dashboard:

  • Framework preset: Jekyll
  • Build command:bundle exec jekyll build
  • Build output directory:_site
  • Production branch:main
  • Root directory:/ (project root)
  • Environment variables:JEKYLL_ENV=production, BUNDLE_PATH=vendor/bundle

Why no github-pages gem? This site uses jekyll-paginate-v2 and jekyll-archives, neither of which is on GitHub Pages' plugin allowlist. The Gemfile pins standalone Jekyll 4.3.x; Cloudflare Pages runs the build itself, so the standard plugin set works without restriction.

Deploy to Cloudflare Pages (first-time setup)

  1. Workers & Pages → Create application → Pages → Connect to Git; pick the GitHub repo.
  2. Production branch:main.
  3. Build command:bundle exec jekyll build.
  4. Build output directory:_site.
  5. Custom domains: add generatedart.com (and www.generatedart.com if desired).
  6. DNS: point generatedart.com's nameservers at Cloudflare, then create the proxied CNAME / apex record Cloudflare suggests in the Pages → Custom Domains tab.
  7. Disable GitHub Pages in the repo settings once Cloudflare Pages is serving traffic and DNS has propagated.

Deploy

SurfaceWhereHow
Static siteCloudflare PagesAuto-deploy on push to main (settings above)
API WorkerCloudflare Workerswrangler deploy --env production (run from workers/api/)
ContractsBase L2forge script script/Deploy.s.sol --rpc-url base --broadcast

Prod prerequisites (one-time, before the first prod Worker deploy):

  • wrangler r2 bucket create generatedart-assets (binding for canvas captures)
  • wrangler secret put JWT_SECRET --env production
  • wrangler secret put GITHUB_PAT --env production
  • wrangler secret put W3S_TOKEN --env production and wrangler secret put PINATA_JWT --env production — without both, every POST /v1/projects/:id/freeze fails closed with 503 pinning_unconfigured, which in turn blocks minting (the mint guard requires an active frozen version). Never set PINNING_MOCK in production.
  • GA_FACTORY_ADDRESS in [env.production.vars] after the Foundry deploy — until then the mint endpoints return 503 mint_unconfigured.

Verify the build before deploying: npx wrangler deploy --env production --dry-run. It fails fast if the vendored runtimes are missing.

License

MIT for platform code. Artist bundles licensed individually (default CC-BY-NC-4.0).

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages