Project stuff

This commit is contained in:
MeowcaTheoRange 2023-12-07 10:34:09 -06:00
parent 4018b3ae6a
commit 16e38ad4b2
113 changed files with 3865 additions and 58 deletions

10
.gitmodules vendored
View file

@ -1,3 +1,9 @@
[submodule "views/projects/midsim"] [submodule "views/projects/item/midsim"]
path = views/projects/midsim path = views/projects/item/midsim
url = https://git.abtmtr.link/MeowcaTheoRange/Mid-Simulator url = https://git.abtmtr.link/MeowcaTheoRange/Mid-Simulator
[submodule "views/projects/item/clock"]
path = views/projects/item/clock
url = https://git.abtmtr.link/MeowcaTheoRange/Clock
[submodule "views/projects/item/dice"]
path = views/projects/item/dice
url = https://git.abtmtr.link/MeowcaTheoRange/DiceApp

View file

@ -5,9 +5,7 @@
"dev": "nodemon --exec 'rm -rf output/*;gulp;node debug.js' --ext '*' --ignore 'output/*'" "dev": "nodemon --exec 'rm -rf output/*;gulp;node debug.js' --ext '*' --ignore 'output/*'"
}, },
"devDependencies": { "devDependencies": {
"gulp": "^4.0.2" "gulp": "^4.0.2",
},
"dependencies": {
"express": "^4.18.2", "express": "^4.18.2",
"through2": "^4.0.2" "through2": "^4.0.2"
} }

View file

