Created
February 4, 2021 13:00
-
-
Save mgiachetti/644f92a8b4b1c56f729239f650ccaf5b to your computer and use it in GitHub Desktop.
Script to run doom on Mural.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// @ts-check | |
function delay(ms) { | |
return new Promise((resolve) => { | |
setTimeout(resolve, ms); | |
}); | |
} | |
function avgColor(data, x0, y0, width, height, dist) { | |
const color = [0, 0, 0, 0]; | |
for (let y = 0; y < dist; y++) { | |
for (let x = 0; x < dist; x++) { | |
const offset = ((y0 * dist + y) * width + x0 * dist + x) * 4; | |
color[0] += data[offset + 0]; | |
color[1] += data[offset + 1]; | |
color[2] += data[offset + 2]; | |
color[3] += data[offset + 3]; | |
} | |
} | |
color[0] = Math.round(color[0] / (dist * dist)); | |
color[1] = Math.round(color[1] / (dist * dist)); | |
color[2] = Math.round(color[2] / (dist * dist)); | |
color[3] = Math.round(color[3] / (dist * dist)); | |
return color; | |
} | |
var boardId = window.location.pathname.match(/([^\/]+\/[^\/]+)\/[a-z0-9]*$/)[1].replace('/', '.'); | |
var userId = app.me.get('username'); | |
async function createScreen() { | |
const TEMPLATE = { "height": 138, "hidden": false, "id": "0-1600259662016", "instruction": "", "locked": false, "lockedByFacilitator": false, "owner": "martingiachetti3508", "parentId": null, "rotation": 0, "stackingOrder": 0, "title": "", "type": "murally.widget.TextWidget", "width": 138, "x": 330, "y": 87, "fontFamily": "proxima-nova", "textAlign": "center", "fontSize": 23, "minLines": 6, "backgroundColor": "#fcfe7d", "textType": "realNote", "bold": false, "italic": false, "strike": false, "underline": false, "text": "", "border": false, "round": false, "create": true, "recover": false }; | |
const mwidth = 80; | |
const mheight = 40; | |
const widgets = []; | |
const sep = 1; | |
const swidth = TEMPLATE.width; | |
const sheight = TEMPLATE.height; | |
for (let y = 0; y < mheight; y++) { | |
for (let x = 0; x < mwidth; x++) { | |
widgets.push({ | |
...TEMPLATE, | |
x: x * (swidth + sep), | |
y: y * (sheight + sep), | |
id: `pixel-${x}-${y}`, | |
}); | |
} | |
} | |
for (let i = 0; i < widgets.length / 50; i++) { | |
const widgetsMap = widgets.slice(i * 50, (i + 1) * 50).reduce((acc, w) => ({ ...acc, [w.id]: w }), {}); | |
// post to mural | |
const authorization = `Bearer ${window.app.getToken().jwt}` | |
const [, , , , workspace, muralId] = location.pathname.split('/'); | |
const url = `https://app.mural.co/api/v2/murals/${workspace}/${muralId}?acceptBadRequest=true` | |
await fetch(url, { | |
"headers": { | |
"accept": "application/json", | |
"accept-language": "en-US,en;q=0.9", | |
authorization, | |
"cache-control": "no-cache", | |
"content-type": "application/json; charset=utf-8", | |
"pragma": "no-cache", | |
"sec-fetch-dest": "empty", | |
"sec-fetch-mode": "cors", | |
"sec-fetch-site": "same-origin", | |
"x-mural-ly-version": "1.0.0", | |
}, | |
"body": JSON.stringify(widgetsMap), | |
"method": "POST", | |
"mode": "cors", | |
"credentials": "include" | |
}); | |
await delay(2000); | |
} | |
} | |
async function updateScreen() { | |
const mwidth = 80; | |
const mheight = 40; | |
const widgets = []; | |
const sep = 0; | |
const swidth = 138; | |
const sheight = 138; | |
const x0 = 138 * 20; | |
const y0 = 138 * 20; | |
for (let y = 0; y < mheight; y++) { | |
for (let x = 0; x < mwidth; x++) { | |
widgets.push({ | |
backgroundColor: '#ffffff', | |
x: x0 + x * (swidth + sep), | |
y: y0 + y * (sheight + sep), | |
id: `pixel-${x}-${y}`, | |
}); | |
} | |
} | |
const sliceSize = 5000; | |
for (let i = 0; i < widgets.length / sliceSize; i++) { | |
const widgetsMap = widgets.slice(i * sliceSize, (i + 1) * sliceSize).reduce((acc, w) => ({ ...acc, [w.id]: w }), {}); | |
// post to mural | |
const authorization = `Bearer ${window.app.getToken().jwt}` | |
const [, , , , workspace, muralId] = location.pathname.split('/'); | |
const url = `https://app.mural.co/api/v2/murals/${workspace}/${muralId}?acceptBadRequest=true` | |
await fetch(url, { | |
"headers": { | |
"accept": "application/json", | |
"accept-language": "en-US,en;q=0.9", | |
authorization, | |
"cache-control": "no-cache", | |
"content-type": "application/json; charset=utf-8", | |
"pragma": "no-cache", | |
"sec-fetch-dest": "empty", | |
"sec-fetch-mode": "cors", | |
"sec-fetch-site": "same-origin", | |
"x-mural-ly-version": "1.0.0", | |
}, | |
"body": JSON.stringify(widgetsMap), | |
"method": "POST", | |
"mode": "cors", | |
"credentials": "include" | |
}); | |
await delay(2000); | |
} | |
} | |
// updateScreen() | |
function updateColor(widgetId, color) { | |
// const boardId = window.location.pathname.match(/([^\/]+\/[^\/]+)\/[a-z0-9]*$/)[1].replace('/', '.'); | |
// const userId = app.me.get('username'); | |
const operation = { | |
boardId, | |
operation: { | |
boardId, | |
action: 'UPDATE_WIDGET', | |
userId, | |
widgetId, | |
validatePayload: false, | |
values: { | |
backgroundColor: color, | |
} | |
}, | |
}; | |
// send remote | |
// _socket.emit('broadcastP2P', JSON.stringify(operation)); | |
// send local | |
// _socket._callbacks.$remoteOperations[0](JSON.stringify(operation)); | |
// const w = window.engine.widgets.get(widgetId); | |
// window.engine.widgets.update({ ...w, properties: { ...w.properties, backgroundColor: color } }); | |
return operation; | |
} | |
function setPixel(x, y, color) { | |
return updateColor(`pixel-${x}-${y}`, `rgb(${color[0]},${color[1]},${color[2]})`); | |
} | |
function clearScreen(color) { | |
const mwidth = 80; | |
const mheight = 40; | |
for (let y = 0; y < mheight; y++) { | |
for (let x = 0; x < mwidth; x++) { | |
setPixel(x, y, color); | |
} | |
} | |
} | |
async function initDoom() { | |
let iframe = document.querySelector('#doom_iframe'); | |
if (!iframe) { | |
iframe = document.createElement('iframe'); | |
iframe.id = 'doom_iframe'; | |
document.body.appendChild(iframe); | |
iframe = document.querySelector('#doom_iframe'); | |
const ibody = iframe.contentDocument.body; | |
const div = document.createElement('div'); | |
div.id = 'dosbox'; | |
ibody.appendChild(div); | |
let script = document.createElement('script'); | |
script.type = 'text/javascript'; | |
script.innerHTML = await (await fetch('https://code.jquery.com/jquery-3.5.1.slim.min.js')).text(); | |
ibody.appendChild(script); | |
script = document.createElement('script'); | |
script.type = 'text/javascript'; | |
script.innerHTML = await (await fetch('https://js-dos.com/cdn/js-dos-api.js')).text(); | |
ibody.appendChild(script); | |
script = document.createElement('script'); | |
script.type = 'text/javascript'; | |
script.innerHTML = ` | |
var dosbox = new Dosbox({ | |
id: "dosbox", | |
onload: function (dosbox) { | |
dosbox.run('https://js-dos.com/cdn/upload/[email protected]', "./DOOM/DOOM.EXE"); | |
//dosbox.run('https://drive.google.com/uc?export=view&id=1XVOF8ktihBL-RP0vqGZMBMC1dpdCfXHZ', "./DOOM/DOOM.EXE"); | |
}, | |
onrun: function (dosbox, app) { | |
console.log("App '" + app + "' is runned"); | |
const canvas = $('.dosbox-container canvas')[0]; | |
const ctx = canvas.getContext("2d"); | |
const cwidth = 640; | |
const cheight = 320; | |
setInterval(() => { | |
console.time('frame'); | |
const img = ctx.getImageData(0, 0, cwidth, cheight); | |
window.top.postMessage({cmd: 'frame', data: img.data}, '*'); | |
}, 50); | |
} | |
}); | |
$(".dosbox-start").click(); | |
`; | |
ibody.appendChild(script); | |
await delay(10000); | |
} | |
screenCastRun(); | |
} | |
function screenCastRun() { | |
const cwidth = 640; | |
const cheight = 320; | |
const downscaleFactor = 8; | |
const mwidth = cwidth / downscaleFactor; | |
const mheight = cheight / downscaleFactor; | |
window.onmessage = function (e) { | |
if (e.data.cmd === 'frame') { | |
console.time('frame'); | |
const data = e.data.data; | |
const operations = []; | |
for (let y = 0; y < mheight; y++) { | |
for (let x = 0; x < mwidth; x++) { | |
const color = avgColor(data, x, y, cwidth, cheight, downscaleFactor); | |
operations.push(setPixel(x, y, color)); | |
} | |
} | |
console.timeEnd('frame'); | |
console.time('render'); | |
const widgets = operations.map((o, i) => { | |
const w = window.engine.widgets.get(o.operation.widgetId); | |
const color = o.operation.values.backgroundColor; | |
const nw = { ...w, properties: { ...w.properties, backgroundColor: color } }; | |
return nw; | |
}) | |
window.engine.widgets.update(...widgets); | |
console.timeEnd('render'); | |
} | |
}; | |
} | |
var _renderParams = { | |
x0: 100, | |
y0: 100, | |
scale: 1, | |
}; | |
function screenCastRun2() { | |
const cwidth = 640; | |
const cheight = 320; | |
const downscaleFactor = 4; | |
const mwidth = cwidth / downscaleFactor; | |
const mheight = cheight / downscaleFactor; | |
const canvas = /** @type {HTMLCanvasElement} */(document.querySelector('.render-engine')); | |
const ctx = canvas.getContext("2d"); | |
const w = canvas.clientWidth; | |
const h = canvas.clientHeight; | |
// clearColor | |
ctx.fillStyle = '#dddddd'; | |
ctx.fillRect(0, 0, w * 2, h * 2); | |
window.onmessage = function (e) { | |
if (e.data.cmd === 'frame') { | |
console.time('frame'); | |
console.time() | |
const data = e.data.data; | |
// clearColor | |
ctx.fillStyle = '#dddddd'; | |
ctx.fillRect(0, 0, w, h); | |
for (let y = 0; y < mheight; y++) { | |
for (let x = 0; x < mwidth; x++) { | |
const x0 = _renderParams.x0; | |
const y0 = _renderParams.y0; | |
const scale = _renderParams.scale; | |
const dp = 138 | |
const sep = 1 | |
const color = avgColor(data, x, y, cwidth, cheight, downscaleFactor); | |
const c = `rgb(${color[0]},${color[1]},${color[2]})`; | |
ctx.fillStyle = c; | |
ctx.fillRect(x0 + x * (dp + sep) * scale, y0 + y * (dp + sep) * scale, dp * scale, dp * scale); | |
} | |
} | |
console.timeEnd('frame'); | |
} | |
}; | |
} | |
async function run() { | |
if (!window.engine.widgets.get('pixel-0-0')) { | |
await createScreen(); | |
await delay(2000); | |
} | |
initDoom() | |
} | |
run() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
To RUN
just paste it on a developer console after an empty mural is loaded