update CHIM to js-dos v8, update maze to latest

This commit is contained in:
Eric Woodward 2025-07-06 12:24:01 -04:00
parent 440cd959fa
commit efc6bca786
102 changed files with 68554 additions and 534 deletions

View File

@ -1,6 +1,6 @@
{ {
"name": "iew-site", "name": "iew-site",
"version": "0.14.0", "version": "0.14.1",
"description": "", "description": "",
"main": "index.js", "main": "index.js",
"scripts": {}, "scripts": {},

Binary file not shown.

View File

@ -1,348 +0,0 @@
/*!
* jQLite JavaScript Library v1.1.1 (http://code.google.com/p/jqlite/)
* Copyright (c) 2010 Brett Fattori (bfattori@gmail.com)
* Licensed under the MIT license
* http://www.opensource.org/licenses/mit-license.php
*
* Many thanks to the jQuery team's efforts. Some code is
* Copyright (c) 2010, John Resig. See
* http://jquery.org/license
*
* @author Brett Fattori (bfattori@gmail.com)
* @author $Author: bfattori $
* @version $Revision: 145 $
*
* Created: 03/29/2010
* Modified: $Date: 2010-06-21 11:08:14 -0400 (Mon, 21 Jun 2010) $
*/
(function(){function B(){return+new Date}var D=function(a,b){if(a===""&&b)return b;var d=a.split(" "),c=d.shift(),e;if(c.charAt(0)=="#"){var g=i.getElementById(c.substring(1));e=g?[g]:[]}else{e=c.charAt(0)!=="."?c.split(".")[0]:"*";var h=c.split("."),j=null;if(e.indexOf("[")!=-1){j=e;e=e.substr(0,e.indexOf("["))}g=function(o){var n=arguments.callee,k;if(!(k=!n.needClass)){k=n.classes;if(o.className.length==0)k=false;else{for(var r=o.className.split(" "),l=k.length,p=0;p<k.length;p++)f.inArray(k[p],
r)!=-1&&l--;k=l==0}}if(k=k){if(!(k=!n.needAttribute)){n=n.attributes;k=true;for(r=0;r<n.length;r++){l=n[r].split("=");p=l[0].indexOf("!")!=-1||l[0].indexOf("*")!=-1?l[0].charAt(l[0].length-1)+"=":"=";if(p!="=")l[0]=l[0].substring(0,l[0].length-1);switch(p){case "=":k&=o.getAttribute(l[0])===l[1];break;case "!=":k&=o.getAttribute(l[0])!==l[1];break;case "*=":k&=o.getAttribute(l[0]).indexOf(l[1])!=-1;break;default:k=false}}k=k}k=k}if(k)return o};for(var u=[],s=0;s<b.length;s++)for(var C=b[s].getElementsByTagName(e),
v=0;v<C.length;v++)u.push(C[v]);h&&h.shift();e=[];g.classes=h;if(j!=null){var w=j.indexOf("[");s=j.lastIndexOf("]");w=j.substring(w+1,s).split("][")}g.attributes=j!=null?w:null;g.needClass=c.indexOf(".")!=-1&&h.length>0;g.needAttribute=j!=null;for(c=0;c<u.length;c++)g(u[c])&&e.push(u[c])}return D(d.join(" "),e)},Q=function(a,b){b=b||i;if(a.nodeType&&a.nodeType===E){a=i.body;if(a===null)return[i]}if(a.nodeType&&a.nodeType===m)return[a];if(a.jquery&&typeof a.jquery==="string")return a.toArray();if(b)b=
F(b);if(f.isArray(a))return a;else if(typeof a==="string"){for(var d=[],c=0;c<b.length;c++){var e=[b[c]];if(!f.forceSimpleSelectorEngine&&e[0].querySelectorAll){e=e[0].querySelectorAll(a);for(var g=0;g<e.length;g++)d.push(e.item(g))}else d=d.concat(D(a,e))}return d}else return null},G=false;setTimeout(function(){var a=i.body;if(a){var b=i.createElement("script"),d="i"+(new Date).getTime();b.type="text/javascript";try{b.appendChild(i.createTextNode("window."+d+"=1;"))}catch(c){}a.insertBefore(b,a.firstChild);
var e=true;if(window[d])delete window[d];else e=false;a.removeChild(b);G=e}else setTimeout(arguments.callee,33)},33);var H=function(a){var b=i.createElement("div");b.innerHTML=a;return{scripts:b.getElementsByTagName("script"),data:a}},I=function(a){a=a.replace(/-/g," ");a=a;var b=true;b=b||false;a=!a?"":a.toString().replace(/^\s*|\s*$/g,"");var d="";if(a.length<=0)a="";else{var c=false;d+=b?a.charAt(0):a.charAt(0).toUpperCase();for(b=1;b<a.length;b++){d+=c?a.charAt(b).toUpperCase():a.charAt(b).toLowerCase();
var e=a.charCodeAt(b);c=e==32||e==45||e==46;if(e==99||e==67)if(a.charCodeAt(b-1)==77||a.charCodeAt(b-1)==109)c=true}a=d}return a.replace(/ /g,"")},J={click:"MouseEvents",dblclick:"MouseEvents",mousedown:"MouseEvents",mouseup:"MouseEvents",mouseover:"MouseEvents",mousemove:"MouseEvents",mouseout:"MouseEvents",contextmenu:"MouseEvents",keypress:"KeyEvents",keydown:"KeyEvents",keyup:"KeyEvents",load:"HTMLEvents",unload:"HTMLEvents",abort:"HTMLEvents",error:"HTMLEvents",resize:"HTMLEvents",scroll:"HTMLEvents",
select:"HTMLEvents",change:"HTMLEvents",submit:"HTMLEvents",reset:"HTMLEvents",focus:"HTMLEvents",blur:"HTMLEvents",touchstart:"MouseEvents",touchend:"MouseEvents",touchmove:"MouseEvents"},K=function(a,b,d){if(f.isFunction(d)){if(typeof b==="string")b=b.toLowerCase();var c=J[b];if(b.indexOf("on")==0)b=b.substring(2);if(c){c=function(e){var g=arguments.callee,h=e.data||[];h.unshift(e);g=g.fn.apply(a,h);if(typeof g!="undefined"&&g===false){if(e.preventDefault&&e.stopPropagation){e.preventDefault();
e.stopPropagation()}else{e.returnValue=false;e.cancelBubble=true}return false}return true};c.fn=d;a.addEventListener?a.addEventListener(b,c,false):a.attachEvent("on"+b,c)}else{if(!a._handlers)a._handlers={};c=a._handlers[b]||[];c.push(d);a._handlers[b]=c}}},f=function(a,b){return(new x).init(a,b)},i=window.document,y=Object.prototype.hasOwnProperty,z=Object.prototype.toString,L=Array.prototype.push,R=Array.prototype.slice,m=1,E=9,A=[],M=false,N=false,q;f.forceSimpleSelectorEngine=false;f.each=function(a,
b){var d,c=0,e=a.length;if(e===undefined||f.isFunction(a))for(d in a){if(b.call(a[d],d,a[d])===false)break}else for(d=a[0];c<e&&b.call(d,c,d)!==false;d=a[++c]);return a};f.noop=function(){};f.isFunction=function(a){return z.call(a)==="[object Function]"};f.isArray=function(a){return z.call(a)==="[object Array]"};f.isPlainObject=function(a){if(!a||z.call(a)!=="[object Object]"||a.nodeType||a.setInterval)return false;if(a.constructor&&!y.call(a,"constructor")&&!y.call(a.constructor.prototype,"isPrototypeOf"))return false;
var b;for(b in a);return b===undefined||y.call(a,b)};f.merge=function(a,b){var d=a.length,c=0;if(typeof b.length==="number")for(var e=b.length;c<e;c++)a[d++]=b[c];else for(;b[c]!==undefined;)a[d++]=b[c++];a.length=d;return a};f.param=function(a){var b="";a&&f.each(a,function(d,c){b+=(b.length!=0?"&":"")+c+"="+encodeURIComponent(d)});return b};f.evalScripts=function(a){for(var b=i.getElementsByTagName("head")[0]||i.documentElement,d=0;d<a.length;d++){var c=i.createElement("script");c.type="text/javascript";
if(G)c.appendChild(i.createTextNode(a[d].text));else c.text=a[d].text;b.insertBefore(c,b.firstChild);b.removeChild(c)}};f.ready=function(){for(M=true;A.length>0;)A.shift()()};var t="jQuery"+B(),S=0,O={};f.noData={embed:true,object:true,applet:true};f.cache={};f.data=function(a,b,d){if(!(a.nodeName&&jQuery.noData[a.nodeName.toLowerCase()])){a=a==window?O:a;var c=a[t];c||(c=a[t]=++S);if(b&&!jQuery.cache[c])jQuery.cache[c]={};if(d!==undefined)jQuery.cache[c][b]=d;return b?jQuery.cache[c][b]:c}};f.removeData=
function(a,b){a=a==window?O:a;var d=a[t];if(b){if(jQuery.cache[d]){delete jQuery.cache[d][b];b="";for(b in jQuery.cache[d])break;b||jQuery.removeData(a)}}else{try{delete a[t]}catch(c){a.removeAttribute&&a.removeAttribute(t)}delete jQuery.cache[d]}};f.ajax={status:-1,statusText:"",responseText:null,responseXML:null,send:function(a,b,d){if(f.isFunction(b)){d=b;b={}}if(a){var c=true,e=null,g=null;if(typeof b.async!=="undefined"){c=b.async;delete b.async}if(typeof b.username!=="undefined"){e=b.username;
delete b.username}if(typeof b.password!=="undefined"){g=b.password;delete b.password}b=f.param(b);if(b.length!=0)a+=(a.indexOf("?")==-1?"?":"&")+b;b=new XMLHttpRequest;b.open("GET",a,c,e,g);b.send();if(c){a=function(h){var j=arguments.callee;h.status==200?f.ajax.complete(h,j.cb):f.ajax.error(h,j.cb)};a.cb=d;d=function(){var h=arguments.callee;h.req.readyState!=4?setTimeout(h,250):h.xcb(h.req)};d.req=b;d.xcb=a;setTimeout(d,250)}}},complete:function(a,b){f.ajax.status=a.status;f.ajax.responseText=a.responseText;
f.ajax.responseXML=a.responseXML;f.isFunction(b)&&b(a.responseText,a.status)},error:function(a,b){f.ajax.status=a.status;f.ajax.statusText=a.statusText;f.isFunction(b)&&b(a.status,a.statusText)}};f.makeArray=function(a,b){var d=b||[];if(a!=null)a.length==null||typeof a==="string"||jQuery.isFunction(a)||typeof a!=="function"&&a.setInterval?L.call(d,a):f.merge(d,a);return d};f.inArray=function(a,b){for(var d=0;d<b.length;d++)if(b[d]===a)return d;return-1};f.trim=function(a){return a!=null?a.toString().replace(/^\s*|\s*$/g,
""):""};var x=function(){};x.prototype={selector:"",context:null,length:0,jquery:"jqlite-1.1.1",init:function(a,b){if(!a)return this;if(a.nodeType){this.context=this[0]=a;this.length=1}else if(typeof a==="function")this.ready(a);else{var d=[];if(a.jquery&&typeof a.jquery==="string")d=a.toArray();else if(f.isArray(a))d=a;else if(typeof a==="string"&&f.trim(a).indexOf("<")==0&&f.trim(a).indexOf(">")!=-1){d=f.trim(a).toLowerCase();d=d.indexOf("<option")==0?"SELECT":d.indexOf("<li")==0?"UL":d.indexOf("<tr")==
0?"TBODY":d.indexOf("<td")==0?"TR":"DIV";d=i.createElement(d);d.innerHTML=a;d=[d.removeChild(d.firstChild)]}else{if(a.indexOf(",")!=-1){d=a.split(",");for(var c=0;c<d.length;c++)d[c]=f.trim(d[c])}else d=[a];c=[];for(var e=0;e<d.length;e++)c=c.concat(Q(d[e],b));d=c}L.apply(this,d)}return this},each:function(a){return f.each(this,a)},size:function(){return this.length},toArray:function(){return R.call(this,0)},ready:function(a){if(M)a();else{A.push(a);return this}},data:function(a,b){if(typeof a===
"undefined"&&this.length)return jQuery.data(this[0]);else if(typeof a==="object")return this.each(function(){jQuery.data(this,a)});var d=a.split(".");d[1]=d[1]?"."+d[1]:"";if(b===undefined){if(data===undefined&&this.length)data=jQuery.data(this[0],a);return data===undefined&&d[1]?this.data(d[0]):data}else return this.each(function(){jQuery.data(this,a,b)})},removeData:function(a){return this.each(function(){jQuery.removeData(this,a)})},addClass:function(a){return this.each(function(){if(this.className.length!=
0){var b=this.className.split(" ");if(f.inArray(a,b)==-1){b.push(a);this.className=b.join(" ")}}else this.className=a})},removeClass:function(a){return this.each(function(){if(this.className.length!=0){var b=this.className.split(" "),d=f.inArray(a,b);if(d!=-1){b.splice(d,1);this.className=b.join(" ")}}})},hasClass:function(a){if(this[0].className.length==0)return false;return f.inArray(a,this[0].className.split(" "))!=-1},isElementName:function(a){return this[0].nodeName.toLowerCase()===a.toLowerCase()},
toggleClass:function(a){return this.each(function(){if(this.className.length==0)this.className=a;else{var b=this.className.split(" "),d=f.inArray(a,b);d!=-1?b.splice(d,1):b.push(a);this.className=b.join(" ")}})},hide:function(a){return this.each(function(){if(this.style&&this.style.display!=null)if(this.style.display.toString()!="none"){this._oldDisplay=this.style.display.toString()||(this.nodeName!="span"?"block":"inline");this.style.display="none"}f.isFunction(a)&&a(this)})},show:function(a){return this.each(function(){this.style.display=
(this._oldDisplay&&this._oldDisplay!=""?this._oldDisplay:null)||(this.nodeName!="span"?"block":"inline");f.isFunction(a)&&a(this)})},css:function(a,b){if(typeof a==="string"&&b==null)return this[0].style[I(a)];else{a=typeof a==="string"?P(a,b):a;return this.each(function(){var d=this;typeof d.style!="undefined"&&f.each(a,function(c,e){e=typeof e==="number"?e+"px":e;var g=I(c);d.style[g]||(g=c);d.style[g]=e})})}},load:function(a,b,d){if(f.isFunction(b)){d=b;b={}}return this.each(function(){var c=function(e,
g){var h=arguments.callee;if(e){var j=H(e);h.elem.innerHTML=j.data;f.evalScripts(j.scripts)}f.isFunction(h.cback)&&h.cback(e,g)};c.cback=d;c.elem=this;f.ajax.send(a,b,c)})},html:function(a){return a?this.each(function(){var b=H(a);this.innerHTML=b.data;f.evalScripts(b.scripts)}):this[0].innerHTML},attr:function(a,b){return typeof a==="string"&&b==null?this[0]?this[0].getAttribute(a):"":this.each(function(){a=typeof a==="string"?P(a,b):a;for(var d in a)this.setAttribute(d,a[d])})},eq:function(a){var b=
this.toArray();this.context=this[0]=a<0?b[b.length+a]:b[a];this.length=1;return this},first:function(){this.context=this[0]=this.toArray()[0];this.length=1;return this},last:function(){var a=this.toArray();this.context=this[0]=a[a.length-1];this.length=1;return this},index:function(a){var b=-1;if(this.length!=0){var d=this[0];if(a){var c=f(a)[0];this.each(function(g){if(this===c){b=g;return false}})}else{a=this.parent()[0].firstChild;for(var e=[];a!=null;){a.nodeType===m&&e.push(a);a=a.nextSibling}f.each(a,
function(g){if(this===d){b=g;return false}})}}return b},next:function(a){var b=[];if(a){var d=f(a);this.each(function(){for(var c=this.nextSibling;c!=null&&c.nodeType!==m;)c=c.nextSibling;if(c!=null){var e=false;d.each(function(){if(this==c){e=true;return false}});e&&b.push(c)}})}else this.each(function(){for(var c=this.nextSibling;c!=null&&c.nodeType!==m;)c=c.nextSibling;c!=null&&b.push(c)});return f(b)},prev:function(a){var b=[];if(a){var d=f(a);this.each(function(){for(var c=this.previousSibling;c!=
null&&c.nodeType!==m;)c=c.previousSibling;if(c!=null){var e=false;d.each(function(){if(this==c){e=true;return false}});e&&b.push(c)}})}else this.each(function(){for(var c=this.previousSibling;c!=null&&c.nodeType!==m;)c=c.previousSibling;c!=null&&b.push(c)});return f(b)},parent:function(a){var b=[];if(a){var d=f(a);this.each(function(){var c=this.parentNode,e=false;d.each(function(){if(this==c){e=true;return false}});e&&b.push(c)})}else this.each(function(){b.push(this.parentNode)});return f(b)},parents:function(a){var b=
[];if(a){var d=f(a);this.each(function(){for(var c=this;c!=i.body;){d.each(function(){this==c&&b.push(c)});c=c.parentNode}})}else this.each(function(){for(var c=this;c!=i.body;){c=c.parentNode;b.push(c)}});return f(b)},children:function(a){var b=[];if(a){var d=f(a);this.each(function(){for(var c=this.firstChild;c!=null;){c.nodeType==m&&d.each(function(){this===c&&b.push(c)});c=c.nextSibling}})}else this.each(function(){for(var c=this.firstChild;c!=null;){c.nodeType==m&&b.push(c);c=c.nextSibling}});
return f(b)},append:function(a){a=F(a);return this.each(function(){for(var b=0;b<a.length;b++)this.appendChild(a[b])})},remove:function(a){return this.each(function(){a?$(a,this).remove():this.parentNode.removeChild(this)})},empty:function(){return this.each(function(){this.innerHTML=""})},val:function(a){if(a==null){var b=null;if(this&&this.length!=0&&typeof this[0].value!="undefined")b=this[0].value;return b}else return this.each(function(){if(typeof this.value!="undefined")this.value=a})},bind:function(a,
b){return this.each(function(){K(this,a,b)})},trigger:function(a,b){return this.each(function(){var d;var c;c=a;if(typeof c==="string")c=c.toLowerCase();var e=null,g=J[c]||"Event";if(i.createEvent){e=i.createEvent(g);e._eventClass=g;c&&e.initEvent(c,true,true)}if(i.createEventObject){e=i.createEventObject();if(c){e.type=c;e._eventClass=g}}c=e;if(c._eventClass!=="Event"){c.data=b;d=this.dispatchEvent(c)}else if(e=(this._handlers||{})[a])for(g=0;g<e.length;g++){var h=f.isArray(b)?b:[];h.unshift(c);
h=e[g].apply(this,h);if(!(typeof h=="undefined"?true:h))break}return d})},submit:function(a){return this.each(function(){if(f.isFunction(a))K(this,"onsubmit",a);else this.submit&&this.submit()})}};if(i.addEventListener)q=function(){i.removeEventListener("DOMContentLoaded",q,false);f.ready()};else if(i.attachEvent)q=function(){if(i.readyState==="complete"){i.detachEvent("onreadystatechange",q);f.ready()}};if(!N){N=true;if(i.readyState==="complete")return f.ready();if(i.addEventListener){i.addEventListener("DOMContentLoaded",
q,false);window.addEventListener("load",f.ready,false)}else if(i.attachEvent){i.attachEvent("onreadystatechange",q);window.attachEvent("onload",f.ready)}}var P=function(a,b){var d={};d[a]=b;return d},F=function(a){if(a.nodeType&&(a.nodeType===m||a.nodeType===E))a=[a];else if(typeof a==="string")a=f(a).toArray();else if(a.jquery&&typeof a.jquery==="string")a=a.toArray();return a};if(typeof window.jQuery=="undefined"){window.jQuery=f;window.jQuery.fn=x.prototype;window.$=window.jQuery;window.now=B}jQuery.extend=
jQuery.fn.extend=function(){var a=arguments[0]||{},b=1,d=arguments.length,c=false,e,g,h,j;if(typeof a==="boolean"){c=a;a=arguments[1]||{};b=2}if(typeof a!=="object"&&!jQuery.isFunction(a))a={};if(d===b){a=this;--b}for(;b<d;b++)if((e=arguments[b])!=null)for(g in e){h=a[g];j=e[g];if(a!==j)if(c&&j&&(jQuery.isPlainObject(j)||jQuery.isArray(j))){h=h&&(jQuery.isPlainObject(h)||jQuery.isArray(h))?h:jQuery.isArray(j)?[]:{};a[g]=jQuery.extend(c,h,j)}else if(j!==undefined)a[g]=j}return a};jQuery.each("click,dblclick,mouseover,mouseout,mousedown,mouseup,keydown,keypress,keyup,focus,blur,change,select,error,load,unload,scroll,resize,touchstart,touchend,touchmove".split(","),
function(a,b){jQuery.fn[b]=function(d){return d?this.bind(b,d):this.trigger(b)}})})();
(function() {
this.Dosbox = (function() {
function Dosbox(options) {
this.onload = options.onload;
this.onrun = options.onrun;
this.ui = new Dosbox.UI(options);
this.module = new Dosbox.Module({
canvas: this.ui.canvas
});
this.ui.onStart((function(_this) {
return function() {
_this.ui.showLoader();
return _this.downloadScript();
};
})(this));
}
Dosbox.prototype.run = function(archiveUrl, executable) {
return new Dosbox.Mount(this.module, archiveUrl, {
success: (function(_this) {
return function() {
var func, hide;
_this.ui.updateMessage("Launching " + executable);
hide = function() {
return _this.ui.hideLoader();
};
func = function() {
return _this._dosbox_main(_this, executable);
};
setTimeout(func, 1000);
return setTimeout(hide, 3000);
};
})(this),
progress: (function(_this) {
return function(total, current) {
return _this.ui.updateMessage("Mount " + executable + " (" + (current * 100 / total | 0) + "%)");
};
})(this)
});
};
Dosbox.prototype.requestFullScreen = function() {
if (this.module.requestFullScreen) {
return this.module.requestFullScreen(true, false);
}
};
Dosbox.prototype.downloadScript = function() {
this.module.setStatus('Downloading js-dos');
this.ui.updateMessage('Downloading js-dos');
return new Dosbox.Xhr('https://js-dos.com/cdn/js-dos-v3.js', {
success: (function(_this) {
return function(script) {
var func;
_this.ui.updateMessage('Initializing dosbox');
func = function() {
return _this._jsdos_init(_this.module, script, _this.onload);
};
return setTimeout(func, 1000);
};
})(this),
progress: (function(_this) {
return function(total, current) {
return _this.ui.updateMessage("Downloading js-dos (" + (current * 100 / total | 0) + "%)");
};
})(this)
});
};
Dosbox.prototype._jsdos_init = function(module, script, onload) {
var Module;
Module = module;
eval(script);
if (onload) {
return onload(this);
}
};
Dosbox.prototype._dosbox_main = function(dosbox, executable) {
var exception, func;
try {
if (dosbox.onrun) {
func = function() {
return dosbox.onrun(dosbox, executable);
};
setTimeout(func, 1000);
}
return dosbox.module.ccall('dosbox_main', 'int', ['string'], [executable]);
} catch (error) {
exception = error;
if (exception === 'SimulateInfiniteLoop') {
} else {
return typeof console !== "undefined" && console !== null ? typeof console.error === "function" ? console.error(exception) : void 0 : void 0;
}
}
};
return Dosbox;
})();
}).call(this);
(function() {
Dosbox.Module = (function() {
function Module(options) {
this.elCanvas = options.canvas;
this.canvas = this.elCanvas[0];
}
Module.prototype.preRun = [];
Module.prototype.postRun = [];
Module.prototype.totalDependencies = 0;
Module.prototype.print = function(text) {
text = Array.prototype.slice.call(arguments).join(' ');
return typeof console !== "undefined" && console !== null ? typeof console.log === "function" ? console.log(text) : void 0 : void 0;
};
Module.prototype.printErr = function(text) {
text = Array.prototype.slice.call(arguments).join(' ');
return typeof console !== "undefined" && console !== null ? typeof console.error === "function" ? console.error(text) : void 0 : void 0;
};
Module.prototype.setStatus = function(text) {
return typeof console !== "undefined" && console !== null ? typeof console.log === "function" ? console.log(text) : void 0 : void 0;
};
Module.prototype.monitorRunDependencies = function(left) {
var status;
this.totalDependencies = Math.max(this.totalDependencies, left);
status = left ? "Preparing... (" + (this.totalDependencies - left) + "/" + this.totalDependencies + ")" : 'All downloads complete.';
return this.setStatus(status);
};
return Module;
})();
}).call(this);
(function() {
Dosbox.Mount = (function() {
function Mount(module, url, options) {
this.module = module;
new Dosbox.Xhr(url, {
success: (function(_this) {
return function(data) {
var bytes;
bytes = _this._toArray(data);
if (_this._mountZip(bytes)) {
return options.success();
} else {
return typeof console !== "undefined" && console !== null ? typeof console.error === "function" ? console.error('Unable to mount', url) : void 0 : void 0;
}
};
})(this),
progress: options.progress
});
}
Mount.prototype._mountZip = function(bytes) {
var buffer, extracted;
buffer = this.module._malloc(bytes.length);
this.module.HEAPU8.set(bytes, buffer);
extracted = this.module.ccall('extract_zip', 'int', ['number', 'number'], [buffer, bytes.length]);
this.module._free(buffer);
return extracted === 0;
};
Mount.prototype._toArray = function(data) {
var arr, i, len;
if (typeof data === 'string') {
arr = new Array(data.length);
i = 0;
len = data.length;
while (i < len) {
arr[i] = data.charCodeAt(i);
++i;
}
return arr;
}
return data;
};
return Mount;
})();
}).call(this);
(function() {
Dosbox.UI = (function() {
function UI(options) {
this.appendCss();
this.div = $('#' + (options.id || 'dosbox'));
this.wrapper = $('<div class="dosbox-container">');
this.canvas = $('<canvas class="dosbox-canvas" oncontextmenu="event.preventDefault()">');
this.overlay = $('<div class="dosbox-overlay">');
this.loaderMessage = $('<div class="dosbox-loader-message">');
this.loader = $('<div class="dosbox-loader">').append($('<div class="st-loader">').append($('<span class="equal">'))).append(this.loaderMessage);
this.start = $('<div class="dosbox-start">Click to start');
this.div.append(this.wrapper);
this.wrapper.append(this.canvas);
this.wrapper.append(this.loader);
this.wrapper.append(this.overlay);
this.overlay.append($('<div class="dosbox-powered">Powered by &nbsp;').append($('<a href="http://js-dos.com">js-dos.com')));
this.overlay.append(this.start);
}
UI.prototype.onStart = function(fun) {
return this.start.click((function(_this) {
return function() {
fun();
return _this.overlay.hide();
};
})(this));
};
UI.prototype.appendCss = function() {
var head, style;
head = document.head || document.getElementsByTagName('head')[0];
style = document.createElement('style');
style.type = 'text/css';
if (style.styleSheet) {
style.styleSheet.cssText = this.css;
} else {
style.appendChild(document.createTextNode(this.css));
}
return head.appendChild(style);
};
UI.prototype.showLoader = function() {
this.loader.show();
return this.loaderMessage.html('');
};
UI.prototype.updateMessage = function(message) {
return this.loaderMessage.html(message);
};
UI.prototype.hideLoader = function() {
return this.loader.hide();
};
UI.prototype.css = '.dosbox-container { position: relative; min-width: 320px; min-height: 200px; } .dosbox-canvas { } .dosbox-overlay, .dosbox-loader { position: absolute; left: 0; right: 0; top: 0; bottom: 0; background-color: #333; } .dosbox-start { text-align: center; position: absolute; left: 0; right: 0; bottom: 50%; color: #f80; font-size: 1.5em; text-decoration: underline; cursor: pointer; } .dosbox-overlay a { color: #f80; } .dosbox-loader { display: none; } .dosbox-powered { position: absolute; right: 1em; bottom: 1em; font-size: 0.8em; color: #9C9C9C; } .dosbox-loader-message { text-align: center; position: absolute; left: 0; right: 0; bottom: 50%; margin: 0 0 -3em 0; box-sizing: border-box; color: #f80; font-size: 1.5em; } @-moz-keyframes loading { 0% { left: 0; } 50% { left: 8.33333em; } 100% { left: 0; } } @-webkit-keyframes loading { 0% { left: 0; } 50% { left: 8.33333em; } 100% { left: 0; } } @keyframes loading { 0% { left: 0; } 50% { left: 8.33333em; } 100% { left: 0; } } .st-loader { width: 10em; height: 2.5em; position: absolute; top: 50%; left: 50%; margin: -1.25em 0 0 -5em; box-sizing: border-box; } .st-loader:before, .st-loader:after { content: ""; display: block; position: absolute; top: 0; bottom: 0; width: 1.25em; box-sizing: border-box; border: 0.25em solid #f80; } .st-loader:before { left: -0.76923em; border-right: 0; } .st-loader:after { right: -0.76923em; border-left: 0; } .st-loader .equal { display: block; position: absolute; top: 50%; margin-top: -0.5em; left: 4.16667em; height: 1em; width: 1.66667em; border: 0.25em solid #f80; box-sizing: border-box; border-width: 0.25em 0; -moz-animation: loading 1.5s infinite ease-in-out; -webkit-animation: loading 1.5s infinite ease-in-out; animation: loading 1.5s infinite ease-in-out; }';
return UI;
})();
}).call(this);
(function() {
Dosbox.Xhr = (function() {
function Xhr(url, options) {
var e;
this.success = options.success;
this.progress = options.progress;
if (window.ActiveXObject) {
try {
this.xhr = new ActiveXObject('Microsoft.XMLHTTP');
} catch (error) {
e = error;
this.xhr = null;
}
} else {
this.xhr = new XMLHttpRequest();
}
this.xhr.open('GET', url, true);
this.xhr.overrideMimeType('text/plain; charset=x-user-defined');
this.xhr.addEventListener('progress', (function(_this) {
return function(evt) {
if (_this.progress) {
return _this.progress(evt.total, evt.loaded);
}
};
})(this));
this.xhr.onreadystatechange = (function(_this) {
return function() {
return _this._onReadyStateChange();
};
})(this);
this.xhr.send();
}
Xhr.prototype._onReadyStateChange = function() {
if (this.xhr.readyState === 4 && this.success) {
return this.success(this.xhr.responseText);
}
};
return Xhr;
})();
}).call(this);

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -1 +0,0 @@
:root{font-family:system-ui,Avenir,Helvetica,Arial,sans-serif;line-height:1.5;font-weight:400;color-scheme:light dark;color:#ffffffde;background-color:#242424;font-synthesis:none;text-rendering:optimizeLegibility;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}a{font-weight:500;color:#646cff;text-decoration:inherit}a:hover{color:#535bf2}body{margin:0;display:flex;place-items:center;min-width:320px;min-height:100vh;font-size:16px}h1{font-size:3.2em;line-height:1.1}h4,h5{margin:1rem 0}pre{font-size:1em;font-family:monospace;font-weight:400;font-style:normal}#app{align-items:center;display:flex;flex-direction:column;flex-wrap:wrap;justify-content:center;margin:0 auto;max-width:800px;position:relative;text-align:center;width:100%}#app-controls-window{display:grid;grid-template-columns:1fr 1fr 1fr 1fr;grid-gap:.5rem;margin-top:.5rem}#app-controls-window>button{grid-column:span 2}#app-controls-window>button:first-child,#app-controls-window>button:last-child{grid-column:2 / span 2}#app-interface-window{display:flex;flex-basis:40%;flex-direction:column;font-size:16px;order:3}#app-inventory-controls{display:flex;flex-direction:row;gap:.5rem;width:100%}#app-inventory-controls select{font-size:16px;width:15rem}#app-maze-window{flex-basis:60%;order:1}#app-modal{background-color:#1b1e1fde;border-radius:4px;left:50%;position:fixed;top:50%;transform:translate(-50%,-50%);visibility:hidden;width:20rem}#app-modal.show{transition:visibility .5s cubic-bezier(.075,.82,.165,1);visibility:visible}#app-modal-button{margin:3rem auto 1rem}#app-text-output{flex-basis:100%;order:2;padding:.5rem;width:95%}#mazeOutput{margin:0}.logo{height:6em;padding:1.5em;will-change:filter;transition:filter .3s}.logo:hover{filter:drop-shadow(0 0 2em #646cffaa)}.logo.vanilla:hover{filter:drop-shadow(0 0 2em #3178c6aa)}.card{padding:2em}.read-the-docs{color:#888}button{background-color:#363c3e;border-radius:8px;border:1px solid transparent;cursor:pointer;font-family:inherit;font-size:1em;font-weight:500;padding:.6em 1.2em;touch-action:manipulation;transition:border-color .25s}button:hover{border-color:#646cff}button:focus,button:focus-visible{outline:4px auto -webkit-focus-ring-color}@media (min-width: 30em) and (orientation: landscape){#app{align-items:start;flex-direction:row;justify-content:space-around}#app-interface-window{order:2}#app-text-output{order:3}}

File diff suppressed because one or more lines are too long

View File

@ -2,15 +2,11 @@
<html lang="en"> <html lang="en">
<head> <head>
<meta charset="UTF-8" /> <meta charset="UTF-8" />
<link rel="icon" href="./favicon.ico" /> <link rel="icon" href="/webtoys/maze/favicon.ico" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Maze of the Minotaur</title> <title>Maze of the Minotaur</title>
<script <script type="module" crossorigin src="/webtoys/maze/assets/index-Bw4OooWg.js"></script>
type="module" <link rel="stylesheet" crossorigin href="/webtoys/maze/assets/index-f4dP9NA-.css">
crossorigin
src="./assets/index-BR90kO-n.js"
></script>
<link rel="stylesheet" crossorigin href="./assets/index-BwPfcn-3.css" />
</head> </head>
<body> <body>
<div id="app"> <div id="app">

View File

@ -0,0 +1,71 @@
// @license magnet:?xt=urn:btih:90dc5c0be029de84e523b9b3922520e79e0e6f08&dn=cc0.txt CC0-1.0
/****************************************************************************
* It's Eric Woodward's Site
*
* Copyright 2014-2025 Eric Woodward
* Source released under CC0 Public Domain License v1.0
* https://www.itsericwoodward.com/licenses/cc0/
* http://creativecommons.org/publicdomain/zero/1.0/
****************************************************************************/
/**
* Execute returned function to add background scrolling
*/
export default (actionBox) => {
if (!window.Cookies || !actionBox) return;
// default to no scrolling on devices under 600 px w
const isMobile = window.matchMedia(
"only screen and (max-width: 600px)"
).matches;
// add background scrolling
const hasScrollToggle =
Cookies.get("scrollToggle") === true ||
Cookies.get("scrollToggle") === "true" ||
(Cookies.get("scrollToggle") === undefined && !isMobile);
const scrollToggle = document.createElement("div");
scrollToggle.innerHTML = [
'<label class="toggleSwitch" for="scrollingToggle">',
'<div class="toggleSwitch-description">',
"Background",
"</div>",
`<input class="toggleSwitch-checkbox" ${
hasScrollToggle ? "checked" : ""
} type="checkbox" id="scrollingToggle" />`,
'<div class="toggleSwitch-status" data-ts-on="SCROLLING" data-ts-off="STATIC"></div>',
"</label>",
].join("\n");
scrollToggle.classList.add("js-scrollToggle", "scrollToggle");
actionBox.append(scrollToggle);
actionBox.classList.add("js-actionBox");
const actionBoxTitle = document.createElement("summary");
actionBoxTitle.innerHTML =
"<h3 class='actionBox-title'>Settings</h3>";
actionBox.append(actionBoxTitle);
// add toggle event
document
.getElementById("scrollingToggle")
.addEventListener("click", function (e) {
const theList =
document.getElementById("gridContainer").classList;
theList.toggle("js-isAnimated");
Cookies.set(
"scrollToggle",
!!theList.contains("js-isAnimated")
);
});
// add class if active at startup
if (hasScrollToggle)
document
.getElementById("gridContainer")
.classList.add("js-isAnimated");
};
// @license-end

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

Binary file not shown.

View File

@ -0,0 +1,113 @@
"use strict";
exports.__esModule = true;
exports.audioNode = void 0;
var SamplesQueue = /** @class */ (function () {
function SamplesQueue() {
this.samplesQueue = [];
}
SamplesQueue.prototype.push = function (samples) {
this.samplesQueue.push(samples);
};
SamplesQueue.prototype.length = function () {
var total = 0;
for (var _i = 0, _a = this.samplesQueue; _i < _a.length; _i++) {
var next = _a[_i];
total += next.length;
}
return total;
};
SamplesQueue.prototype.writeTo = function (dst, bufferSize) {
var writeIt = 0;
while (this.samplesQueue.length > 0) {
var src = this.samplesQueue[0];
var toRead = Math.min(bufferSize - writeIt, src.length);
if (toRead === src.length) {
dst.set(src, writeIt);
this.samplesQueue.shift();
}
else {
dst.set(src.slice(0, toRead), writeIt);
this.samplesQueue[0] = src.slice(toRead);
}
writeIt += toRead;
if (writeIt === bufferSize) {
break;
}
}
if (writeIt < bufferSize) {
dst.fill(0, writeIt);
}
};
return SamplesQueue;
}());
function audioNode(ci) {
var sampleRate = ci.soundFrequency();
var channels = 1;
if (sampleRate === 0) {
console.warn("Can't create audio node with sampleRate === 0, ingnoring");
return;
}
var audioContext = null;
if (typeof AudioContext !== "undefined") {
audioContext = new AudioContext({
sampleRate: sampleRate,
latencyHint: "interactive"
});
}
else if (typeof window.webkitAudioContext !== "undefined") {
// eslint-disable-next-line new-cap
audioContext = new window.webkitAudioContext({
sampleRate: sampleRate,
latencyHint: "interactive"
});
}
if (audioContext == null) {
return;
}
var samplesQueue = new SamplesQueue();
var bufferSize = 2048;
var preBufferSize = 2048;
ci.events().onSoundPush(function (samples) {
if (samplesQueue.length() < bufferSize * 2 + preBufferSize) {
samplesQueue.push(samples);
}
});
var audioNode = audioContext.createScriptProcessor(bufferSize, 0, channels);
var started = false;
var active = 0;
var onQueueProcess = function (event) {
var numFrames = event.outputBuffer.length;
var numChannels = event.outputBuffer.numberOfChannels;
var samplesCount = samplesQueue.length();
if (!started) {
started = samplesCount >= preBufferSize;
}
if (!started) {
return;
}
for (var channel = 0; channel < numChannels; channel++) {
var channelData = event.outputBuffer.getChannelData(channel);
samplesQueue.writeTo(channelData, numFrames);
}
};
audioNode.onaudioprocess = onQueueProcess;
audioNode.connect(audioContext.destination);
var resumeWebAudio = function () {
if (audioContext !== null && audioContext.state === "suspended") {
audioContext.resume();
}
};
document.addEventListener("click", resumeWebAudio, { once: true });
document.addEventListener("touchstart", resumeWebAudio, { once: true });
document.addEventListener("keydown", resumeWebAudio, { once: true });
ci.events().onExit(function () {
if (audioContext !== null) {
audioNode.disconnect();
audioContext.close();
}
document.removeEventListener("click", resumeWebAudio);
document.removeEventListener("touchstart", resumeWebAudio);
document.removeEventListener("keydown", resumeWebAudio);
});
}
exports.audioNode = audioNode;

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,85 @@
const fs = require("fs");
require("../emulators");
const backend = process.argv[2] === "x" ? "dosboxXNode" : "dosboxNode";
const emulators = global.emulators;
emulators.pathPrefix = "./";
const bundle = fs.readFileSync("dhry2.jsdos");
let startedAt = null;
let runStartedAt = Date.now();
let prevNonSkippableSleepCount = 0;
let prevSleepCount = 0;
let prevCycles = 0;
const medianVax = [];
const medianCycles = [];
const medianNonSkippableSleepCount = [];
const medianSleepCount = [];
const sortFn = (a, b) => a - b;
console.log("Dhrystone 2 Test for " + backend);
emulators[backend](bundle)
.then((ci) => {
ci.events().onStdout((message) => {
if (!message.startsWith("dhry2:")) {
return;
}
if (startedAt === null) {
startedAt = Date.now();
}
const [_, runs, delta, vax] = message.split(" ");
console.log("dhry2: " + runs + " runs, browser time " + delta + " ms, " +
"VAX rating " + vax);
ci.asyncifyStats().then((stats) => {
const dt = Date.now() - runStartedAt;
const nonSkippableSleepCount = stats.nonSkippableSleepCount - prevNonSkippableSleepCount;
const sleepCount = stats.sleepCount - prevSleepCount;
const cycles = stats.cycles - prevCycles;
prevNonSkippableSleepCount = stats.nonSkippableSleepCount;
prevSleepCount = stats.sleepCount;
prevCycles = stats.cycles;
runStartedAt = Date.now();
medianNonSkippableSleepCount.push(nonSkippableSleepCount * 1000 / dt);
medianSleepCount.push(sleepCount * 1000 / dt);
medianCycles.push(cycles / dt);
console.log("dhry2: sleep p/sec: " + Math.round(sleepCount * 1000 / dt) +
" , non skippable p/sec: " + Math.round(nonSkippableSleepCount * 1000 / dt) +
" , avg cycles p/ms: " + Math.round(cycles / dt));
});
medianVax.push(vax);
if (runs === "320000") {
const executionTimeSec = (Date.now() - startedAt) / 1000;
medianVax.sort(sortFn);
medianNonSkippableSleepCount.sort(sortFn);
medianSleepCount.sort(sortFn);
medianCycles.sort(sortFn);
console.log("Time:", Math.round(executionTimeSec * 10) / 10, "sec",
"RpS:", Math.round((runs - 1000) / executionTimeSec),
"Med VAX:", medianVax[Math.round(medianVax.length / 2)]);
ci.asyncifyStats().then((stats) => {
console.log("Message sent:", stats.messageSent,
"(frame", stats.messageFrame + ")",
"(sound", stats.messageSound + ")");
console.log("Message recv:", stats.messageReceived);
console.log("Sleep count:", stats.sleepCount);
console.log("Sleep time:", Math.round(stats.sleepTime / 1000 * 10) / 10, "sec");
console.log("Avg sleep:", stats.sleepTime / stats.sleepCount, "ms");
console.log("Med non skippable sleep p/sec: ",
Math.round(medianNonSkippableSleepCount[Math.round(medianNonSkippableSleepCount.length / 2)]));
console.log("Med sleep p/sec:",
Math.round(medianSleepCount[Math.round(medianSleepCount.length / 2)]));
console.log("Med cycles p/ms:",
Math.round(medianCycles[Math.round(medianCycles.length / 2)]));
// properly exit
ci.exit();
});
}
});
})
.catch(console.error);

View File

@ -0,0 +1,135 @@
<!doctype html>
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
<style>
html,
body {
width: 100%;
height: 100%;
margin: 0;
padding: 0;
}
</style>
<script src="../emulators.js"></script>
</head>
<body>
<div>
<button onClick="javascript:downloadBundleAndRun({worker: true, x: false})">dosboxWorker</button>
<button onClick="javascript:downloadBundleAndRun({worker: false, x: false})">dosboxDirect</button>
<button onClick="javascript:downloadBundleAndRun({worker: true, x: true})">xWorker</button>
<button onClick="javascript:downloadBundleAndRun({worker: false, x: true})">xDirect</button>
<pre id="stdout"></pre>
</div>
<script>
emulators.pathPrefix = "../";
let runId = 0;
async function runBundle(bundle, options) {
const id = runId++;
const stdout = document.getElementById("stdout");
// promise is resolved when emulator is started
const ci = await (options.worker ?
(options.x ? emulators.dosboxXWorker(bundle) : emulators.dosboxWorker(bundle)) :
(options.x ? emulators.dosboxXDirect(bundle) : emulators.dosDirect(bundle)));
let startedAt = null;
let runStartedAt = Date.now();
let prevNonSkippableSleepCount = 0;
let prevSleepCount = 0;
let prevCycles = 0;
const medianVax = [];
const medianCycles = [];
const medianNonSkippableSleepCount = [];
const medianSleepCount = [];
const sortFn = (a, b) => a - b;
ci.events().onStdout((message) => {
if (!message.startsWith("dhry2:")) {
return;
}
if (startedAt === null) {
startedAt = Date.now();
}
const [_, runs, delta, vax] = message.split(" ");
stdout.innerHTML += (id) + ": " + runs + " runs, browser time " + delta + " ms, " +
"VAX rating " + vax + "\n";
ci.asyncifyStats().then((stats) => {
const dt = Date.now() - runStartedAt;
const nonSkippableSleepCount = stats.nonSkippableSleepCount - prevNonSkippableSleepCount;
const sleepCount = stats.sleepCount - prevSleepCount;
const cycles = stats.cycles - prevCycles;
prevNonSkippableSleepCount = stats.nonSkippableSleepCount;
prevSleepCount = stats.sleepCount;
prevCycles = stats.cycles;
runStartedAt = Date.now();
medianNonSkippableSleepCount.push(nonSkippableSleepCount * 1000 / dt);
medianSleepCount.push(sleepCount * 1000 / dt);
medianCycles.push(cycles / dt);
stdout.innerHTML += (id) + ": sleep p/sec: " + Math.round(sleepCount * 1000 /dt) +
" , non skippable p/sec: " + Math.round(nonSkippableSleepCount * 1000 / dt) +
" , avg cycles p/ms: " + Math.round(cycles / dt) + "\n";
});
medianVax.push(vax);
if (runs === "320000") {
const executionTimeSec = (Date.now() - startedAt) / 1000;
medianVax.sort(sortFn);
medianNonSkippableSleepCount.sort(sortFn);
medianSleepCount.sort(sortFn);
medianCycles.sort(sortFn);
stdout.innerHTML += (id) +
": Time: " + Math.round(executionTimeSec * 10) / 10 + " sec" +
" RpS: " + Math.round((runs - 1000) / executionTimeSec) +
" Med VAX: " + medianVax[medianVax.length / 2] + "\n";
ci.asyncifyStats().then((stats) => {
const dt = Date.now() - startedAt;
stdout.innerHTML += (id) + ": Message sent: " + stats.messageSent +
"(frame " + stats.messageFrame + ") " +
"(sound " + stats.messageSound + ")\n";
stdout.innerHTML += (id) + ": Message recv: " + stats.messageReceived + "\n";
stdout.innerHTML += (id) + ": Sleep count: " + stats.sleepCount + "\n";
stdout.innerHTML += (id) + ": Sleep time: " + Math.round(stats.sleepTime / 1000 * 10) / 10 + "sec\n";
stdout.innerHTML += (id) + ": Avg sleep time: " + stats.sleepTime / stats.sleepCount + "ms\n";
stdout.innerHTML += (id) + ": Med non skippable sleep p/sec: " +
Math.round(medianNonSkippableSleepCount[Math.round(medianNonSkippableSleepCount.length / 2)]) + "\n";
stdout.innerHTML += (id) + ": Med sleep p/sec: " +
Math.round(medianSleepCount[Math.round(medianSleepCount.length / 2)]) + "\n";
stdout.innerHTML += (id) + ": Med cycles p/ms: " +
Math.round(medianCycles[Math.round(medianCycles.length / 2)]) + "\n";
//properly exit
ci.exit();
});
}
});
}
function downloadBundleAndRun(options) {
const bundleUrl = "dhry2.jsdos";
// we need to download bundle, emulators accept only Uint8Array
const xhr = new XMLHttpRequest();
xhr.open("GET", bundleUrl, true);
xhr.overrideMimeType("text/plain; charset=x-user-defined");
xhr.responseType = "arraybuffer";
xhr.onreadystatechange = () => {
if (xhr.readyState === 4 && xhr.status === 200) {
// do not forget to create Uint8Array,
// arraybuffer will not work!
runBundle(new Uint8Array(xhr.response), options);
}
};
xhr.send();
};
</script>
</body>
</html>

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

View File

@ -0,0 +1,325 @@
@charset "utf-8";
body {
margin:0;
}
#mocha {
font: 20px/1.5 "Helvetica Neue", Helvetica, Arial, sans-serif;
margin: 60px 50px;
}
#mocha ul,
#mocha li {
margin: 0;
padding: 0;
}
#mocha ul {
list-style: none;
}
#mocha h1,
#mocha h2 {
margin: 0;
}
#mocha h1 {
margin-top: 15px;
font-size: 1em;
font-weight: 200;
}
#mocha h1 a {
text-decoration: none;
color: inherit;
}
#mocha h1 a:hover {
text-decoration: underline;
}
#mocha .suite .suite h1 {
margin-top: 0;
font-size: .8em;
}
#mocha .hidden {
display: none;
}
#mocha h2 {
font-size: 12px;
font-weight: normal;
cursor: pointer;
}
#mocha .suite {
margin-left: 15px;
}
#mocha .test {
margin-left: 15px;
overflow: hidden;
}
#mocha .test.pending:hover h2::after {
content: '(pending)';
font-family: arial, sans-serif;
}
#mocha .test.pass.medium .duration {
background: #c09853;
}
#mocha .test.pass.slow .duration {
background: #b94a48;
}
#mocha .test.pass::before {
content: '✓';
font-size: 12px;
display: block;
float: left;
margin-right: 5px;
color: #00d6b2;
}
#mocha .test.pass .duration {
font-size: 9px;
margin-left: 5px;
padding: 2px 5px;
color: #fff;
-webkit-box-shadow: inset 0 1px 1px rgba(0,0,0,.2);
-moz-box-shadow: inset 0 1px 1px rgba(0,0,0,.2);
box-shadow: inset 0 1px 1px rgba(0,0,0,.2);
-webkit-border-radius: 5px;
-moz-border-radius: 5px;
-ms-border-radius: 5px;
-o-border-radius: 5px;
border-radius: 5px;
}
#mocha .test.pass.fast .duration {
display: none;
}
#mocha .test.pending {
color: #0b97c4;
}
#mocha .test.pending::before {
content: '◦';
color: #0b97c4;
}
#mocha .test.fail {
color: #c00;
}
#mocha .test.fail pre {
color: black;
}
#mocha .test.fail::before {
content: '✖';
font-size: 12px;
display: block;
float: left;
margin-right: 5px;
color: #c00;
}
#mocha .test pre.error {
color: #c00;
max-height: 300px;
overflow: auto;
}
#mocha .test .html-error {
overflow: auto;
color: black;
display: block;
float: left;
clear: left;
font: 12px/1.5 monaco, monospace;
margin: 5px;
padding: 15px;
border: 1px solid #eee;
max-width: 85%; /*(1)*/
max-width: -webkit-calc(100% - 42px);
max-width: -moz-calc(100% - 42px);
max-width: calc(100% - 42px); /*(2)*/
max-height: 300px;
word-wrap: break-word;
border-bottom-color: #ddd;
-webkit-box-shadow: 0 1px 3px #eee;
-moz-box-shadow: 0 1px 3px #eee;
box-shadow: 0 1px 3px #eee;
-webkit-border-radius: 3px;
-moz-border-radius: 3px;
border-radius: 3px;
}
#mocha .test .html-error pre.error {
border: none;
-webkit-border-radius: 0;
-moz-border-radius: 0;
border-radius: 0;
-webkit-box-shadow: 0;
-moz-box-shadow: 0;
box-shadow: 0;
padding: 0;
margin: 0;
margin-top: 18px;
max-height: none;
}
/**
* (1): approximate for browsers not supporting calc
* (2): 42 = 2*15 + 2*10 + 2*1 (padding + margin + border)
* ^^ seriously
*/
#mocha .test pre {
display: block;
float: left;
clear: left;
font: 12px/1.5 monaco, monospace;
margin: 5px;
padding: 15px;
border: 1px solid #eee;
max-width: 85%; /*(1)*/
max-width: -webkit-calc(100% - 42px);
max-width: -moz-calc(100% - 42px);
max-width: calc(100% - 42px); /*(2)*/
word-wrap: break-word;
border-bottom-color: #ddd;
-webkit-box-shadow: 0 1px 3px #eee;
-moz-box-shadow: 0 1px 3px #eee;
box-shadow: 0 1px 3px #eee;
-webkit-border-radius: 3px;
-moz-border-radius: 3px;
border-radius: 3px;
}
#mocha .test h2 {
position: relative;
}
#mocha .test a.replay {
position: absolute;
top: 3px;
right: 0;
text-decoration: none;
vertical-align: middle;
display: block;
width: 15px;
height: 15px;
line-height: 15px;
text-align: center;
background: #eee;
font-size: 15px;
-webkit-border-radius: 15px;
-moz-border-radius: 15px;
border-radius: 15px;
-webkit-transition:opacity 200ms;
-moz-transition:opacity 200ms;
-o-transition:opacity 200ms;
transition: opacity 200ms;
opacity: 0.3;
color: #888;
}
#mocha .test:hover a.replay {
opacity: 1;
}
#mocha-report.pass .test.fail {
display: none;
}
#mocha-report.fail .test.pass {
display: none;
}
#mocha-report.pending .test.pass,
#mocha-report.pending .test.fail {
display: none;
}
#mocha-report.pending .test.pass.pending {
display: block;
}
#mocha-error {
color: #c00;
font-size: 1.5em;
font-weight: 100;
letter-spacing: 1px;
}
#mocha-stats {
position: fixed;
top: 15px;
right: 10px;
font-size: 12px;
margin: 0;
color: #888;
z-index: 1;
}
#mocha-stats .progress {
float: right;
padding-top: 0;
/**
* Set safe initial values, so mochas .progress does not inherit these
* properties from Bootstrap .progress (which causes .progress height to
* equal line height set in Bootstrap).
*/
height: auto;
-webkit-box-shadow: none;
-moz-box-shadow: none;
box-shadow: none;
background-color: initial;
}
#mocha-stats em {
color: black;
}
#mocha-stats a {
text-decoration: none;
color: inherit;
}
#mocha-stats a:hover {
border-bottom: 1px solid #eee;
}
#mocha-stats li {
display: inline-block;
margin: 0 5px;
list-style: none;
padding-top: 11px;
}
#mocha-stats canvas {
width: 40px;
height: 40px;
}
#mocha code .comment { color: #ddd; }
#mocha code .init { color: #2f6fad; }
#mocha code .string { color: #5890ad; }
#mocha code .keyword { color: #8a6343; }
#mocha code .number { color: #2f6fad; }
@media screen and (max-device-width: 480px) {
#mocha {
margin: 60px 0px;
}
#mocha #stats {
position: absolute;
}
}

File diff suppressed because one or more lines are too long

Binary file not shown.

View File

@ -0,0 +1,5 @@
// stats.js - http://github.com/mrdoob/stats.js
(function(f,e){"object"===typeof exports&&"undefined"!==typeof module?module.exports=e():"function"===typeof define&&define.amd?define(e):f.Stats=e()})(this,function(){var f=function(){function e(a){c.appendChild(a.dom);return a}function u(a){for(var d=0;d<c.children.length;d++)c.children[d].style.display=d===a?"block":"none";l=a}var l=0,c=document.createElement("div");c.style.cssText="position:fixed;top:0;left:0;cursor:pointer;opacity:0.9;z-index:10000";c.addEventListener("click",function(a){a.preventDefault();
u(++l%c.children.length)},!1);var k=(performance||Date).now(),g=k,a=0,r=e(new f.Panel("FPS","#0ff","#002")),h=e(new f.Panel("MS","#0f0","#020"));if(self.performance&&self.performance.memory)var t=e(new f.Panel("MB","#f08","#201"));u(0);return{REVISION:16,dom:c,addPanel:e,showPanel:u,begin:function(){k=(performance||Date).now()},end:function(){a++;var c=(performance||Date).now();h.update(c-k,200);if(c>=g+1E3&&(r.update(1E3*a/(c-g),100),g=c,a=0,t)){var d=performance.memory;t.update(d.usedJSHeapSize/
1048576,d.jsHeapSizeLimit/1048576)}return c},update:function(){k=this.end()},domElement:c,setMode:u}};f.Panel=function(e,f,l){var c=Infinity,k=0,g=Math.round,a=g(window.devicePixelRatio||1),r=80*a,h=48*a,t=3*a,v=2*a,d=3*a,m=15*a,n=74*a,p=30*a,q=document.createElement("canvas");q.width=r;q.height=h;q.style.cssText="width:80px;height:48px";var b=q.getContext("2d");b.font="bold "+9*a+"px Helvetica,Arial,sans-serif";b.textBaseline="top";b.fillStyle=l;b.fillRect(0,0,r,h);b.fillStyle=f;b.fillText(e,t,v);
b.fillRect(d,m,n,p);b.fillStyle=l;b.globalAlpha=.9;b.fillRect(d,m,n,p);return{dom:q,update:function(h,w){c=Math.min(c,h);k=Math.max(k,h);b.fillStyle=l;b.globalAlpha=1;b.fillRect(0,0,r,m);b.fillStyle=f;b.fillText(g(h)+" "+e+" ("+g(c)+"-"+g(k)+")",t,v);b.drawImage(q,d+a,m,n-a,p,d,m,n-a,p);b.fillRect(d+n-a,m,a,p);b.fillStyle=l;b.globalAlpha=.9;b.fillRect(d+n-a,m,a,g((1-h/w)*p))}}};return f});