@ -65,7 +65,7 @@
<script src="/scripts/windows.js"></script> <script src="/scripts/windows.js"></script>
<script src="/scripts/accessibility.js"></script> <script src="/scripts/accessibility.js"></script>
<script src="./scripts/data_get_whoami.js"></script> <script src="./scripts/data_get_whoami.js"></script>
<script src="/projects/hex/scripts/index.js"></script> <script src="/projects/item/hex/scripts/index.js"></script>
<script> <script>
window.manager = new WindowManager( window.manager = new WindowManager(
document.getElementById("WindowHolder") document.getElementById("WindowHolder")

View file

@ -0,0 +1,7 @@
# Clock
Budda dawg. Dawg with the budda. Put the budda on 'im :]
Partially done on a SMART Board. It was painful.
[jqtp.js](/jqtp.js) courtesy of [furf](https://github.com/furf) ([JQuery Touch Punch](https://github.com/furf/jquery-ui-touch-punch))

Binary file not shown.

After

Width:  |  Height:  |  Size: 830 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 986 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 874 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 143 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 425 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 453 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 423 B

View file

@ -0,0 +1,150 @@
var tone = new Audio();
document.querySelectorAll(".clock").forEach((clock) => {
var canvas = clock.querySelector("canvas");
var ctx = canvas.getContext("2d");
ctx.resetTransform();
ctx.translate(32, 32);
ctx.strokeStyle = getComputedStyle(document.documentElement).getPropertyValue('--foreground');
ctx.lineWidth = 2;
ctx.lineCap = "round";
update();
});
document.querySelectorAll(".timer").forEach((clock) => {
var canvas = clock.querySelector("canvas");
var ctx = canvas.getContext("2d");
ctx.resetTransform();
ctx.translate(32, 32);
ctx.strokeStyle = getComputedStyle(document.documentElement).getPropertyValue('--foreground');
ctx.lineWidth = 2;
ctx.lineCap = "round";
update();
});
function update() {
document.querySelectorAll(".clock").forEach((clock, i) => {
var canvas = clock.querySelector("canvas");
var ctx = canvas.getContext("2d");
ctx.strokeStyle = getComputedStyle(document.documentElement).getPropertyValue('--foreground');
if (clock.classList.contains("main-clock")) return;
ctx.resetTransform();
ctx.translate(32, 32);
ctx.lineWidth = 2;
ctx.lineCap = "round";
var canvas = clock.querySelector("canvas");
var ctx = canvas.getContext("2d");
var now = new Date();
var hour = now.toLocaleTimeString(undefined, {
timeZone: clock.dataset.timezone,
hour: "2-digit",
hour12: false
}) % 12;
var minute = now.getMinutes();
clock.querySelector(".timezone").innerHTML = now.toLocaleDateString(undefined, {
timeZone: clock.dataset.timezone,
year: "numeric",
month: "long",
day: "numeric",
weekday: "long",
timeZoneName: 'long'
});
clock.querySelector(".title").innerHTML = now.toLocaleTimeString(undefined, {
timeZone: clock.dataset.timezone,
hc: "h12", timeStyle: "short"
});
ctx.clearRect(-32,-32, 64, 64);
ctx.beginPath();
ctx.arc(0, 0, 30, 0, Math.PI * 2);
ctx.stroke();
drawHand(ctx, (hour*Math.PI/6)+(minute*Math.PI/(6*60)), 16);
drawHand(ctx, (minute*Math.PI/30), 24);
});
}
function drawHand(ctx, pos, length) {
ctx.beginPath();
ctx.moveTo(0,0);
ctx.rotate(pos);
ctx.lineTo(0, -length);
ctx.stroke();
ctx.rotate(-pos);
}
var theClock = document.querySelector(".main-clock");
var prevMin = new Date().getMinutes();
function updateMain() {
var canvas = theClock.querySelector("canvas");
var ctx = canvas.getContext("2d");
var now = new Date();
var hour = now.getHours() % 12;
var minute = now.getMinutes();
if (prevMin != minute) update();
prevMin = minute;
theClock.querySelector(".timezone").innerHTML = now.toLocaleDateString(undefined, {
year: "numeric",
month: "long",
day: "numeric",
weekday: "long",
timeZoneName: 'long'
});
theClock.querySelector(".title").innerHTML = now.toLocaleTimeString(undefined, {
hc: "h12", timeStyle: "short"
});
ctx.clearRect(-32,-32, 64, 64);
ctx.beginPath();
ctx.arc(0, 0, 30, 0, Math.PI * 2);
ctx.stroke();
drawHand(ctx, (hour*Math.PI/6)+(minute*Math.PI/(6*60)), 16);
drawHand(ctx, (minute*Math.PI/30), 24);
window.requestAnimationFrame(updateMain);
}
window.requestAnimationFrame(updateMain);
function updateTimer() {
document.querySelectorAll(".timer-enabled").forEach((clock, i) => {
var timer = clock.dataset.time;
var mins = Math.floor(timer / 60);
mins = (mins < 10 ? "0" + mins : mins);
var secs = timer % 60;
secs = (secs < 10 ? "0" + secs : secs);
var canvas = clock.querySelector("canvas");
var ctx = canvas.getContext("2d");
ctx.strokeStyle = getComputedStyle(document.documentElement).getPropertyValue('--foreground');
ctx.resetTransform();
ctx.translate(32, 32);
ctx.lineWidth = 2;
ctx.lineCap = "round";
var canvas = clock.querySelector("canvas");
var ctx = canvas.getContext("2d");
clock.querySelector(".mins").innerHTML = mins;
clock.querySelector(".seconds").innerHTML = secs;
ctx.clearRect(-32,-32, 64, 64);
ctx.beginPath();
ctx.arc(0, 0, 30, 0, Math.PI * 2);
ctx.stroke();
drawHand(ctx, (secs*Math.PI/30), 16);
});
}
setInterval(() => {
document.querySelectorAll(".timer-enabled:not(.timer-paused)").forEach((clock, i) => {
var timer = clock.dataset.time;
var bool = clock.dataset.ctp == "true";
clock.dataset.time--;
if (bool) {
document.querySelector(".poplight .press").classList.remove("popped");
}
if (timer <= 0) {
clock.classList.remove("timer-enabled");
tone.src = "./assets/tones/" + clock.dataset.tone + ".mp3";
tone.currentTime = 0;
tone.play();
if (bool) {
document.querySelector(".poplight .press").classList.add("popped");
}
}
});
updateTimer();
}, 1000);
updateTimer();

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

View file

@ -0,0 +1,356 @@
<!DOCTYPE html>
<!--[if lt IE 7]> <html class="no-js lt-ie9 lt-ie8 lt-ie7"> <![endif]-->
<!--[if IE 7]> <html class="no-js lt-ie9 lt-ie8"> <![endif]-->
<!--[if IE 8]> <html class="no-js lt-ie9"> <![endif]-->
<!--[if gt IE 8]> <html class="no-js"> <!--<![endif]-->
<html>
<head>
<meta charset="utf-8">
<title>FunnyClock²</title>
<link rel="stylesheet" href="./styles/root.css">
<link rel="stylesheet" href="./styles/clock.css">
<link rel="stylesheet" href="./styles/style.css">
<link rel="stylesheet" href="./styles/dialog.css">
<link href="https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined" rel="stylesheet" />
<script src="https://code.jquery.com/jquery-3.6.1.min.js" integrity="sha256-o88AwQnZB+VDvE9tvIXrMQaPlFFSUTR+nldQm1LuPXQ=" crossorigin="anonymous"></script>
<script src="https://code.jquery.com/ui/1.13.0/jquery-ui.min.js" integrity="sha256-hlKLmzaRlE8SCJC1Kw8zoUbU8BxA+8kR3gseuKfMjxA=" crossorigin="anonymous"></script>
<script src="jqtp.js"></script>
</head>
<body>
<div id="back"></div>
<div id="backconstrain"></div>
<div class="header">
<div>
<button class="material-symbols-outlined hiw" data-title="Menu" onclick="this.parentElement.parentElement.classList.toggle('wide')">menu</button>
<sep></sep>
<button class="material-symbols-outlined" data-title="Add World Clock" onclick="document.querySelector('.header').classList.remove('wide');document.querySelector('.scr-timezone--').classList.add('open');">schedule</button>
<button class="material-symbols-outlined" data-title="Add Timer" onclick="document.querySelector('.header').classList.remove('wide');document.querySelector('.scr-timer--').classList.add('open');">timer</button>
<button class="material-symbols-outlined" data-title="Add Note" onclick="addNote();">description</button>
<button class="material-symbols-outlined" data-title="Add Checklist" onclick="addChecklist();">checklist</button>
</div>
<div>
<button class="material-symbols-outlined" data-title="Customize Color" onclick="document.querySelector('.header').classList.remove('wide');document.querySelector('.scr-dialog--').classList.add('open');">palette</button>
<button class="material-symbols-outlined" data-title="Open Fullscreen" onclick="openFullscreen();">fullscreen</button>
<button class="material-symbols-outlined" data-title="About FunnyClock²" onclick="document.querySelector('.header').classList.remove('wide');document.querySelector('.scr-about--').classList.add('open');">info</button>
</div>
</div>
<div class="body">
<div class="clock main-clock">
<canvas width="64" height="64"></canvas><!--
--><div class="labels">
<h1 class="title">Loading...</h1><br />
<p class="timezone">Loading...</p>
</div><br />
<textarea class="txt" title="Notes" placeholder="Take some notes..." oninput='this.style.height = "";this.style.height = this.scrollHeight + "px"'></textarea>
</div>
<div class="dialog" id="updatedialog" style="display: none;">
<p class="dlg-top">There's an update!</p>
<p>You should restart - there's a new update of FunnyClock².</p>
<small id="updatesha">If you can see this message, well, you shouldn't! It's an error~!</small>
<br />
<div>
<button onclick="location.reload(true)">UPDATE</button>
</div>
</div>
</div>
<div class="poplight">
<button class="hide material-symbols-outlined" data-title="Toggle Poplight Size" onclick="checkHeight(this.parentElement)">unfold_less</button>
<div class="drag material-symbols-outlined" data-title="Drag Poplight" ondblclick="checkHeight(this.parentElement)">open_with</div>
<button class="press material-symbols-outlined popped" onclick="this.classList.toggle('popped')"></button>
</div>
<div class="scrim-over-- scr-dialog--">
<div class="dialog" id="colordia">
<form id="color">
<p class="dlg-top">Customize Color</p>
<input type="radio" name="color" id="colorred" value="#FF0000|#400000|#800000|#FFFFFF" /><!--
--><label for="colorred" style="background-color:#800000">RED</label><!--
--><input type="radio" name="color" id="coloramber" value="#f2aa58|#582007|#7c300a|#FFFFFF" /><!--
--><label for="coloramber" style="background-color:#7c300a">AMBER</label><!--
--><input type="radio" name="color" id="colororange" value="#FF8000|#402000|#804000|#FFFFFF" /><!--
--><label for="colororange" style="background-color:#804000">ORANGE</label><!--
--><input type="radio" name="color" id="coloryellow" value="#FFFF00|#404000|#808000|#FFFFFF" /><!--
--><label for="coloryellow" style="background-color:#808000">YELLOW</label><!--
--><input type="radio" name="color" id="colorgreen" value="#00FF00|#003000|#006000|#FFFFFF" /><!--
--><label for="colorgreen" style="background-color:#006000">GREEN</label><!--
--><input type="radio" name="color" id="colorblue" value="#00FFFF|#003040|#006080|#FFFFFF" /><!--
--><label for="colorblue" style="background-color:#006080">BLUE</label><!--
--><input type="radio" name="color" id="colornavy" value="#5865f2|#08116a|#0b168e|#FFFFFF" /><!--
--><label for="colornavy" style="background-color:#0b168e">NAVY</label><!--
--><input type="radio" name="color" id="colorpurple" value="#FF00FF|#300030|#600060|#FFFFFF" /><!--
--><label for="colorpurple" style="background-color:#600060">PURPLE</label><!--
--><input type="radio" name="color" id="colordark" value="#FFFF00|#202020|#404040|#FFFFFF" checked /><!--
--><label for="colordark" style="background-color:#404040">DARK</label><!--
--><input type="radio" name="color" id="colorlight" value="#FFFF00|#d0d0d0|#b0b0b0|#000000" /><!--
--><label for="colorlight" style="background-color:#d0d0d0;color:#000000;">LIGHT</label><br /><!--
--><input type="radio" name="color" id="colortrans" value="#FF00FF|url(../assets/trans.png)|#004040|#FFFFFF" /><!--
--><label for="colortrans" style="background:url(./assets/trans.png)">TRANS</label><!--
--><input type="radio" name="color" id="colorrainbow" value="#FFFFFF|url(../assets/rainbow.png)|#400000|#FFFFFF" /><!--
--><label for="colorrainbow" style="background:url(./assets/rainbow.png)">RAINBOW</label><br />
<p class="dlg-top">Customize Background</p>
<input type="radio" name="background" id="bgnone" value="../assets/none.png" /><!--
--><label for="bgnone" style="background-image: url(./assets/none.png)">NOTHING</label><!--
--><input type="radio" name="background" id="bgclocks" value="../assets/clock.png" checked /><!--
--><label for="bgclocks" style="background-image: url(./assets/clock.png)">CLOCKS</label><!--
--><input type="radio" name="background" id="bgclockstwo" value="../assets/clock2.png" /><!--
--><label for="bgclockstwo" style="background-image: url(./assets/clock2.png)">CLOCKS 2</label><!--
--><input type="radio" name="background" id="bgsus" value="../assets/sussy.png" /><!--
--><label for="bgsus" style="background-image: url(./assets/sussy.png)">SUSSY</label><!--
--><input type="radio" name="background" id="bghour" value="../assets/hourglass.png" /><!--
--><label for="bghour" style="background-image: url(./assets/hourglass.png)">WORKING</label><!--
--><input type="radio" name="background" id="bginter" value="../assets/interro.png" /><!--
--><label for="bginter" style="background-image: url(./assets/interro.png)">INTERRO</label><!--
--><input type="radio" name="background" id="bgbad" value="../assets/chemistry.png" /><!--
--><label for="bgbad" style="background-image: url(./assets/chemistry.png)">CHEMIST</label><!--
--><input type="radio" name="background" id="bgsport" value="../assets/sport.png" /><!--
--><label for="bgsport" style="background-image: url(./assets/sport.png)">SPORT</label><!--
--><input type="radio" name="background" id="bgmark" value="../assets/mark.png" /><!--
--><label for="bgmark" style="background-image: url(./assets/mark.png)">MARK</label><!--
--><input type="radio" name="background" id="bgtile" value="../assets/tile.png" /><!--
--><label for="bgtile" style="background-image: url(./assets/tile.png)">TILE</label><!--
--><input type="radio" name="background" id="bgtiletwo" value="../assets/tile2.png" /><!--
--><label for="bgtiletwo" style="background-image: url(./assets/tile2.png)">DIAG</label><br />
<div>
<input type="submit" name="action" value="DONE"/>
</div>
</form>
</div>
</div>
<div class="scrim-over-- scr-timezone--">
<div class="dialog" id="timezonedia">
<p class="dlg-top">Select Timezone</p>
<form id="timezone">
<select name="timezone" title="Timezone">
<option value="Etc/GMT">GMT</option>
<option value="Etc/GMT-1">GMT+1 ECT</option>
<option value="Etc/GMT-2">GMT+2 ART</option>
<option value="Etc/GMT-3">GMT+3 EAT</option>
<option value="Etc/GMT-4">GMT+4 NET</option>
<option value="Etc/GMT-5">GMT+5 IET</option>
<option value="Etc/GMT-6">GMT+6 BST</option>
<option value="Etc/GMT-7">GMT+7 VST</option>
<option value="Etc/GMT-8">GMT+8 CTT</option>
<option value="Etc/GMT-9">GMT+9 JST</option>
<option value="Etc/GMT-10">GMT+10 AET</option>
<option value="Etc/GMT-11">GMT+11 SST</option>
<option value="Etc/GMT+1">GMT-1 ???</option>
<option value="Etc/GMT+2">GMT-2 ???</option>
<option value="Etc/GMT+3">GMT-3 BET</option>
<option value="Etc/GMT+4">GMT-4 PRT</option>
<option value="Etc/GMT+5">GMT-5 EST</option>
<option value="Etc/GMT+6">GMT-6 CST</option>
<option value="Etc/GMT+7">GMT-7 MST</option>
<option value="Etc/GMT+8">GMT-8 PST</option>
<option value="Etc/GMT+9">GMT-9 AST</option>
<option value="Etc/GMT+10">GMT-10 HST</option>
<option value="Etc/GMT+11">GMT-11 ???</option>
<option value="Etc/GMT+12">GMT12</option>
</select>
<div>
<input type="submit" name="action" value="DONE"/>
</div>
</form>
</div>
</div>
<div class="scrim-over-- scr-timer--">
<div class="dialog" id="timerdia">
<p class="dlg-top">Configure Timer</p>
<form id="timerform">
<!-- <Peter... the="horse" is h=ere /> -->
<input type="number" name="minute" placeholder="05" min="00" value="05" /><span>:</span><input type="number" name="second" placeholder="00" min="00" value="00" max="59" /><br />
<input type="checkbox" name="ctp" id="ctp" /> <label for="ctp">Connected To Poplight (running = on, done = off)</label><br />
<p class="dlg-top">Configure Tone</p>
<input type="radio" name="tone" id="tonebeet" value="beethoven" /><!--
--><label for="tonebeet">BEETHOVEN</label><!--
--><input type="radio" name="tone" id="tonemegalo" value="megalo" /><!--
--><label for="tonemegalo">MEGALO</label><!--
--><input type="radio" name="tone" id="toneringer" value="ringer" /><!--
--><label for="toneringer">RINGER</label><!--
--><input type="radio" name="tone" id="toneringertwo" value="ringer2" /><!--
--><label for="toneringertwo">RINGER 2</label><!--
--><input type="radio" name="tone" id="tonesweet" value="sweet" /><!--
--><label for="tonesweet">DANCE</label><!--
--><input type="radio" name="tone" id="tonetone" value="tone" checked /><!--
--><label for="tonetone">DRY</label><!--
--><input type="radio" name="tone" id="tonetwinkle" value="twinkle" /><!--
--><label for="tonetwinkle">TWINKLE</label><!--
--><input type="radio" name="tone" id="toneviolin" value="violin" /><!--
--><label for="toneviolin">VIOLIN</label><!--
--><input type="radio" name="tone" id="tonenone" value="none" /><!--
--><label for="tonenone">NONE</label>
<div>
<input type="submit" name="action" value="DONE"/>
</div>
</form>
</div>
</div>
<div class="scrim-over-- scr-about--">
<div class="dialog" id="aboutdia">
<p class="dlg-top">About FunnyClock²</p>
<form id="aboutform">
<!-- FUCK -->
<p>FunnyClock² is the successor of FunnyClock, an application made for my school to show when smartboards are idle.</p>
<p>FunnyClock was originally a single-file local webpage hosted on the computers of the teachers, and now with FunnyClock², it's a multi-file customizable suite for clocks and timers.</p>
<p class="dlg-top">Special Thanks to</p>
<ul>
<li>Josh, science and tech teacher</li>
<li>Everyone who accepted my pitch for the FunnyClock² app</li>
<li>Among Us (Sussy background)</li>
<li>Portal 2 (Tile background)</li>
<li>Kaboom.js (Mark background)</li>
<li>Material Design (UI inspiration)</li>
</ul>
<div>
<input type="submit" name="action" value="OK"/>
</div>
</form>
</div>
</div>
<div class="scrim--" onclick="document.querySelector('.header').classList.remove('wide')"> </div>
<script>
$(".poplight").draggable({
containment: $("#backconstrain"),
handle: "div.drag",
drag: (e, u) => {
var bottom = ($(window).height() - u.position.top);
if ((bottom < 210 && bottom >= 78) && !u.helper[0].classList.contains("hidden")) {
u.position.top = ($(window).height() - 210);
} else if (bottom < 78) {
u.helper[0].classList.add("hidden");
}
}
});
function checkHeight(el) {
var bottom = ($(window).height() - el.getBoundingClientRect().top);
if (bottom < 210) {
el.classList.add('hidden');
} else {
el.classList.toggle('hidden');
}
}
var elem = document.documentElement;
function openFullscreen() {
if (document.fullscreenElement == null) {
if (elem.requestFullscreen) {
elem.requestFullscreen();
} else if (elem.webkitRequestFullscreen) { /* Safari */
elem.webkitRequestFullscreen();
} else if (elem.msRequestFullscreen) { /* IE11 */
elem.msRequestFullscreen();
}
} else {
if (document.exitFullscreen) {
document.exitFullscreen();
} else if (document.webkitExitFullscreen) { /* Safari */
document.webkitExitFullscreen();
} else if (document.msExitFullscreen) { /* IE11 */
document.msExitFullscreen();
}
}
}
document.querySelector("#color").addEventListener("submit", (e) => {
const formData = new FormData(e.target);
var colors = formData.get("color").split("|");
localStorage.setItem("colors", formData.get("color"));
console.log(colors);
localStorage.setItem("background", formData.get("background"));
document.documentElement.style.setProperty('--main-color', colors[0]);
document.documentElement.style.setProperty('--background', colors[1]);
document.documentElement.style.setProperty('--background-light', colors[2]);
document.documentElement.style.setProperty('--foreground', colors[3]);
document.documentElement.style.setProperty('--background-image', "url(" + formData.get("background") + ")");
document.querySelector('.scr-dialog--').classList.remove('open');
event.preventDefault();
})
var colors = (localStorage.getItem("colors") ?? "#FFFF00|#202020|#404040|#FFFFFF").split("|");
document.documentElement.style.setProperty('--main-color', colors[0]);
document.documentElement.style.setProperty('--background', colors[1]);
document.documentElement.style.setProperty('--background-light', colors[2]);
document.documentElement.style.setProperty('--foreground', colors[3]);
document.documentElement.style.setProperty('--background-image', "url(" + (localStorage.getItem("background") ?? "../assets/clock.png") + ")");
document.querySelector("#color").addEventListener("change", (e) => {
const formData = new FormData(document.querySelector("#color"));
var colors = formData.get("color").split("|");
document.documentElement.style.setProperty('--main-color', colors[0]);
document.documentElement.style.setProperty('--background', colors[1]);
document.documentElement.style.setProperty('--foreground', colors[3]);
document.documentElement.style.setProperty('--background-light', colors[2]);
})
document.querySelector("#timerform").addEventListener("submit", (e) => {
event.preventDefault();
const formData = new FormData(e.target);
var checked = formData.get("ctp") == "on";
var time = (parseInt(formData.get("minute")) * 60) + parseInt(formData.get("second"));
document.querySelector(".body").insertAdjacentHTML( "beforeend", `<div class="timer timer-enabled" data-time="${time}" data-orig="${time}" data-ctp="${checked}" data-tone="${formData.get("tone")}">
<canvas width="64" height="64"></canvas><!--
--><div class="labels">
<h1 class="time"><span class="mins">00</span>:<span class="seconds">00</span></h1><br />
</div><br />
<button class="deleteclock material-symbols-outlined" onclick="this.parentElement.remove()">close</button>
<button class="normalclock material-symbols-outlined" onclick="this.parentElement.classList.toggle('timer-paused');">pause</button>
<button class="normalclock material-symbols-outlined" onclick="this.parentElement.dataset.time = this.parentElement.dataset.orig;this.parentElement.classList.add('timer-enabled');updateTimer()">refresh</button>
</div>`);
if (checked) {
document.querySelector(".poplight .press").classList.remove("popped");
}
updateTimer();
document.querySelector('.scr-timer--').classList.remove('open');
})
document.querySelector("#aboutform").addEventListener("submit", (e) => {
event.preventDefault();
document.querySelector('.scr-about--').classList.remove('open');
})
document.querySelector("#timezone").addEventListener("submit", (e) => {
event.preventDefault();
const formData = new FormData(e.target);
document.querySelector(".body").insertAdjacentHTML( "beforeend", `<div class="clock" data-timezone="${formData.get("timezone")}">
<canvas width="64" height="64"></canvas><!--
--><div class="labels">
<h1 class="title">Loading...</h1><br />
<p class="timezone">Loading...</p>
</div><br />
<button class="deleteclock material-symbols-outlined" onclick="this.parentElement.remove()">close</button>
</div>`);
update();
document.querySelector('.scr-timezone--').classList.remove('open');
})
function addNote() {
document.querySelector(".body").insertAdjacentHTML( "beforeend", `<div class="noteobject">
<textarea class="txt" title="Notes" placeholder="Take some notes..." oninput='this.style.height = "";this.style.height = this.scrollHeight + "px"'></textarea>
<button class="deleteclock material-symbols-outlined" onclick="this.parentElement.remove()">close</button>
</div>`);
}
function addChecklist() {
document.querySelector(".body").insertAdjacentHTML( "beforeend", `<div class="noteobject">
<div class="lister">
<div class="checkobject">
<button onclick="this.parentElement.remove();" class="deleteclock material-symbols-outlined">close</button>
<input type="text" placeholder="Checklist item" />
</div>
</div>
<button class="deleteclock material-symbols-outlined" onclick="this.parentElement.remove()">close</button>
<button class="normalclock material-symbols-outlined" onclick="addCheckbox(this.parentElement.querySelector('.lister'));">add</button>
</div>`);
}
function addCheckbox(obj) {
obj.insertAdjacentHTML( "beforeend", `<div class="checkobject">
<button onclick="this.parentElement.remove();" class="deleteclock material-symbols-outlined">close</button>
<input type="text" placeholder="Checklist item" />
</div>`);
}
</script>
<script src="./canvas.js"></script>
<script src="./update.js"></script>
</body>
</html>

View file

@ -0,0 +1,11 @@
/*!
* jQuery UI Touch Punch 0.2.3
*
* Copyright 20112014, Dave Furfero
* Dual licensed under the MIT or GPL Version 2 licenses.
*
* Depends:
* jquery.ui.widget.js
* jquery.ui.mouse.js
*/
!function(a){function f(a,b){if(!(a.originalEvent.touches.length>1)){a.preventDefault();var c=a.originalEvent.changedTouches[0],d=document.createEvent("MouseEvents");d.initMouseEvent(b,!0,!0,window,1,c.screenX,c.screenY,c.clientX,c.clientY,!1,!1,!1,!1,0,null),a.target.dispatchEvent(d)}}if(a.support.touch="ontouchend"in document,a.support.touch){var e,b=a.ui.mouse.prototype,c=b._mouseInit,d=b._mouseDestroy;b._touchStart=function(a){var b=this;!e&&b._mouseCapture(a.originalEvent.changedTouches[0])&&(e=!0,b._touchMoved=!1,f(a,"mouseover"),f(a,"mousemove"),f(a,"mousedown"))},b._touchMove=function(a){e&&(this._touchMoved=!0,f(a,"mousemove"))},b._touchEnd=function(a){e&&(f(a,"mouseup"),f(a,"mouseout"),this._touchMoved||f(a,"click"),e=!1)},b._mouseInit=function(){var b=this;b.element.bind({touchstart:a.proxy(b,"_touchStart"),touchmove:a.proxy(b,"_touchMove"),touchend:a.proxy(b,"_touchEnd")}),c.call(b)},b._mouseDestroy=function(){var b=this;b.element.unbind({touchstart:a.proxy(b,"_touchStart"),touchmove:a.proxy(b,"_touchMove"),touchend:a.proxy(b,"_touchEnd")}),d.call(b)}}}(jQuery);

View file

@ -0,0 +1,148 @@
.body {
width: calc(100vw - 64px);
height: 100%;
position: fixed;
left: 64px;
top: 0;
padding: 0 16px;
box-sizing: border-box;
z-index: 1;
overflow-y: auto;
}
.body .clock, .body .timer, .body .noteobject {
width: 100%;
min-height: max-content;
border-radius: 8px;
position: relative;
overflow: hidden;
padding: 16px;
box-sizing: border-box;
color: var(--foreground);
margin: 16px 0;
zoom: 1.25;
}
.body .clock::before, .body .timer::before, .body .noteobject::before {
content: "";
background-color: #FFFFFF40;
position: absolute;
width: 100%;
height: 100%;
left: 0;
top: 0;
backdrop-filter: blur(8px);
z-index: -1;
}
.body .timer-paused::before {
content: "";
background-color: #40404040;
position: absolute;
width: 100%;
height: 100%;
left: 0;
top: 0;
backdrop-filter: blur(8px);
z-index: -1;
}
.body .clock h1, .body .timer h1, .body .noteobject h1 {
margin: 0;
margin-top: 16px;
padding: 0;
color: var(--foreground);
font-weight: lighter;
vertical-align: middle;
}
.body .clock div.labels, .body .timer div.labels, .body .noteobject div.labels {
display: inline-block;
vertical-align: middle;
}
.body .clock div.labels *, .body .timer div.labels *, .body .noteobject div.labels * {
margin: 0;
padding: 0;
color: var(--foreground);
font-weight: lighter;
display: inline-block;
vertical-align: middle;
}
canvas {
margin: 0;
margin-right: 16px;
padding: 0;
vertical-align: middle;
}
textarea {
resize: none;
width: 100%;
margin-top: 8px;
box-sizing: border-box;
height: max-content;
font-size: 48px;
max-height: 100%;
padding: 8px;
border: none;
border-radius: 4px;
background-color: #00000040;
color: var(--foreground);
}
.deleteclock {
margin-top: 16px;
min-width: 32px;
width: 32px;
height: 32px;
padding: 0;
border: none;
background-color: #FF000080;
color: var(--foreground);
border-radius: 16px;
transition: background-color 0.125s;
}
.deleteclock:focus {
background-color: #FF0000A0;
}
.deleteclock:hover {
background-color: #FF0000C0;
}
.deleteclock:active {
background-color: #FF0000FF;
}
.normalclock {
margin-top: 16px;
min-width: 32px;
width: 32px;
height: 32px;
padding: 0;
border: none;
background-color: #00000040;
color: var(--foreground);
border-radius: 16px;
transition: background-color 0.125s;
}
.normalclock:focus {
background-color: #00000030;
}
.normalclock:hover {
background-color: #00000010;
}
.normalclock:active {
background-color: #00000020;
}

View file

@ -0,0 +1,186 @@
.scrim-over--.open {
background-color: #0006;
backdrop-filter: blur(4px);
pointer-events: auto;
}
@keyframes myAnim {
from {
box-shadow: 0px 0px 6px -6px #FFFFFF80;
}
to {
box-shadow: 0px 0px 6px 32px #FFFFFF00;
}
}
#updatedialog {
box-shadow: 0px 0px 6px 32px #FFFFFF00;
animation: myAnim 2s ease 0s infinite normal forwards;
}
#updatedialog button {
animation: myAnim 2s ease 1s infinite normal forwards;
}
.dialog {
display: none;
}
.body .dialog {
width: 100%;
}
.scrim-over--.open .dialog, .dialog.open {
display: inline-block !important;
}
.dialog {
min-width: 320px;
max-width: calc(100vw - 64px);
min-height: 128px;
max-height: calc(100vh - 64px);
background-color: var(--background-light);
transition: background-color 0.125s;
color: var(--foreground);
border-radius: 8px;
padding: 16px;
box-sizing: border-box;
pointer-events: auto;
overflow-y: auto;
}
.dialog p {
margin: 0;
padding: 0;
margin-bottom: 4px;
}
.dialog .dlg-top {
display: block;
font-weight: bold;
font-size: 18px;
margin: 8px 0;
}
.dialog div {
text-align: right;
margin-top: 8px;
box-sizing: border-box;
}
.dialog div input[type=submit], .dialog div button {
margin: 0;
padding: 8px;
height: 32px;
box-sizing: border-box;
border: none;
background-color: transparent;
color: var(--main-color);
font-weight: bold;
border-radius: 4px;
transition: background-color 0.125s, color 0.125s;
}
.dialog div input:focus, .dialog div button:focus {
background-color: #00000020;
}
.dialog div input:hover, .dialog div button:hover {
background-color: #00000040;
}
.dialog div input:active, .dialog div button:active {
background-color: #00000080;
}
input[type="radio"] {
opacity: 0;
width: 0;
margin: 0;
padding: 0;
}
input[type="radio"] + label {
display: inline-block;
margin: 8px;
padding: 0;
width: 96px;
height: 64px;
border-radius: 4px;
box-shadow: 0 0 4px 2px rgba(0,0,0,0.25);
color: #FFFFFF;
transition: border 0.25s;
box-sizing: border-box;
border: 8px solid transparent;
background-size: 96px;
background-repeat: no-repeat;
}
input[type="radio"] + label[for^="bg"] {
color: var(--foreground);
}
input[type="radio"]:checked + label {
border: 8px solid #FFF6;
}
input[type="radio"]:focus + label {
outline: 4px solid white;
}
.dialog select {
width: 100%;
margin: 8px 0;
box-sizing: border-box;
height: max-content;
max-height: 100%;
padding: 8px;
border: none;
border-radius: 4px;
background-color: #00000040;
color: var(--foreground);
}
.dialog input[type="number"] {
width: 16ch;
margin: 8px 0;
box-sizing: border-box;
height: max-content;
max-height: 100%;
padding: 8px;
border: none;
border-radius: 4px;
background-color: #00000040;
color: var(--foreground);
}
.checkobject input[type="text"] {
width: 100%;
margin: 8px 0;
box-sizing: border-box;
height: max-content;
max-height: 100%;
padding: 8px;
border: none;
border-radius: 4px;
font-size: 48px;
background-color: #00000040;
color: var(--foreground);
}
.checkobject {
display: flex;
gap: 12px;
flex-direction: row;
display: flex;
flex-direction: row;
flex-wrap: nowrap;
justify-content: flex-start;
align-content: space-around;
align-items: center;
}
.checkobject .deleteclock {
padding: 0;
margin: 0;
}

View file

@ -0,0 +1,7 @@
:root {
--main-color: #FFFF00;
--background: #202020;
--background-light: #404040;
--foreground: #FFFFFF;
--background-image: url("../assets/clock.png");
}

View file

@ -0,0 +1,338 @@
body {
background: var(--background);
background-size: 100vw 100vh;
image-rendering: -webkit-optimize-contrast;
image-rendering: crisp-edges;
transition: background 0.125s;
margin: 0;
padding: 0;
}
#back {
background-image: var(--background-image);
background-size: 128px;
background-position: center;
opacity: 0.35;
position: fixed;
height: 100vh;
width: 100vw;
}
#backconstrain {
position: fixed;
height: calc(100vh + 128px);
width: calc(100vw - 36px);
left: 20px;
top: 64px;
}
* {
font-family: monospace;
}
.header {
width: 64px;
height: 100%;
position: fixed;
left: 0;
top: 0;
display: flex;
flex-direction: column;
flex-wrap: nowrap;
justify-content: space-between;
align-content: stretch;
align-items: center;
z-index: 9;
transition: width 0.125s;
}
.header.wide {
width: 256px;
}
.scrim--, .scrim-over-- {
display: inline-block;
width: 100vw;
height: 100vh;
z-index: 8;
position: absolute;
top: 0;
left: 0;
background-color: transparent;
backdrop-filter: none;
pointer-events: none;
transition: background-color 0.125s, backdrop-filter 0.125s;
}
.scrim-over-- {
z-index: 10;
display: flex;
flex-direction: column;
flex-wrap: nowrap;
justify-content: center;
align-content: center;
align-items: center;
}
.header.wide ~ .scrim-- {
background-color: #0006;
backdrop-filter: blur(4px);
pointer-events: auto;
}
.header::before {
background-color: #FFFFFF40;
content: "";
position: absolute;
left: 0;
top: 0;
width: 100%;
height: 100%;
backdrop-filter: blur(8px);
}
.header div {
display: flex;
flex-direction: column;
flex-wrap: nowrap;
align-content: space-around;
align-items: center;
gap: 8px;
padding: 8px;
width: 100%;
box-sizing: border-box;
height: 50%;
}
.header div:first-child {
justify-content: flex-start;
}
.header div:last-child {
justify-content: flex-end;
}
.header button {
height: 48px;
width: 100%;
border-radius: 24px;
border: none;
padding: 12px;
margin: none;
background-color: transparent;
transition: background-color 0.125s;
color: var(--foreground);
position: relative;
display: flex;
flex-direction: row;
flex-wrap: nowrap;
justify-content: flex-start;
align-items: center;
}
.header.wide button {
overflow: hidden;
}
.header button:hover {
background-color: #FFFFFF40;
}
.header button::after {
position: absolute;
display: inline-block;
content: attr(data-title);
font-family: monospace;
font-size: 12px;
height: 12px;
box-sizing: content-box;
background-color: transparent;
color: transparent;
left: calc(100% + 16px);
border-radius: 4px;
top: calc(50% - 14px);
transition: color 0.125s, width 0.125s;
width: 0;
padding: 8px 0;
overflow: hidden;
}
.header:not(.wide) button:hover::after {
background-color: #202020;
color: #FFFFFF;
width: initial;
padding: 8px;
}
.header:not(.wide) button:focus::after {
background-color: #202020;
color: #FFFFFF;
width: initial;
padding: 8px;
}
.header.wide button::after {
left: 48px;
top: calc(50% - 7px);
color: var(--foreground);
width: initial;
height: 14px;
padding: 0;
font-size: 14px;
}
.header button:focus {
background-color: #FFFFFF20;
}
.header button:active {
background-color: #FFFFFF80;
}
sep {
display: inline-block;
width: 100%;
height: 0;
background-color: transparent;
border: 1px dashed var(--foreground);
margin: 4px;
z-index: 9;
}
.poplight {
position: fixed;
right: 16px;
bottom: 16px;
width: 192px;
height: 192px;
transition: bottom 0.125s;
z-index: 9;
}
.poplight.hidden {
bottom: -128px;
}
.poplight button.hide {
position: absolute;
width: 32px;
height: 32px;
right: 48px;
top: -48px;
margin: 0;
padding: 0;
border: none;
border-radius: 16px;
background-color: transparent;
color: var(--foreground);
}
.poplight button.hide::after {
position: absolute;
display: inline-block;
content: attr(data-title);
font-family: monospace;
font-size: 12px;
height: 12px;
box-sizing: content-box;
background-color: transparent;
color: transparent;
right: 0;
border-radius: 4px;
top: -48px;
transition: color 0.125s, width 0.125s;
width: 0;
padding: 8px 0;
overflow: hidden;
}
.poplight button.hide:not(:disabled):hover::after {
background-color: #202020;
color: #FFFFFF;
width: initial;
padding: 8px;
}
.poplight button.hide:not(:disabled):focus {
background-color: #FFFFFF20;
}
.poplight button.hide:disabled {
color: #808080;
}
.poplight button.hide:not(:disabled):hover {
background-color: #FFFFFF40;
}
.poplight button.hide:not(:disabled):active {
background-color: #FFFFFF80;
}
.poplight button.press {
position: absolute;
top: 0;
right: 0;
width: 100%;
height: 100%;
border-radius: 96px;
background-color: #808080;
overflow: hidden;
border: none;
font-size: 96px;
transition: top 0.125s, right 0.125s, width 0.125s, height 0.125s, background-color 0.125s, color 0.125s, font-size 0.125s;
}
.poplight.hidden button.press {
top: -48px;
right: 96px;
width: 32px;
height: 32px;
border-radius: 128px;
font-size: 24px;
color: transparent;
}
.poplight button.press.popped {
background-color: var(--main-color);
box-shadow: 0px 0px 32px 0px var(--main-color);
}
.poplight button.press::after {
position: absolute;
content: "devices";
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
border-radius: 128px;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: transparent;
}
.poplight button.press:hover::after {
background-color: #ffffff40;
}
.poplight button.press:active::after {
background-color: #ffffff80;
}
.poplight button.press.popped::after {
content: "phonelink_off";
}
.poplight .drag {
position: absolute;
width: 32px;
height: 32px;
right: 0;
top: -48px;
margin: 0;
padding: 4px;
border: none;
border-radius: 16px;
box-sizing: border-box;
user-select: none;
background-color: transparent;
color: var(--foreground);
}

