Problem
The game icons on the LiveOps page are terrible. They’re pulled from the same 150x150px endpoint the games page on Roblox.com uses and exploded to 340px. They look blurry and pixelated.
As a developer I would not be happy advertising my game like this, and as a player I find this incredibly unattractive. I would be very turned off by Roblox after seeing this webpage if I were a new user.
Solution
Use https://www.roblox.com/item-thumbnails
to populate the game icons. This endpoint takes multiple IDs in a list formatted like params=[{assetId:#},{assetId:#}]
.
or
Change https://www.thumbnails.roblox.com/v1/games/icons
to return images at a more variable (higher) resolution. I have complained about the game icon endpoint before. I recommend making it more versatile.
Insight
Presumably the JS used to fetch information for the list of games on the webpage.
There is a function called init() that is called immediately. This function calls getGameInfo() to get game information for each game.
In getGameInfo() after getting game information it hits the exact same endpoint the games page on Roblox.com uses to populate game icons. (This endpoint unusually imposes a hard limit on image size unlike other endpoints that let you specify the size you’d like returned)
https://www.thumbnails.roblox.com/v1/games/icons
Defined immediately above getGameInfo() is a function called getGameImage(). This hits an endpoint that returns these icons at a reasonable resolution. I’m not sure how nobody noticed this while they were building this webpage.
Experimenting with this endpoint a little bit, I’ve discovered that it takes multiple parameters just like the games page endpoint, as seen below:
https://www.roblox.com/item-thumbnails?params=[{assetId:463915360},{assetId:463915360},{assetId:463915360}]
Here is some sample JS you can run from the console on the LiveOps page that will use this endpoint to update all of the icons so you can see the difference.
{
let url = "https://www.roblox.com/item-thumbnails?params=[";
games.forEach((game) => {
if (game.placeId > 0) {
url += "{assetId:" + game.placeId + "},"
}
});
url = url.substr(0, url.length - 1)
url += "]"
fetch(url).then((res) => {
res.json().then((dataArr) => {
games.forEach((game, i) => {
data = dataArr[i];
if (data) {
let url = data.thumbnailUrl;
if (url) {
let img = document.querySelector("[data-place-id='" + game.placeId + "'] .game-icon");
img.src = url;
}
}
});
})
});
}