View File

@ -0,0 +1,161 @@
<!doctype html>
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
<style>
html,
body {
width: 100%;
height: 100%;
margin: 0;
padding: 0;
}
layout {
display: flex;
flex-direction: column;
}
</style>
<script src="../emulators.js"></script>
<script src="audio-node.js"></script>
<script src="webgl.js"></script>
<script src="stats.min.js"></script>
</head>
<body>
<div class="layout">
<div id="controls">
<button onClick="javascript:downloadBundleAndRun({worker: true, x: false})">dosboxWorker</button>
<button onClick="javascript:downloadBundleAndRun({worker: false, x: false})">dosboxDirect</button>
<button onClick="javascript:downloadBundleAndRun({worker: true, x: true})">xWorker</button>
<button onClick="javascript:downloadBundleAndRun({worker: false, x: true})">xDirect</button>
</div>
<p>FRAME:</p>
<canvas id="canvas"></canvas>
<p id="stats"></p>
<p>STDOUT:</p>
<pre id="stdout"></pre>
</div>
<script>
emulators.pathPrefix = "../";
const stats = new Stats();
stats.showPanel(0);
stats.dom.style.left = "initial";
stats.dom.style.right = "0px";
document.body.appendChild(stats.dom);
let runId = 0;
async function runBundle(bundle, options) {
const id = runId++;
const stdout = document.getElementById("stdout");
const canvas = document.getElementById("canvas");
const gl = canvas.getContext("webgl");
const statsEl = document.getElementById("stats");
// promise is resolved when emulator is started
const ci = await (options.worker ?
(options.x ? emulators.dosboxXWorker(bundle) : emulators.dosboxWorker(bundle)) :
(options.x ? emulators.dosboxXDirect(bundle) : emulators.dosDirect(bundle)));
let intervalStartedAt = Date.now();
let prevNonSkippableSleepCount = 0;
let prevSleepCount = 0;
let prevCycles = 0;
setInterval(() => {
ci.asyncifyStats().then((stats) => {
const dt = Date.now() - intervalStartedAt;
const nonSkippableSleep = stats.nonSkippableSleepCount - prevNonSkippableSleepCount;
const avgSleep = (stats.sleepCount - prevSleepCount) * 1000 / dt;
const avgNonSkippableSleep = (stats.nonSkippableSleepCount - prevNonSkippableSleepCount) * 1000 / dt;
const avgCycles = (stats.cycles - prevCycles) / dt;
intervalStartedAt = Date.now();
prevNonSkippableSleepCount = stats.nonSkippableSleepCount;
prevSleepCount = stats.sleepCount;
prevCycles = stats.cycles;
statsEl.innerHTML = "Avg sleep p/sec: " + Math.round(avgSleep) +
", avg non skippable sleep p/sec: " + Math.round(avgNonSkippableSleep) +
", cycles p/ms: " + Math.round(avgCycles);
});
}, 3000);
window.ci = ci;
webGl({
canvas,
addOnResize: () => {},
}, ci, stats);
audioNode(ci);
ci.events().onStdout((message) => {
stdout.innerHTML += message;
});
// ci.events().onMessage(console.log.bind(console));
function getKeyCode(code) {
switch (code) {
case 13: return 257;
case 38: return 265;
case 39: return 262;
case 37: return 263;
case 40: return 264;
case 17: return 342;
case 190: return 46;
default: return code;
}
}
window.addEventListener("keydown", (e) => {
ci.sendKeyEvent(getKeyCode(e.keyCode), true);
e.stopPropagation();
e.preventDefault();
});
window.addEventListener("keyup", (e) => {
ci.sendKeyEvent(getKeyCode(e.keyCode), false);
e.stopPropagation();
e.preventDefault();
});
canvas.addEventListener("mousemove", (e) => {
ci.sendMouseMotion(
(e.clientX - canvas.offsetLeft) / canvas.width,
(e.clientY - canvas.offsetTop) / canvas.height);
e.stopPropagation();
e.preventDefault();
});
canvas.addEventListener("mousedown", (e) => {
ci.sendMouseButton(0, true);
e.stopPropagation();
e.preventDefault();
});
canvas.addEventListener("mouseup", (e) => {
ci.sendMouseButton(0, false);
e.stopPropagation();
e.preventDefault();
});
}
function downloadBundleAndRun(options) {
document.getElementById("controls").style.display = "none";
const bundleUrl = "temp.jsdos?timestamp=" + Date.now();
// we need to download bundle, emulators accept only Uint8Array
const xhr = new XMLHttpRequest();
xhr.open("GET", bundleUrl, true);
xhr.overrideMimeType("text/plain; charset=x-user-defined");
xhr.responseType = "arraybuffer";
xhr.onreadystatechange = () => {
if (xhr.readyState === 4 && xhr.status === 200) {
// do not forget to create Uint8Array,
// arraybuffer will not work!
runBundle(new Uint8Array(xhr.response), options);
}
};
xhr.send();
};
</script>
</body>
</html>