View file

@ -0,0 +1,23 @@
function reqData(start) {
console.log("Pinged API server. Starting: " + start);
var donedata = (e) => {
var resp = e;
var prevSha = "A";
if (!start) prevSha = window.sessionStorage.getItem("commitsha");
if (resp != prevSha) {
window.sessionStorage.setItem("commitsha", resp);
if (start) return;
document.querySelector("#updatesha").innerHTML = `from job v. ${prevSha} to job v. ${resp}`;
document.querySelector("#updatedialog").classList.add("open");
}
};
fetch("https://ClockCheckGithub.meowcatheorange.repl.co")
.then(x => x.text())
.then(y => donedata(y));
}
setInterval(reqData, 60000);
reqData(true);

Binary file not shown.

View file

@ -0,0 +1,58 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title>Dice Tool</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="style.css">
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
<script src="https://code.jquery.com/jquery-3.6.0.min.js" integrity="sha256-/xUj+3OJU5yExlq6GSYGSHk7tPXikynS7ogEvDej/m4=" crossorigin="anonymous"></script>
</head>
<body class="compactMode">
<div class="headerBar">
<div style="float: left; text-align: left;">
Dice Tool
</div>
<div style="float: right; text-align: right;">
<button class="material-icons toc" onclick="document.body.classList.toggle('compactMode');">build</button>
<button class="material-icons" onclick="rollAllDie(cont)">shuffle</button>
<button class="material-icons" onclick="if (confirm('Are you sure you want to remove everything?')) $('.content').find('.die').remove()">cancel</button>
</div>
</div>
<div class="fab">
<button class="material-icons" title="Add Dice" onclick="addDie(cont);">add_circle</button>
<button class="material-icons" title="Add Counter" onclick="addDie(cont, 1, 'Counter', true);">pin</button>
<button class="material-icons" title="Add Bag" onclick="addDieBag(cont);">create_new_folder</button>
</div>
<div class="content" ondrop="drop(event)" ondragover="allowDrop(event)"><div class="dropHere"></div></div>
<templates>
<template id="dieUI"><div class="die rollable{IS_COUNTER}" id="{RAND_ID}" draggable="true" ondragstart="drag(event)">
<div>
<span class="material-icons icon ident">casino</span><input class="title hos" placeholder="Name" type="text" value="{TITLE_DIE}" onfocusout="this.setAttribute('value', this.value);" />
<input class="die-color hos" type="color" value="transparent" onchange="this.setAttribute('value', this.value);this.parentElement.parentElement.style.backgroundColor = this.value;" />
<button class="material-icons icon indi neg" onclick="tp(this).remove()">delete</button><br class="hos" />
<div class="hideIfCounter"><button class="material-icons icon indi pos" title="Roll die" onclick="rollDie(ht(tpp(this)))">shuffle</button></div>
</div>
<div style="text-align: right;">
<button class="material-icons icon hos" onclick="changeVal(ht($(this)), -1)">remove</button>
<button class="material-icons icon hos" onclick="changeVal(ht($(this)), 1)">add</button>
<span class="hideIfCounter hos"><button class="material-icons icon" title="Cut die to value" onclick="cutVal(ht(tp(this)))">content_cut</button></span><br />
<span><h2 class="die-value">{DIE_VALUE}</h2><span class="hideIfCounter hos"> / <input class="die-sides" type="number" min="1" max="10000" value="{DIE_SIDES}" onfocusout="this.setAttribute('value', this.value);" /></span></span>
</div>
</div></template>
<template id="dieBagUI"><div class="die bag" id="{RAND_ID}" draggable="true" ondragstart="drag(event)">
<div>
<span class="material-icons icon ident">folder</span><input class="title hos" placeholder="Name" type="text" value="{TITLE_DIE}" onfocusout="this.setAttribute('value', this.value);" /><input class="die-color hos" tabIndex="0" type="color" value="transparent" onchange="this.setAttribute('value', this.value);this.parentElement.parentElement.style.backgroundColor = this.value;" />
<button class="material-icons icon indi neg" onclick="if (confirm('Are you sure you want to remove this bag?')) tp(this).remove()">delete</button><br class="hos" />
<button class="material-icons icon indi pos" title="Roll all dies inside" onclick="rollAllDie(ht(tp(this)))">shuffle</button>
<button class="material-icons icon indi pos hos" title="Add Dice" onclick="addDie(tp(this).find('.dropHere').get(0))">add_circle</button>
<button class="material-icons icon indi pos hos" title="Add Counter" onclick="addDie(tp(this).find('.dropHere').get(0), 1, 'Counter', true)">pin</button>
<button class="material-icons icon indi pos hos" title="Add Bag" onclick="addDieBag(tp(this).find('.dropHere').get(0))">create_new_folder</button>
</div>
<div class="dropHere"></div>
</div></template>
</templates>
<script src="script.js"></script>
</body>
</html>

