This commit is contained in:
slweeb 2025-11-30 17:45:34 -05:00
commit a0a634fe76
3 changed files with 310 additions and 11 deletions

21
mods/mobile_keybinds.js Normal file
View File

@ -0,0 +1,21 @@
(() => {
function runKeybind() {
promptInput("Input the keybind you want to run. (e.g. KeyA, Digit1, Backspace)", (keybind) => {
if (keybinds[keybind]) {
keybinds[keybind]();
}
})
}
if (isMobile) {
const keybindButton = document.createElement("button")
keybindButton.id = "keybindButton"
keybindButton.title = "Change static mode"
keybindButton.classList.add("controlButton")
keybindButton.onclick = () => {
runKeybind()
}
keybindButton.textContent = "Keybind"
document.getElementById("pauseButton").before(keybindButton)
}
})()

View File

@ -8,14 +8,10 @@
}
function randomColor() {
const letters = "0123456789ABCDEF";
let color = "#";
for (let i = 0; i < 6; i++) {
color += letters[Math.floor(Math.random() * 16)];
}
return color;
return '#' + Math.floor(Math.random() * 0xFFFFFF).toString(16).padStart(6, '0');
}
function loopScreen(callback) {
for (let x = 0; x <= width; x++) {
for (let y = 0; y <= height; y++) {
@ -24,19 +20,163 @@
}
}
keybinds["KeyS"] = () => {
staticMode === 0 ? staticMode = 1 : staticMode === 1 ? staticMode = 2 : staticMode = 0
/**
* Converts RGB to RGBA
* @param {string|object} rgb - Either "rgb(r, g, b)" string or {r, g, b} object
* @param {number} alpha - Alpha value between 0 and 1
* @returns {string} RGBA string
*/
function rgbToRgba(rgb, alpha = 1) {
let r, g, b;
if (typeof rgb === 'string') {
const match = rgb.match(/\d+/g);
if (!match || match.length < 3) throw new Error('Invalid RGB string');
[r, g, b] = match.map(Number);
} else if (typeof rgb === 'object') {
({ r, g, b } = rgb);
} else {
throw new Error('Invalid input: must be RGB string or object');
}
alpha = Math.min(Math.max(alpha, 0), 1);
return `rgba(${r}, ${g}, ${b}, ${alpha})`;
}
/**
* Updates the alpha value of an rgba string
* @param {string} rgbaString - Example: "rgba(255, 0, 0, 0.5)"
* @param {number} newAlpha - New alpha value (0 to 1)
* @returns {string} - Updated rgba string
*/
function setAlpha(rgbaString, newAlpha) {
// Use a regex to capture the r, g, b values
const match = rgbaString.match(/rgba?\(\s*(\d+),\s*(\d+),\s*(\d+)(?:,\s*[\d.]+)?\s*\)/);
if (!match) {
throw new Error("Invalid rgba string: " + rgbaString);
}
const [_, r, g, b] = match;
return `rgba(${r}, ${g}, ${b}, ${newAlpha})`;
}
function drawCircle(ctx, x, y, radius, options = {}) {
const { fill = 'blue', stroke = null, lineWidth = 1 } = options;
// Only compute offset if needed
const offset = lineWidth % 2 === 0 ? 0 : 0.5;
const cx = x + offset;
const cy = y + offset;
ctx.beginPath();
ctx.arc(cx, cy, radius, 0, Math.PI * 2);
// Set styles only if needed
if (fill) {
if (ctx.fillStyle !== fill) ctx.fillStyle = fill;
ctx.fill();
}
if (stroke) {
if (ctx.strokeStyle !== stroke) ctx.strokeStyle = stroke;
if (ctx.lineWidth !== lineWidth) ctx.lineWidth = lineWidth;
ctx.stroke();
}
}
function toggleStaticMode() {
staticMode = (staticMode + 1) % 5
}
if (isMobile) {
const staticButton = document.createElement("button")
staticButton.id = "staticButton"
staticButton.title = "Change static mode"
staticButton.classList.add("controlButton")
staticButton.onclick = () => {
toggleStaticMode()
}
staticButton.textContent = "Static"
document.getElementById("pauseButton").before(staticButton)
}
keybinds["KeyS"] = () => {
toggleStaticMode()
}
keybinds["KeyK"] = () => {
toggleStaticMode()
}
// Static rendering loop
let cachedColorMap = []
renderPostPixel(function (ctx) {
if (!staticMode) return
if (!paused) {
cachedColorMap = []
} else {
cachedColorMap.forEach(renderObj => {
let x = renderObj.x
let y = renderObj.y
let color = renderObj.color
if (color.match(/^#[0-9A-Fa-f]{6}$/)) {
color = rgbToRgba(hexToRGB(color), 1)
}
let colorFullAlpha = setAlpha(color, 1)
let isCircle = renderObj.circle
if (isCircle) {
drawCircle(ctx, canvasCoord(x) + 2.1, canvasCoord(y) + 2.1, 3, { fill: color })
} else {
drawSquare(ctx, colorFullAlpha, x, y, 1, 0.2)
}
})
return
}
loopScreen((x, y) => {
if (staticMode === 1) {
drawSquare(ctx, randomGrayscale(), x, y, 1, 0.2)
let color = randomGrayscale()
drawSquare(ctx, color, x, y, 1, 0.2)
cachedColorMap.push({ x, y, color })
}
if (staticMode === 2) {
drawSquare(ctx, randomColor(), x, y, 1, 0.3)
let color = randomColor()
drawSquare(ctx, color, x, y, 1, 0.2)
cachedColorMap.push({ x, y, color })
}
if (staticMode === 3) {
let color = rgbToRgba(randomGrayscale(), 0.2)
drawCircle(ctx, canvasCoord(x) + 2.1, canvasCoord(y) + 2.1, 3, { fill: color })
cachedColorMap.push({ x, y, color, circle: true })
}
if (staticMode === 4) {
let color = rgbToRgba(hexToRGB(randomColor()), 0.2)
drawCircle(ctx, canvasCoord(x) + 2.1, canvasCoord(y) + 2.1, 3, { fill: color })
cachedColorMap.push({ x, y, color, circle: true })
}
// Currently broken with pausing
/*
if (staticMode === 5) {
let color = rgbToRgba(randomGrayscale(), 0.2)
const random = Math.random()
if (random <= 0.5) {
drawSquare(ctx, color, x, y)
cachedColorMap.push({ x, y, color })
} else {
drawCircle(ctx, canvasCoord(x) + 2.1, canvasCoord(y) + 2.1, 3, { fill: color })
cachedColorMap.push({ x, y, color, circle: true })
}
}
if (staticMode === 6) {
let color = rgbToRgba(hexToRGB(randomColor()), 0.2)
const random = Math.random()
if (random <= 0.5) {
drawSquare(ctx, color, x, y)
cachedColorMap.push({ x, y, color })
} else {
drawCircle(ctx, canvasCoord(x) + 2.1, canvasCoord(y) + 2.1, 3, { fill: color })
cachedColorMap.push({ x, y, color, circle: true })
}
}
*/
})
})
})()

View File

@ -45,6 +45,140 @@
rescale()
}
function gen_button(row, col, html, click, nopos, id){
const elem = document.createElement("button")
if (!nopos){
elem.style.gridColumn = row
elem.style.gridRow = col
}
if (id) { elem.id = id }
// Table for the data-pos to assign (row major). If null, don't add.
const data_pos_map = [
["tl", null, "tr"],
[null, null, null],
["bl", null, "br"]
]
elem.innerHTML = html
elem.onclick = click
if (data_pos_map[row-1][col-1] !== null) {
elem.dataset.pos = data_pos_map[row-1][col-1]
}
return elem
}
function add_css(){
const FLOATER_CSS = `
#zm_data_div {
margin-bottom: 10px;
}
#canvasDiv {
overflow: hidden
}
#zm_floater_container {
position: absolute;
display: grid;
right: 5px;
bottom: 5px;
height: 24%;
aspect-ratio: 1;
border: 2px solid white;
background-color: black;
font-size: 1.2em;
button { text-align: center; border: 0px solid white }
button:where([data-pos="tl"]) { border-width: 0px 2px 2px 0px };
button:where([data-pos="tr"]) { border-width: 2px 2px 0px 0px };
button:where([data-pos="bl"]) { border-width: 0px 0px 2px 2px };
button:where([data-pos="br"]) { border-width: 2px 0px 0px 2px };
}
#zm_floater_container:has(#zm_collapse[data-collapsed="true"]) {
height: calc(8% - 1px);
button:not(#zm_collapse) {
display: none
}
}
.zm_corner {
border: 2px solid white;
}
#zm_collapse {
grid-row: 3;
grid-column: 3;
}
#zm_collapse[data-collapsed="true"] {
grid-row: 1;
grid-column: 1;
border-width: 0px;
}
`
const style_div = document.createElement("style")
style_div.innerHTML = FLOATER_CSS
document.head.appendChild(style_div)
}
function add_zoom_floaters(){
const container = document.createElement("div")
container.id = "zm_floater_container"
// Pan mode selector (C: Coarse F: Fine)
const pan_mode_sel = gen_button(
1,3, "C",
(evt) => {
evt.target.dataset.mode = evt.target.dataset.mode == "F" ? "C" : "F"
evt.target.innerText = evt.target.dataset.mode
},
false,
"zm_panmode_sel"
)
const speed = () =>
(window.zoom_level > 3 ? 5 : 10) * // More granular at higher zoom levels
(pan_mode_sel.dataset.mode == "F" ? 0.25 : 1) // Increase granularity in fine mode
container.append(
// Direction buttons
gen_button(2,1, "&uarr;", () => handle_pan("up" ,speed())),
gen_button(1,2, "&larr;", () => handle_pan("left" ,speed())),
gen_button(3,2, "&rarr;", () => handle_pan("right" ,speed())),
gen_button(2,3, "&darr;", () => handle_pan("down" ,speed())),
// Zoom buttons
gen_button(1,1, "+", () => handle_zoom("in")),
gen_button(3,1, "-", () => handle_zoom("out")),
// Collapse button
gen_button(
3,3, "#",
(evt) => {
evt.target.dataset.collapsed = evt.target.dataset.collapsed == "true"
? "false"
: "true"
},
true,
"zm_collapse"
),
pan_mode_sel
)
const canvas_div = document.getElementById("canvasDiv")
canvas_div.appendChild(container)
}
function rescale(){
log_info()
@ -87,8 +221,12 @@
}
function patch_ui(){
add_css()
add_zoom_floaters()
zoom_data_div = document.createElement("div")
document.getElementById("logDiv").appendChild(zoom_data_div)
zoom_data_div.id = "zm_data_div"
document.getElementById("logDiv").prepend(zoom_data_div)
const controls_table = document.getElementById("controlsTable").lastElementChild
controls_table.insertAdjacentHTML("beforeBegin",`