View File

@ -0,0 +1,75 @@
<html>
<head>
<meta charset="utf-8">
<title>Emulators Tests</title>
<link href="mocha.css" rel="stylesheet" />
<style>
.test-config {
position: fixed;
left: 15px;
top: 15px;
display: flex;
flex-direction: column;
width: fit-content;
}
.test-config-row {
display: flex;
flex-direction: row;
align-items: center;
justify-content: center;
}
</style>
</head>
<body>
<div id="mocha"></div>
<script src="mocha.js"></script>
<script src="chai.js"></script>
<script>
mocha.setup({
ui: 'qunit',
allowUncaught: true,
bail: true,
fullTrace: true,
timeout: 60000
});
mocha.allowUncaught();
</script>
<script src="test.js"></script>
<div id="test-config" class="test-config">
<div class="test-config-row">
Server Address:&nbsp;
<input id="server-ip" type="text" value="wss://netherlands.dos.zone"></input>
&nbsp;&nbsp;
<button id="start-net">Start Net Tests</button>
</div>
<br/>
<button id="start">Start Tests</button>
</div>
<script>
const testConfig = document.getElementById("test-config");
const start = document.getElementById("start");
const startNet = document.getElementById("start-net");
start.addEventListener("click", () => {
testConfig.style.display = "none";
window.createTests();
mocha.run();
});
startNet.addEventListener("click", () => {
testConfig.style.display = "none";
window.ipxServerAddress = document.getElementById("server-ip").value.trim();
window.createNetworkTests();
mocha.run();
});
</script>
</body>
</html>

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,136 @@
"use strict";
exports.__esModule = true;
exports.webGl = void 0;
var vsSource = "\nattribute vec4 aVertexPosition;\nattribute vec2 aTextureCoord;\n\nvarying highp vec2 vTextureCoord;\n\nvoid main(void) {\n gl_Position = aVertexPosition;\n vTextureCoord = aTextureCoord;\n}\n";
var fsSource = "\nvarying highp vec2 vTextureCoord;\nuniform sampler2D uSampler;\n\n\nvoid main(void) {\n highp vec4 color = texture2D(uSampler, vTextureCoord);\n gl_FragColor = vec4(color.r, color.g, color.b, 1.0);\n}\n";
function webGl(layers, ci, stats) {
var canvas = layers.canvas;
var gl = canvas.getContext("webgl");
if (gl === null) {
throw new Error("Unable to create webgl context on given canvas");
}
var shaderProgram = initShaderProgram(gl, vsSource, fsSource);
var vertexPosition = gl.getAttribLocation(shaderProgram, "aVertexPosition");
var textureCoord = gl.getAttribLocation(shaderProgram, "aTextureCoord");
var uSampler = gl.getUniformLocation(shaderProgram, "uSampler");
initBuffers(gl, vertexPosition, textureCoord);
var texture = gl.createTexture();
gl.bindTexture(gl.TEXTURE_2D, texture);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
var pixel = new Uint8Array([0, 0, 0]);
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGB, 1, 1, 0, gl.RGB, gl.UNSIGNED_BYTE, pixel);
gl.useProgram(shaderProgram);
gl.activeTexture(gl.TEXTURE0);
gl.uniform1i(uSampler, 0);
var containerWidth = layers.width;
var containerHeight = layers.height;
var frameWidth = 0;
var frameHeight = 0;
var onResize = function () {
var aspect = frameWidth / frameHeight;
var width = containerWidth;
var height = containerWidth / aspect;
if (height > containerHeight) {
height = containerHeight;
width = containerHeight * aspect;
}
canvas.style.position = "relative";
canvas.style.top = (containerHeight - height) / 2 + "px";
canvas.style.left = (containerWidth - width) / 2 + "px";
canvas.style.width = width + "px";
canvas.style.height = height + "px";
};
var onResizeLayer = function (w, h) {
containerWidth = w;
containerHeight = h;
onResize();
};
layers.addOnResize(onResizeLayer);
var onResizeFrame = function (w, h) {
frameWidth = w;
frameHeight = h;
canvas.width = frameWidth;
canvas.height = frameHeight;
gl.viewport(0, 0, frameWidth, frameHeight);
onResize();
};
ci.events().onFrameSize(onResizeFrame);
onResizeFrame(ci.width(), ci.height());
var requestAnimationFrameId = null;
var frame = null;
var frameFormat = 0;
stats.begin();
ci.events().onFrame(function (rgb, rgba) {
stats.end();
stats.begin();
frame = rgb != null ? rgb : rgba;
frameFormat = rgb != null ? gl.RGB : gl.RGBA;
if (requestAnimationFrameId === null) {
requestAnimationFrameId = requestAnimationFrame(updateTexture);
}
});
var updateTexture = function () {
gl.texImage2D(gl.TEXTURE_2D, 0, frameFormat, frameWidth, frameHeight, 0, frameFormat, gl.UNSIGNED_BYTE, frame);
gl.drawArrays(gl.TRIANGLES, 0, 6);
requestAnimationFrameId = null;
frame = null;
};
ci.events().onExit(function () {
layers.removeOnResize(onResizeLayer);
});
}
exports.webGl = webGl;
function initShaderProgram(gl, vsSource, fsSource) {
var vertexShader = loadShader(gl, gl.VERTEX_SHADER, vsSource);
var fragmentShader = loadShader(gl, gl.FRAGMENT_SHADER, fsSource);
var shaderProgram = gl.createProgram();
gl.attachShader(shaderProgram, vertexShader);
gl.attachShader(shaderProgram, fragmentShader);
gl.linkProgram(shaderProgram);
if (!gl.getProgramParameter(shaderProgram, gl.LINK_STATUS)) {
throw new Error("Unable to initialize the shader program: " + gl.getProgramInfoLog(shaderProgram));
}
return shaderProgram;
}
function loadShader(gl, shaderType, source) {
var shader = gl.createShader(shaderType);
gl.shaderSource(shader, source);
gl.compileShader(shader);
if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
var info = gl.getShaderInfoLog(shader);
gl.deleteShader(shader);
throw new Error("An error occurred compiling the shaders: " + info);
}
return shader;
}
function initBuffers(gl, vertexPosition, textureCoord) {
var positionBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
var positions = [
-1.0, -1.0, 0.0,
1.0, -1.0, 0.0,
1.0, 1.0, 0.0,
-1.0, -1.0, 0.0,
1.0, 1.0, 0.0,
-1.0, 1.0, 0.0,
];
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(positions), gl.STATIC_DRAW);
gl.vertexAttribPointer(vertexPosition, 3, gl.FLOAT, false, 0, 0);
gl.enableVertexAttribArray(vertexPosition);
var textureCoordBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, textureCoordBuffer);
var textureCoordinates = [
0.0, 1.0,
1.0, 1.0,
1.0, 0.0,
0.0, 1.0,
1.0, 0.0,
0.0, 0.0,
];
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(textureCoordinates), gl.STATIC_DRAW);
gl.vertexAttribPointer(textureCoord, 2, gl.FLOAT, false, 0, 0);
gl.enableVertexAttribArray(textureCoord);
}