View file

@ -0,0 +1,65 @@
var cont = document.querySelector(".content > div");
var dieTemp = document.querySelector("template#dieUI");
var dieBagTemp = document.querySelector("template#dieBagUI");
var ids = {
die: 0,
bag: 0
};
function addDie(ctx, int, name, count) {
ctx.innerHTML += dieTemp.innerHTML
.replace("{RAND_ID}", "die" + ids.die)
.replace("{TITLE_DIE}", name ?? "")
.replace("{DIE_SIDES}", int ?? "6")
.replace("{IS_COUNTER}", count ? " counter" : "")
.replace("{DIE_VALUE}", Math.round(Math.random() * ((int ?? 6) - 1)) + 1);
ids.die++;
}
function addDieBag(ctx) {
ctx.innerHTML += dieBagTemp.innerHTML
.replace("{RAND_ID}", "dieBag" + ids.bag)
.replace("{TITLE_DIE}", "");
ids.bag++;
}
function rollDie(thisObj) {
var val = thisObj.querySelector('.die-value');
var sides = thisObj.querySelector('.die-sides');
val.innerHTML = Math.round(Math.random() * (sides.value - 1)) + 1;
}
function rollAllDie(ctx) {
var allDies = ctx.querySelectorAll(".rollable");
console.log(allDies, ctx);
allDies.forEach((v) => {
rollDie(v);
})
}
function cutVal(thisObj) {
var val = thisObj.parentElement.querySelector('.die-value');
var sides = thisObj.parentElement.querySelector('.die-sides');
sides.value = val.innerHTML;
}
function changeVal(thisObj, int) {
var val = thisObj.parentElement.querySelector('.die-value');
val.innerHTML = parseInt(val.innerHTML) + int;
}
function allowDrop(ev) {
ev.preventDefault();
}
function drag(ev) {
ev.dataTransfer.setData("element", ev.target.id);
}
function drop(ev) {
if (!ev.target.classList.contains("dropHere")) return;
ev.preventDefault();
var data = ev.dataTransfer.getData("element");
ev.target.appendChild(document.getElementById(data));
}
var tp = (t) => {return $(t).parent().parent()};
var tpp = (t) => {return $(t).parent().parent().parent()};
var ht = (t) => {return t.get(0)};

View file

@ -0,0 +1,375 @@
@import url('https://fonts.googleapis.com/css2?family=Roboto:wght@400;900&display=swap');
@font-face {
font-family: 'PFW';
src: url('assets/ProFontWindows.ttf');
}
:root {
--mainColor: #f80;
--mainColorThemed: #fdb;
--mainColorThemedLight: #fed;
--mainFG: #000;
--mainFGDark: #FFF;
--mainFGTP: #0002;
--mainFGDarkTP: #FFF2;
--mainFGTP4: #0008;
--mainFGDarkTP4: #FFF8;
--negColor: #f00;
--negColorThemed: #fbb;
--negColorThemedLight: #fdd;
--posColor: #f80;
--posColorThemed: #ffd0a0;
--material-outline-boxshadow: #0004 0 0 4px;
--material-outline-border: none;
}
* {
font-family: 'PFW', 'Roboto', 'Lucida Sans', 'Lucida Sans Regular', 'Lucida Grande', 'Lucida Sans Unicode', Geneva, Verdana, sans-serif;
transition: background-color 0.25s;
}
@media (prefers-color-scheme: dark) {
:root {
--mainColorThemed: #840;
--mainColorThemedLight: #420;
--mainFG: #FFF;
--mainFGDark: #000;
--mainFGTP: #FFF2;
--mainFGDarkTP: #0002;
--mainFGTP4: #FFF8;
--mainFGDarkTP4: #0008;
--negColorThemed: #800;
--negColorThemedLight: #400;
--posColorThemed: #840;
--posColorThemedLight: #630;
--material-outline-boxshadow: none;
--material-outline-border: var(--mainFGTP) 1px solid;
}
}
body {padding:0;margin:0;background-color:var(--mainColorThemedLight);}
.headerBar {
width: 100%;
height: 56px;
z-index: 9;
display: inline-grid;
grid-template-columns: auto auto;
grid-template-rows: 40px;
position: fixed;
-webkit-user-select: none;
user-select: none;
top: 0;
background-color: var(--mainColorThemed);
box-shadow: var(--material-outline-boxshadow);
border-bottom: var(--material-outline-border);
line-height: 40px;
color: var(--mainFG);
font-size: 24px;
font-weight: bold;
padding: 8px 16px;
box-sizing: border-box;
transition: box-shadow 0.25s, background-color 0.25s;
}
.fab {
position: fixed;
z-index: 9;
background-color: var(--mainColorThemed);
border-radius: 64px;
height: 64px;
width: 192px;
right: 32px;
bottom: 32px;
display: grid;
overflow: hidden;
user-select: none;
grid-template-columns: auto auto auto;
box-shadow: #0004 0 0 4px 0;
}
.fab button {
border: none;
background-color: transparent;
color: var(--mainFG);
font-size: 32px;
}
.fab button:hover {
background-color: var(--mainFGTP);
}
.fab button:active {
transition: none;
background-color: var(--mainColor);
}
.headerBar button {
height: 40px;
background-color: transparent;
padding: 4px; margin: 0;
margin-left: 8px;
color: var(--mainFG);
border: none;
border-radius: 40px;
transition: background 0.25s;
vertical-align: middle;
}
.headerBar button:hover {
background-color: var(--mainFGTP);
}
.content {
background-color: var(--mainColorThemedLight);
color: var(--mainFG);
height: calc(100vh - 56px);
margin-top: 56px;
overflow-y: auto;
box-sizing: border-box;
padding: 0 64px;
}
.content > div:empty::before {
position: absolute;
top: 56px;
left: 0;
width: 100vw;
text-align: center;
padding: 8px;
box-sizing: border-box;
content: "No dice.";
font-size: 24px;
}
.content > div {
padding-bottom: 64px;
min-height: calc(100% - 16px);
box-sizing:border-box;
}
templates, template {
display: none;
}
div.die {
width: 100%;
border: var(--material-outline-border);
box-shadow: var(--material-outline-boxshadow);
color: var(--mainFG);
margin: 16px 0;
border-radius: 8px;
padding: 16px;
padding-bottom: 8px;
box-sizing: border-box;
display: grid;
grid-template-columns: auto auto;
animation-name: horizontal-shaking;
animation-duration: 0.25s;
}
.counter .hideIfCounter {
display: none;
}
.compactMode .hos {
display: none;
}
div.hideIfCounter {
display: inline-block;
}
body:not(.compactMode) .headerBar button.toc {
color: var(--posColor);
}
.compactMode div.die h2 {
height: 32px;
line-height: 32px;
margin-top: -16px;
margin-right: 8px;
}
div.bag {
grid-template-columns: auto;
grid-template-rows: auto auto;
height: max-content;
}
div.die > div {
user-select: none;
}
div.bag > div.dropHere {
border: var(--mainFGTP) 1px solid;
border-radius: 4px;
padding: 16px;
padding-bottom: 64px;
position: relative;
}
div.bag > div.dropHere:empty {
padding: 32px;
}
div.bag > div.dropHere:empty::before {
position: absolute;
top: 0;
left: 0;
width: 100%;
text-align: center;
padding: 8px;
box-sizing: border-box;
content: "No dice.";
font-size: 24px;
}
div.die h2 {
padding: 0; margin: 0;
display: inline-block;
}
div.die input {
border-radius: 4px;
padding: 4px;
margin: 0;
font-size: 16px;
margin-bottom: 8px;
background-color: var(--mainFGDarkTP4);
border: 1px solid var(--mainFGTP);
color: var(--mainFG);
outline: none;
transition: border 0.25s, border-radius 0.25s, background-color 0.25s;
vertical-align: middle;
}
div.die input[type=color] {
height: 34px;
width: 34px;
margin-left: -8px;
position: absolute;
left: -10000px;
}
div.bag > div > input[type=color] {
margin-left: 0;
}
div.die input[type=color]:hover {
position: static;
}
div.die input[type=color]:focus {
position: static;
}
div.die input[type=text]:hover + input[type=color] {
position: static;
}
div.die .die-value {
vertical-align: middle;
}
div.die input.die-sides {
vertical-align: baseline;
width: 48px;
height: 24px;
}
div.die input.title {
padding: 8px;
}
div.die input:focus {
background-color: var(--mainFGTP);
border: 1px solid var(--mainFG);
}
div.die input.title:not(:placeholder-shown) {
border: none;
border-radius: 0;
background-color: transparent;
}
div.die input.title:not(:placeholder-shown):hover {
border-bottom: 1px solid var(--mainFG);
}
div.die button {
border-radius: 4px;
padding: 8px;
margin: 0;
font-size: 12px;
background-color: transparent;
border: 1px solid var(--mainFGTP);
color: var(--mainFG);
transition: background-color 0.25s;
}
div.die button.icon {
margin-bottom: 8px;
font-size: 19px;
vertical-align: middle;
}
div.die button:hover {
background-color: var(--mainFGTP);
}
div.die button:active {
border: 1px solid var(--mainFG);
}
.indi.neg {
background-color: var(--negColorThemed);
}
.indi.neg:hover {
background-color: var(--negColorThemedLight);
}
.indi.pos {
background-color: var(--posColorThemed);
}
.ident {
font-size: 19px;
vertical-align: top;
margin: 6px;
margin-right: 8px;
}
@media (max-width: 675px) {
div.content {
padding: 0 16px;
}
}
@media (min-width: 875px) {
div.content {
padding: 0 20%;
}
}
@media (min-width: 1200px) {
div.content {
padding: 0 10%;
padding-top: 16px;
padding-bottom: 16px;
overflow-y: auto;
}
div.content > div {
column-count: 2;
}
div.die {
break-inside: avoid-column;
list-style-type: none;
margin-top: 0;
border: var(--mainFGTP) 1px solid;
box-shadow: none;
}
div.bag {
column-span: all;
margin-top: 16px;
}
div.bag div.dropHere {
column-count: 2;
}
}
@media (min-width: 1775px) {
div.content > div {
column-count: 3;
}
}

View file

