SteamTheWoz v2
68
index.html
|
@ -5,7 +5,7 @@
|
||||||
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
|
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
|
||||||
<title>HexFlagGen</title>
|
<title>HexFlagGen</title>
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||||
<link rel="stylesheet" href="styles/normal.css" />
|
<link rel="stylesheet" href="https://cdn.abtmtr.link/cdn/css/normal.css" />
|
||||||
<style>
|
<style>
|
||||||
@import url("https://fonts.googleapis.com/css2?family=Lexend+Deca:wght@100;200;300;400;500;600;700;800;900&display=swap");
|
@import url("https://fonts.googleapis.com/css2?family=Lexend+Deca:wght@100;200;300;400;500;600;700;800;900&display=swap");
|
||||||
|
|
||||||
|
@ -21,13 +21,13 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
* {
|
* {
|
||||||
transition: background-color 0.125s, color 0.125s;
|
transition: background-color 0.125s, color 0.125s, opacity 0.125s;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<section>
|
<section>
|
||||||
<h1>HexFlagGen</h1>
|
<h1>SteamTheWoz</h1>
|
||||||
<label for="size_width"
|
<label for="size_width"
|
||||||
><input
|
><input
|
||||||
type="number"
|
type="number"
|
||||||
|
@ -48,53 +48,53 @@
|
||||||
Base style
|
Base style
|
||||||
</label>
|
</label>
|
||||||
<p>by <a href="https://abtmtr.link/">MeowcaTheoRange</a></p>
|
<p>by <a href="https://abtmtr.link/">MeowcaTheoRange</a></p>
|
||||||
<p>
|
<p>Make a Scott The Woz thumbnail out of any Steam game.</p>
|
||||||
Welcome, here you can make a flag out of the hexadecimal bytes of your
|
|
||||||
choice!
|
|
||||||
</p>
|
|
||||||
</section>
|
</section>
|
||||||
<hr />
|
<hr />
|
||||||
<section>
|
<section>
|
||||||
<label for="data">Generator string</label><br />
|
|
||||||
<input
|
<input
|
||||||
type="text"
|
type="number"
|
||||||
id="data"
|
id="steam_game"
|
||||||
value="5BCEFAF5A9B8FFFFFFF5A9B85BCEFABA53"
|
style="width: 8ch"
|
||||||
style="width: 100%"
|
min="10"
|
||||||
/><br />
|
value="620"
|
||||||
|
/>
|
||||||
|
<label for="steam_game">Steam Game ID</label><br />
|
||||||
<button id="generateButton">Generate!</button>
|
<button id="generateButton">Generate!</button>
|
||||||
</section>
|
</section>
|
||||||
<section>
|
<section>
|
||||||
|
<label for="scott_index">Extras</label><br />
|
||||||
<input
|
<input
|
||||||
type="number"
|
type="number"
|
||||||
id="size_width"
|
id="scott_index"
|
||||||
style="width: 8ch"
|
style="width: 8ch"
|
||||||
min="0"
|
min="0"
|
||||||
max="3000"
|
max="9"
|
||||||
value="300"
|
value="0"
|
||||||
/>
|
/>
|
||||||
<label for="size_width">Width (px)</label><br />
|
<label for="scott_index">Scott Index</label>
|
||||||
<input
|
<small
|
||||||
type="number"
|
>(
|
||||||
id="size_height"
|
<label for="stash" class="checkbox">
|
||||||
style="width: 8ch"
|
<input
|
||||||
min="0"
|
type="checkbox"
|
||||||
max="3000"
|
id="stash"
|
||||||
value="200"
|
onchange="scott_index.disabled = event.target.checked"
|
||||||
/>
|
/>
|
||||||
<label for="size_height">Height (px)</label><br />
|
<span class="checkbox">O</span>
|
||||||
<select id="flag_type">
|
Scott's Stash </label
|
||||||
<option value="horiz">Horizontal</option>
|
>)</small
|
||||||
<option value="vert" selected>Vertical</option>
|
><br />
|
||||||
|
<select id="align">
|
||||||
|
<option value="left">Left</option>
|
||||||
|
<option value="center" selected>Center</option>
|
||||||
|
<option value="right">Right</option>
|
||||||
</select>
|
</select>
|
||||||
<label for="flag_type">Flag type</label>
|
<label for="align">Background Alignment</label>
|
||||||
</section>
|
</section>
|
||||||
<hr />
|
<hr />
|
||||||
<section>
|
<section>
|
||||||
<p>
|
<canvas id="canvas" width="1280" height="720"></canvas>
|
||||||
Hex: <code><span id="hexdisplay">...</span></code>
|
|
||||||
</p>
|
|
||||||
<canvas id="canvas" width="300" height="200"></canvas>
|
|
||||||
</section>
|
</section>
|
||||||
<script src="scripts/index.js"></script>
|
<script src="scripts/index.js"></script>
|
||||||
</body>
|
</body>
|
||||||
|
|
BIN
public/woz0.png
Normal file
After Width: | Height: | Size: 453 KiB |
BIN
public/woz1.png
Normal file
After Width: | Height: | Size: 821 KiB |
BIN
public/woz2.png
Normal file
After Width: | Height: | Size: 677 KiB |
BIN
public/woz3.png
Normal file
After Width: | Height: | Size: 827 KiB |
BIN
public/woz4.png
Normal file
After Width: | Height: | Size: 740 KiB |
BIN
public/woz5.png
Normal file
After Width: | Height: | Size: 687 KiB |
BIN
public/woz6.png
Normal file
After Width: | Height: | Size: 515 KiB |
BIN
public/woz7.png
Normal file
After Width: | Height: | Size: 515 KiB |
BIN
public/woz8.png
Normal file
After Width: | Height: | Size: 359 KiB |
BIN
public/woz9.png
Normal file
After Width: | Height: | Size: 295 KiB |
BIN
public/wozstash.png
Normal file
After Width: | Height: | Size: 128 KiB |
156
scripts/index.js
|
@ -3,113 +3,79 @@ const data = document.getElementById("data");
|
||||||
const generateButton = document.getElementById("generateButton");
|
const generateButton = document.getElementById("generateButton");
|
||||||
const hexdisplay = document.getElementById("hexdisplay");
|
const hexdisplay = document.getElementById("hexdisplay");
|
||||||
|
|
||||||
const size_width = document.getElementById("size_width");
|
const steam_game = document.getElementById("steam_game");
|
||||||
const size_height = document.getElementById("size_height");
|
const scott_index = document.getElementById("scott_index");
|
||||||
const flag_type = document.getElementById("flag_type");
|
const stash = document.getElementById("stash");
|
||||||
|
const align = document.getElementById("align");
|
||||||
|
|
||||||
const root = document.querySelector(":root");
|
const root = document.querySelector(":root");
|
||||||
|
|
||||||
const ctx = canvas.getContext("2d");
|
const ctx = canvas.getContext("2d");
|
||||||
|
|
||||||
function getData() {
|
async function loadImage(url) {
|
||||||
data.value = data.value.toUpperCase().replace(/[^0-9A-F]*/g, "");
|
return new Promise((r) => {
|
||||||
|
let img = new Image();
|
||||||
var hexValue = data.value.match(/.{1,2}/g).map((x) => x.padStart(2, "0"));
|
img.onload = () => r(img);
|
||||||
|
img.src = url;
|
||||||
hexdisplay.innerHTML = hexValue.join(" ");
|
|
||||||
|
|
||||||
createFlag(
|
|
||||||
hexValue.join("").match(/.{1,6}/g),
|
|
||||||
size_width.value,
|
|
||||||
size_height.value,
|
|
||||||
flag_type.value
|
|
||||||
);
|
|
||||||
var ac = averageColors(hexValue);
|
|
||||||
console.log(ac);
|
|
||||||
root.style.setProperty(
|
|
||||||
"--background-color",
|
|
||||||
arrayToColor(darkenColor(ac, 70))
|
|
||||||
);
|
|
||||||
root.style.setProperty("--color", arrayToColor(lightenColor(ac, 70)));
|
|
||||||
root.style.setProperty("--accent-color", arrayToColor(ac));
|
|
||||||
root.style.setProperty(
|
|
||||||
"--accent-color-fg",
|
|
||||||
arrayToColor(lightenColor(ac, 90))
|
|
||||||
);
|
|
||||||
}
|
|
||||||
generateButton.addEventListener("click", getData);
|
|
||||||
|
|
||||||
function averageColors(hex) {
|
|
||||||
var averageSet = [[], [], []];
|
|
||||||
hex.forEach((number, index) => {
|
|
||||||
averageSet[index % 3].push(parseInt(number, 16));
|
|
||||||
});
|
});
|
||||||
return averageSet.map((array) =>
|
|
||||||
Math.floor(array.reduce((a, b) => a + b) / array.length)
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function createFlag(hex, w, h, type) {
|
async function getScott() {
|
||||||
canvas.width = w;
|
var gameID = steam_game.value;
|
||||||
canvas.height = h;
|
var scottID = scott_index.value;
|
||||||
|
var alignment = align.value;
|
||||||
|
|
||||||
// Initialize stuff
|
const ctx = canvas.getContext("2d");
|
||||||
|
|
||||||
var width = ctx.canvas.width;
|
var hero = await loadImage(
|
||||||
var height = ctx.canvas.height;
|
`https://cdn.cloudflare.steamstatic.com/steam/apps/${gameID}/library_hero.jpg`
|
||||||
var textHeight = 24;
|
).catch(() => "404");
|
||||||
ctx.font = `${textHeight}px "Lexend Deca"`;
|
var scott = await loadImage(
|
||||||
|
stash.checked ? `public/wozstash.png` : `public/woz${scottID}.png`
|
||||||
|
).catch(() => "404");
|
||||||
|
var logo = await loadImage(
|
||||||
|
`https://cdn.cloudflare.steamstatic.com/steam/apps/${gameID}/logo.png`
|
||||||
|
).catch(() => "404");
|
||||||
|
|
||||||
ctx.clearRect(0, 0, width, height);
|
if (scott === "404") {
|
||||||
|
console.log("Scott error: " + scottID);
|
||||||
console.log(hex);
|
return `Scott ID ${scottID} does not exist.`;
|
||||||
|
|
||||||
var hexColors = [];
|
|
||||||
var excessHex = "";
|
|
||||||
|
|
||||||
hex.forEach((compound) => {
|
|
||||||
if (compound.length < 6) excessHex = compound;
|
|
||||||
else hexColors.push(compound);
|
|
||||||
});
|
|
||||||
|
|
||||||
var rectWidth = width / hexColors.length;
|
|
||||||
var rectHeight = height / hexColors.length;
|
|
||||||
for (color in hexColors) {
|
|
||||||
ctx.fillStyle = "#" + hexColors[color];
|
|
||||||
if (type === "horiz") ctx.fillRect(rectWidth * color, 0, rectWidth, height);
|
|
||||||
else if (type === "vert")
|
|
||||||
ctx.fillRect(0, rectHeight * color, width, rectHeight);
|
|
||||||
}
|
}
|
||||||
if (excessHex.length > 0) {
|
if (hero === "404" || logo === "404") {
|
||||||
var text = "+ " + excessHex.match(/.{1,2}/g).join(" ");
|
console.log("404 error: " + gameID);
|
||||||
var textWidth = ctx.measureText(text).width;
|
return `Steam ID ${gameID} does not have logo, hero image, or does not exist.`;
|
||||||
ctx.strokeStyle = "black";
|
|
||||||
ctx.lineWidth = 4;
|
|
||||||
ctx.fillStyle = "white";
|
|
||||||
ctx.strokeText(text, width - (textWidth + 8), height - textHeight / 2);
|
|
||||||
ctx.fillText(text, width - (textWidth + 8), height - textHeight / 2);
|
|
||||||
}
|
}
|
||||||
|
var xalign;
|
||||||
|
switch (alignment) {
|
||||||
|
case "left":
|
||||||
|
xalign = 0;
|
||||||
|
break;
|
||||||
|
case "right":
|
||||||
|
xalign = -950;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
xalign = -505;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
console.log("Generating: " + gameID);
|
||||||
|
ctx.drawImage(hero, xalign, 0, 2229, 720);
|
||||||
|
ctx.drawImage(scott, 0, 0, 1280, 720);
|
||||||
|
|
||||||
|
const newHeight = 800 / (logo.width / logo.height);
|
||||||
|
ctx.fillStyle = "#000";
|
||||||
|
ctx.shadowColor = "#000";
|
||||||
|
ctx.shadowBlur = 16;
|
||||||
|
|
||||||
|
if (stash.checked)
|
||||||
|
ctx.drawImage(
|
||||||
|
logo,
|
||||||
|
400,
|
||||||
|
Math.min(560 - newHeight / 2, 669 - newHeight),
|
||||||
|
800,
|
||||||
|
newHeight
|
||||||
|
);
|
||||||
|
else
|
||||||
|
ctx.drawImage(logo, 64, Math.max(240 - newHeight / 2, 32), 800, newHeight);
|
||||||
}
|
}
|
||||||
|
|
||||||
const clamp = (n, mi, ma) => Math.max(mi, Math.min(n, ma));
|
generateButton.addEventListener("click", getScott);
|
||||||
|
|
||||||
function lightenColor(color, mult) {
|
|
||||||
return [
|
|
||||||
clamp(color[0] + (mult / 100) * (255 - color[0]), 0, 255),
|
|
||||||
clamp(color[1] + (mult / 100) * (255 - color[1]), 0, 255),
|
|
||||||
clamp(color[2] + (mult / 100) * (255 - color[2]), 0, 255),
|
|
||||||
];
|
|
||||||
}
|
|
||||||
function darkenColor(color, mult) {
|
|
||||||
return [
|
|
||||||
clamp(color[0] - (mult / 100) * color[0], 0, 255),
|
|
||||||
clamp(color[1] - (mult / 100) * color[1], 0, 255),
|
|
||||||
clamp(color[2] - (mult / 100) * color[2], 0, 255),
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
function arrayToColor(color) {
|
|
||||||
return (
|
|
||||||
"#" + color.map((x) => Math.floor(x).toString(16).padStart(2, "0")).join("")
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,217 +0,0 @@
|
||||||
/* Document form */
|
|
||||||
|
|
||||||
:root {
|
|
||||||
--base-scale: 16px;
|
|
||||||
|
|
||||||
--background-color: hsl(0, 0%, 15%);
|
|
||||||
--color: hsl(0, 0%, 85%);
|
|
||||||
--accent-color: #808080;
|
|
||||||
--accent-color-fg: hsl(0, 0%, 95%);
|
|
||||||
--font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto,
|
|
||||||
Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji",
|
|
||||||
"Segoe UI Symbol";
|
|
||||||
--document-width: 40em;
|
|
||||||
|
|
||||||
--border-style: 0.0625em solid var(--color);
|
|
||||||
}
|
|
||||||
|
|
||||||
body {
|
|
||||||
width: 100vw;
|
|
||||||
max-width: var(--document-width);
|
|
||||||
margin: auto;
|
|
||||||
padding: 0.5em;
|
|
||||||
}
|
|
||||||
|
|
||||||
html.base {
|
|
||||||
--background-color: #fff !important;
|
|
||||||
--color: #000 !important;
|
|
||||||
--accent-color: #000 !important;
|
|
||||||
--accent-color-fg: #fff !important;
|
|
||||||
--font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto,
|
|
||||||
Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji",
|
|
||||||
"Segoe UI Symbol" !important;
|
|
||||||
--document-width: 40em;
|
|
||||||
|
|
||||||
--border-style: 0.0625em solid var(--color);
|
|
||||||
}
|
|
||||||
|
|
||||||
html.base body {
|
|
||||||
margin: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Size and type normalize */
|
|
||||||
|
|
||||||
html {
|
|
||||||
font-size: var(--base-scale);
|
|
||||||
background-color: var(--background-color);
|
|
||||||
color: var(--color);
|
|
||||||
}
|
|
||||||
|
|
||||||
h1 {
|
|
||||||
font-size: 2em;
|
|
||||||
line-height: 1.5em;
|
|
||||||
margin: 0;
|
|
||||||
margin-bottom: 0.125em;
|
|
||||||
}
|
|
||||||
|
|
||||||
h2 {
|
|
||||||
font-size: 1.5em;
|
|
||||||
line-height: 1.25em;
|
|
||||||
margin: 0;
|
|
||||||
margin-bottom: 0.25em;
|
|
||||||
}
|
|
||||||
|
|
||||||
h3 {
|
|
||||||
font-size: 1.1em;
|
|
||||||
line-height: 1.25em;
|
|
||||||
margin: 0;
|
|
||||||
margin-bottom: 0.25em;
|
|
||||||
}
|
|
||||||
|
|
||||||
p {
|
|
||||||
font-size: 1em;
|
|
||||||
line-height: 1.25em;
|
|
||||||
margin: 0.5em 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
small {
|
|
||||||
font-size: 0.75em;
|
|
||||||
}
|
|
||||||
|
|
||||||
big {
|
|
||||||
font-size: 1.5em;
|
|
||||||
}
|
|
||||||
|
|
||||||
code {
|
|
||||||
font-size: 1em;
|
|
||||||
line-height: 1.25em;
|
|
||||||
font-family: monospace;
|
|
||||||
}
|
|
||||||
|
|
||||||
hr {
|
|
||||||
border: none;
|
|
||||||
border-top: var(--border-style);
|
|
||||||
background-color: transparent;
|
|
||||||
margin: 0.25em 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Form normalize */
|
|
||||||
|
|
||||||
html {
|
|
||||||
font-family: var(--font-family);
|
|
||||||
}
|
|
||||||
|
|
||||||
* {
|
|
||||||
box-sizing: border-box;
|
|
||||||
}
|
|
||||||
|
|
||||||
*:focus {
|
|
||||||
outline: 2px solid var(--accent-color-fg);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Interactive normalize */
|
|
||||||
|
|
||||||
a {
|
|
||||||
color: var(--accent-color);
|
|
||||||
}
|
|
||||||
|
|
||||||
a:hover,
|
|
||||||
a:focus {
|
|
||||||
opacity: 0.8;
|
|
||||||
}
|
|
||||||
|
|
||||||
a:active {
|
|
||||||
opacity: 0.5;
|
|
||||||
}
|
|
||||||
|
|
||||||
input,
|
|
||||||
select,
|
|
||||||
textarea {
|
|
||||||
font-family: inherit;
|
|
||||||
border: var(--border-style);
|
|
||||||
padding: 0.25em 0.5em;
|
|
||||||
margin: 0.25em 0;
|
|
||||||
font-size: 1em;
|
|
||||||
background-color: var(--background-color);
|
|
||||||
color: var(--color);
|
|
||||||
}
|
|
||||||
|
|
||||||
button,
|
|
||||||
input[type="button"],
|
|
||||||
input[type="submit"],
|
|
||||||
input[type="reset"] {
|
|
||||||
border: var(--border-style);
|
|
||||||
padding: 0.25em 0.5em;
|
|
||||||
margin: 0.25em 0;
|
|
||||||
font-size: 1em;
|
|
||||||
font-family: inherit;
|
|
||||||
background-color: var(--accent-color);
|
|
||||||
color: var(--accent-color-fg);
|
|
||||||
}
|
|
||||||
|
|
||||||
button[data-outlined],
|
|
||||||
input[type="button"][data-outlined],
|
|
||||||
input[type="submit"][data-outlined],
|
|
||||||
input[type="reset"][data-outlined] {
|
|
||||||
border: var(--border-style);
|
|
||||||
background-color: var(--background-color);
|
|
||||||
color: var(--accent-color);
|
|
||||||
}
|
|
||||||
|
|
||||||
button:hover,
|
|
||||||
input[type="button"]:hover,
|
|
||||||
input[type="submit"]:hover,
|
|
||||||
input[type="reset"]:hover,
|
|
||||||
button:focus,
|
|
||||||
input[type="button"]:focus,
|
|
||||||
input[type="submit"]:focus,
|
|
||||||
input[type="reset"]:focus {
|
|
||||||
opacity: 0.8;
|
|
||||||
}
|
|
||||||
button:active,
|
|
||||||
input[type="button"]:active,
|
|
||||||
input[type="submit"]:active,
|
|
||||||
input[type="reset"]:active {
|
|
||||||
opacity: 0.5;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* -- Checkbox styling */
|
|
||||||
|
|
||||||
label.checkbox {
|
|
||||||
display: inline-block;
|
|
||||||
position: relative;
|
|
||||||
margin: 0.25em 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
label.checkbox input[type="checkbox"] {
|
|
||||||
/* visibility: hidden; */
|
|
||||||
opacity: 0;
|
|
||||||
width: 0;
|
|
||||||
height: 0;
|
|
||||||
position: absolute;
|
|
||||||
top: 0;
|
|
||||||
left: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
label.checkbox input[type="checkbox"] + span.checkbox {
|
|
||||||
display: inline-block;
|
|
||||||
width: 1em;
|
|
||||||
height: 1em;
|
|
||||||
line-height: 1em;
|
|
||||||
padding: 0.25em;
|
|
||||||
box-sizing: content-box;
|
|
||||||
border: var(--border-style);
|
|
||||||
color: transparent;
|
|
||||||
text-align: center;
|
|
||||||
user-select: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
label.checkbox input[type="checkbox"]:focus + span.checkbox {
|
|
||||||
outline: 2px solid var(--accent-color-fg);
|
|
||||||
}
|
|
||||||
|
|
||||||
label.checkbox input[type="checkbox"]:checked + span.checkbox {
|
|
||||||
background-color: var(--accent-color);
|
|
||||||
border: var(--border-style);
|
|
||||||
color: var(--accent-color-fg);
|
|
||||||
}
|
|