View File

@ -0,0 +1,28 @@
export declare const Build: {
version: string;
buildSeed: number;
"wdosbox-x.wasm": {
size: number;
gzSize: number;
};
"wdosbox-x.js": {
size: number;
gzSize: number;
};
"wdosbox.wasm": {
size: number;
gzSize: number;
};
"wdosbox.js": {
size: number;
gzSize: number;
};
"wlibzip.wasm": {
size: number;
gzSize: number;
};
"wlibzip.js": {
size: number;
gzSize: number;
};
};

View File

@ -0,0 +1,20 @@
import { WasmModule } from "../../impl/modules";
export interface DosArchiveSource {
url: string;
path: string;
type?: "zip";
}
export default class DosBundle {
dosboxConf: string;
jsdosConf: {
version: string;
};
sources: DosArchiveSource[];
private libzipWasm;
constructor(libzipWasm: WasmModule);
autoexec(...lines: string[]): DosBundle;
extract(url: string, path?: string, type?: "zip"): DosBundle;
extractAll(sources: DosArchiveSource[]): DosBundle;
toUint8Array(overwriteConfig?: boolean): Promise<Uint8Array>;
}
export declare const defaultConfig: string;

View File

@ -0,0 +1,3 @@
import { WasmModule } from "../../../impl/modules";
import { TransportLayer } from "../../../protocol/protocol";
export declare function dosDirect(wasmModule: WasmModule, sessionId: string, canvas?: OffscreenCanvas): Promise<TransportLayer>;