@ -0,0 +1,545 @@
import { kaboom } from "../deps.js";
export var charts = [
{
id: "tutorial",
name: "Tutorial",
speed: 5, // How much seconds it takes to get from Right Stage to the hitmarker
bpm: 135, // Song BPM
events: {
preload: function() {
loadSound("hitsoundJellyBean", "sounds/hitsoundJellyBean.wav");
loadSound("hitsoundCarterRedacted", "sounds/hitsoundJellyBean.wav");
loadSound("hitsoundMarc", "sounds/hitsoundJellyBean.wav");
loadSound("hitsoundRedVelvety", "sounds/hitsoundRedVelvety.wav");
loadSound("hitsoundMarkyMark", "sounds/burp.mp3");
loadSprite("JellyBeanPre", "sprites/previews/JellyBeanPre.png");
loadSprite("RedVelvetyPre", "sprites/previews/RedVelvetyPre.png");
loadSprite("MarkyMarkPre", "sprites/previews/MarkyMarkPre.png");
loadSprite("CarterRedactedPre", "sprites/previews/CarterRedactedPre.png");
loadSprite("MarcPre", "sprites/previews/MarcPre.png");
loadSprite("tutorialBG0", "sprites/bgCake.png");
loadSprite("tutorialFG0", "sprites/fgCake0.png");
loadSprite("tutorialFG1", "sprites/fgCake1.png");
loadSprite("Marctutorial", "sprites/marcCake.png", {
sliceX: 3,
sliceY: 3,
anims: {
idle: {
from: 0,
to: 3,
speed: 20
},
talk: {
from: 4,
to: 5,
speed: 20
},
miss: {
from: 6,
to: 8,
speed: 10
},
},
})
loadSprite("CarterRedactedtutorial", "sprites/carterredactedCake.png", {
sliceX: 3,
sliceY: 3,
anims: {
idle: {
from: 0,
to: 3,
speed: 20
},
talk: {
from: 4,
to: 5,
speed: 20
},
miss: {
from: 6,
to: 8,
speed: 10
},
},
})
loadSprite("MarkyMarktutorial", "sprites/markymarkCake.png", {
sliceX: 3,
sliceY: 4,
anims: {
idle: {
from: 0,
to: 3,
speed: 20
},
talk: {
from: 4,
to: 7,
speed: 40
},
miss: {
from: 8,
to: 10,
speed: 10
},
},
})
loadSprite("RedVelvetytutorial", "sprites/redvelvetyCake.png", {
sliceX: 3,
sliceY: 4,
anims: {
idle: {
from: 0,
to: 3,
speed: 20
},
talk: {
from: 4,
to: 5,
speed: 20
},
dox: {
from: 6,
to: 7,
speed: 20
},
miss: {
from: 8,
to: 10,
speed: 10
},
},
})
loadSprite("JellyBeantutorial", "sprites/jellybeanCake.png", {
sliceX: 3,
sliceY: 4,
anims: {
idle: {
from: 0,
to: 3,
speed: 20
},
talk: {
from: 4,
to: 5,
speed: 20
},
dox: {
from: 6,
to: 7,
speed: 20
},
miss: {
from: 8,
to: 10,
speed: 10
},
},
})
}
},
characters: [
["JellyBean", "JellyBean", 186, 0],
["RedVelvety", "RedVelvety", 186, 0],
["Marc", "Marc", 186, 0],
["CarterRedacted", "CarterRedacted", 186, 0],
["MarkyMark", "Mark", 186, 0]
],
noteTypes: {
"J": noteDefault,
},
makeScript: {
customChar: false,
customBG: false,
charPos: [],
script: function() {
add([
sprite("tutorialFG1"),
layer("fg"),
scale(1)
]);
return {returnType: null};
}
},
chart: "................................................................................................................................J...........J.J...........J.J.J.............J.J.................J...........J.J...........J.J...J...............................J...........J.J...........J.J.J.............J.J...J.............J...........J.J...........J.J...J...............................J...........J.J...........J.J.J.............J.J...J.............J...........J.J...........J.J...J...............................J...........J.J...........J.J.J.............J.J...J...J...J.J...J...........J.J...........J.J...J...............................J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J...................................J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.....J.............................J.J.J.J.J.J.J.J.J.J.J.J.J.J.J...................................J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.....J.J.....J.J.....J...........J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.................................J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.....J.J.....J.J.....J.J.....J...................................................................................................................................J...........J.J...........J.J.J.............J.J...J...J...J.J...J...........J.J...........J.J...J...............................J...........J.J...........J.J.J.............J.J...J...J...J.J...J...........J.J...........J.J...J...............................J...........J.J...........J.J.J.............J.J...J...J...J.J...J...........J.J...........J.J...J...............................J...........J.J...........J.J.J.............J.J...J...J...J.J...J...........J.J...........J.J...J...............................................................................................................................................................................................................................................................",
scale: 1 //Texture Scale (too lazy to upsize sprites sometimes)
},
{
id: "faith",
name: "Friendly Faith Plate",
speed: 2,
bpm: 120,
events: {
preload: function() {
loadSound("faith", "sounds/The Friendly Faith Plate.mp3"); //120
loadSound("hitsoundFaithPlate", "sounds/hitsoundFaithPlate.mp3");
loadSprite("FaithPlatePre", "sprites/previews/FaithPlatePre.png");
loadSprite("faithBG0", "sprites/bgFaith.png");
loadSprite("faithFG0", "sprites/fgFaith.png");
loadSprite("FaithPlatefaith", "sprites/faithplateFaith.png", {
sliceX: 3,
sliceY: 3,
anims: {
idle: {
from: 0,
to: 3,
speed: 20
},
talk: {
from: 4,
to: 5,
speed: 20
},
miss: {
from: 6,
to: 8,
speed: 10
},
},
})
}
},
characters: [
["FaithPlate", "Faith Plate", 0, 0]
],
noteTypes: {
"J": noteDefault,
},
makeScript: {
customChar: false,
customBG: false,
charPos: [],
script: function() {
return {returnType: null};
}
},
chart: "................................................................................................................................J...J...J...JJJJJ...J...J...J...J.J.J.J.J.J.J.J.JJJJJJJJJ.J.J.JJJ.J.J.J.J.J.JJJJJ.JJJ.J.J.J.J.J.J.JJJ.JJJ.J.J.J.JJJJJJJJJJJJJJJJJ.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.JJJ.JJJ.JJJ.JJJ.JJJ.J.J.J.J.JJJ.J.JJJJJJJJJJJJJ.J.J.J.JJJJJ.J.J.J.J.J.J.J.JJJJJ.J.J.J.J.JJ.J..J.JJJ.JJJ.J.J.JJJ.JJJ.J.J.J.JJJJJ.J.J.JJJ.JJJJJJJJJJJJJJJJJ.J.JJJ.J.J.JJJ.J.J.JJJ.J.J.JJJ.J.J.JJJ.J.J.JJJ.J.J.JJJJJJJJJJJJJ.J.J.JJJ.J.JJJ.J.J.JJJ.J.J.JJJ.J.J.J.J.J.J.JJJ.JJJJ.JJ.J.J.J.JJ..J...J.J.J.J.J.J.JJJJJJJJJJJJJ.J.J.J.J.J.J.J.J.J.JJJJJ.J.J.J.J.J.J.J.J...J...J.J.J.J.JJJJJJJJJ.J.J.J.J.J.J.JJJ.J.JJJJJJJJJJJJJJJ.J.J.JJJ.J.JJJ.JJJJJJJJJJJJJJJJJ.J.J.JJJ.J.JJJ.JJJJJJJJJJJJJJJJJ.J.J.JJJ.J.JJJ.JJJJJJJJJJJJJJJJJ.J.J.JJJJ.JJJJJJJJJJJJJJJ.JJJJJJJJJJJJJ..J.JJJ.JJJJJJJJJJ....J.J.JJJJJJJ.J.JJJ.JJJJJJJJJJJJJJJJJJJJJ.J.J.J.JJJ.JJJJJJJJJ....JJJJJJJJJ....JJJJJJJ.JJJJJJJ..JJJ..J.JJJJJJJJJJJJJJJ.JJJJJJJ..JJJ....JJJJJJJJJJJJJJJ.JJJJJJJ..JJJ....JJJJJJJJJJJJJJJ.JJJJJJJJ.JJJ..J.JJJJJJJ.J.JJJ.JJJJJJJJJJJJJ.JJJ.J...JJJ.J.JJJ.JJJJJJJJJJJJJ.JJJ.JJJ.JJJ.J.JJJJJJJJJJJJJJJJJJJJJ.JJJ.JJJ.J.JJJ.JJJJJJJJJJJJJJJJJ.JJJ.JJJ.J.JJJ.JJJJJJJJJJJJJJJ...JJJJ........J...JJJJ........J...JJJJ........J...JJJJ........J.J.JJJJ........JJJ.JJJ.JJJ.J.JJJ.J.JJJJ........JJJ.JJJ.JJJ.JJJJJ.J.JJJJ........JJJ.JJJ.JJJ.J.JJJ.J.JJJJ........JJJ.JJJ.JJJ.JJJJJ.J.JJJJJ.......JJJ.J.............",
scale: 4
},
{
id: "green",
name: "Green Hill Zone",
speed: 2,
bpm: 150,
events: {
preload: function() {
loadSound("green", "sounds/GreenHill.wav"); //139
loadSound("hitsoundSonicAndTails", "sounds/hitsoundJellyBean.wav");
loadSound("hitsoundTails", "sounds/hitsoundJellyBean.wav");
loadSprite("SonicAndTailsPre", "sprites/previews/SonicAndTailsPre.png");
loadSprite("TailsPre", "sprites/previews/TailsPre.png");
loadSprite("sonicBG0", "sprites/SonicBG.png", {
sliceX: 3,
sliceY: 3,
anims: {
idle: {
from: 0,
to: 6,
speed: 10,
loop: true
}
},
});
loadSprite("sonicFG0", "sprites/SonicFG.png", {
sliceX: 3,
sliceY: 3,
anims: {
idle: {
from: 0,
to: 0,
speed: 20
}
},
});
loadSprite("SonicAndTailssonic0", "sprites/SonicMidSim.png", {
sliceX: 3,
sliceY: 4,
anims: {
idle: {
from: 0,
to: 6,
speed: 20
},
talk: {
from: 7,
to: 8,
speed: 20
},
miss: {
from: 9,
to: 11,
speed: 10
},
},
});
loadSprite("SonicAndTailssonic1", "sprites/TailsMidSim.png", {
sliceX: 3,
sliceY: 9,
anims: {
idle: {
from: 0,
to: 15,
speed: 20
},
talk: {
from: 16,
to: 23,
speed: 20
},
miss: {
from: 24,
to: 26,
speed: 10
},
},
});
loadSprite("greenBG0", "sprites/SonicBG.png", {
sliceX: 3,
sliceY: 3,
anims: {
idle: {
from: 0,
to: 6,
speed: 10,
loop: true
}
},
});
loadSprite("greenFG0", "sprites/SonicFG.png", {
sliceX: 3,
sliceY: 3,
anims: {
idle: {
from: 0,
to: 0,
speed: 20
}
},
});
loadSprite("SonicAndTailsgreen0", "sprites/SonicMidSim.png", {
sliceX: 3,
sliceY: 4,
anims: {
idle: {
from: 0,
to: 6,
speed: 20
},
talk: {
from: 7,
to: 8,
speed: 20
},
miss: {
from: 9,
to: 11,
speed: 10
},
},
});
loadSprite("SonicAndTailsgreen1", "sprites/TailsMidSim.png", {
sliceX: 3,
sliceY: 9,
anims: {
idle: {
from: 0,
to: 15,
speed: 20
},
talk: {
from: 16,
to: 23,
speed: 20
},
miss: {
from: 24,
to: 26,
speed: 10
},
},
});
}
},
characters: [
["SonicAndTails", "Sonic"],
["Tails", "Tails"]
],
noteTypes: {
"J": function(time, prevStep, char) {
if (char == "Tails") {
customNote(time, "J", prevStep, 0, [0, 0, 0], true);
} else {
noteDefault(time, prevStep)
}
},
"T": function(time, prevStep, char) {
if (char == "Tails") {
noteDefault(time, prevStep)
} else {
customNote(time, "T", prevStep, 0, [0, 0, 0], true);
}
},
"D": function(time, prevStep) {
noteDefault(time, prevStep);
customNote(time, "D", prevStep, 0, [0, 0, 0], true);
}
},
makeScript: {
customChar: true,
customBG: false,
charPos: [],
script: function(players, char, bgEl) {
var player, player2;
bgEl.play("idle");
if (char == "Tails") {
player = add([
sprite("SonicAnd" + char + "green" + "1"),
layer("JELLYBEAN"),
"dances",
pos(224, 20),
scale(1)
])
player2 = add([
sprite("SonicAnd" + char + "green" + "0"),
layer("JELLYBEAN"),
"dances",
pos(20, 108),
scale(1)
])
} else {
player = add([
sprite(char + "green" + "0"),
layer("JELLYBEAN"),
"dances",
pos(20, 108),
scale(1)
])
player2 = add([
sprite(char + "green" + "1"),
layer("JELLYBEAN"),
"dances",
pos(224, 20),
scale(1)
])
}
return {returnType: "character", main: player, empty: player2};
}
},
chart: "................J.....J.....J.....J.....J...J...J.....J.....J...................J.....J.....J...J.....J.....J...J.....J.................................T.T...T.T...T.T...T...........T.T.T...T.T...T.T...T.............T.T...T.T...T.T...T...........T.T.T...T.T...T.T...T.....T.......J.J...J.J...D.J.T.J.T...T.....J.J.J...J.J...D.J.T.J.T...T.......J.J...J.J...D.J.T.J.T...T.....J.J.J...J.J...D.J.T.J.D...D.....J.....J.....J.....J.T.D.T.J.....J.....J.....J.....J.T.D.T.J.....J.....J.....J.....J.T.D.T.J.T.T.T...T.T.T...T.T.T.T.T.T.T.........J.J...J.J...J.J...J...........J.J.J...J.J...J.J...J.............J.J...J.J...J.J...J...........J.J.J...J.J...J.J...J.....J.......T.T...T.T...D.T.J.T.J...J.....T.T.T...T.T...D.T.J.T.J...J.......T.T...T.T...D.T.J.T.J...J.....T.T.T...T.T...D.T.J.T.J.T.D.....T.....T.....T.....T.J.D.J.T.....T.....T.....T.....T.J.D.J.T.....T.....T.....T.....T.J.D.J.T.J.J.J...J.J.J...J.J.J.J.J.J.J................................................................................................................................................................",
scale: 1
},
{
id: "sonic",
name: "Emerald Hill Zone",
speed: 2,
bpm: 139,
events: {
preload: function() {
loadSound("tutorial", "sounds/Getting it Done.mp3"); //135
loadSound("faith", "sounds/The Friendly Faith Plate.mp3"); //120
loadSound("sonic", "sounds/SonicInMidSim.wav"); //139
loadSound("green", "sounds/GreenHill.wav"); //139
}
},
characters: [
["SonicAndTails", "Sonic"],
["Tails", "Tails"]
],
noteTypes: {
"J": function(time, prevStep, char) {
if (char == "Tails") {
customNote(time, "J", prevStep, 0, [0, 0, 0], true);
} else {
noteDefault(time, prevStep)
}
},
"T": function(time, prevStep, char) {
if (char == "Tails") {
noteDefault(time, prevStep)
} else {
customNote(time, "T", prevStep, 0, [0, 0, 0], true);
}
},
"D": function(time, prevStep) {
noteDefault(time, prevStep);
customNote(time, "D", prevStep, 0, [0, 0, 0], true);
}
},
makeScript: {
customChar: true,
customBG: false,
charPos: [],
script: function(players, char, bgEl) {
var player, player2;
bgEl.play("idle");
if (char == "Tails") {
player = add([
sprite("SonicAnd" + char + "green" + "1"),
layer("JELLYBEAN"),
"dances",
pos(224, 20),
scale(1)
])
player2 = add([
sprite("SonicAnd" + char + "green" + "0"),
layer("JELLYBEAN"),
"dances",
pos(20, 108),
scale(1)
])
} else {
player = add([
sprite(char + "green" + "0"),
layer("JELLYBEAN"),
"dances",
pos(20, 108),
scale(1)
])
player2 = add([
sprite(char + "green" + "1"),
layer("JELLYBEAN"),
"dances",
pos(224, 20),
scale(1)
])
}
return {returnType: "character", main: player, empty: player2};
}
},
chart: "..................................................J.J.J.J.J.JJ....J.J.J.J..J.........JJJJ.J.JJ.J..................T.T.T.T.T.TT....T...T.T..T........TTT.T.T.TT.T..................J.J.J.J.J.J.J.J.J...J...........J.J.J.J.J.JJ..J.................T.T.T.T.T.T.T.T.T...T...........T.T.T.T.T.TT..T...............J.....J.....J.J.J.JJ....T.TT........J.J.J.J.J.J.J.J...J.........T.....T.....T.T.T.TT....J.JJ....DD.D.............................................................",
scale: 1
},
]
export function noteDefault(time, prevStep) {
add([
rect(10, 50),
pos(width(), 20),
color(232, 3, 252),
("note" + prevStep),
"note",
{
created: time,
type: "J",
empty: false,
normal: true
}
]);
}
export function customNote(time, letter, prevStep, w, colorArray, empty, funclol) {
add([
rect(w, 50),
pos(width(), 20),
colorArray ? color(colorArray[0], colorArray[1], colorArray[2]) : color(0, 0, 0),
("note" + prevStep),
"note",
{
created: time,
type: letter,
function: funclol,
empty: empty,
normal: funclol != undefined ? false : true
}
]);
}

