Created
September 26, 2023 22:01
-
-
Save jakobbouchard/dc0d44cc1f18642eafa40acd9b9780e6 to your computer and use it in GitHub Desktop.
Custom Godot HTML5 shell
This file contains 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
<!DOCTYPE html> | |
<html lang="en"> | |
<head> | |
<meta charset="utf-8" /> | |
<meta name="viewport" content="width=device-width, user-scalable=no" /> | |
<title>$GODOT_PROJECT_NAME</title> | |
<style> | |
body { | |
touch-action: none; | |
margin: 0; | |
border: 0; | |
padding: 0; | |
/* For pixel-art scaling */ | |
image-rendering: pixelated; | |
width: 100vw; | |
height: 100vh; | |
background-color: #000000; | |
} | |
#app { | |
margin: auto; | |
background-repeat: no-repeat; | |
background-size: cover; | |
width: calc(160 * var(--pixel-size)); | |
height: 100vh; /* "144px" */ | |
} | |
#canvas:focus { | |
outline: none; | |
} | |
#status { | |
display: flex; | |
align-items: center; | |
justify-content: center; | |
height: 100%; | |
visibility: hidden; | |
} | |
#status-progress { | |
display: block; | |
box-sizing: border-box; | |
border: calc(1 * var(--pixel-size)) solid #4d4d80; | |
width: calc(50 * var(--pixel-size)); | |
height: calc(6 * var(--pixel-size)); | |
background-color: transparent; | |
visibility: visible; | |
} | |
#status-progress-inner { | |
box-sizing: border-box; | |
width: 0; | |
height: 100%; | |
background-color: #e6a1cf; | |
} | |
#status-notice { | |
display: flex; | |
align-items: center; | |
justify-content: center; | |
border: calc(1 * var(--pixel-size)) solid #e6a1cf; | |
width: calc(100 * var(--pixel-size)); | |
height: calc(24 * var(--pixel-size)); | |
background-color: #4d4d80; | |
color: #ffe6ea; | |
text-align: center; | |
line-height: 1.5; | |
font-family: monospace; | |
font-size: calc(3.5 * var(--pixel-size)); | |
visibility: visible; | |
} | |
</style> | |
<script> | |
// Add a custom CSS variable to get a "pixel" size in CSS | |
document.documentElement.style.setProperty( | |
"--pixel-size", | |
`${window.innerHeight / 144}px` | |
); | |
const GODOT_CONFIG = $GODOT_CONFIG; | |
const style = document.createElement("style"); | |
style.textContent = `#app { background-image: url("${GODOT_CONFIG.executable}.png") }`; | |
document.head.append(style); | |
</script> | |
$GODOT_HEAD_INCLUDE | |
</head> | |
<body> | |
<div id="app"> | |
<canvas style="display: none" id="canvas"></canvas> | |
<div id="status"> | |
<div | |
id="status-progress" | |
style="display: none" | |
oncontextmenu="event.preventDefault();" | |
> | |
<div id="status-progress-inner"></div> | |
</div> | |
<div id="status-notice" style="display: none"></div> | |
</div> | |
</div> | |
<script src="$GODOT_URL"></script> | |
<script> | |
const engine = new Engine(GODOT_CONFIG); | |
(function () { | |
const statusProgress = document.getElementById("status-progress"); | |
const statusProgressInner = document.getElementById( | |
"status-progress-inner" | |
); | |
const statusNotice = document.getElementById("status-notice"); | |
const canvas = document.getElementById("canvas"); | |
let initializing = true; | |
let statusMode = "hidden"; | |
function setStatusMode(mode) { | |
if (statusMode === mode || !initializing) { | |
return; | |
} | |
[statusProgress, statusNotice].forEach((elem) => { | |
elem.style.display = "none"; | |
}); | |
switch (mode) { | |
case "progress": | |
statusProgress.style.display = ""; | |
break; | |
case "notice": | |
statusNotice.style.display = ""; | |
break; | |
case "hidden": | |
break; | |
default: | |
throw new Error("Invalid status mode"); | |
} | |
statusMode = mode; | |
} | |
function displayFailureNotice(err) { | |
setStatusMode("notice"); | |
initializing = false; | |
const msg = err.message || err; | |
console.error(msg); | |
while (statusNotice.lastChild) { | |
statusNotice.removeChild(statusNotice.lastChild); | |
} | |
msg.split("\n").forEach((line) => { | |
statusNotice.appendChild(document.createTextNode(line)); | |
statusNotice.appendChild(document.createElement("br")); | |
}); | |
} | |
const missing = Engine.getMissingFeatures(); | |
if (missing.length !== 0) { | |
console.error( | |
"The following features required to run Godot projects on the Web are missing:\n" + | |
missing.join("\n") | |
); | |
displayFailureNotice("Your browser is missing required features."); | |
return; | |
} | |
if ( | |
navigator.platform.indexOf("Mac") === 0 || | |
navigator.platform === "iPhone" | |
) { | |
displayFailureNotice("macOS and iOS browsers are not supported.\nPlease download the native version."); | |
return; | |
} | |
engine | |
.startGame({ | |
onProgress: function (current, total) { | |
setStatusMode("progress"); | |
if (total > 0) { | |
if (current === total) { | |
statusProgressInner.style.width = "100%"; | |
return; | |
} | |
const pixels = Math.floor((current / total) * 48); | |
statusProgressInner.style.width = `calc(${pixels} * var(--pixel-size))`; | |
} | |
}, | |
onExit: function (code) { | |
canvas.style.display = "none"; | |
if (code !== 0) { | |
displayFailureNotice(`Process exited with code ${code}`); | |
} | |
}, | |
}) | |
.then(() => { | |
setStatusMode("hidden"); | |
initializing = false; | |
canvas.style.display = "block"; | |
}, displayFailureNotice); | |
})(); | |
</script> | |
</body> | |
</html> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment