gamespace.1

gamespace.1 embeds Steam games into a 128-dimensional space where games that play alike sit close together. It powers the GameMerge recommender, which ranks every game on Steam by cosine similarity to the games you like.

It is all-MiniLM-L6-v2, fine-tuned on 138,920 Steam games, with a trained projection from 384 to 128 dimensions. Output vectors are L2-normalised, so a dot product is the cosine similarity.

Usage

The model reads one short text document per game, built from store metadata. Use docs.py from this repo to build documents in exactly the format the model was trained on.

from huggingface_hub import hf_hub_download
from sentence_transformers import SentenceTransformer
import importlib.util

model = SentenceTransformer("GulkoA/gamespace.1")

spec = importlib.util.spec_from_file_location("docs", hf_hub_download("GulkoA/gamespace.1", "docs.py"))
docs = importlib.util.module_from_spec(spec); spec.loader.exec_module(docs)

game = {
    "name": "Hollow Knight",
    "genres": ["Action", "Adventure", "Indie"],
    "tags": ["Metroidvania", "Souls-like", "Platformer", "Difficult", "Atmospheric"],  # most-voted first
    "categories": ["Single-player"],
    "developers": ["Team Cherry"],
    "short": "Forge your own path in Hollow Knight! An epic action adventure through a vast ruined kingdom of insects and heroes.",
    "about": "",
}
vec = model.encode(docs.build_doc(game))  # shape (128,), unit length

The resulting document looks like this:

Hollow Knight. Genres: Action, Adventure, Indie. Tags: Metroidvania, Souls-like, ... Modes: Single-player. Developer: Team Cherry. Forge your own path...

In the browser

onnx/model_quantized.onnx (22 MB, per-channel int8, cosine 0.995 to the PyTorch model) runs with transformers.js. Apply the 128x384 projection in dense.bin (float32 weights, row-major, followed by the 128 biases) to the mean-pooled output:

import { pipeline } from "@huggingface/transformers";

const extractor = await pipeline("feature-extraction", "GulkoA/gamespace.1", { dtype: "q8" });
const w = new Float32Array(await (await fetch("https://huggingface.co/GulkoA/gamespace.1/resolve/main/dense.bin")).arrayBuffer());
const { data: x } = await extractor("cozy farming game with fishing", { pooling: "mean", normalize: false });
const y = Array.from({ length: 128 }, (_, i) => w[128 * 384 + i] + x.reduce((s, xj, j) => s + w[i * 384 + j] * xj, 0));
const norm = Math.hypot(...y);
const vec = y.map((v) => v / norm); // 128-d, unit length

Use dtype: "fp32" with onnx/model.onnx for output identical to PyTorch.

Missing fields are simply left out. Games with no user tags still embed well from their description, since training deliberately hid tags half the time.

Training

  • Data. The Steam Games Dataset has 147,352 apps. Soundtracks, demos, playtests, dedicated servers, SDKs, and empty records were removed, leaving 138,920 games. 3,000 tagged games were held out from all training.
  • Objective. Contrastive training uses CachedMultipleNegativesRankingLoss with 128 in-batch negatives and 140,000 positive pairs:
    • 70,000 pairs are two randomly degraded views of the same game. Each view may drop the tag list, the description, or part of each.
    • 70,000 pairs are two different games whose vote-weighted user-tag profiles have a cosine of at least 0.6.
  • Projection. A Dense(384โ†’128) layer, initialised from the PCA basis of the base model's embeddings, is trained end to end.
  • Settings. One epoch, learning rate 3e-5, 128-token documents, fp16, on one RTX 3050 Ti laptop GPU in about 20 minutes.
  • Excluded signals. Review counts, price, playtime, and owner counts are never shown to the model. Similarity reflects what a game is, not how popular it is.

Evaluation

For each held-out game, we retrieve its 10 nearest neighbours from a fixed pool of 30,000 tagged games. The score is the mean cosine between the query's vote-weighted, IDF-scaled tag profile and those of its neighbours. "Description only" embeds the query with its tags removed.

Model With tags Description only
Random pairs 0.076 0.076
all-MiniLM-L6-v2, no fine-tuning 0.230 0.208
TSDAE denoising autoencoder, then contrastive 0.493 0.370
gamespace.1, contrastive only 0.503 0.376
Ceiling, matching on true tags 0.621 n/a

A TSDAE denoising-autoencoder stage before contrastive training scored the same within noise. A side-by-side look at the neighbours of well-known games slightly favoured the model without it, so gamespace.1 skips that stage.

Example neighbours

Game Nearest games
DARK SOULS III Dark Souls II: Scholar of the First Sin, Dark Souls Remastered, Elden Ring, Lies of P
Stardew Valley Staxel, Dinkum, Coral Island, Sun Haven
Factorio FOUNDRY, Satisfactory, shapez, Techtonica
Euro Truck Simulator 2 American Truck Simulator, Truck & Logistics Simulator, The Bus

Limitations

  • Similarity is about content, so obscure, low-quality, or unreleased games rank alongside well-known ones.
  • Tags are user-generated and English-centric. Descriptions in other languages embed less reliably.
  • The catalog snapshot ends in September 2026.

License

The model is licensed under Apache 2.0, the same as the base model. The training data is MIT-licensed.

Downloads last month
27
Safetensors
Model size
22.7M params
Tensor type
F32
ยท
Inference Providers NEW
This model isn't deployed by any Inference Provider. ๐Ÿ™‹ Ask for provider support

Model tree for GulkoA/gamespace.1

Dataset used to train GulkoA/gamespace.1

Space using GulkoA/gamespace.1 1