View file

@ -0,0 +1,175 @@
export var easings = { // Easings taken from https://easings.net/
linear: (x) => {
return x;
},
easeInSine: (x) => {
return 1 - Math.cos((x * Math.PI) / 2);
},
easeOutSine: (x) => {
return Math.sin((x * Math.PI) / 2);
},
easeInOutSine: (x) => {
return -(Math.cos(Math.PI * x) - 1) / 2;
},
easeInQuad: (x) => {
return x * x;
},
easeOutQuad: (x) => {
return 1 - (1 - x) * (1 - x);
},
easeInOutQuad: (x) => {
return x < 0.5 ? 2 * x * x : 1 - Math.pow(-2 * x + 2, 2) / 2;
},
easeInCubic: (x) => {
return x * x * x;
},
easeOutCubic: (x) => {
return 1 - Math.pow(1 - x, 3);
},
easeInOutCubic: (x) => {
return x < 0.5 ? 4 * x * x * x : 1 - Math.pow(-2 * x + 2, 3) / 2;
},
easeInQuart: (x) => {
return x * x * x * x;
},
easeOutQuart: (x) => {
return 1 - Math.pow(1 - x, 4);
},
easeInOutQuart: (x) => {
return x < 0.5 ? 8 * x * x * x * x : 1 - Math.pow(-2 * x + 2, 4) / 2;
},
easeInQuint: (x) => {
return x * x * x * x * x;
},
easeOutQuint: (x) => {
return 1 - Math.pow(1 - x, 5);
},
easeInOutQuint: (x) => {
return x < 0.5 ? 16 * x * x * x * x * x : 1 - Math.pow(-2 * x + 2, 5) / 2;
},
easeInExpo: (x) => {
return x === 0 ? 0 : Math.pow(2, 10 * x - 10);
},
easeOutExpo: (x) => {
return x === 1 ? 1 : 1 - Math.pow(2, -10 * x);
},
easeInOutExpo: (x) => {
return x === 0
? 0
: x === 1
? 1
: x < 0.5 ? Math.pow(2, 20 * x - 10) / 2
: (2 - Math.pow(2, -20 * x + 10)) / 2;
},
easeInCirc: (x) => {
return 1 - Math.sqrt(1 - Math.pow(x, 2));
},
easeOutCirc: (x) => {
return Math.sqrt(1 - Math.pow(x - 1, 2));
},
easeInOutCirc: (x) => {
return x < 0.5
? (1 - Math.sqrt(1 - Math.pow(2 * x, 2))) / 2
: (Math.sqrt(1 - Math.pow(-2 * x + 2, 2)) + 1) / 2;
},
easeInBack: (x) => {
const c1 = 1.70158;
const c3 = c1 + 1;
return c3 * x * x * x - c1 * x * x;
},
easeOutBack: (x) => {
const c1 = 1.70158;
const c3 = c1 + 1;
return 1 + c3 * Math.pow(x - 1, 3) + c1 * Math.pow(x - 1, 2);
},
easeInOutBack: (x) => {
const c1 = 1.70158;
const c2 = c1 * 1.525;
return x < 0.5
? (Math.pow(2 * x, 2) * ((c2 + 1) * 2 * x - c2)) / 2
: (Math.pow(2 * x - 2, 2) * ((c2 + 1) * (x * 2 - 2) + c2) + 2) / 2;
},
easeInBounce: (x) => {
return 1 - easings.easeOutBounce(1 - x);
},
easeOutBounce: (x) => {
const n1 = 7.5625;
const d1 = 2.75;
if (x < 1 / d1) {
return n1 * x * x;
} else if (x < 2 / d1) {
return n1 * (x -= 1.5 / d1) * x + 0.75;
} else if (x < 2.5 / d1) {
return n1 * (x -= 2.25 / d1) * x + 0.9375;
} else {
return n1 * (x -= 2.625 / d1) * x + 0.984375;
}
},
easeInOutBounce: (x) => {
return x < 0.5
? (1 - easings.easeOutBounce(1 - 2 * x)) / 2
: (1 + easings.easeOutBounce(2 * x - 1)) / 2;
}
}
export var tweentypes = {
FOREVER: (t, st, tl) => {
if (t - st >= tl) {
return "FOREVER";
}
return "CONTINUE";
},
LERPFOREVER: (t, st, tl) => {
return "LF";
},
PINGPONG: (t, st, tl) => {
if (t - st >= tl) {
return "PING";
}
return "CONTINUE";
},
NORMAL: (t, st, tl) => {
if (t - st >= tl) {
return "CALLBACK";
}
return "CONTINUE";
}
}
export function tween(func, attrs, timeLen, minVal, maxVal, ease, type, onFinish) {
var minVal = minVal != undefined ? minVal : func[attrs[0]];
var ease = ease != undefined ? ease : easings.linear;
var type = type != undefined ? type : tweentypes.NORMAL;
var stTime = time();
var onFinish = onFinish != undefined ? onFinish : "ud";
var upd = onUpdate(() => {
switch (type(time(), stTime, timeLen)) {
case "CALLBACK":
for (let h in attrs) {
func[attrs[h]] = maxVal;
}
upd();
return onFinish == "ud" ? true : onFinish();
case "FOREVER":
stTime = time();
break;
case "CONTINUE":
for (let h in attrs) {
func[attrs[h]] = minVal;
}
break;
case "PING":
var buffer = minVal;
minVal = maxVal;
maxVal = buffer;
stTime = time();
break;
default:
break;
}
for (let i in attrs) {
func[attrs[i]] = lerp(minVal, maxVal, ease((time() - stTime) / timeLen));
}
});
}

View file

