Skip to content

akdevv/goatify

Repository files navigation

GOATify, morph any photo into a football GOAT

GOATify

Settle the GOAT debate the only honest way: become one.

Drop in a photo and watch it melt into Messi or Ronaldo, pixel by pixel, right in the browser. Pick your side. No backend, no sign-up, nothing leaves your machine.

Try it →


The debate

Messi or Ronaldo. People have argued about it for two decades and nobody has won. GOATify does not pick a winner, it lets you join the argument by morphing your own face into whichever GOAT you ride for. Choose Messi, choose Ronaldo, and watch the transformation happen frame by frame.

(Yes, you can also load your own target image and morph into your local pub legend instead.)

How the morph works

Every photo is just a bag of colored dots. To turn picture A into picture B, you need to decide where each dot in A should travel to land on B, then slide them all there at once. That "where does each pixel go" question is an assignment problem, and how you answer it is the whole game.

GOATify ships three matchers, from rough-and-cheap to slow-and-perfect:

Matcher The idea Quality Speed Max size
Sliced OT (default) Approximate optimal transport by sorting along random directions, refined over N passes High Fast 256
Greedy Grab the nearest unused pixel, repeat Okay Medium 256
Hungarian The textbook exact minimum-cost matching (O(N³)) Perfect Slow 32

Hungarian is the "correct" answer but it scales like a brick, so it is locked to tiny resolutions. Sliced OT is what you actually want: nearly as clean, fast enough to feel live. All of it runs in a Web Worker, so the slider stays buttery while the math grinds.

You also control the resolution, the number of iterations, and how the source is zoomed and framed before the run. More pixels and more iterations means a sharper morph and a longer wait. Hit play, watch it go, download the frame you like.

Run it locally

pnpm install
pnpm dev        # dev server with HMR
pnpm build      # type-check + production build
pnpm preview    # serve the build
pnpm lint       # oxlint

Under the hood

  • React 19 + TypeScript + Vite
  • Material 3 (@material/web), custom green theme, light and dark modes
  • Web Workers to keep matching off the main thread
  • Canvas 2D to draw the morph
  • munkres-js for the Hungarian solver
src/
├─ components/      canvas, settings, app bar, M3 bits
├─ layouts/         desktop & mobile (all state lives in App)
├─ hooks/           use-is-mobile, use-theme
├─ lib/
│  ├─ match.worker.ts   worker entry, picks a matcher
│  ├─ slicedOT.ts       sliced optimal transport
│  ├─ hungarian.ts      exact assignment
│  ├─ match/greedy.ts   greedy nearest-match
│  ├─ morph.ts          interpolates between matched point sets
│  └─ image.ts          turns an image into a point set
└─ App.tsx          top-level state & wiring

Pick a side. 🐐

About

Settle the GOAT debate the only honest way: become one.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

No releases published

Packages

 
 
 

Contributors