View File

@ -0,0 +1,3 @@
import { WasmModule } from "../../../impl/modules";
import { TransportLayer } from "../../../protocol/protocol";
export declare function dosWorker(workerUrl: string, wasmModule: WasmModule, sessionId: string, canvas?: OffscreenCanvas): Promise<TransportLayer>;

View File

@ -0,0 +1,85 @@
import DosBundle from "./dos/bundle/dos-bundle";
import { AsyncifyStats, TransportLayer, FsNode } from "./protocol/protocol";
export interface DosConfig {
dosboxConf: string;
jsdosConf: {
version: string;
};
}
export declare enum NetworkType {
NETWORK_DOSBOX_IPX = 0
}
export interface BackendOptions {
token?: string | undefined;
onExtractProgress?: (bundleIndex: number, file: string, extracted: number, total: number) => void;
canvas?: OffscreenCanvas;
}
export type InitBundleEntry = Uint8Array;
export interface InitFileEntry {
path: string;
contents: Uint8Array;
}
export type InitFsEntry = InitBundleEntry | InitFileEntry | DosConfig | string;
export type InitFs = InitFsEntry | InitFsEntry[];
export type PersistedSockdrives = {
drives: {
url: string;
persist: Uint8Array;
}[];
} | null;
export interface Emulators {
pathPrefix: string;
pathSuffix: string;
version: string;
wdosboxJs: string;
bundle: () => Promise<DosBundle>;
bundleConfig: (bundle: InitBundleEntry) => Promise<DosConfig | null>;
bundleUpdateConfig: (bundle: InitBundleEntry, config: DosConfig) => Promise<Uint8Array>;
dosboxNode: (init: InitFs, options?: BackendOptions) => Promise<CommandInterface>;
dosboxDirect: (init: InitFs, options?: BackendOptions) => Promise<CommandInterface>;
dosboxWorker: (init: InitFs, options?: BackendOptions) => Promise<CommandInterface>;
dosboxXNode: (init: InitFs, options?: BackendOptions) => Promise<CommandInterface>;
dosboxXDirect: (init: InitFs, options?: BackendOptions) => Promise<CommandInterface>;
dosboxXWorker: (init: InitFs, options?: BackendOptions) => Promise<CommandInterface>;
backend: (init: InitFs, transportLayer: TransportLayer, options?: BackendOptions) => Promise<CommandInterface>;
}
export interface CommandInterface {
config: () => Promise<DosConfig>;
height: () => number;
width: () => number;
soundFrequency: () => number;
screenshot: () => Promise<ImageData>;
pause: () => void;
resume: () => void;
mute: () => void;
unmute: () => void;
exit: () => Promise<void>;
simulateKeyPress: (...keyCodes: number[]) => void;
sendKeyEvent: (keyCode: number, pressed: boolean) => void;
sendMouseMotion: (x: number, y: number) => void;
sendMouseRelativeMotion: (x: number, y: number) => void;
sendMouseButton: (button: number, pressed: boolean) => void;
sendMouseSync: () => void;
sendBackendEvent: (event: any) => void;
persist(onlyChanges?: boolean): Promise<Uint8Array | PersistedSockdrives | null>;
events(): CommandInterfaceEvents;
networkConnect(networkType: NetworkType, address: string): Promise<void>;
networkDisconnect(networkType: NetworkType): Promise<void>;
asyncifyStats(): Promise<AsyncifyStats>;
fsTree(): Promise<FsNode>;
fsReadFile(file: string): Promise<Uint8Array>;
fsWriteFile(file: string, contents: ReadableStream<Uint8Array> | Uint8Array): Promise<void>;
fsDeleteFile(file: string): Promise<boolean>;
}
export type MessageType = "log" | "warn" | "error" | string;
export interface CommandInterfaceEvents {
onStdout: (consumer: (message: string) => void) => void;
onFrameSize: (consumer: (width: number, height: number) => void) => void;
onFrame: (consumer: (rgb: Uint8Array | null, rgba: Uint8Array | null) => void) => void;
onSoundPush: (consumer: (samples: Float32Array) => void) => void;
onExit: (consumer: () => void) => void;
onMessage: (consumer: (msgType: MessageType, ...args: any[]) => void) => void;
onNetworkConnected: (consumer: (networkType: NetworkType, address: string) => void) => void;
onNetworkDisconnected: (consumer: (networkType: NetworkType) => void) => void;
onUnload: (consumer: () => Promise<void>) => void;
}

View File

@ -0,0 +1,9 @@
export interface XhrOptions {
method?: string;
progress?: (total: number, loaded: number) => void;
data?: string;
responseType?: XMLHttpRequestResponseType;
}
export declare const httpRequest: typeof XhrRequest;
declare function XhrRequest(url: string, options: XhrOptions): Promise<string | ArrayBuffer>;
export {};

View File

@ -0,0 +1,32 @@
import { CommandInterfaceEvents, MessageType, NetworkType } from "../emulators";
export declare class CommandInterfaceEventsImpl implements CommandInterfaceEvents {
private onStdoutConsumers;
private delayedStdout;
private onFrameSizeConsumers;
private onFrameConsumers;
private onSoundPushConsumers;
private onExitConsumers;
private onMessageConsumers;
private delayedMessages;
private onNetworkConnectedConsumers;
private onNetworkDisconnectedConsumers;
private onUnloadConsumers;
onStdout: (consumer: (message: string) => void) => void;
onFrameSize: (consumer: (width: number, height: number) => void) => void;
onFrame: (consumer: (rgb: Uint8Array | null, rgba: Uint8Array | null) => void) => void;
onSoundPush: (consumer: (samples: Float32Array) => void) => void;
onExit: (consumer: () => void) => void;
onMessage: (consumer: (msgType: MessageType, ...args: any[]) => void) => void;
onNetworkConnected(consumer: (networkType: NetworkType, address: string) => void): void;
onNetworkDisconnected(consumer: (networkType: NetworkType) => void): void;
onUnload: (consumer: () => Promise<void>) => void;
fireStdout: (message: string) => void;
fireFrameSize: (width: number, height: number) => void;
fireFrame: (rgb: Uint8Array | null, rgba: Uint8Array | null) => void;
fireSoundPush: (samples: Float32Array) => void;
fireExit: () => void;
fireMessage: (msgType: MessageType, ...args: any[]) => void;
fireNetworkConnected: (networkType: NetworkType, address: string) => void;
fireNetworkDisconnected: (networkType: NetworkType) => void;
fireUnload: () => Promise<void>;
}

View File

@ -0,0 +1,27 @@
import { Emulators, CommandInterface, BackendOptions, DosConfig, InitFs, InitBundleEntry } from "../emulators";
import { IWasmModules } from "./modules";
import DosBundle from "../dos/bundle/dos-bundle";
import { TransportLayer } from "../protocol/protocol";
declare class EmulatorsImpl implements Emulators {
pathPrefix: string;
pathSuffix: string;
version: string;
wdosboxJs: string;
wdosboxxJs: string;
private wasmModulesPromise?;
bundle(): Promise<DosBundle>;
bundleConfig(bundle: InitBundleEntry): Promise<DosConfig | null>;
bundleUpdateConfig(bundle: InitBundleEntry, config: DosConfig): Promise<Uint8Array>;
dosboxNode(init: InitFs, options?: BackendOptions): Promise<CommandInterface>;
dosboxDirect(init: InitFs, options?: BackendOptions): Promise<CommandInterface>;
dosboxWorker(init: InitFs, options?: BackendOptions): Promise<CommandInterface>;
dosboxXNode(init: InitFs, options?: BackendOptions): Promise<CommandInterface>;
dosboxXDirect(init: InitFs, options?: BackendOptions): Promise<CommandInterface>;
dosboxXWorker(init: InitFs, options?: BackendOptions): Promise<CommandInterface>;
backend(init: InitFs, transportLayer: TransportLayer, options?: BackendOptions): Promise<CommandInterface>;
wasmModules(): Promise<IWasmModules>;
dosDirect(init: InitFs): Promise<CommandInterface>;
dosWorker(init: InitFs): Promise<CommandInterface>;
}
declare const emulators: EmulatorsImpl;
export default emulators;

View File

@ -0,0 +1,42 @@
export interface WasmModule {
instantiate: (module?: any) => Promise<any>;
}
export interface IWasmModules {
libzip: () => Promise<WasmModule>;
dosbox: () => Promise<WasmModule>;
dosboxx: () => Promise<WasmModule>;
}
interface Globals {
exports: {
[moduleName: string]: any;
};
module: {
exports?: () => void;
};
compiled: {
[moduleName: string]: Promise<WasmModule>;
};
}
declare class Host {
wasmSupported: boolean;
globals: Globals;
constructor();
}
export declare const host: Host;
export declare class WasmModulesImpl implements IWasmModules {
private pathPrefix;
private pathSuffix;
private wdosboxJs;
private wdosboxxJs;
private libzipPromise?;
private dosboxPromise?;
private dosboxxPromise?;
wasmSupported: boolean;
constructor(pathPrefix: string, pathSuffix: string, wdosboxJs: string, wdosboxxJs: string);
libzip(): Promise<WasmModule>;
dosbox(): Promise<WasmModule>;
dosboxx(): Promise<WasmModule>;
private loadModule;
}
export declare function loadWasmModule(url: string, moduleName: string, onprogress: (stage: string, total: number, loaded: number) => void): Promise<WasmModule>;
export {};

View File

@ -0,0 +1,16 @@
export default class LibZip {
module: any;
private home;
constructor(module: any, home?: string);
zipFromFs(changedAfterMs?: number): Promise<Uint8Array>;
zipToFs(zipArchive: Uint8Array, path?: string, filter?: string): Promise<void>;
writeFile(file: string, body: ArrayBuffer | Uint8Array | string): void;
readFile(file: string, encoding?: "binary" | "utf8"): Promise<string | Uint8Array>;
exists(file: string): boolean;
destroy(): any;
private normalizeFilename;
private createPath;
private chdirToHome;
private chdir;
zipAddFile(archive: string, file: string): Promise<void>;
}

View File

@ -0,0 +1,8 @@
import { ServerMessage, MessageHandler } from "./protocol";
export declare class MessagesQueue {
private messages;
handler(name: ServerMessage, props: {
[key: string]: any;
}): void;
sendTo(handler: MessageHandler): void;
}

View File

@ -0,0 +1,3 @@
export declare const compressBound: any;
export declare const compress: any;
export declare const uncompress: any;

View File

@ -0,0 +1,137 @@
import { CommandInterface, NetworkType, BackendOptions, DosConfig, InitFsEntry, PersistedSockdrives } from "../emulators";
import { CommandInterfaceEventsImpl } from "../impl/ci-impl";
export type ClientMessage = "wc-install" | "wc-run" | "wc-pack-fs-to-bundle" | "wc-add-key" | "wc-mouse-move" | "wc-mouse-button" | "wc-mouse-sync" | "wc-exit" | "wc-sync-sleep" | "wc-pause" | "wc-resume" | "wc-mute" | "wc-unmute" | "wc-connect" | "wc-disconnect" | "wc-backend-event" | "wc-asyncify-stats" | "wc-fs-tree" | "wc-fs-get-file" | "wc-send-data-chunk" | "wc-net-connected" | "wc-net-received" | "wc-sockdrive-opened" | "wc-sockdrive-new-range" | "wc-unload" | "wc-fs-delete-file";
export type ServerMessage = "ws-extract-progress" | "ws-ready" | "ws-server-ready" | "ws-frame-set-size" | "ws-update-lines" | "ws-log" | "ws-warn" | "ws-err" | "ws-stdout" | "ws-exit" | "ws-persist" | "ws-sound-init" | "ws-sound-push" | "ws-config" | "ws-sync-sleep" | "ws-connected" | "ws-disconnected" | "ws-asyncify-stats" | "ws-fs-tree" | "ws-send-data-chunk" | "ws-net-connect" | "ws-net-disconnect" | "ws-net-send" | "ws-sockdrive-open" | "ws-sockdrive-ready" | "ws-sockdrive-close" | "ws-sockdrive-load-range" | "ws-sockdrive-write-sector" | "ws-unload" | "ws-fs-delete-file";
export type MessageHandler = (name: ServerMessage, props: {
[key: string]: any;
}) => void;
export interface TransportLayer {
sessionId: string;
sendMessageToServer(name: ClientMessage, props: {
[key: string]: any;
}, transfer?: (ArrayBuffer | OffscreenCanvas)[]): void;
initMessageHandler(handler: MessageHandler): void;
exit?: () => void;
}
export interface FrameLine {
start: number;
heapu8: Uint8Array;
}
export interface DataChunk {
type: "ok" | "file" | "bundle";
name: string;
data: ArrayBuffer | null;
}
export interface AsyncifyStats {
offscreenCanvas?: boolean;
messageSent: number;
messageReceived: number;
messageFrame: number;
messageSound: number;
nonSkippableSleepCount: number;
sleepCount: number;
sleepTime: number;
cycles: number;
netSent: number;
netRecv: number;
driveIo: {
url: string;
preload: number;
total: number;
read: number;
write: number;
}[];
}
export interface FsNode {
name: string;
size: number | null;
nodes: FsNode[] | null;
}
export declare class CommandInterfaceOverTransportLayer implements CommandInterface {
private startedAt;
private exited;
private frameWidth;
private frameHeight;
private rgb;
private rgba;
private freq;
private utf8Decoder;
private init?;
private transport;
private ready;
private persistPromise?;
private persistResolve?;
private exitPromise?;
private exitResolve?;
private eventsImpl;
private keyMatrix;
private configPromise;
private configResolve;
private panicMessages;
private connectPromise;
private connectResolve;
private connectReject;
private disconnectPromise;
private disconnectResolve;
private asyncifyStatsPromise;
private asyncifyStatsResolve;
private fsTreePromise;
private fsTreeResolve;
private fsGetFilePromise;
private fsGetFileResolve;
private fsGetFileParts;
private fsDeleteFilePromise;
private fsDeleteFileResolve;
private dataChunkPromise;
private dataChunkResolve;
private networkId;
private network;
private sockdrives;
options: BackendOptions;
constructor(init: InitFsEntry[], transport: TransportLayer, ready: (err: Error | null) => void, options: BackendOptions);
private sendClientMessage;
private onServerMessage;
private onConfig;
private onFrameSize;
private onFrameLines;
private onSoundInit;
private onSoundPush;
private onLog;
private onWarn;
private onErr;
private onStdout;
config(): Promise<DosConfig>;
width(): number;
height(): number;
soundFrequency(): number;
screenshot(): Promise<ImageData>;
simulateKeyPress(...keyCodes: number[]): void;
sendKeyEvent(keyCode: number, pressed: boolean): void;
addKey(keyCode: number, pressed: boolean, timeMs: number): void;
sendMouseMotion(x: number, y: number): void;
sendMouseRelativeMotion(x: number, y: number): void;
sendMouseButton(button: number, pressed: boolean): void;
sendMouseSync(): void;
sendBackendEvent(payload: any): void;
persist(optOnlyChanges?: boolean): Promise<Uint8Array | PersistedSockdrives | null>;
private onPersist;
pause(): void;
resume(): void;
mute(): void;
unmute(): void;
exit(): Promise<void>;
private onExit;
events(): CommandInterfaceEventsImpl;
networkConnect(networkType: NetworkType, address: string): Promise<void>;
networkDisconnect(networkType: NetworkType): Promise<void>;
asyncifyStats(): Promise<AsyncifyStats>;
fsTree(): Promise<FsNode>;
fsReadFile(file: string): Promise<Uint8Array>;
fsWriteFile(file: string, contents: ReadableStream<Uint8Array> | Uint8Array): Promise<void>;
fsDeleteFile(file: string): Promise<boolean>;
persistSockdrives(): Promise<PersistedSockdrives>;
private sendDataChunk;
private sendFullDataChunk;
private dataChunkKey;
private mergeChunks;
}

View File

@ -0,0 +1,18 @@
export declare const RAW_STORE = "raw";
export declare const WRITE_STORE = "write";
export interface Store {
put: (key: number, data: Uint8Array, store: string) => Promise<void>;
get: (key: number, store: string) => Promise<Uint8Array | null>;
keys: (store: string) => Promise<number[]>;
each: (key: number[], store: string, callback: (key: number, data: Uint8Array) => void) => Promise<void>;
close: () => void;
}
export declare class NoStore implements Store {
owner: string;
close(): void;
put(key: number, data: Uint8Array, store: string): Promise<void>;
get(range: number, store: string): Promise<Uint8Array | null>;
keys(store: string): Promise<number[]>;
each(keys: number[], store: string, callback: (key: number, data: Uint8Array) => void): Promise<void>;
}
export declare function getStore(owner: string): Promise<Store>;

View File

@ -0,0 +1,28 @@
interface DriveInfo {
ahead_read: number;
range_count: number;
dropped_ranges: number[];
preload_ranges: number[] | "_";
small_ranges: number[];
cylinders: number;
heads: number;
sectors: number;
sector_size: number;
size: number;
name: string;
url: string;
preloadSizeInBytes: number;
sizeInBytes: number;
readInBytes: number;
writeInBytes: number;
}
export interface Drive {
info: DriveInfo;
range(sector: number): number;
readRangeAsync(range: number): void;
ready(): void;
write(sector: number, buffer: Uint8Array): void;
persist(): Promise<Uint8Array | null>;
}
export declare function sockdrive(url: string, _onNewRange: (range: number, buffer: Uint8Array) => void): Promise<Drive>;
export {};

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

Binary file not shown.

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

Binary file not shown.

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,277 @@
0:exit
1:__wasi_fd_close
2:__wasi_fd_write
3:emsc_getMTimeMs
4:__syscall_openat
5:__syscall_fcntl64
6:legalimport$_mktime_js
7:legalimport$_localtime_js
8:legalimport$__wasi_fd_seek
9:emscripten_resize_heap
10:emscripten_force_exit
11:emscripten_exit_with_live_runtime
12:emscripten_date_now
13:emsc_progress
14:_tzset_js
15:_setitimer_js
16:_emscripten_runtime_keepalive_clear
17:_abort_js
18:__wasi_proc_exit
19:__wasi_fd_read
20:__syscall_unlinkat
21:__syscall_stat64
22:__syscall_rmdir
23:__syscall_renameat
24:__syscall_newfstatat
25:__syscall_mkdirat
26:__syscall_lstat64
27:__syscall_ioctl
28:__syscall_getdents64
29:__syscall_fstat64
30:__syscall_chmod
31:__call_sighandler
32:zip_error_set
33:emmalloc_free
34:_zip_error_set_from_source
35:emmalloc_memalign
36:_zip_buffer_free
37:crc32_z
38:zip_source_free
39:_zip_buffer_put_16
40:_zip_buffer_get_16
41:_zip_buffer_get
42:strlen
43:out
44:pad
45:fiprintf
46:_zip_source_call
47:_zip_buffer_put_32
48:_tr_flush_block
49:zip_source_seek
50:_zip_string_free
51:_zip_buffer_new
52:_zip_buffer_get_32
53:zip_strerror
54:zip_error_init
55:zip_source_read
56:_zip_ef_free
57:_zip_buffer_set_offset
58:_zip_buffer_put_64
59:adler32_z
60:_zip_buffer_left
61:_zip_buffer_get_64
62:__syscall_ret
63:zip_source_tell_write
64:zip_source_stat
65:zip_source_make_command_bitmap
66:zip_source_close
67:fwrite
68:buffer_free
69:_zip_write
70:zip_stat_init
71:strchr
72:_zip_guess_encoding
73:_zip_dirent_free
74:_zip_buffer_offset
75:__wasi_syscall_ret
76:zip_error_to_data
77:zip_error_fini
78:strcmp
79:fmt_u
80:flush_pending
81:fclose
82:crc32
83:_zip_buffer_put
84:_zip_buffer_new_from_source
85:__memcpy
86:zip_close
87:umask
88:remove
89:memcmp
90:fflush
91:emmalloc_realloc
92:buffer_new
93:_zip_string_get
94:_zip_error_copy
95:_zip_dirent_clone
96:_zip_cdir_free
97:_zip_buffer_eof
98:_tr_flush_bits
99:zip_source_tell
100:zip_source_open
101:tolower
102:open
103:hash_resize
104:fill_window
105:_zip_string_new
106:_zip_string_length
107:_zip_progress_update
108:_zip_get_dirent
109:_zip_ef_new
110:_zip_dirent_write
111:_zip_dirent_init
112:_tr_stored_block
113:zip_source_rollback_write
114:zip_source_layered
115:zip_source_keep
116:zip_source_error
117:zip_open
118:vfiprintf
119:strcpy
120:stat
121:siprintf
122:memchr
123:inflate_table
124:hash_string
125:fputc
126:fopen
127:decrypt
128:close
129:build_tree
130:attempt_allocate
131:abort
132:_zip_unchange_data
133:_zip_u2d_time
134:_zip_read_data
135:_zip_read
136:_zip_get_name
137:_zip_get_encryption_implementation
138:_zip_fseek
139:_zip_file_get_offset
140:_zip_entry_finalize
141:_zip_ef_get_by_id
142:_zip_dirent_finalize
143:_zip_checkcons
144:_zip_allocate_new
145:__towrite
146:__strerror_l
147:__memset
148:__fwritex
149:__ftello
150:__fseeko_unlocked
151:zipfile_to_fs
152:zip_stat_index
153:zip_source_seek_write
154:zip_source_seek_compute_offset
155:zip_source_layered_create
156:zip_source_function_create
157:zip_source_file_create
158:zip_source_file
159:zip_source_decompress
160:zip_source_crc
161:zip_source_buffer
162:zip_set_file_compression
163:zip_recursively
164:zip_file_add
165:zip_error_to_str
166:zip_error_strerror
167:zip_discard
168:zError
169:wctomb
170:strdup
171:snprintf
172:send_tree
173:safe_create_dir
174:printf_core
175:pop_arg
176:longest_match
177:init_block.llvm.13708832007047381696
178:getint
179:frexp
180:fread
181:ferror
182:emmalloc_calloc
183:deflate_stored
184:deflateEnd
185:context_free
186:compression_source_new
187:compress_block
188:claim_more_memory
189:chmod
190:buffer_seek
191:buffer_grow_fragments
192:buffer_find_fragment
193:allocate
194:_zip_string_write
195:_zip_string_equal
196:_zip_string_crc32
197:_zip_stat_merge
198:_zip_source_zip_new
199:_zip_source_window_new
200:_zip_source_new
201:_zip_read_string
202:_zip_progress_end
203:_zip_name_locate
204:_zip_hash_delete
205:_zip_hash_add
206:_zip_fseek_u
207:_zip_file_replace
208:_zip_error_clear
209:_zip_entry_init
210:_zip_ef_write
211:_zip_ef_utf8
212:_zip_ef_size
213:_zip_ef_remove_internal
214:_zip_ef_parse
215:_zip_ef_merge
216:_zip_dirent_read
217:_zip_dirent_process_ef_utf_8
218:_zip_dirent_needs_zip64
219:_zip_cdir_new
220:_zip_cdir_grow
221:_zip_buffer_put_8
222:_zip_buffer_get_8
223:__vfprintf_internal
224:__tzset
225:__time
226:__overflow
227:__ftello_unlocked
228:__fstatat
229:__fseeko
230:__fdopen
231:zipfile_add
232:zip_to_fs
233:zip_source_pkware
234:zip_from_fs
235:zcfree
236:zcalloc
237:window_read
238:strcasecmp
239:start
240:sn_write
241:read_file
242:read_data
243:process
244:pop_arg_long_double
245:pkware_decrypt
246:main
247:libzip_destroy
248:input
249:get_changes_mtime_ms
250:fmt_fp
251:end_of_input
252:end
253:emmalloc_malloc
254:demangling_terminate_handler\28\29
255:deflate_slow
256:deflate_fast
257:decompress_allocate
258:deallocate
259:crc_read
260:compression_flags
261:compress_callback
262:compress_allocate
263:action_terminate
264:action_abort
265:abort_message
266:_emscripten_timeout
267:_emscripten_tempret_set
268:_emscripten_stack_alloc
269:__wasm_call_ctors
270:__stdio_write
271:__stdio_seek
272:__stdio_read
273:__stdio_close
274:__pthread_mutex_lock
275:__funcs_on_exit
276:__emscripten_stdout_seek

Binary file not shown.

View File

@ -2,11 +2,14 @@
/**************************************************************************** /****************************************************************************
* It's Eric Woodward's Site * It's Eric Woodward's Site
* *
* Copyright 2014-2024 Eric Woodward * Copyright 2014-2025 Eric Woodward
* Source released under CC0 Public Domain License v1.0 * Source released under CC0 Public Domain License v1.0
* https://www.itsericwoodward.com/licenses/cc0/ * https://www.itsericwoodward.com/licenses/cc0/
* http://creativecommons.org/publicdomain/zero/1.0/ * http://creativecommons.org/publicdomain/zero/1.0/
****************************************************************************/ ****************************************************************************/
import backgroundScroller from './backgroundScroller.js';
import themeSwitcher from './themeSwitcher.js';
export default (() => { export default (() => {
// we load this library via "module" to guarantee baseline ES6 functionality // we load this library via "module" to guarantee baseline ES6 functionality
@ -51,119 +54,9 @@ export default (() => {
actionBox.setAttribute("open", "true"); actionBox.setAttribute("open", "true");
/** THEME SWITCHER */ themeSwitcher(actionBox);
// load last theme backgroundScroller(actionBox);
const currentTheme = Cookies.get("currentTheme") ?? "";
const themeSwitch = document.createElement("div");
themeSwitch.innerHTML = [
'<label class="themeSwitch" for="themeSwitch">',
'<div class="themeSwitch-description">',
"Theme",
"</div>",
'<select id="themeSwitch" name="themeSwitch">',
`<option value="" ${
currentTheme === "" ? "selected" : ""
}>Default</option>`,
`<option value="themeAdmiral" ${
currentTheme === "themeAdmiral" ? "selected" : ""
}>Admiral</option>`,
`<option value="themeAntsy92" ${
currentTheme === "themeAntsy92" ? "selected" : ""
}>Antsy92</option>`,
`<option value="themeBingo" ${
currentTheme === "themeBingo" ? "selected" : ""
}>Bingo</option>`,
`<option value="themeCyber77" ${
currentTheme === "themeCyber77" ? "selected" : ""
}>Cyber77</option>`,
`<option value="themeLightCyan" ${
currentTheme === "themeLightCyan" ? "selected" : ""
}>LightCyan</option>`,
`<option value="themeTerminalGreen" ${
currentTheme === "themeTerminalGreen" ? "selected" : ""
}>Terminal Green</option>`,
`<option value="themeVagabond" ${
currentTheme === "themeVagabond" ? "selected" : ""
}>Vagabond</option>`,
"</label>",
].join("\n");
themeSwitch.classList.add("js-themeSwitch", "themeSwitch");
if (currentTheme)
document
.getElementsByTagName("body")[0]
.classList.add(currentTheme);
actionBox.append(themeSwitch);
// add toggle event
document
.getElementById("themeSwitch")
.addEventListener("change", function (e) {
const body = document.getElementsByTagName("body")[0];
body.className = body.className
.split(/\s/)
.filter((val) => !val.startsWith("theme"))
.concat(e.target.value)
.join(" ");
Cookies.set("currentTheme", e.target.value);
});
/** SCROLLING BACKGROUND */
// default to no scrolling on devices under 600 px w
const isMobile = window.matchMedia(
"only screen and (max-width: 600px)"
).matches;
// add background scrolling
const hasScrollToggle =
Cookies.get("scrollToggle") === true ||
Cookies.get("scrollToggle") === "true" ||
(Cookies.get("scrollToggle") === undefined && !isMobile);
const scrollToggle = document.createElement("div");
scrollToggle.innerHTML = [
'<label class="toggleSwitch" for="scrollingToggle">',
'<div class="toggleSwitch-description">',
"Background",
"</div>",
`<input class="toggleSwitch-checkbox" ${
hasScrollToggle ? "checked" : ""
} type="checkbox" id="scrollingToggle" />`,
'<div class="toggleSwitch-status" data-ts-on="SCROLLING" data-ts-off="STATIC"></div>',
"</label>",
].join("\n");
scrollToggle.classList.add("js-scrollToggle", "scrollToggle");
actionBox.append(scrollToggle);
actionBox.classList.add("js-actionBox");
const actionBoxTitle = document.createElement("summary");
actionBoxTitle.innerHTML =
"<h3 class='actionBox-title'>Settings</h3>";
actionBox.append(actionBoxTitle);
// add toggle event
document
.getElementById("scrollingToggle")
.addEventListener("click", function (e) {
const theList =
document.getElementById("gridContainer").classList;
theList.toggle("js-isAnimated");
Cookies.set(
"scrollToggle",
!!theList.contains("js-isAnimated")
);
});
// add class if active at startup
if (hasScrollToggle)
document
.getElementById("gridContainer")
.classList.add("js-isAnimated");
if (document.documentElement.className.indexOf("is404") > -1) { if (document.documentElement.className.indexOf("is404") > -1) {
document.getElementById("searchQuery").value = document.getElementById("searchQuery").value =

View File

@ -0,0 +1,76 @@
// @license magnet:?xt=urn:btih:90dc5c0be029de84e523b9b3922520e79e0e6f08&dn=cc0.txt CC0-1.0
/****************************************************************************
* It's Eric Woodward's Site
*
* Copyright 2014-2025 Eric Woodward
* Source released under CC0 Public Domain License v1.0
* https://www.itsericwoodward.com/licenses/cc0/
* http://creativecommons.org/publicdomain/zero/1.0/
****************************************************************************/
/**
* Execute returned function to add theme switching
*/
export default (actionBox) => {
if (!window.Cookies) return;
// load last theme
const currentTheme = Cookies.get("currentTheme") ?? "";
const themeSwitch = document.createElement("div");
themeSwitch.innerHTML = [
'<label class="themeSwitch" for="themeSwitch">',
'<div class="themeSwitch-description">',
"Theme",
"</div>",
'<select id="themeSwitch" name="themeSwitch">',
`<option value="" ${
currentTheme === "" ? "selected" : ""
}>Default</option>`,
`<option value="themeAdmiral" ${
currentTheme === "themeAdmiral" ? "selected" : ""
}>Admiral</option>`,
`<option value="themeAntsy92" ${
currentTheme === "themeAntsy92" ? "selected" : ""
}>Antsy92</option>`,
`<option value="themeBingo" ${
currentTheme === "themeBingo" ? "selected" : ""
}>Bingo</option>`,
`<option value="themeCyber77" ${
currentTheme === "themeCyber77" ? "selected" : ""
}>Cyber77</option>`,
`<option value="themeLightCyan" ${
currentTheme === "themeLightCyan" ? "selected" : ""
}>LightCyan</option>`,
`<option value="themeTerminalGreen" ${
currentTheme === "themeTerminalGreen" ? "selected" : ""
}>Terminal Green</option>`,
`<option value="themeVagabond" ${
currentTheme === "themeVagabond" ? "selected" : ""
}>Vagabond</option>`,
"</label>",
].join("\n");
themeSwitch.classList.add("js-themeSwitch", "themeSwitch");
if (currentTheme)
document
.getElementsByTagName("body")[0]
.classList.add(currentTheme);
actionBox.append(themeSwitch);
// add toggle event
document
.getElementById("themeSwitch")
.addEventListener("change", function (e) {
const body = document.getElementsByTagName("body")[0];
body.className = body.className
.split(/\s/)
.filter((val) => !val.startsWith("theme"))
.concat(e.target.value)
.join(" ");
Cookies.set("currentTheme", e.target.value);
});
}
// @license-end

View File

@ -662,6 +662,16 @@ samp {
margin: 0.5em; margin: 0.5em;
} }
.dosboxScreen {
margin: 1rem 0;
width: 100%;
}
.dosboxScreen > div > div > .relative > .flex {
background-color: #000;
padding: .5rem;
}
.embed { .embed {
display: block; display: block;
margin: 1em auto; margin: 1em auto;
@ -1720,3 +1730,42 @@ samp {
display: inherit; display: inherit;
} }
} }
/****************************************************************************
* CHIM / JS-DOS Pages Only
****************************************************************************/
#jsChimDb {
width: 100%;
height: 24em;
}
#jsChimDb a {
color: #049c74;
}
#jsChimDb a:hover {
color: #040308;
}
#jsChimDb a:hover:visited {
color: #040308;
}
#jsChimDb a:visited {
color: #1e6e58;
}
#jsChimDb .dosbox-canvas {
display: block;
margin: auto;
}
.dosbox-overlay, .dosbox-loader {
background-color: #111;
background-color: rgba(3,3,3,.7);
}
.dosbox-start {
color: #049c74;
}

View File

@ -12,7 +12,7 @@
<meta charset="utf-8" /> <meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1"> <meta name="viewport" content="width=device-width, initial-scale=1">
<meta http-equiv="Content-Security-Policy" <meta http-equiv="Content-Security-Policy"
content="<%- site.csp %>" /> content="<%- page.csp ? page.csp : site.csp %>" />
<meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta http-equiv="X-UA-Compatible" content="IE=edge">
<!-- LEARN MORE: <!-- LEARN MORE:
@ -48,7 +48,7 @@
<link rel="icon" type="image/png" sizes="192x192" href="/images/favicons/android-icon-192x192.png"> <link rel="icon" type="image/png" sizes="192x192" href="/images/favicons/android-icon-192x192.png">
<link rel="icon" type="image/png" sizes="32x32" href="/images/favicons/favicon-32x32.png"> <link rel="icon" type="image/png" sizes="32x32" href="/images/favicons/favicon-32x32.png">
<link rel="icon" type="image/png" sizes="96x96" href="/images/favicons/favicon-96x96.png"> <link rel="icon" type="image/png" sizes="96x96" href="/images/favicons/favicon-96x96.png">
<link rel="icon" type="image/png" sizes="16x16" href="/images/favicons/favicon-16x16.png"> <link rel="icon" type="image/png" sizes="16x16" href="/images/favicons/favicon.png">
<link rel="manifest" href="/manifest.json"> <link rel="manifest" href="/manifest.json">
<meta name="msapplication-TileColor" content="#9aa8bc"> <meta name="msapplication-TileColor" content="#9aa8bc">
<meta name="msapplication-TileImage" content="/images/favicons/ms-icon-144x144.png"> <meta name="msapplication-TileImage" content="/images/favicons/ms-icon-144x144.png">

View File

@ -6,7 +6,9 @@ license: CC0
section: games section: games
subsection: chim subsection: chim
content_type: feature content_type: feature
csp: "default-src 'self' data:; img-src 'self' https://*; media-src 'self' https://* data:; script-src 'self' 'unsafe-eval' 'unsafe-inline'; style-src 'self' 'unsafe-inline'; worker-src 'self' blob:;"
--- ---
<style type='text/css'> <style type='text/css'>
a code { a code {
background-color: transparent; background-color: transparent;
@ -22,65 +24,37 @@ content_type: feature
a:visited code { a:visited code {
color: #1e6e58; color: #1e6e58;
} }
#jsChimDb a {
color: #049c74;
}
#jsChimDb a:hover {
color: #040308;
}
#jsChimDb a:hover:visited {
color: #040308;
}
#jsChimDb a:visited {
color: #1e6e58;
}
#jsChimDb .dosbox-canvas {
display: block;
margin: auto;
}
.btnFullscreen {
background-color: #111;
background-color: rgba(3,3,3,.7);
color: #049c74 !important;
display: block;
margin: .5em auto;
padding: .5em;
}
.dosbox-overlay, .dosbox-loader {
background-color: #111;
background-color: rgba(3,3,3,.7);
}
.dosbox-start {
color: #049c74;
}
</style> </style>
In 1997, I released my first (and, so far, only) computer game, **Camp Happy Island Massacre**, a comedy-horror text game for the DOS operating system. Originally written while I was still in college, the game is about a cursed summer camp and the 3 surviving counselors who try to stop a horrific force before it claims them. In 1997, I released my first (and, so far, only) computer game, **Camp Happy Island Massacre**, a comedy-horror text game for the DOS operating system. Originally written while I was still in college, the game is about a cursed summer camp and the 3 surviving counselors who try to stop a horrific force before it claims them.
If you have a functional DOS machine (or an emulator, like [DOSBox](https://www.dosbox.com/)), you can download the game in a [ZIP file](/files/chim/chim.zip), which contains the following files: If you have a functional DOS machine (or an emulator, like [DOSBox](https://www.dosbox.com/)), you can download the game in a [ZIP file](/files/chim/chim.zip), which contains the following files:
+ [`CHIM.EXE`](/files/chim/chim.exe) *(the main executable file)* - [`CHIM.EXE`](/files/chim/chim.exe) _(the main executable file)_
+ [`CHIM.FAQ`](/files/chim/chim.faq) *(list of frequently asked questions)* - [`CHIM.FAQ`](/files/chim/chim.faq) _(list of frequently asked questions)_
+ [`FILE_ID.DIZ`](/files/chim/file_id.diz) *(ZIP file descriptor)* - [`FILE_ID.DIZ`](/files/chim/file_id.diz) _(ZIP file descriptor)_
+ [`INTRO.TXT`](/files/chim/intro.txt) *(the intro screen)* - [`INTRO.TXT`](/files/chim/intro.txt) _(the intro screen)_
+ [`LICENSE.TXT`](/files/chim/license.txt) *(the distribution license)* - [`LICENSE.TXT`](/files/chim/license.txt) _(the distribution license)_
+ [`MAP.TXT`](/files/chim/map.txt) *(a text map of the island)* - [`MAP.TXT`](/files/chim/map.txt) _(a text map of the island)_
And now, thanks to [DOSBox](https://www.dosbox.com/), [Emscripten](http://emscripten.org/), and their unholy lovechild, [JS-DOS](https://js-dos.com/), you can play **Camp Happy Island Massacre** in your browser: And now, thanks to [DOSBox](https://www.dosbox.com/), [Emscripten](http://emscripten.org/), and their unholy lovechild, [JS-DOS](https://js-dos.com/), you can play **Camp Happy Island Massacre** in your browser:
<div id="jsChimDb"></div> <div class="dosboxScreen" id="jsChimDb"></div>
<button class="btnFullscreen" onclick="chim_db.requestFullScreen();">Open in Fullscreen</button>
<script type="text/javascript" src="./js-dos-api.js"></script> <!-- js-dos style sheet -->
<script type="text/javascript"> <link rel="stylesheet" href="/scripts/lib/js-dos/js-dos.css">
var chim_db = new Dosbox({ <link rel="stylesheet" href="/styles/imports.css" type="text/css" />
id: "jsChimDb", <link rel="stylesheet" href="/styles/fonts.css" type="text/css" />
onload: function (chim_db) { <link rel="stylesheet" href="/styles/styles.css" type="text/css" />
chim_db.run("/chim/chim-exe.zip", "./CHIM.EXE");
}, <!-- js-dos -->
onrun: function (chim_db, app) { <script src="/scripts/lib/js-dos/js-dos.js"></script>
console.log("App '" + app + "' is running!");
} <script>
Dos(document.getElementById("jsChimDb"), {
pathPrefix: '/scripts/lib/js-dos/',
theme: 'dark',
thinSidebar: true,
url: "./chim.jsdos",
}); });
</script> </script>

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