@ -0,0 +1,981 @@
"use strict";
import { kaboom, easings, tween, tweentypes } from "../deps.js";
import { charts } from "./charts.js";
// initialize context
kaboom({
width: 700,
height: 400,
background: [ 0, 0, 0 ],
crisp: true,
touchToMouse: true,
canvas: document.querySelector("#kaboom"),
font: "MidSim",
scale: 1,
});
var ismobile = isTouch();
load(new Promise((resolve, reject) => {
loadFont("unscii", "sprites/unscii_8x8.png", 8, 8, {chars: " !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~"});
loadFont("MidSim", "sprites/MidSimFont2.png", 10, 10, {chars: "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz:;><^%-.!?/()[]\"'|1234567890"});
// Music
loadSound("gameover", "sounds/gameover.mp3");
//
// Sounds
loadSound("nullHit", "sounds/nullHit.mp3");
loadSound("score", "sounds/score.mp3");
loadSound("metro", "sounds/metro.wav");
loadSound("explode", "sounds/explode.mp3");
//
//Menus
loadSprite("bgCake", "sprites/bgCake.png");
loadSprite("jellybeanTitle", "sprites/jellybeanTitle.png");
loadSprite("logo", "sprites/logo.png");
loadSprite("jellybeanFail", "sprites/jellybeanFail.png");
//
// Main Game
loadSprite("noteClick", "sprites/noteClick.png", {
sliceX: 4,
sliceY: 2,
anims: {
idle: {
from: 7,
to: 7,
speed: 30
},
click: {
from: 0,
to: 7,
speed: 60
}
},
})
for (let ided in charts) {
console.log("Loading game assets...");
charts[ided].events.preload();
console.log("Assets of song " + charts[ided].name + " loaded.");
}
resolve("All assets loaded.");
}));
scene("Game", (idx, noTrans) => {
var song = charts[idx.song].id; //Also Chart access
var char = charts[idx.song].characters[idx.character][0];
var hitsound = "hitsound" + charts[idx.song].characters[idx.character][0];
var chart = charts[idx.song].chart;
var crochet = ((60 / charts[idx.song].bpm) * 1000);
var board = width() - strumLine;
var curBeat;
var prevBeat;
var prevStep;
var curStep;
var autoplay = false;
var debugMode = false;
var score = 0;
var combo = 0;
var health = 1;
var font = "MidSim";
if (char == "MarkyMark") {
font = "unscii";
}
// Music
var strumLine = width() / 2;
const music = play(charts[idx.song].id, {
volume: 1,
loop: false
});
const underlay = play("score", {
volume: 1,
loop: false
});
music.pause()
wait(charts[idx.song].speed, () => {
underlay.pause();
music.play();
underlay.play(music.time() + charts[idx.song].speed);
});
// Sprites
layers([
"bg",
"JELLYBEAN",
"SKELETONS",
"fg",
"ui0",
"ui1"
], "ui0");
var players = {
main: 0,
empty: 0,
};
var bg;
var tweenVals = {
fade: 1,
triggered: false
}
tween(tweenVals, ["fade"], 1, 1, 0, easings.easeOutCirc, tweentypes.NORMAL);
if (!charts[idx.song].makeScript.customChar) {
players.main = add([
sprite(char + song),
layer("JELLYBEAN"),
"dances",
pos(charts[idx.song].characters[idx.character][2], charts[idx.song].characters[idx.character][3]),
scale(charts[idx.song].scale)
]);
}
if (!charts[idx.song].makeScript.customBG) {
bg = add([
sprite(song + "BG0"),
layer("bg"),
scale(charts[idx.song].scale)
]);
const fg = add([
sprite(song + "FG0"),
(song == "faith" ? layer("bg") : layer("fg")),
scale(charts[idx.song].scale)
]);
}
var script = charts[idx.song].makeScript.script(players, char, bg);
if (script.returnType != undefined && script.returnType == "character") {
players.main = script.main;
players.empty = script.empty;
}
const noteClick = add([
sprite("noteClick"),
scale(0.25),
pos(strumLine, 15)
])
const bspButton = add([
pos(0, 0),
color(CYAN),
text(ismobile ? "<" : "BACKSPACE TO EXIT", {
size: ismobile? 32 : 20, // 48 pixels tall
}),
area({
offset: ismobile ? vec2(canvas.offsetLeft, canvas.offsetTop) : vec2(0, 0),
}),
"back"
])
const entButton = add([
pos(width(), 0),
origin("topright"),
color(YELLOW),
text(ismobile ? "||" : "ENTER TO PAUSE", {
size: ismobile? 32 : 20, // 48 pixels tall
}),
area({
offset: ismobile ? vec2(canvas.offsetLeft, canvas.offsetTop) : vec2(0, 0),
}),
"ent"
])
// Gameplay
onUpdate(() => {
if (health > 1) health = 1;
if (health < 0) {
health = 0;
if(!tweenVals.triggered) {
tween(tweenVals, ["fade"], 1, 0, 1, easings.easeOutCirc, tweentypes.NORMAL, function () {
underlay.stop();
music.stop();
go("Lose", score, idx);
});
underlay.pause();
music.pause();
tweenVals.triggered = true;
}
}
if (music.time() > music.duration() && health >= 0) {
if(!tweenVals.triggered) {
tween(tweenVals, ["fade"], 1, 0, 1, easings.easeOutCirc, tweentypes.NORMAL, function () {
go("Help");
});
tweenVals.triggered = true;
}
}
strumLine = lerp(18, width() / 2, health);
noteClick.pos.x = strumLine - 5;
curBeat = Math.floor(((music.time() * 1000) / crochet) * 10) / 10;
curStep = Math.floor((music.time() * 1000) / (crochet / 4));
prevBeat = Math.floor(((underlay.time() * 1000) / crochet));
prevStep = Math.floor((underlay.time() * 1000) / (crochet / 4));
if (!get("bar" + prevBeat).length) {
var bar = add([
prevBeat % 4 == 0 ? rect(3, 50) : rect(2, 50),
pos(width(), 20),
color(255, 255, 255),
("bar" + prevBeat),
{
mainBar: prevBeat % 4 == 0,
created: underlay.time()
},
"bar"
]);
}
if (get("note" + prevStep).length <= 0) {
makeNote(charts[idx.song].chart[Math.floor(prevStep)]);
}
if (!underlay.isPaused()) {
every("bar", (j) => {
j.pos.x = lerp(width(), strumLine, (underlay.time() - j.created) / charts[idx.song].speed);
if(j.pos.x <= strumLine) {
beatHit();
if (debugMode) play("metro", {detune: j.mainBar ? 200 : 0});
destroy(j);
}
if (charts[idx.song].events.onBeat != undefined) {
charts[idx.song].events.onBeat(curBeat);
}
});
every("note", (j) => {
j.pos.x = lerp(width(), strumLine, (underlay.time() - j.created) / charts[idx.song].speed);
if(autoplay) {
if(j.pos.x <= strumLine && !j.empty) {
play(hitsound);
players.main.play("talk"); //Check this area later, you want to add in Note Modularity!
destroy(j);
}
} else {
if(j.pos.x <= strumLine - 20 && !j.empty) {
score -= 200;
destroy(j);
play("explode");
players.main.play("miss");
shake(5);
combo = 0;
health -= 0.1;
}
}
if(j.pos.x <= strumLine && j.empty) {
if (!j.normal) {
j.function(j.empty, curBeat, j.type);
}
destroy(j);
players.empty?.play("talk");
}
});
}
})
var mt;
onKeyPress("enter", () => {
if (!underlay.isPaused()) {
underlay.pause();
music.pause();
mt = [underlay.time(), music.time()];
} else {
underlay.play(mt[0]);
music.play(mt[1]);
}
});
onKeyPress("space", () => {judgeHitsLol()});
onKeyPress("backspace", () => {
tween(tweenVals, ["fade"], 1, 0, 1, easings.easeOutCirc, tweentypes.NORMAL, function () {
underlay.stop();
music.stop();
go("Help");
});
underlay.pause();
music.pause();
});
onKeyPress("a", () => {autoplay = !autoplay});
onKeyPress("d", () => {debugMode = !debugMode});
onClick("back", () => {
tween(tweenVals, ["fade"], 1, 0, 1, easings.easeOutCirc, tweentypes.NORMAL, function () {
underlay.stop();
music.stop();
go("Help");
});
underlay.pause();
music.pause();
});
onClick("ent", () => {
if (!underlay.isPaused()) {
underlay.pause();
music.pause();
mt = [underlay.time(), music.time()];
} else {
underlay.play(mt[0]);
music.play(mt[1]);
}
});
onClick(() => {judgeHitsLol()});
onDraw(() => {
drawLine({
p1: vec2(0, 20),
p2: vec2(width(), 20),
width: 2,
color: rgb(255, 255, 255),
})
drawLine({
p1: vec2(0, 70),
p2: vec2(width(), 70),
width: 2,
color: rgb(255, 255, 255),
})
drawLines({ // 80 * 240, 20 * 60
pts: [ vec2(strumLine, 18), vec2(strumLine + 10, 18), vec2(strumLine + 10, 72), vec2(strumLine, 72), vec2(strumLine, 18) ],
width: 2,
pos: vec2(100, 200),
color: rgb(255, 255, 255),
})
drawText({
text: "MID-SIMULATOR DEMO",
size: 20,
pos: vec2(0, height() - 20),
font: font
});
if (debugMode) {
drawText({
text: underlay.time() * 1000,
size: 20,
pos: vec2(0, 20),
font: font
});
drawText({
text: curBeat,
size: 20,
pos: vec2(0, 40),
font: font
});
drawText({
text: prevStep + "/" + (charts[idx.song].chart.length - 1),
size: 20,
pos: vec2(0, 60),
font: font
});
drawText({
text: (charts[idx.song].chart[Math.floor(prevStep)] ? charts[idx.song].chart[Math.floor(prevStep)] : "."),
size: 20,
pos: vec2(0, 80),
font: font
});
drawText({
text: (charts[idx.song].chart[Math.floor(curStep)] ? charts[idx.song].chart[Math.floor(curStep)] : "."),
size: 20,
pos: vec2(0, 100),
font: font
});
drawText({
text: "Health: " + health,
size: 20,
pos: vec2(strumLine, 120),
font: font
});
}
drawText({
text: "Score: " + score,
size: 20,
pos: vec2(strumLine, 80),
font: font
});
drawText({
text: "Combo: " + combo,
size: 20,
pos: vec2(strumLine, 100),
font: font
});
if (autoplay) {
drawText({
text: "AUTOPLAY",
size: 20,
pos: vec2(strumLine, debugMode? 140: 120),
font: font
});
}
drawRect({
width: 702,
height: 402,
pos: vec2(-1, -1),
color: BLACK,
opacity: tweenVals.fade
})
})
//Functions
function makeNote(letter) {
if (charts[idx.song].noteTypes.hasOwnProperty(letter)) {
charts[idx.song].noteTypes[letter](underlay.time(), prevStep, char);
}
}
function judgeHitsLol() {
var iv = false;
var hits = 0;
every("note", (j) => {
if (!iv) {
if (!j.empty) {
var str = "No Rating";
var theColor = WHITE;
if(j.pos.x >= strumLine - 20) {
if(j.pos.x <= strumLine + 22) {
hits++;
iv = true;
if (!j.normal) {
j.function(j.empty, curBeat, j.type);
}
destroy(j); //Destroys note. No score.
noteClick.play("click");
combo += 1;
str = "MID";
theColor = RED;
}
if(j.pos.x <= strumLine + 12) {
play(hitsound); //Plays sound!
players.main.play("talk");
score += 20;
health += 0.01;
str = "Perfect!";
theColor = MAGENTA;
}
if(j.pos.x <= strumLine + 5) {
score += 50;
health += 0.02;
str = "Perfect!!";
}
if(j.pos.x <= strumLine - 3) {
score += 50;
health -= 0.01;
str = "Perfect!";
}
if(j.pos.x <= strumLine - 8) {
score -= 100;
health -= 0.02;
str = "Overshot";
theColor = CYAN;
}
}
if (str != "No Rating") {
var origpos = strumLine - 16;
var ratingtxt = add([
text(str, {
size: 30, // 48 pixels tall
}),
pos(origpos, 48),
color(theColor),
origin("right")
]);
tween(ratingtxt.pos, ["y"], 5, 48, 300, easings.easeOutSine, tweentypes.NORMAL);
tween(ratingtxt, ["opacity"], 5, 1, 0, easings.easeOutSine, tweentypes.NORMAL, function() {
destroy(ratingtxt);
});
}
}
}
});
if (hits <= 0) {
play("nullHit");
}
}
function beatHit() {
every("dances", (obj) => {
if (obj.curAnim() != "talk" && obj.curAnim() != "miss") {
obj.play("idle");
}
});
}
});
scene("Help", (noTrans) => {
var index = {
character: 0,
song: 0
}
var tweenVals = {
fade: 0
}
if (!noTrans) tween(tweenVals, ["fade"], 1, 1, 0, easings.easeOutCirc, tweentypes.NORMAL);
const bg = add([
sprite("bgCake")
]);
onDraw(() => {
if (!ismobile) {
drawText({
text: "D: ENABLE DEBUG MODE",
size: 30,
pos: vec2(25, 25)
});
drawText({
text: "A: ENABLE AUTOPLAY",
size: 30,
pos: vec2(25, 60)
});
}
drawText({
text: ismobile ? "TAP TO HIT NOTES" : "SPACE/CLICK: HIT NOTE",
size: 30,
pos: ismobile ? vec2(25, 60) : vec2(25, 95)
});
drawText({
text: charts[index.song].characters[index.character][1] + " ("+ (index.character + 1) +"/"+ charts[index.song].characters.length +")",
size: 30,
pos: vec2(width() / 2, 200),
origin: "top"
});
drawText({
text: charts[index.song].name,
size: 30,
pos: vec2(width() / 2, 160),
origin: "top"
});
drawSprite({
sprite: charts[index.song].characters[index.character][0] + "Pre",
width: 64,
height: 64,
pos: vec2((width() / 2) - 34, 248)
});
drawRect({
width: 702,
height: 402,
pos: vec2(-1, -1),
color: BLACK,
opacity: tweenVals.fade
})
})
add([
pos(0, 140),
rect(700, 200),
color(0, 0, 0)
])
var lt = add([
pos(10, 200),
text("<", {
size: 30
}),
area({
height: 30,
offset: ismobile ? vec2(canvas.offsetLeft, canvas.offsetTop) : vec2(0, 0),
width: 30,
cursor: "pointer"
}),
"LeftText"
])
var rt = add([
pos(width() - 10, 200),
origin("topright"),
text(">", {
size: 30
}),
area({
height: 30,
offset: ismobile ? vec2(canvas.offsetLeft, canvas.offsetTop) : vec2(0, 0),
width: 30,
cursor: "pointer"
}),
"RightText"
])
var dt = add([
pos(10, 160),
text("%", {
size: 30
}),
area({
height: 30,
offset: ismobile ? vec2(canvas.offsetLeft, canvas.offsetTop) : vec2(0, 0),
width: 30,
cursor: "pointer"
}),
"DownText"
])
var ut = add([
pos(width() - 10, 160),
origin("topright"),
text("^", {
size: 30
}),
area({
height: 30,
offset: ismobile ? vec2(canvas.offsetLeft, canvas.offsetTop) : vec2(0, 0),
width: 30,
cursor: "pointer"
}),
"UpText"
])
var clickText = add([
pos(width() / 2, height() - 45),
text(ismobile ? "TAP HERE TO START" : "SPACE TO START", {
size: 30
}),
origin("top"),
area({
height: 30,
offset: ismobile ? vec2(canvas.offsetLeft, canvas.offsetTop) : vec2(0, 0),
width: 700,
cursor: "pointer"
}),
"TEXT TEXT"
])
function changeIdx(amt) {
index.character += amt;
if (index.character < 0) {
index.character = charts[index.song].characters.length - 1;
} else if (index.character >= charts[index.song].characters.length) {
index.character = 0;
}
}
function changeSongIdx(amt) {
index.song += amt;
index.character = 0;
if (index.song < 0) {
index.song = charts.length - 1;
} else if (index.song >= charts.length) {
index.song = 0;
}
}
onKeyPress("left", () => {changeIdx(-1)});
onKeyPress("right", () => {changeIdx(1)});
onKeyPress("down", () => {changeSongIdx(-1)});
onKeyPress("up", () => {changeSongIdx(1)});
onKeyPress("`", () => {go("Chart", index.song)});
onKeyPress("D", () => {go("Chart", index.song)});
onKeyPress("/", () => {go("Chart", index.song)});
onKeyPress("7", () => {go("Chart", index.song)});
lt.onClick(() => {changeIdx(-1)});
rt.onClick(() => {changeIdx(1)});
dt.onClick(() => {changeSongIdx(-1)});
ut.onClick(() => {changeSongIdx(1)});
onKeyPress("space", () => {
tween(tweenVals, ["fade"], 1, 0, 1, easings.easeOutCirc, tweentypes.NORMAL, function () {
go("Game", index);
});
});
clickText.onClick(() => {go("Game", index);/*losemus.stop();*/});
});
scene("Title", () => {
const bg = add([
sprite("bgCake")
]);
const jb = add([
sprite("jellybeanTitle"),
pos(0, height() - 320)
]);
const logo = add([
sprite("logo"),
pos(0, 0),
scale(0.5, 0.5)
]);
onDraw(() => {
drawText({
text: "SPACE TO START",
size: 30,
origin: "top",
pos: vec2(width() / 2, height() - 45)
});
})
onKeyPress("space", () => {go("Help", true);/*losemus.stop();*/});
onClick(() => {go("Help", true);/*losemus.stop();*/});
onTouchStart(() => {go("Help", true);/*losemus.stop();*/});
});
scene("Lose", (score, song) => {
const lost = add([
sprite("jellybeanFail"),
"dances",
pos((width() / 2) - 162, height() / 2 - 162)
])
const losemus = play("gameover", {
volume: 1,
loop: true
});
onDraw(() => {
drawText({
text: "OUCHIE!",
size: 60,
pos: vec2(0, height() - 120)
});
drawText({
text: ismobile ? "TAP TO RESTART" : "SPACE TO RESTART",
size: 30,
pos: vec2(0, height() - 60)
});
drawText({
text: "SCORE: " + score,
size: 30,
pos: vec2(0, height() - 30)
});
})
onKeyPress("space", () => {go("Game", song);losemus.stop();});
onClick(() => {go("Game", song);losemus.stop();});
});
scene("Chart", (idx) => {
var chart = charts[idx].chart;
var crochet = ((60 / charts[idx].bpm) * 1000);
var curBeat;
var curStep;
var songTime = 0;
var tool = "J";
const music = play(charts[idx].id, {
volume: 1,
loop: false
});
music.pause();
var lastTargeted = 4;
var tempChart = Array.from(Array(Math.floor((music.duration() * 1000) / (crochet / 4))), () => ".");
// Incredibly redundant, sadly I don't care
var coords = [
width() * 0.1,
width() * 0.2,
width() * 0.3,
width() * 0.4,
width() * 0.5,
width() * 0.6,
width() * 0.7,
width() * 0.8,
width() * 0.9
];
var theEmpty = add([
pos(width() * 0.2, height() * 0.8),
rect(60, 60),
text(".", {
size: 48, // 48 pixels tall
width: 60
}),
color(255, 255, 255),
outline(4, WHITE),
origin("center"),
area(),
"theEmpty"
]);
var theJ = add([
pos(width() * 0.4, height() * 0.8),
rect(60, 60),
text("J", {
size: 48, // 48 pixels tall
width: 60
}),
color(255, 255, 255),
outline(4, WHITE),
origin("center"),
area(),
"theJ"
]);
var theP = add([
pos(width() * 0.6, height() * 0.8),
rect(60, 30),
text("P", {
size: 24, // 48 pixels tall
width: 60
}),
color(255, 255, 255),
outline(4, WHITE),
origin("center"),
area(),
"theP"
]);
var theD = add([
pos(width() * 0.6, height() * 0.8 + 30),
rect(60, 30),
text("D", {
size: 24, // 48 pixels tall
width: 60
}),
color(255, 255, 255),
outline(4, WHITE),
origin("center"),
area(),
"theD"
]);
var consoleButton = add([
pos(width() * 0.8, height() * 0.8),
rect(60, 60),
text("EXPORT", {
size: 30, // 48 pixels tall
}),
color(255, 255, 255),
outline(4, WHITE),
origin("center"),
area(),
"consoleButton"
]);
onClick("theEmpty", (o) => {tool = "."})
onClick("theJ", (o) => {tool = "J"})
onClick("theP", (o) => {tool = "P"})
onClick("theD", (o) => {tool = "D"})
onClick("consoleButton", (o) => {console.log(tempChart.join(""));})
onUpdate(() => {
curBeat = Math.floor(((music.time() * 1000) / crochet) * 10) / 10;
curStep = Math.floor((music.time() * 1000) / (crochet / 4));
if (mousePos().y >= height() * 0.4 && mousePos().y < (height() / 2) + 34) { // I shouldve used a Switch Case here :/
if (mousePos().x < width() * 0.15) {
// blk0
lastTargeted = 0;
} else if (mousePos().x < width() * 0.25) {
// blk1
lastTargeted = 1;
} else if (mousePos().x < width() * 0.35) {
// blk2
lastTargeted = 2;
} else if (mousePos().x < width() * 0.45) {
// blk3
lastTargeted = 3;
} else if (mousePos().x < width() * 0.55) {
// blk4
lastTargeted = 4;
} else if (mousePos().x < width() * 0.65) {
// blk5
lastTargeted = 5;
} else if (mousePos().x < width() * 0.75) {
// blk6
lastTargeted = 6;
} else if (mousePos().x < width() * 0.85) {
// blk7
lastTargeted = 7;
} else if (mousePos().x < width()) {
// blk8
lastTargeted = 8;
}
}
});
onMouseDown(() => {
if (mousePos().y >= height() * 0.4 && mousePos().y < (height() / 2) + 34) {
tempChart[curStep + lastTargeted] = tool;
}
});
onDraw(() => {
drawText({
text: songTime * 1000,
size: 20,
pos: vec2(0, )
});
drawText({
text: music.time() * 1000,
size: 20,
pos: vec2(0, 20)
});
drawText({
text: curBeat,
size: 20,
pos: vec2(0, 40)
});
drawText({
text: curStep + "/" + (tempChart.length - 1),
size: 20,
pos: vec2(0, 60)
});
drawText({
text: tool,
size: 50,
pos: vec2(width() / 2, height() * 0.65),
origin: "center"
});
drawLine({
p1: vec2(coords[lastTargeted] - 30, (height() / 2) + 30),
p2: vec2(coords[lastTargeted] + 30, (height() / 2) + 30),
width: 4,
color: rgb(255, 0, 0),
})
drawText({
text: tempChart[curStep] ? tempChart[curStep] : "",
size: 30,
pos: vec2(coords[0], height() / 2),
color: curStep % 4 == 0 ? RED : MAGENTA,
origin: "center"
})
drawText({
text: tempChart[curStep + 1] ? tempChart[curStep + 1] : "",
size: 30,
pos: vec2(coords[1], height() / 2),
color: (curStep + 1) % 4 == 0 ? RED : WHITE,
origin: "center"
})
drawText({
text: tempChart[curStep + 2] ? tempChart[curStep + 2] : "",
size: 30,
pos: vec2(coords[2], height() / 2),
color: (curStep + 2) % 4 == 0 ? RED : WHITE,
origin: "center"
})
drawText({
text: tempChart[curStep + 3] ? tempChart[curStep + 3] : "",
size: 30,
pos: vec2(coords[3], height() / 2),
color: (curStep + 3) % 4 == 0 ? RED : WHITE,
origin: "center"
})
drawText({
text: tempChart[curStep + 4] ? tempChart[curStep + 4] : "",
size: 30,
pos: vec2(coords[4], height() / 2),
color: (curStep + 4) % 4 == 0 ? RED : WHITE,
origin: "center"
})
drawText({
text: tempChart[curStep + 5] ? tempChart[curStep + 5] : "",
size: 30,
pos: vec2(coords[5], height() / 2),
color: (curStep + 5) % 4 == 0 ? RED : WHITE,
origin: "center"
})
drawText({
text: tempChart[curStep + 6] ? tempChart[curStep + 6] : "",
size: 30,
pos: vec2(coords[6], height() / 2),
color: (curStep + 6) % 4 == 0 ? RED : WHITE,
origin: "center"
})
drawText({
text: tempChart[curStep + 7] ? tempChart[curStep + 7] : "",
size: 30,
pos: vec2(coords[7], height() / 2),
color: (curStep + 7) % 4 == 0 ? RED : WHITE,
origin: "center"
})
drawText({
text: tempChart[curStep + 8] ? tempChart[curStep + 8] : "",
size: 30,
pos: vec2(coords[8], height() / 2),
color: (curStep + 8) % 4 == 0 ? RED : WHITE,
origin: "center"
})
});
onKeyPress("left", () => {
music.pause();
songTime = songTime - ((crochet / 4) / 1000);
try {
music.play(songTime);
} catch (err) {
console.log(err);
songTime = 0;
music.play(0);
}
music.pause();
});
onKeyPress("right", () => {
music.pause();
songTime = songTime + ((crochet / 4) / 1000);
try {
music.play(songTime);
} catch (err) {
console.log(err);
songTime = 0;
music.play(0);
}
music.pause();
});
onKeyPress("space", () => {
if (!music.isPaused()) {
music.pause();
songTime = music.time();
} else {
try {
music.play(songTime);
} catch (err) {
console.log(err);
songTime = 0;
music.play(0);
}
}
});
});
go("Title");

