Skip to content
JenspalmborgPublic

About

Two games on BehaviorGPT's map of 8,409 products: ProductGuessr and MapGolf

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Latest commit

 

History

10 Commits

Folders and files

Repository files navigation

Map Arcade

Two games on BehaviorGPT's map of 8,409 products.

  • ProductGuessr (/productguessr/): GeoGuessr for products.
  • MapGolf (/mapgolf/): get from one product to another in as few shots as possible, jumping only between products the model ranks as similar.

ProductGuessr

GeoGuessr, but for products. BehaviorGPT has placed 8,409 products on a map where similar things live side by side, grouped into seven continents. You get a mystery product (a blurred photo and a price), drop a pin where you think it lives, and score up to 5,000 points depending on how close you land. Unblurring the photo or showing the name costs 300 points each. From round 3 the map loses a clue each round: first the continent names, then the landmarks, then the legend. Five rounds, a daily challenge, and a shareable result.

▶ Play here

Where on the map is the phone mount?

It is a small, complete example of building on the BehaviorGPT SDK's embedding map: harvesting products, embedding them as your own catalog, pulling coordinates out of client.umap(), and turning them into a game that runs without an API key.

Status: working prototype.

MapGolf

A side-view golf hole: tee on the left, pin on the right, and a ball that flies forward or backward with every shot. Each turn offers three shots as picture cards, all taken from client.similar_products() for the product your ball is on: a chip (one of the 4 most similar products), an iron (ranks 9–18) and a driver (ranks 25–36). Pick the one that feels closest to the pin, and the game tells you how it went and why: "WOW, what a drive! 310 m closer. Shoppers who look at iTouch Air Smartwatch also look at SAMSUNG Galaxy Watch, and that's Tech & Gaming, where the pin is."

The distance to the pin counts the steps left along the model's links (200 m each, found by a breadth-first search backwards from the pin), plus map distance to break ties. Two of the three shots get you closer whenever the links allow it, and the pin shows up as a putt once it is in reach. Holes are 2–3 steps on the best route, par is two more. Long Amazon titles are shortened on the cards (full title on hover).

What it shows

In the game BehaviorGPT call
The products client.complete(history=[Search(q)]) over 150 everyday queries, plus the cold-start ranking
Your own catalog to map client.embed(parquet)
The map itself client.umap(catalog_id=...), coordinates parsed out of the Plotly page
"It lives next to…" after each guess the product's nearest neighbours on that map
MapGolf's shots client.similar_products(id, limit=60) for all 8,409 products (top 36 kept)

The reveal: your pin, the answer and its neighbours

Play it locally

The built map is committed in docs/data.json, so playing needs no key at all:

git clone https://github.com/Jenspalmborg/maparcade.git
cd maparcade
python3 -m http.server 8000 -d docs

Open http://localhost:8000 and pick a game. Links like /productguessr/?seed=2026-09-27 or /mapgolf/?seed=2026-09-27 replay the same game, so friends can play it too.

The site is plain HTML, CSS and JS with no build step, so GitHub Pages can host it straight from the docs/ folder.

Rebuild the map

Needs Python 3.11+, uv and a BehaviorGPT API key from unboxai.com/behaviorgpt.

uv sync
cp .env.example .env                        # paste your key as UNBOXAI_API_KEY

uv run python scripts/harvest.py            # ~8,400 products from retail_catalog (~1 min)
uv run python scripts/embed.py --sample 300 # optional: quick test upload first
uv run python scripts/embed.py              # upload and embed them (a few minutes)
uv run python scripts/build_map.py          # fetch the map, write docs/data.json
uv run python scripts/neighbours.py         # similar products for MapGolf (~5 min, resumable)
uv run python scripts/build_golf.py         # links -> docs/golf.json, plus a connectivity check

How it was built

  1. Harvest. The pre-embedded catalogs have no map (umap returns a server error for them), so harvest.py copies products into a catalog of our own. It runs 150 searches across everyday shopping areas plus the popularity ranking, and drops near-identical variants ("Nike Men's Retro" × 20), which would otherwise pile onto one spot and make rounds repetitive.
  2. Embed. The API returns every field as a string ("None", "[1, 2, 3]"), so embed.py converts each column back to the types in the catalog format before uploading. Each API key holds one catalog: a new upload replaces the previous one under the same id.
  3. Map. build_map.py pulls the coordinates out of the umap page, as aic-artworks does.
  4. Continents. The raw map is an archipelago (see below), which reads as confetti. So the categories are folded into seven broad groups, and each group's islands are gathered into one continent: the model's arrangement within a group is kept, shrunk, with far-flung islands tucked in. The biggest continent sits in the middle and the others around it, in the direction the model's map puts them. Products with no category join the group of their nearest neighbours on the model's map.
  5. Even clouds. The model packs similar products onto the exact same point (8,409 products on ~1,900 spots). Dots that overlap push each other apart, a mild pull keeps each continent together, and a little noise makes it look organic. Neighbours stay neighbours; only the spacing changes.
  6. Landmarks. For each region of the map, the word that is far more common there than elsewhere ("espresso", "mattress", "iphone") becomes a label, so players can find their way.
  7. Game. docs/productguessr/index.html draws the map on a canvas with pan, zoom and pinch. Scoring is 5000 × e^(−distance / 0.09) in map units. Rounds are drawn with a seeded RNG, from popular products with descriptive titles, spread over different departments. Hovering over products only works after you guess, so no peeking. Difficulty climbs by removing clues per round (CLUES in the page), and every clue comes back on the reveal so players learn the map as they go.

What the map looks like up close

Locally the map is very good: 82% of each product's ten nearest neighbours are from the same department (13% by chance), and the neighbours are the kind of thing you'd expect (phone mounts next to phone mounts, pasta next to ravioli). Globally it is an archipelago rather than continents: each department is spread over many small islands, interleaved with the others.

So be clear about what the game's map is: within a continent, positions come from BehaviorGPT; which continent sits next to which is my layout, guided by the model's map but not measured by it. Knowing a phone mount is "Tech & Gaming" gets you to the right continent; finding the phone-accessory corner of it is where the points are.

Final score with a shareable result

Layout

scripts/
  harvest.py      retail_catalog -> data/products.jsonl
  embed.py        products -> data/productguessr.parquet -> embedded catalog
  build_map.py    umap page -> docs/data.json (points, landmarks, round pool)
  neighbours.py   similar_products for every product -> data/neighbours.jsonl
  build_golf.py   neighbours -> docs/golf.json (36 most similar per product)
docs/
  index.html      start page: pick a game
  productguessr/  ProductGuessr (no build step)
  mapgolf/        MapGolf (no build step)
  guessr/, golf/  redirects from the old paths
  data.json       the built map, shared by both games
  golf.json       MapGolf's links between products
  screenshots/    README images
data/             harvested products, parquet, catalog id (git-ignored)

Data and license

Product names, prices and images come from BehaviorGPT's pre-embedded retail_catalog; images are hot-linked, not copied. The code is MIT licensed.

About

Two games on BehaviorGPT's map of 8,409 products: ProductGuessr and MapGolf

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages