OhMyGame
OhMyGame은 AI로 게임을 만들 수 있는 오픈소스 스튜디오로, 디자인·구축·플레이테스트·출판을 하나의 앱에서 모델 키와 함께 수행합니다
개인 계정의 공개 저장소 소유자는 GitHub로 로그인해 운영자를 확인하고 소개를 직접 관리할 수 있습니다. 관리자 승인은 필요하지 않습니다.
로그인한 뒤 확인 파일을 만들어 이 저장소의 기본 브랜치에 30분 안에 커밋해 주세요. 다른 브랜치나 포크의 파일은 인정하지 않습니다. 파일을 올린 뒤 아래에서 확인하면 관리자 승인 없이 관리할 수 있습니다. 자격을 유지하려면 파일을 남겨 두세요.
로그인이 필요하면 로그인 화면으로 이동합니다. 로그인 후 이곳으로 돌아와 원하는 확인 버튼을 다시 눌러 주세요.
프로젝트 폴더에서 /nomorevibe verify를 실행하면 소유권을 확인하고 소개를 직접 관리할 수 있습니다.
1분 만에 확인하기메이커가 쓴 소개는 위의 한 줄이 전부입니다. 더 자세한 내용은 저장소 README에서 읽을 수 있습니다. 저장소 README ↗
README 전체를 불러오는 중입니다.
README 전문 보기 ↗Plot every game on Steam in a semantic vector space, find the empty places, and turn them into new game ideas, ranked by how unlike every existing game they are.
Try it: obsoleterobot.com/ideaplotter · Watch: what you're looking at (YouTube)
Every point of light on the map is a Steam game, placed by what its store page says, so similar games sit together. The dark gaps between them are games nobody has made yet. Pick a gap, a region or a few games you like, and IdeaPlotter finds the emptiest spot there, has an AI write the game that would live in it, then measures where that game actually lands and revises it.
You need:
Download the project (Code → Download ZIP on GitHub and unzip it, or git clone https://github.com/Obsolete-Robot/IdeaPlotter.git), then run the installer:
install.bat./install.sh in a terminalThe installer:
.venv/;.env in the project folder.A status line under each step shows what the installer is doing, how long that has taken, and how much has been downloaded or unpacked so far. The spinner and clock keep moving as long as the installer is working, including during the few minutes PyTorch takes to unpack. If a download gets no data for 20 seconds, the line says so.
It is safe to run again at any time: finished steps are skipped, and it is how you change or add your key later.
run.bat./run.shThe map opens in your browser at http://127.0.0.1:8765. Keep the window open while you use it; close it or press Ctrl+C to stop. The first start also downloads the embedding model (about 1.2 GB); after that, starting takes about 30 seconds.
The map is a 3-D cloud: drag to orbit, right-drag (or Alt-drag) to pan, scroll to zoom. Drift slowly turns it while nothing is selected. 2D / 3D at the top (or the 2 and 3 keys) switches to a flat map and back. There are four ways to find empty space:
Each ends the same way: the AI writes a game for that point, and you watch each draft get measured and revised. Ideas are saved in out/ideas/ and appear in the list on the right.
The map holds Steam's catalog as of October 2026. For newer games, type a name in the search box, choose Search Steam, then add to map to place one.
| Writer | Set up with | Cost and speed per idea |
|---|---|---|
| OpenRouter, Claude Sonnet 5.5 (default) | an OpenRouter key | about $0.03, 20 seconds; wrote the most original ideas in a side-by-side test |
| OpenRouter, any other model | an OpenRouter key, plus --model | e.g. anthropic/claude-haiku-5.5: about $0.002 |
| Anthropic API, Claude Opus 5.5 | an Anthropic key | more per idea; highest effort |
| Claude Code | your Claude Code login | uses your Claude plan |
To switch, run the installer again, or edit .env. To try another OpenRouter model for one session: run.bat --model google/gemini-3.8-flash (or ./run.sh --model ...). Any OpenRouter model that supports structured outputs works.
Everything the map does is also available as commands. Use .venv\Scripts\python on Windows and .venv/bin/python on macOS/Linux:
.venv/bin/python -m ideaplotter serve --open # the map (what run.bat / run.sh start)
.venv/bin/python -m ideaplotter voids --top 40 # batch: the 40 emptiest coherent spots on Steam
.venv/bin/python -m ideaplotter ideas --limit 12 # write games for them -> out/ideas.md, out/explorer.html
.venv/bin/python -m ideaplotter calibrate # optional: measure the rewrite noise floor
.venv/bin/python -m ideaplotter --help # everything else
Outputs:
out/ideas.md: ranked ideas with metrics, recipe, closest games and draft historyout/ideas.json: the same, machine-readableout/explorer.html: a self-contained copy of the map with all ideas (browsing works; writing needs the running app)out/ideas/*.json: one file per idea, the cache everything else is built fromSteam catalog ──► store pages ──► embeddings ──► find voids ──► LLM writes a game ──► embed it, measure, revise
~195k games clean text 1024-d (math) for each void rank by novelty
1. Data. Steam's public store API (IStoreQueryService/Query, no key, 1000 games per call) provides each game's short description, store text, weighted user tags, reviews and release data. Stubs, games with fewer than 3 tags and non-Latin-script pages are dropped, which leaves about 189k games. Unreleased "coming soon" pages stay in, because they are ideas someone already had.
2. Embedding. Each game becomes one document (title / short description / Tags: ... / first 800 chars of About), embedded with Qwen/Qwen3-Embedding-0.6B (1024-d, cosine). Generated ideas are embedded in exactly the same format, so they are measured on the same scale as real games.
3. Geometry:
4. Voids. A void target is a convex blend of a few real games, x = normalize(Σ wⱼ aⱼ). Keeping it inside the region real store pages occupy avoids extrapolating into meaningless directions. The weights are optimised by gradient descent to minimise a soft maximum of the cosine similarity to all 189k games:
loss = τ · log Σᵢ exp(cos(x, eᵢ)/τ) + λ · relu(c_min − ‖Σ wⱼ aⱼ‖)
The first term pushes the point away from every game, including its own ingredients. The second is a coherence constraint. Averaging unrelated games cancels what is specific about each one: a blend of a subway sim, a JRPG and a card game collapses into a generic "indie game" vector, which looks far from everything only because real games are specific. The length of the un-normalised blend measures this cancellation, so blends must keep it above --coherence (default 0.82), and their ingredients must be related but different (pairwise cosine 0.3–0.8). In the map, the search is limited to the games you picked, but novelty is always measured against all of Steam.
5. Decoding, closed loop. To turn a point back into a game, the AI gets a brief: the blend recipe, the tags the probe reads off the point, and the closest existing games, which its idea has to differ from. It writes a store page, which is embedded and measured:
| measure | meaning |
|---|---|
target_sim | cosine between the draft and the void it was aimed at |
nearest_sim | cosine to the closest real Steam game |
| landed | target_sim > nearest_sim: the draft sits closer to the void than to any existing game |
The measurements go back to the AI for another round, and the best draft is kept, preferring drafts that landed.
6. Ranking. Ideas are ranked by novelty = 1 − nearest_sim of the idea's own page, plus its isolation: the share of real Steam games whose own nearest twin is closer than the idea's. calibrate measures how far an AI rewrite of an existing game lands from the original: the noise floor from writing style alone, shown on every idea's histogram.
The installer downloads a snapshot of the finished game space from this project's GitHub release: embeddings, neighbour tables, clusters, tag probe and map layouts, plus each game's name, tags and review count. Your computer only embeds the drafts the AI writes.
Store descriptions are looked up from Steam's public store API as they are needed: opening a game (one request), writing an idea (one request for the dozen or so games its brief quotes; if Steam is unreachable, the brief uses titles and tags), Search Steam / add to map, and calibrate. Lookups go out one at a time, at most one per second, and each game is cached in data/steam_cache/ for 30 days.
Building the data yourself crawls the whole Steam catalog (about 195 API calls) and embeds 189k games (about 1.5 hours on an RTX 2080 Ti), so it is meant for publishing a new snapshot. With a full build, the app reads all store text from your own data:
.venv/bin/python -m ideaplotter fetch # crawl the catalog into data/raw/
.venv/bin/python -m ideaplotter build # clean, embed, analyse, lay out the map
.venv/bin/python -m ideaplotter export # optional: pack out/snapshot/ for publishing as a release
To publish a new snapshot, attach out/snapshot/* to a GitHub release and set SNAPSHOT_TAG in ideaplotter/config.py to its tag. download checks every file against the release's manifest.json; IDEAPLOTTER_SNAPSHOT_URL points it somewhere else.
serve can host the map for other people, as on obsoleterobot.com/ideaplotter:
.venv/bin/python -m ideaplotter serve --host 0.0.0.0 --port 8765 --base-path /ideaplotter \
--daily-limit 40 --visitor-limit 5 --steam-daily-limit 500
--base-path serves the app under a path on a shared domain.--daily-limit and --visitor-limit cap the ideas written per day (in total and per visitor) and write one at a time, which bounds the AI bill. Visitors are identified by Cloudflare's CF-Connecting-IP header when present, and stored hashed.--steam-daily-limit caps the Steam lookups visitors can trigger.The server log prints each idea's title and, on OpenRouter, what it cost.
IDEAPLOTTER_SPACE=<dir> points every command at a different data directory.IdeaPlotter's source code is available under the MIT License. Third-party dependencies, model weights, and Steam content are not covered by this license and remain subject to their respective licenses and terms.