View file

@ -0,0 +1,6 @@
import kaboom from "https://unpkg.com/kaboom@2000.2.9/dist/kaboom.mjs";
import { easings, tween, tweentypes } from "./code/easing.js"
export {
kaboom, easings, tween, tweentypes
}

View file

@ -0,0 +1,17 @@
<!DOCTYPE html>
<html style="height: 100vh; width: 100vw; overflow: hidden; margin: 0; padding: 0;">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<title>Mid Sim</title>
</head>
<body style="background-color: black; height: 100vh; width: 100vw; margin: 0; padding: 0; overflow: hidden;">
<canvas id="kaboom"></canvas>
<script src="code/main.js" type="module"></script> <!-- I hate how the scrollbar is still there on Replit -->
<style>
#kaboom {position: absolute;top: calc(50vh - 200px);left: calc(50vw - 350px);}
</style>
</body>
</html>

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 37 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 187 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 944 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 68 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 249 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 206 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 230 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 173 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 179 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 236 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 283 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 287 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

View file

@ -0,0 +1,59 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>MTRUWSaDMfHTML5</title>
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link rel="stylesheet" href="/styles/normal.css" />
<link rel="stylesheet" href="/styles/windows.css" />
<link rel="stylesheet" href="./styles/endplorer.css" />
<style>
@import url("https://fonts.googleapis.com/css2?family=Lexend+Deca:wght@100;200;300;400;500;600;700;800;900&display=swap");
:root {
--base-scale: 16px;
--background-color: hsl(0, 0%, 15%);
--color: hsl(0, 0%, 85%);
--accent-color: hsl(0, 0%, 50%);
--accent-color-fg: hsl(0, 0%, 95%);
--font-family: "Lexend Deca";
--document-width: 40em;
}
</style>
</head>
<body>
<$ loader.html $>
<header>
<section>
<h1>MTRUWSaDMfHTML5</h1>
</section>
<section id="accessibility" hidden></section>
</header>
<section>
<button
onclick="window.top.manager.createWindow('./pages/welcome.html', false)"
>
Test</button
><br />
<input id="url" type="url" />
<button
onclick="window.top.manager.createWindow(document.querySelector('#url').value, false)"
>
Open URL
</button>
</section>
<div id="WindowHolder"></div>
<script src="./scripts/endplorer.js"></script>
<script src="/scripts/windows.js"></script>
<script src="/scripts/accessibility.js"></script>
<script src="/scripts/interface.js"></script>
<script>
window.manager = new WindowManager(
document.getElementById("WindowHolder")
);
window.taskbar = new TaskbarObject(window.top.manager);
window.top.manager.createWindow("./pages/welcome.html", false);
</script>
</body>
</html>

View file

@ -0,0 +1,33 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>Welcome!</title>
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link rel="stylesheet" href="/styles/normal.css" />
<style>
@import url("https://fonts.googleapis.com/css2?family=Lexend+Deca:wght@100;200;300;400;500;600;700;800;900&display=swap");
:root {
--font-family: "Lexend Deca";
}
</style>
</head>
<body>
<$ loader.html $>
<header>
<section>
<h1>Welcome to MTRUWSaDMfHTML5!</h1>
<p>
(MeowcaTheoRange's Unnecessary Windowing System and Desktop Manager
for HTML5)
</p>
<p>A basic windowing system made in HTML5 and JavaScript.</p>
</section>
<section id="accessibility" hidden></section>
</header>
<section id="accessibility" hidden></section>
<script src="/scripts/accessibility.js"></script>
<script src="/scripts/interface.js"></script>
</body>
</html>

View file

@ -0,0 +1,110 @@
class TaskbarObject {
parentManager;
taskbarObject;
taskbarStart;
children;
constructor(manager) {
this.parentManager = manager;
this.taskbarObject = TaskbarObject.createTaskbar(this);
this.parentManager.addExtension(this, "taskbarObject");
this.parentManager.overscan_bottom = "2.5625em";
this.taskbarStart = this.taskbarObject.querySelector(".taskbar-start");
this.children = [];
this.parentManager.managerObject.addEventListener("windowcreate", (e) =>
this.addToTabs(e)
);
this.parentManager.managerObject.addEventListener("windowdestroy", (e) =>
this.removeFromTabs(e)
);
this.parentManager.managerObject.addEventListener("windowfocus", (e) =>
this.refocusTabs(e)
);
this.parentManager.managerObject.addEventListener(
"windowmanager_title",
(e) => this.updateTab(e)
);
}
addToTabs(e) {
const button = document.createElement("button");
button.classList.add("taskbar-button");
button.addEventListener("click", (e2) => this.event_raiseWindow(e, e2));
console.log(button);
this.children.splice(e.detail.windowId, 0, button);
this.taskbarStart.appendChild(button);
}
removeFromTabs(e) {
const button = this.children[e.detail.windowId];
console.log(this.children, e.detail.windowId);
this.children.splice(e.detail.windowId, 1);
this.taskbarStart.removeChild(button);
}
updateTab(e, mode) {
const button = this.children[e.detail.windowId];
button.textContent = e.detail.title;
}
refocusTabs(e) {
this.parentManager.children.forEach((child) => {
if (child.focusOrder <= 0) {
this.children[child.windowId].classList.add("taskbar-button-focusing");
} else
this.children[child.windowId].classList.remove(
"taskbar-button-focusing"
);
});
}
destroy() {
this.parentManager.overscan_bottom = "0px";
}
event_raiseWindow(e, e2) {
if (e.detail.focusOrder <= 0) {
e.detail.minimizeWindow();
} else {
this.parentManager.raiseWindow(e.detail);
}
refocusTabs();
}
static createTaskbar(taskbarRef) {
const taskbarObject = document.createElement("div");
taskbarObject.classList.add("taskbar-object");
taskbarObject.tabIndex = "0";
taskbarObject.style.zIndex = taskbarRef.parentManager.maxZIndex + 1;
{
const taskbarStart = document.createElement("div");
taskbarStart.classList.add("taskbar-start");
taskbarObject.appendChild(taskbarStart);
}
{
const taskbarEnd = document.createElement("div");
taskbarEnd.classList.add("taskbar-end");
taskbarObject.appendChild(taskbarEnd);
}
return taskbarObject;
}
}

View file

@ -0,0 +1,46 @@
.taskbar-object {
position: fixed;
width: 100%;
left: 0;
bottom: 0;
display: grid;
grid-template-columns: auto auto;
vertical-align: middle;
user-select: none;
background-color: var(--accent-color);
color: var(--accent-color-fg);
border: var(--border-style);
overflow: hidden;
padding: 0.25em;
}
.taskbar-object > .taskbar-start {
text-align: start;
height: 2em;
}
.taskbar-object > .taskbar-end {
text-align: end;
height: 2em;
}
.taskbar-object > .taskbar-start > button {
height: 2em;
padding: 0.5em;
margin: 0;
margin-inline-end: 0.25em;
border: var(--border-style);
background-color: transparent;
color: currentColor;
text-align: center;
vertical-align: middle;
font-size: 1em;
line-height: 1em;
}
.taskbar-object > .taskbar-start > button.taskbar-button-focusing {
background-color: var(--accent-color-fg);
color: var(--accent-color);
}

View file

Before

Width:  |  Height:  |  Size: 453 KiB

After

Width:  |  Height:  |  Size: 453 KiB

View file

Before

Width:  |  Height:  |  Size: 821 KiB

After

Width:  |  Height:  |  Size: 821 KiB

View file

Before

Width:  |  Height:  |  Size: 677 KiB

After

Width:  |  Height:  |  Size: 677 KiB

View file

Before

Width:  |  Height:  |  Size: 827 KiB

After

Width:  |  Height:  |  Size: 827 KiB

View file

Before

Width:  |  Height:  |  Size: 740 KiB

After

Width:  |  Height:  |  Size: 740 KiB

Some files were not shown because too many files have changed in this diff Show more