Compare commits
5 Commits
c6221f1e30
...
69a1760a11
Author | SHA1 | Date |
---|---|---|
Leon van Kammen | 69a1760a11 | |
Leon van Kammen | 7bfa591536 | |
Leon van Kammen | 3c8d84c46d | |
Leon van Kammen | 68ee93f6e9 | |
Leon van Kammen | 2b4eb3123e |
|
@ -57,6 +57,7 @@ AFRAME.registerComponent('helloworld-html', {
|
||||||
"icons": [
|
"icons": [
|
||||||
{
|
{
|
||||||
"src": "https://css.gg/browser.svg",
|
"src": "https://css.gg/browser.svg",
|
||||||
|
"src": "data:image/svg+xml;base64,PHN2ZwogIHdpZHRoPSIyNCIKICBoZWlnaHQ9IjI0IgogIHZpZXdCb3g9IjAgMCAyNCAyNCIKICBmaWxsPSJub25lIgogIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIKPgogIDxwYXRoCiAgICBkPSJNNCA4QzQuNTUyMjggOCA1IDcuNTUyMjggNSA3QzUgNi40NDc3MiA0LjU1MjI4IDYgNCA2QzMuNDQ3NzIgNiAzIDYuNDQ3NzIgMyA3QzMgNy41NTIyOCAzLjQ0NzcyIDggNCA4WiIKICAgIGZpbGw9ImN1cnJlbnRDb2xvciIKICAvPgogIDxwYXRoCiAgICBkPSJNOCA3QzggNy41NTIyOCA3LjU1MjI4IDggNyA4QzYuNDQ3NzIgOCA2IDcuNTUyMjggNiA3QzYgNi40NDc3MiA2LjQ0NzcyIDYgNyA2QzcuNTUyMjggNiA4IDYuNDQ3NzIgOCA3WiIKICAgIGZpbGw9ImN1cnJlbnRDb2xvciIKICAvPgogIDxwYXRoCiAgICBkPSJNMTAgOEMxMC41NTIzIDggMTEgNy41NTIyOCAxMSA3QzExIDYuNDQ3NzIgMTAuNTUyMyA2IDEwIDZDOS40NDc3MSA2IDkgNi40NDc3MiA5IDdDOSA3LjU1MjI4IDkuNDQ3NzEgOCAxMCA4WiIKICAgIGZpbGw9ImN1cnJlbnRDb2xvciIKICAvPgogIDxwYXRoCiAgICBmaWxsLXJ1bGU9ImV2ZW5vZGQiCiAgICBjbGlwLXJ1bGU9ImV2ZW5vZGQiCiAgICBkPSJNMyAzQzEuMzQzMTUgMyAwIDQuMzQzMTUgMCA2VjE4QzAgMTkuNjU2OSAxLjM0MzE1IDIxIDMgMjFIMjFDMjIuNjU2OSAyMSAyNCAxOS42NTY5IDI0IDE4VjZDMjQgNC4zNDMxNSAyMi42NTY5IDMgMjEgM0gzWk0yMSA1SDNDMi40NDc3MiA1IDIgNS40NDc3MiAyIDZWOUgyMlY2QzIyIDUuNDQ3NzIgMjEuNTUyMyA1IDIxIDVaTTIgMThWMTFIMjJWMThDMjIgMTguNTUyMyAyMS41NTIzIDE5IDIxIDE5SDNDMi40NDc3MiAxOSAyIDE4LjU1MjMgMiAxOFoiCiAgICBmaWxsPSJjdXJyZW50Q29sb3IiCiAgLz4KPC9zdmc+",
|
||||||
"type": "image/svg+xml",
|
"type": "image/svg+xml",
|
||||||
"sizes": "512x512"
|
"sizes": "512x512"
|
||||||
}
|
}
|
||||||
|
|
|
@ -107,6 +107,7 @@ AFRAME.registerComponent('helloworld-htmlform', {
|
||||||
"icons": [
|
"icons": [
|
||||||
{
|
{
|
||||||
"src": "https://css.gg/browser.svg",
|
"src": "https://css.gg/browser.svg",
|
||||||
|
"src": "data:image/svg+xml;base64,PHN2ZwogIHdpZHRoPSIyNCIKICBoZWlnaHQ9IjI0IgogIHZpZXdCb3g9IjAgMCAyNCAyNCIKICBmaWxsPSJub25lIgogIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIKPgogIDxwYXRoCiAgICBkPSJNNCA4QzQuNTUyMjggOCA1IDcuNTUyMjggNSA3QzUgNi40NDc3MiA0LjU1MjI4IDYgNCA2QzMuNDQ3NzIgNiAzIDYuNDQ3NzIgMyA3QzMgNy41NTIyOCAzLjQ0NzcyIDggNCA4WiIKICAgIGZpbGw9ImN1cnJlbnRDb2xvciIKICAvPgogIDxwYXRoCiAgICBkPSJNOCA3QzggNy41NTIyOCA3LjU1MjI4IDggNyA4QzYuNDQ3NzIgOCA2IDcuNTUyMjggNiA3QzYgNi40NDc3MiA2LjQ0NzcyIDYgNyA2QzcuNTUyMjggNiA4IDYuNDQ3NzIgOCA3WiIKICAgIGZpbGw9ImN1cnJlbnRDb2xvciIKICAvPgogIDxwYXRoCiAgICBkPSJNMTAgOEMxMC41NTIzIDggMTEgNy41NTIyOCAxMSA3QzExIDYuNDQ3NzIgMTAuNTUyMyA2IDEwIDZDOS40NDc3MSA2IDkgNi40NDc3MiA5IDdDOSA3LjU1MjI4IDkuNDQ3NzEgOCAxMCA4WiIKICAgIGZpbGw9ImN1cnJlbnRDb2xvciIKICAvPgogIDxwYXRoCiAgICBmaWxsLXJ1bGU9ImV2ZW5vZGQiCiAgICBjbGlwLXJ1bGU9ImV2ZW5vZGQiCiAgICBkPSJNMyAzQzEuMzQzMTUgMyAwIDQuMzQzMTUgMCA2VjE4QzAgMTkuNjU2OSAxLjM0MzE1IDIxIDMgMjFIMjFDMjIuNjU2OSAyMSAyNCAxOS42NTY5IDI0IDE4VjZDMjQgNC4zNDMxNSAyMi42NTY5IDMgMjEgM0gzWk0yMSA1SDNDMi40NDc3MiA1IDIgNS40NDc3MiAyIDZWOUgyMlY2QzIyIDUuNDQ3NzIgMjEuNTUyMyA1IDIxIDVaTTIgMThWMTFIMjJWMThDMjIgMTguNTUyMyAyMS41NTIzIDE5IDIxIDE5SDNDMi40NDc3MiAxOSAyIDE4LjU1MjMgMiAxOFoiCiAgICBmaWxsPSJjdXJyZW50Q29sb3IiCiAgLz4KPC9zdmc+",
|
||||||
"type": "image/svg+xml",
|
"type": "image/svg+xml",
|
||||||
"sizes": "512x512"
|
"sizes": "512x512"
|
||||||
}
|
}
|
||||||
|
|
|
@ -104,6 +104,7 @@ AFRAME.registerComponent('helloworld-iframe', {
|
||||||
"icons": [
|
"icons": [
|
||||||
{
|
{
|
||||||
"src": "https://css.gg/browse.svg",
|
"src": "https://css.gg/browse.svg",
|
||||||
|
"src": "data:image/svg+xml;base64,PHN2ZwogIHdpZHRoPSIyNCIKICBoZWlnaHQ9IjI0IgogIHZpZXdCb3g9IjAgMCAyNCAyNCIKICBmaWxsPSJub25lIgogIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIKPgogIDxwYXRoCiAgICBkPSJNNCA4QzQuNTUyMjggOCA1IDcuNTUyMjggNSA3QzUgNi40NDc3MiA0LjU1MjI4IDYgNCA2QzMuNDQ3NzIgNiAzIDYuNDQ3NzIgMyA3QzMgNy41NTIyOCAzLjQ0NzcyIDggNCA4WiIKICAgIGZpbGw9ImN1cnJlbnRDb2xvciIKICAvPgogIDxwYXRoCiAgICBkPSJNOCA3QzggNy41NTIyOCA3LjU1MjI4IDggNyA4QzYuNDQ3NzIgOCA2IDcuNTUyMjggNiA3QzYgNi40NDc3MiA2LjQ0NzcyIDYgNyA2QzcuNTUyMjggNiA4IDYuNDQ3NzIgOCA3WiIKICAgIGZpbGw9ImN1cnJlbnRDb2xvciIKICAvPgogIDxwYXRoCiAgICBkPSJNMTAgOEMxMC41NTIzIDggMTEgNy41NTIyOCAxMSA3QzExIDYuNDQ3NzIgMTAuNTUyMyA2IDEwIDZDOS40NDc3MSA2IDkgNi40NDc3MiA5IDdDOSA3LjU1MjI4IDkuNDQ3NzEgOCAxMCA4WiIKICAgIGZpbGw9ImN1cnJlbnRDb2xvciIKICAvPgogIDxwYXRoCiAgICBmaWxsLXJ1bGU9ImV2ZW5vZGQiCiAgICBjbGlwLXJ1bGU9ImV2ZW5vZGQiCiAgICBkPSJNMyAzQzEuMzQzMTUgMyAwIDQuMzQzMTUgMCA2VjE4QzAgMTkuNjU2OSAxLjM0MzE1IDIxIDMgMjFIMjFDMjIuNjU2OSAyMSAyNCAxOS42NTY5IDI0IDE4VjZDMjQgNC4zNDMxNSAyMi42NTY5IDMgMjEgM0gzWk0yMSA1SDNDMi40NDc3MiA1IDIgNS40NDc3MiAyIDZWOUgyMlY2QzIyIDUuNDQ3NzIgMjEuNTUyMyA1IDIxIDVaTTIgMThWMTFIMjJWMThDMjIgMTguNTUyMyAyMS41NTIzIDE5IDIxIDE5SDNDMi40NDc3MiAxOSAyIDE4LjU1MjMgMiAxOFoiCiAgICBmaWxsPSJjdXJyZW50Q29sb3IiCiAgLz4KPC9zdmc+",
|
||||||
"type": "image/svg+xml",
|
"type": "image/svg+xml",
|
||||||
"sizes": "512x512"
|
"sizes": "512x512"
|
||||||
}
|
}
|
||||||
|
|
|
@ -86,6 +86,7 @@ AFRAME.registerComponent('helloworld-window', {
|
||||||
"icons": [
|
"icons": [
|
||||||
{
|
{
|
||||||
"src": "https://css.gg/browser.svg",
|
"src": "https://css.gg/browser.svg",
|
||||||
|
"src": "data:image/svg+xml;base64,PHN2ZwogIHdpZHRoPSIyNCIKICBoZWlnaHQ9IjI0IgogIHZpZXdCb3g9IjAgMCAyNCAyNCIKICBmaWxsPSJub25lIgogIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIKPgogIDxwYXRoCiAgICBkPSJNNCA4QzQuNTUyMjggOCA1IDcuNTUyMjggNSA3QzUgNi40NDc3MiA0LjU1MjI4IDYgNCA2QzMuNDQ3NzIgNiAzIDYuNDQ3NzIgMyA3QzMgNy41NTIyOCAzLjQ0NzcyIDggNCA4WiIKICAgIGZpbGw9ImN1cnJlbnRDb2xvciIKICAvPgogIDxwYXRoCiAgICBkPSJNOCA3QzggNy41NTIyOCA3LjU1MjI4IDggNyA4QzYuNDQ3NzIgOCA2IDcuNTUyMjggNiA3QzYgNi40NDc3MiA2LjQ0NzcyIDYgNyA2QzcuNTUyMjggNiA4IDYuNDQ3NzIgOCA3WiIKICAgIGZpbGw9ImN1cnJlbnRDb2xvciIKICAvPgogIDxwYXRoCiAgICBkPSJNMTAgOEMxMC41NTIzIDggMTEgNy41NTIyOCAxMSA3QzExIDYuNDQ3NzIgMTAuNTUyMyA2IDEwIDZDOS40NDc3MSA2IDkgNi40NDc3MiA5IDdDOSA3LjU1MjI4IDkuNDQ3NzEgOCAxMCA4WiIKICAgIGZpbGw9ImN1cnJlbnRDb2xvciIKICAvPgogIDxwYXRoCiAgICBmaWxsLXJ1bGU9ImV2ZW5vZGQiCiAgICBjbGlwLXJ1bGU9ImV2ZW5vZGQiCiAgICBkPSJNMyAzQzEuMzQzMTUgMyAwIDQuMzQzMTUgMCA2VjE4QzAgMTkuNjU2OSAxLjM0MzE1IDIxIDMgMjFIMjFDMjIuNjU2OSAyMSAyNCAxOS42NTY5IDI0IDE4VjZDMjQgNC4zNDMxNSAyMi42NTY5IDMgMjEgM0gzWk0yMSA1SDNDMi40NDc3MiA1IDIgNS40NDc3MiAyIDZWOUgyMlY2QzIyIDUuNDQ3NzIgMjEuNTUyMyA1IDIxIDVaTTIgMThWMTFIMjJWMThDMjIgMTguNTUyMyAyMS41NTIzIDE5IDIxIDE5SDNDMi40NDc3MiAxOSAyIDE4LjU1MjMgMiAxOFoiCiAgICBmaWxsPSJjdXJyZW50Q29sb3IiCiAgLz4KPC9zdmc+",
|
||||||
"type": "image/svg+xml",
|
"type": "image/svg+xml",
|
||||||
"sizes": "512x512"
|
"sizes": "512x512"
|
||||||
}
|
}
|
||||||
|
|
|
@ -44,6 +44,7 @@ AFRAME.registerComponent('helloworld', {
|
||||||
"icons": [
|
"icons": [
|
||||||
{
|
{
|
||||||
"src": "https://css.gg/shape-hexagon.svg",
|
"src": "https://css.gg/shape-hexagon.svg",
|
||||||
|
"src": "data:image/svg+xml;base64,PHN2ZwogIHdpZHRoPSIyNCIKICBoZWlnaHQ9IjI0IgogIHZpZXdCb3g9IjAgMCAyNCAyNCIKICBmaWxsPSJub25lIgogIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIKPgogIDxwYXRoCiAgICBmaWxsLXJ1bGU9ImV2ZW5vZGQiCiAgICBjbGlwLXJ1bGU9ImV2ZW5vZGQiCiAgICBkPSJNNiAxNS4yMzQ4TDEyIDE4LjU2ODFMMTggMTUuMjM0OFY4Ljc2NTIxTDEyIDUuNDMxODhMNiA4Ljc2NTIxVjE1LjIzNDhaTTEyIDJMMyA3VjE3TDEyIDIyTDIxIDE3VjdMMTIgMloiCiAgICBmaWxsPSJjdXJyZW50Q29sb3IiCiAgLz4KPC9zdmc+",
|
||||||
"type": "image/svg+xml",
|
"type": "image/svg+xml",
|
||||||
"sizes": "512x512"
|
"sizes": "512x512"
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,7 +3,7 @@ AFRAME.registerComponent('isoterminal', {
|
||||||
iso: { type:"string", "default":"com/isoterminal/xrsh.iso" },
|
iso: { type:"string", "default":"com/isoterminal/xrsh.iso" },
|
||||||
cols: { type: 'number',"default": 120 },
|
cols: { type: 'number',"default": 120 },
|
||||||
rows: { type: 'number',"default": 30 },
|
rows: { type: 'number',"default": 30 },
|
||||||
padding:{ type: 'number',"default": 15 },
|
padding:{ type: 'number',"default": 18 },
|
||||||
transparent: { type:'boolean', "default":false } // need good gpu
|
transparent: { type:'boolean', "default":false } // need good gpu
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -13,10 +13,8 @@ AFRAME.registerComponent('isoterminal', {
|
||||||
|
|
||||||
requires:{
|
requires:{
|
||||||
'window': "com/window.js",
|
'window': "com/window.js",
|
||||||
winboxjs: "https://unpkg.com/winbox@0.2.82/dist/winbox.bundle.min.js", // deadsimple windows: https://nextapps-de.github.io/winbox
|
xtermjs: "https://unpkg.com/@xterm/xterm@5.5.0/lib/xterm.js",
|
||||||
winboxcss: "https://unpkg.com/winbox@0.2.82/dist/css/winbox.min.css", //
|
xtermcss: "https://unpkg.com/@xterm/xterm@5.5.0/css/xterm.css",
|
||||||
xtermcss: "https://unpkg.com/xterm@3.12.0/dist/xterm.css",
|
|
||||||
xtermjs: "https://unpkg.com/xterm@3.12.0/dist/xterm.js",
|
|
||||||
v86: "com/isoterminal/libv86.js"
|
v86: "com/isoterminal/libv86.js"
|
||||||
//axterm: "https://unpkg.com/aframe-xterm-component/aframe-xterm-component.js"
|
//axterm: "https://unpkg.com/aframe-xterm-component/aframe-xterm-component.js"
|
||||||
},
|
},
|
||||||
|
@ -24,15 +22,12 @@ AFRAME.registerComponent('isoterminal', {
|
||||||
dom: {
|
dom: {
|
||||||
scale: 0.7,
|
scale: 0.7,
|
||||||
events: ['click','keydown'],
|
events: ['click','keydown'],
|
||||||
html: (me) => `<div class="isoterminal">
|
html: (me) => `<div class="isoterminal"></div>`,
|
||||||
<div style="white-space: pre; font: 14px monospace; line-height: 14px"></div>
|
|
||||||
<canvas></canvas>
|
|
||||||
</div>`,
|
|
||||||
|
|
||||||
css: (me) => `.isoterminal{
|
css: (me) => `.isoterminal{
|
||||||
background:#000;
|
|
||||||
padding: ${me.com.data.padding}px;
|
padding: ${me.com.data.padding}px;
|
||||||
/*overflow:hidden; */
|
width:100%;
|
||||||
|
height:100%;
|
||||||
}
|
}
|
||||||
.isoterminal *{
|
.isoterminal *{
|
||||||
white-space: pre;
|
white-space: pre;
|
||||||
|
@ -42,7 +37,14 @@ AFRAME.registerComponent('isoterminal', {
|
||||||
display:inline;
|
display:inline;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
.wb-body:has(> .isoterminal){ background: #000; }
|
|
||||||
|
.isoterminal style{ display:none }
|
||||||
|
|
||||||
|
.wb-body:has(> .isoterminal){
|
||||||
|
background: #000c;
|
||||||
|
overflow:hidden;
|
||||||
|
}
|
||||||
|
|
||||||
.isoterminal div{ display:block; }
|
.isoterminal div{ display:block; }
|
||||||
.isoterminal span{ display: inline }
|
.isoterminal span{ display: inline }
|
||||||
|
|
||||||
|
@ -76,12 +78,41 @@ AFRAME.registerComponent('isoterminal', {
|
||||||
return uint8Array;
|
return uint8Array;
|
||||||
},
|
},
|
||||||
|
|
||||||
runISO: function(dom){
|
runISO: function(dom,instance){
|
||||||
|
//var term = new Terminal()
|
||||||
|
//term.open(dom)
|
||||||
|
//term.write('Hello from \x1B[1;3;31mxterm.js\x1B[0m $ ')``
|
||||||
|
if( typeof Terminal == undefined ) throw 'xterm terminal not loaded'
|
||||||
|
// monkeypatch Xterm (which V86 initializes) so we can add our own constructor args
|
||||||
|
window._Terminal = window.Terminal
|
||||||
|
window.Terminal = function(opts){
|
||||||
|
const term = new window._Terminal({ ...opts,
|
||||||
|
cursorBlink:true,
|
||||||
|
onSelectionChange: function(e){
|
||||||
|
debugger
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
term.onSelectionChange( () => {
|
||||||
|
document.execCommand('copy')
|
||||||
|
term.select(0, 0, 0)
|
||||||
|
instance.setStatus('copied to clipboard')
|
||||||
|
})
|
||||||
|
return term
|
||||||
|
}
|
||||||
|
|
||||||
|
instance.setStatus = (msg) => {
|
||||||
|
const w = instance.winbox
|
||||||
|
w.titleBak = w.titleBak || w.title
|
||||||
|
instance.winbox.setTitle( `${w.titleBak} [${msg}]` )
|
||||||
|
}
|
||||||
|
|
||||||
var emulator = window.emulator = dom.emulator = new V86({
|
var emulator = window.emulator = dom.emulator = new V86({
|
||||||
wasm_path: "com/isoterminal/v86.wasm",
|
wasm_path: "com/isoterminal/v86.wasm",
|
||||||
memory_size: 32 * 1024 * 1024,
|
memory_size: 32 * 1024 * 1024,
|
||||||
vga_memory_size: 2 * 1024 * 1024,
|
vga_memory_size: 2 * 1024 * 1024,
|
||||||
screen_container: dom, //this.canvas.parentElement,
|
serial_container_xtermjs: dom,
|
||||||
|
//screen_container: dom, //this.canvas.parentElement,
|
||||||
bios: {
|
bios: {
|
||||||
url: "com/isoterminal/bios/seabios.bin",
|
url: "com/isoterminal/bios/seabios.bin",
|
||||||
},
|
},
|
||||||
|
@ -92,11 +123,10 @@ AFRAME.registerComponent('isoterminal', {
|
||||||
cdrom: {
|
cdrom: {
|
||||||
url: this.data.iso,
|
url: this.data.iso,
|
||||||
},
|
},
|
||||||
network_relay_url: "<UNUSED>",
|
cmdline: "rw root=host9p rootfstype=9p rootflags=trans=virtio,cache=loose modules=virtio_pci tsc=reliable init_on_free=on",
|
||||||
cmdline: "rw root=host9p rootfstype=9p rootflags=trans=virtio,cache=loose modules=virtio_pci tsc=reliable init_on_free=on init=/bin/date",
|
bzimage:{
|
||||||
//bzimage:{
|
url: "com/isoterminal/images/buildroot-bzimage.bin"
|
||||||
// url: "com/isoterminal/images/buildroot-bzimage.bin"
|
},
|
||||||
//},
|
|
||||||
//bzimage_initrd_from_filesystem: true,
|
//bzimage_initrd_from_filesystem: true,
|
||||||
//filesystem: {
|
//filesystem: {
|
||||||
// baseurl: "com/isoterminal/v86/images/alpine-rootfs-flat",
|
// baseurl: "com/isoterminal/v86/images/alpine-rootfs-flat",
|
||||||
|
@ -108,59 +138,195 @@ AFRAME.registerComponent('isoterminal', {
|
||||||
autostart: true,
|
autostart: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
emulator.bus.register("emulator-started", () => {
|
const loading = [
|
||||||
emulator.create_file("motd", this.toUint8Array(`
|
'loading quantum bits and bytes',
|
||||||
[38;5;57m ____ _____________ _________ ___ ___
|
'preparing quantum flux capacitors',
|
||||||
[38;5;93m \ \/ /\______ \/ _____// | \
|
'crunching peanuts and chakras',
|
||||||
[38;5;93m \ / | _/\_____ \/ ~ \
|
'preparing parallel universe',
|
||||||
[38;5;129m / \ | | \/ \ Y /
|
'loading quantum state fluctuations',
|
||||||
[38;5;165m /___/\ \ |____|_ /_______ /\___|_ /
|
'preparing godmode',
|
||||||
[38;5;201m \_/ \/ \/ \/
|
'loading cat pawns and cuteness',
|
||||||
|
'beaming up scotty',
|
||||||
|
'still faster than Windows update',
|
||||||
|
'loading a microlinux',
|
||||||
|
'figuring out meaning of life',
|
||||||
|
'Aligning your chakras now',
|
||||||
|
'Breathing in good vibes',
|
||||||
|
'Finding inner peace soon',
|
||||||
|
'Centering your Zen energy',
|
||||||
|
'Awakening third eye powers',
|
||||||
|
'Tuning into the universe',
|
||||||
|
'Balancing your cosmic karma',
|
||||||
|
'Stretching time and space',
|
||||||
|
'Recharging your soul battery',
|
||||||
|
'Transcending earthly limits'
|
||||||
|
]
|
||||||
|
|
||||||
`+ "\033[0m" ))
|
let motd = "\n\r"
|
||||||
|
motd += "[38;5;57m " + ' ____ _____________ _________ ___ ___ ' + "\n\r"
|
||||||
|
motd += "[38;5;93m " + ' \\ \\/ /\\______ \\/ _____// | \\ ' + "\n\r"
|
||||||
|
motd += "[38;5;93m " + ' \\ / | _/\\_____ \\/ ~ \\ ' + "\n\r"
|
||||||
|
motd += "[38;5;129m " + ' / \\ | | \\/ \\ Y / ' + "\n\r"
|
||||||
|
motd += "[38;5;165m " + ' /___/\\ \\ |____|_ /_______ /\\___|_ / ' + "\n\r"
|
||||||
|
motd += "[38;5;201m " + ' \\_/ \\/ \\/ \\/ ' + "\n\r"
|
||||||
|
motd += " \n\r"
|
||||||
|
motd += `${loading[ Math.floor(Math.random()*1000) % loading.length-1 ]}, please wait..\n\r\n\r`
|
||||||
|
motd += "\033[0m"
|
||||||
|
|
||||||
|
const files = [
|
||||||
|
"com/isoterminal/mnt/js",
|
||||||
|
"com/isoterminal/mnt/jsh",
|
||||||
|
"com/isoterminal/mnt/confirm",
|
||||||
|
"com/isoterminal/mnt/prompt",
|
||||||
|
"com/isoterminal/mnt/alert",
|
||||||
|
"com/isoterminal/mnt/hook",
|
||||||
|
"com/isoterminal/mnt/xrsh",
|
||||||
|
"com/isoterminal/mnt/profile",
|
||||||
|
"com/isoterminal/mnt/profile.xrsh",
|
||||||
|
"com/isoterminal/mnt/profile.js",
|
||||||
|
"com/isoterminal/mnt/motd",
|
||||||
|
"com/isoterminal/mnt/v86pipe"
|
||||||
|
]
|
||||||
|
|
||||||
|
const redirectConsole = (handler) => {
|
||||||
|
const log = console.log;
|
||||||
|
const dir = console.dir;
|
||||||
|
const err = console.error;
|
||||||
|
const warn = console.warn;
|
||||||
|
console.log = (...args)=>{
|
||||||
|
const textArg = args[0];
|
||||||
|
handler(textArg+'\n');
|
||||||
|
log.apply(log, args);
|
||||||
|
};
|
||||||
|
console.error = (...args)=>{
|
||||||
|
const textArg = args[0].message?args[0].message:args[0];
|
||||||
|
handler( textArg+'\n', '\x1b[31merror\x1b[0m');
|
||||||
|
err.apply(log, args);
|
||||||
|
};
|
||||||
|
console.dir = (...args)=>{
|
||||||
|
const textArg = args[0].message?args[0].message:args[0];
|
||||||
|
handler( JSON.stringify(textArg,null,2)+'\n');
|
||||||
|
dir.apply(log, args);
|
||||||
|
};
|
||||||
|
console.warn = (...args)=>{
|
||||||
|
const textArg = args[0].message?args[0].message:args[0];
|
||||||
|
handler(textArg+'\n','\x1b[38;5;208mwarn\x1b[0m');
|
||||||
|
err.apply(log, args);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
emulator.bus.register("emulator-started", async () => {
|
||||||
|
emulator.serial_adapter.term.element.querySelector('.xterm-viewport').style.background = 'transparent'
|
||||||
|
emulator.serial_adapter.term.clear()
|
||||||
|
emulator.serial_adapter.term.write(motd)
|
||||||
|
|
||||||
|
emulator.create_file("motd", this.toUint8Array(motd) )
|
||||||
emulator.create_file("js", this.toUint8Array(`#!/bin/sh
|
emulator.create_file("js", this.toUint8Array(`#!/bin/sh
|
||||||
cat /mnt/motd
|
cat /mnt/motd
|
||||||
cat > /dev/null
|
cat > /dev/null
|
||||||
`))
|
`))
|
||||||
|
|
||||||
|
redirectConsole( (str,prefix) => {
|
||||||
|
if( emulator.log_to_tty ){
|
||||||
|
prefix = prefix ? prefix+' ' : ' '
|
||||||
|
str.trim().split("\n").map( (line) => {
|
||||||
|
emulator.serial_adapter.term.write( '\r\x1b[38;5;165m/dev/browser: \x1b[0m'+prefix+line+'\n' )
|
||||||
|
})
|
||||||
|
emulator.serial_adapter.term.write( '\r' )
|
||||||
|
}
|
||||||
|
emulator.create_file( "console", this.toUint8Array( str ) )
|
||||||
|
})
|
||||||
|
|
||||||
|
let p = files.map( (f) => fetch(f) )
|
||||||
|
Promise.all(p)
|
||||||
|
.then( (files) => {
|
||||||
|
files.map( (f) => {
|
||||||
|
f.arrayBuffer().then( (buf) => {
|
||||||
|
emulator.create_file( f.url.replace(/.*mnt\//,''), new Uint8Array(buf) )
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
//emulator.serial0_send('chmod +x /mnt/js')
|
//emulator.serial0_send('chmod +x /mnt/js')
|
||||||
//emulator.serial0_send()
|
//emulator.serial0_send()
|
||||||
|
let line = ''
|
||||||
|
let ready = false
|
||||||
|
emulator.add_listener("serial0-output-byte", async (byte) => {
|
||||||
|
var chr = String.fromCharCode(byte);
|
||||||
|
if(chr < " " && chr !== "\n" && chr !== "\t" || chr > "~")
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(chr === "\n")
|
||||||
|
{
|
||||||
|
var new_line = line;
|
||||||
|
line = "";
|
||||||
|
}
|
||||||
|
else if(chr >= " " && chr <= "~")
|
||||||
|
{
|
||||||
|
line += chr;
|
||||||
|
}
|
||||||
|
|
||||||
|
//if(!ran_command && line.endsWith("~% "))
|
||||||
|
//{
|
||||||
|
// ran_command = true;
|
||||||
|
// emulator.serial0_send("chmod +x /mnt/test-i386\n");
|
||||||
|
// emulator.serial0_send("/mnt/test-i386 > /mnt/result\n");
|
||||||
|
// emulator.serial0_send("echo test fini''shed\n");
|
||||||
|
//}
|
||||||
|
//console.dir({line,new_line})
|
||||||
|
if( !ready && line.match(/^(\/ #|~%)/) ){
|
||||||
|
instance.dom.classList.remove('blink')
|
||||||
|
// set environment
|
||||||
|
let env = ['export BROWSER=1']
|
||||||
|
for ( let i in document.location ){
|
||||||
|
if( typeof document.location[i] == 'string' )
|
||||||
|
env.push( 'export '+String(i).toUpperCase()+'="'+document.location[i]+'"')
|
||||||
|
}
|
||||||
|
env.map( (e) => emulator.serial0_send(`echo '${e}' >> /mnt/profile\n`) )
|
||||||
|
let boot = `source /mnt/profile`
|
||||||
|
// exec hash as extra boot cmd
|
||||||
|
if( document.location.hash.length > 1 ){
|
||||||
|
boot += `&& cmd='${decodeURI(document.location.hash.substr(1))}' && $cmd`
|
||||||
|
}
|
||||||
|
emulator.serial0_send(boot+"\n")
|
||||||
|
instance.winbox.maximize()
|
||||||
|
emulator.serial_adapter.term.focus()
|
||||||
|
ready = true
|
||||||
|
//emulator.serial0_send("root\n")
|
||||||
|
//emulator.serial0_send("mv /mnt/js . && chmod +x js\n")
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// unix to js device
|
||||||
|
emulator.add_listener("9p-write-end", async (opts) => {
|
||||||
|
const decoder = new TextDecoder('utf-8');
|
||||||
|
|
||||||
|
if ( opts[0] == 'js' ){
|
||||||
|
const buf = await emulator.read_file("dev/browser/js")
|
||||||
|
const script = decoder.decode(buf)
|
||||||
|
try{
|
||||||
|
let res = (new Function(`${script}`))()
|
||||||
|
if( res && typeof res != 'string' ) res = JSON.stringify(res,null,2)
|
||||||
|
}catch(e){
|
||||||
|
console.error(e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
// enable/disable logging file (echo 1 > mnt/console.tty)
|
||||||
|
emulator.add_listener("9p-write-end", async (opts) => {
|
||||||
|
const decoder = new TextDecoder('utf-8');
|
||||||
|
if ( opts[0] == 'console.tty' ){
|
||||||
|
const buf = await emulator.read_file("console.tty")
|
||||||
|
const val = decoder.decode(buf)
|
||||||
|
emulator.log_to_tty = ( String(val).trim() == '1')
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
let line = ''
|
|
||||||
emulator.add_listener("serial0-output-byte", async (byte) => {
|
|
||||||
var chr = String.fromCharCode(byte);
|
|
||||||
if(chr < " " && chr !== "\n" && chr !== "\t" || chr > "~")
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(chr === "\n")
|
|
||||||
{
|
|
||||||
var new_line = line;
|
|
||||||
line = "";
|
|
||||||
}
|
|
||||||
else if(chr >= " " && chr <= "~")
|
|
||||||
{
|
|
||||||
line += chr;
|
|
||||||
}
|
|
||||||
|
|
||||||
//if(!ran_command && line.endsWith("~% "))
|
|
||||||
//{
|
|
||||||
// ran_command = true;
|
|
||||||
// emulator.serial0_send("chmod +x /mnt/test-i386\n");
|
|
||||||
// emulator.serial0_send("/mnt/test-i386 > /mnt/result\n");
|
|
||||||
// emulator.serial0_send("echo test fini''shed\n");
|
|
||||||
//}
|
|
||||||
console.dir({line,new_line})
|
|
||||||
|
|
||||||
if(new_line && new_line.includes("buildroot login:"))
|
|
||||||
{
|
|
||||||
emulator.serial0_send("root\n")
|
|
||||||
emulator.serial0_send("mv /mnt/js . && chmod +x js\n")
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
},
|
},
|
||||||
|
|
||||||
events:{
|
events:{
|
||||||
|
@ -179,8 +345,6 @@ AFRAME.registerComponent('isoterminal', {
|
||||||
launcher: async function(){
|
launcher: async function(){
|
||||||
if( this.instance ){
|
if( this.instance ){
|
||||||
const el = document.querySelector('.isoterminal')
|
const el = document.querySelector('.isoterminal')
|
||||||
el.classList.add('blink')
|
|
||||||
setTimeout( () => el.classList.remove('blink'), 2000 )
|
|
||||||
return console.warn('TODO: allow multiple terminals (see v86 examples)')
|
return console.warn('TODO: allow multiple terminals (see v86 examples)')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -190,32 +354,32 @@ AFRAME.registerComponent('isoterminal', {
|
||||||
this.el.sceneEl.appendChild( instance )
|
this.el.sceneEl.appendChild( instance )
|
||||||
|
|
||||||
instance.addEventListener('DOMready', () => {
|
instance.addEventListener('DOMready', () => {
|
||||||
this.runISO(instance.dom)
|
this.runISO(instance.dom, instance)
|
||||||
instance.setAttribute("window", `title: ${this.data.iso}; uid: ${instance.uid}; attach: #overlay; dom: #${instance.dom.id}`)
|
instance.setAttribute("window", `title: ${this.data.iso}; uid: ${instance.uid}; attach: #overlay; dom: #${instance.dom.id}`)
|
||||||
})
|
})
|
||||||
|
|
||||||
instance.addEventListener('window.oncreate', (e) => {
|
instance.addEventListener('window.oncreate', (e) => {
|
||||||
instance.dom.classList.add('blink')
|
instance.dom.classList.add('blink')
|
||||||
// resize after the dom content has been rendered & updated
|
|
||||||
setTimeout( () => {
|
|
||||||
let spans = [...instance.dom.querySelectorAll('span')]
|
|
||||||
instance.winbox.resize(
|
|
||||||
(spans[0].offsetWidth + (2*this.data.padding))+'px',
|
|
||||||
((spans.length * spans[0].offsetHeight) ) +'px'
|
|
||||||
)
|
|
||||||
},1200)
|
|
||||||
setTimeout( () => instance.dom.classList.remove('blink'), 5000 )
|
|
||||||
})
|
})
|
||||||
|
|
||||||
instance.addEventListener('window.onclose', (e) => {
|
instance.addEventListener('window.onclose', (e) => {
|
||||||
if( !confirm('do you want to kill this virtual machine and all its processes?') ) e.halt = true
|
if( !confirm('do you want to kill this virtual machine and all its processes?') ) e.halt = true
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const resize = (w,h) => {
|
||||||
|
if( instance.dom.emulator && instance.dom.emulator.serial_adapter ){
|
||||||
|
setTimeout( () => {
|
||||||
|
this.autoResize(instance.dom.emulator.serial_adapter.term,instance,-5)
|
||||||
|
},500) // wait for resize anim
|
||||||
|
}
|
||||||
|
}
|
||||||
|
instance.addEventListener('window.onresize', resize )
|
||||||
|
instance.addEventListener('window.onmaximize', resize )
|
||||||
|
|
||||||
instance.setAttribute("dom", "")
|
instance.setAttribute("dom", "")
|
||||||
instance.setAttribute("xd", "") // allows flipping between DOM/WebGL when toggling XD-button
|
instance.setAttribute("xd", "") // allows flipping between DOM/WebGL when toggling XD-button
|
||||||
instance.setAttribute("visible", AFRAME.utils.XD() == '3D' ? 'true' : 'false' )
|
instance.setAttribute("visible", AFRAME.utils.XD() == '3D' ? 'true' : 'false' )
|
||||||
instance.setAttribute("position", AFRAME.utils.XD.getPositionInFrontOfCamera(0.5) )
|
instance.setAttribute("position", AFRAME.utils.XD.getPositionInFrontOfCamera(0.5) )
|
||||||
instance.setAttribute("grabbable","")
|
|
||||||
|
|
||||||
const focus = () => document.querySelector('canvas.a-canvas').focus()
|
const focus = () => document.querySelector('canvas.a-canvas').focus()
|
||||||
instance.addEventListener('obbcollisionstarted', focus )
|
instance.addEventListener('obbcollisionstarted', focus )
|
||||||
|
@ -226,6 +390,39 @@ AFRAME.registerComponent('isoterminal', {
|
||||||
|
|
||||||
},
|
},
|
||||||
|
|
||||||
|
autoResize: function(term,instance,rowoffset){
|
||||||
|
if( !term.element ) return
|
||||||
|
|
||||||
|
const defaultScrollWidth = 24;
|
||||||
|
const MINIMUM_COLS = 2;
|
||||||
|
const MINIMUM_ROWS = 2;
|
||||||
|
|
||||||
|
const dims = term._core._renderService.dimensions;
|
||||||
|
const scrollbarWidth = (term.options.scrollback === 0
|
||||||
|
? 0
|
||||||
|
: (term.options.overviewRuler?.width || defaultScrollWidth ));
|
||||||
|
|
||||||
|
const parentElementStyle = window.getComputedStyle(instance.dom);
|
||||||
|
const parentElementHeight = parseInt(parentElementStyle.getPropertyValue('height'));
|
||||||
|
const parentElementWidth = Math.max(0, parseInt(parentElementStyle.getPropertyValue('width')));
|
||||||
|
const elementStyle = window.getComputedStyle(term.element);
|
||||||
|
const elementPadding = {
|
||||||
|
top: parseInt(elementStyle.getPropertyValue('padding-top')),
|
||||||
|
bottom: parseInt(elementStyle.getPropertyValue('padding-bottom')),
|
||||||
|
right: parseInt(elementStyle.getPropertyValue('padding-right')),
|
||||||
|
left: parseInt(elementStyle.getPropertyValue('padding-left'))
|
||||||
|
};
|
||||||
|
const elementPaddingVer = elementPadding.top + elementPadding.bottom;
|
||||||
|
const elementPaddingHor = elementPadding.right + elementPadding.left;
|
||||||
|
const availableHeight = parentElementHeight - elementPaddingVer;
|
||||||
|
const availableWidth = parentElementWidth - elementPaddingHor - scrollbarWidth;
|
||||||
|
const geometry = {
|
||||||
|
cols: Math.max(MINIMUM_COLS, Math.floor(availableWidth / dims.css.cell.width)),
|
||||||
|
rows: Math.max(MINIMUM_ROWS, Math.floor(availableHeight / dims.css.cell.height))
|
||||||
|
};
|
||||||
|
term.resize(geometry.cols, geometry.rows + (rowoffset||0) );
|
||||||
|
},
|
||||||
|
|
||||||
manifest: { // HTML5 manifest to identify app to xrsh
|
manifest: { // HTML5 manifest to identify app to xrsh
|
||||||
"iso": "linux-x64-4.15.iso",
|
"iso": "linux-x64-4.15.iso",
|
||||||
"short_name": "ISOTerm",
|
"short_name": "ISOTerm",
|
||||||
|
@ -233,6 +430,7 @@ AFRAME.registerComponent('isoterminal', {
|
||||||
"icons": [
|
"icons": [
|
||||||
{
|
{
|
||||||
"src": "https://css.gg/terminal.svg",
|
"src": "https://css.gg/terminal.svg",
|
||||||
|
"src": "data:image/svg+xml;base64,PHN2ZwogIHdpZHRoPSIyNCIKICBoZWlnaHQ9IjI0IgogIHZpZXdCb3g9IjAgMCAyNCAyNCIKICBmaWxsPSJub25lIgogIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIKPgogIDxwYXRoCiAgICBkPSJNNS4wMzMzIDE0LjgyODRMNi40NDc1MSAxNi4yNDI2TDEwLjY5MDIgMTJMNi40NDc1MSA3Ljc1NzMzTDUuMDMzMyA5LjE3MTU1TDcuODYxNzIgMTJMNS4wMzMzIDE0LjgyODRaIgogICAgZmlsbD0iY3VycmVudENvbG9yIgogIC8+CiAgPHBhdGggZD0iTTE1IDE0SDExVjE2SDE1VjE0WiIgZmlsbD0iY3VycmVudENvbG9yIiAvPgogIDxwYXRoCiAgICBmaWxsLXJ1bGU9ImV2ZW5vZGQiCiAgICBjbGlwLXJ1bGU9ImV2ZW5vZGQiCiAgICBkPSJNMiAyQzAuODk1NDMxIDIgMCAyLjg5NTQzIDAgNFYyMEMwIDIxLjEwNDYgMC44OTU0MyAyMiAyIDIySDIyQzIzLjEwNDYgMjIgMjQgMjEuMTA0NiAyNCAyMFY0QzI0IDIuODk1NDMgMjMuMTA0NiAyIDIyIDJIMlpNMjIgNEgyTDIgMjBIMjJWNFoiCiAgICBmaWxsPSJjdXJyZW50Q29sb3IiCiAgLz4KPC9zdmc+",
|
||||||
"type": "image/svg+xml",
|
"type": "image/svg+xml",
|
||||||
"sizes": "512x512"
|
"sizes": "512x512"
|
||||||
}
|
}
|
||||||
|
|
Binary file not shown.
|
@ -0,0 +1,6 @@
|
||||||
|
#!/bin/sh
|
||||||
|
title=$1
|
||||||
|
shift
|
||||||
|
msg="$*"
|
||||||
|
echo "[38;5;165m$title $(printf "\033[0m")$msg"
|
||||||
|
hook alert $title "$msg"
|
|
@ -0,0 +1,4 @@
|
||||||
|
#!/bin/sh
|
||||||
|
read -p "$(printf "\033[0m")[?] [38;5;165m$1 [y/n] $(printf "\033[0m")" y
|
||||||
|
test $y = y && echo true && exit
|
||||||
|
echo false
|
|
@ -0,0 +1 @@
|
||||||
|
alert("hello")
|
|
@ -0,0 +1,11 @@
|
||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
test -z $1 && { echo "usage: hook <cmd_or_jsfunction> [args]"; exit 0; }
|
||||||
|
cmd=$1
|
||||||
|
shift
|
||||||
|
|
||||||
|
test -d ~/hook.d/$cmd && {
|
||||||
|
find ~/hook.d/$cmd/ -type f -executable | while read hook; do
|
||||||
|
{ $hook "$@" || true; } | awk '{ gsub(/\/root\/\//,"",$1); $1 = sprintf("%-40s", $1)} 1'
|
||||||
|
done
|
||||||
|
}
|
|
@ -0,0 +1,19 @@
|
||||||
|
#!/bin/sh
|
||||||
|
test -z "$1" && { echo "Usage: js 'somefunction(1)'"; exit 0; }
|
||||||
|
|
||||||
|
test -n "$BROWSER" || { alert warning "/dev/browser not active (are you running outside of v86?)"; }
|
||||||
|
javascript="$*"
|
||||||
|
|
||||||
|
# if we are run as shebang, use the file as input
|
||||||
|
case "$1" in
|
||||||
|
*/*) javascript="args = String('$*').split(' '); $(cat $1 | tail +2)"
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
echo -n "$javascript" > /dev/browser/js
|
||||||
|
|
||||||
|
# should we use flock, an awesome way to make processes read/write the same file
|
||||||
|
# while preventing 1001 concurrency issues?
|
||||||
|
# attempt:
|
||||||
|
#
|
||||||
|
# flock /dev/browser/js -c "echo \"$javascript\" > /dev/browser/js"
|
|
@ -0,0 +1,42 @@
|
||||||
|
#!/bin/sh
|
||||||
|
# usage: jsh <function> [arg1] [arg2] ...
|
||||||
|
#
|
||||||
|
# 'jsh prompt question answer' executes: js prompt('question','answer') )
|
||||||
|
|
||||||
|
to_js(){
|
||||||
|
printf "%s(" "$1"
|
||||||
|
shift
|
||||||
|
for arg in "$@"; do
|
||||||
|
case "$arg" in
|
||||||
|
(*[\.0-9]*)
|
||||||
|
printf '%s,' "$arg"
|
||||||
|
;;
|
||||||
|
(*)
|
||||||
|
printf '"%s",' "$arg"
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
printf ")\n"
|
||||||
|
}
|
||||||
|
|
||||||
|
# run argument as js
|
||||||
|
test -z "$1" || {
|
||||||
|
func=$(to_js "$@")
|
||||||
|
func=${func/,)/)}
|
||||||
|
js "$func"
|
||||||
|
hook "$@"
|
||||||
|
exit 0
|
||||||
|
}
|
||||||
|
|
||||||
|
# otherwise start repl
|
||||||
|
echo "jsh> type 'exit' or CTRL-C to quit"
|
||||||
|
echo "jsh> HINT: to run alert('foo') outside this REPL, run 'jsh alert foo'"
|
||||||
|
echo "jsh>"
|
||||||
|
while true; do
|
||||||
|
echo -n -e "\r$(printf "\033[0m")jsh> $(printf "\033[0m")"
|
||||||
|
read line
|
||||||
|
test "$line" = exit && exit
|
||||||
|
js "$line"
|
||||||
|
done
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,15 @@
|
||||||
|
[38;5;93m . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
|
||||||
|
[38;5;57m . . ____ _____________ ________. ._. ._. . . . . . . . .
|
||||||
|
[38;5;93m . . _\ \/ /\______ \/ _____// | \. . . . . . . .
|
||||||
|
[38;5;93m . . _ \ / | _/\_____ \/ ~ \ . . . . . . .
|
||||||
|
[38;5;129m _ _ / \ | | \/ \ Y / _ _ _ _ _ _ _
|
||||||
|
[38;5;165m . . /___/\ \ |____|_ /_______ /\___|_ /. . . . . . . .
|
||||||
|
[38;5;201m . . . . . .\_/. . . . \/ . . . .\/ . . _ \/ . . . . . . . .
|
||||||
|
[38;5;165m ▬ ▬ ▬ https://xrsh.isvery.ninja ▬ ▬ ▬ ▬ ▬ ▬ ▬ ▬ ▬ ▬ ▬ ▬ ▬ ▬
|
||||||
|
[38;5;93m . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
|
||||||
|
|
||||||
|
[38;5;165mOpen, local-first, hackable & selfcontained XR apps.
|
||||||
|
|
||||||
|
credits: all FOSS devs | @lvk@mastodon.online
|
||||||
|
copy.sh (v86) | @utopiah@mastodon.pirateparty.be
|
||||||
|
|
|
@ -0,0 +1,22 @@
|
||||||
|
# install xrsh env
|
||||||
|
source /mnt/profile.xrsh
|
||||||
|
|
||||||
|
## forward not-found commands to javascript (via jsh)
|
||||||
|
command_not_found_handle(){
|
||||||
|
echo "$1 not found, did you mean $1(...) (javascript?)"
|
||||||
|
alert '[XRSH TIPS]'
|
||||||
|
alert 'js console: ' "type 'jsh'"
|
||||||
|
alert 'js shellfunction:' "type 'alias $1=\"jsh $1\"' to run '$1 yo' as $1('yo')"
|
||||||
|
alert 'js logging: ' "type 'echo 0 > /dev/browser/console.tty' to disable"
|
||||||
|
alert 'js capture log: ' "type 'tail -f /dev/browser/console'"
|
||||||
|
alert 'jsh<->sh hooks: ' "type 'chmod +x ~/hook.d/alert/* && alert helloworld'"
|
||||||
|
}
|
||||||
|
|
||||||
|
# source javascript functions
|
||||||
|
#js "$(cat /mnt/profile.js)"
|
||||||
|
|
||||||
|
resize
|
||||||
|
#clear
|
||||||
|
cat /mnt/motd
|
||||||
|
export PATH=$PATH:/mnt
|
||||||
|
export PS1="\n[38;5;57mx[38;5;93mr[38;5;129ms[38;5;165mh [38;5;201m# \033[0m"
|
|
@ -0,0 +1,3 @@
|
||||||
|
window.helloworld = function(){
|
||||||
|
alert("hello world")
|
||||||
|
}
|
|
@ -0,0 +1,47 @@
|
||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
test -d /dev/browser || {
|
||||||
|
|
||||||
|
setup_binaries(){
|
||||||
|
for bin in /mnt/prompt /mnt/alert /mnt/confirm /mnt/hook /mnt/js* /mnt/v86pipe /mnt/xrsh; do
|
||||||
|
chmod +x $bin
|
||||||
|
ln -s $bin /bin/.
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
setup_browser_dev(){
|
||||||
|
mkdir -p /mnt/dev/browser
|
||||||
|
touch /mnt/dev/browser/js
|
||||||
|
touch /mnt/dev/browser/html
|
||||||
|
touch /mnt/console.tty
|
||||||
|
ln -s /mnt/dev/browser /dev/browser
|
||||||
|
# setup console goodies
|
||||||
|
ln -s /mnt/console.tty /dev/browser/console.tty # emulator.write_file() only writes to /mnt/. :(
|
||||||
|
echo 1 > /dev/browser/console.tty # should be in /proc, but v86 gives 'no such file or dir' when creating it there
|
||||||
|
v86pipe /mnt/console /dev/browser/console &
|
||||||
|
|
||||||
|
test -f /etc/profile && rm /etc/profile
|
||||||
|
ln -s /mnt/profile /etc/profile
|
||||||
|
}
|
||||||
|
|
||||||
|
setup_hook_dirs(){ # see /mnt/hook for usage
|
||||||
|
mkdir -p ~/hook.d/alert
|
||||||
|
mkdir -p ~/hook.d/confirm
|
||||||
|
mkdir -p ~/hook.d/prompt
|
||||||
|
echo -e "#!/bin/sh\necho hook.d/alert/yo: yo \$*" > ~/hook.d/alert/yo
|
||||||
|
echo -e "#!/bin/js\nalert(\"hook.d/alert/yo.js \"+args.slice(1).join(' '))" > ~/hook.d/alert/yo.js
|
||||||
|
echo -e "#!/usr/bin/lua\nprint(\"hook.d/alert/yo.lua: yo \" .. arg[1])" > ~/hook.d/alert/yo.lua
|
||||||
|
}
|
||||||
|
|
||||||
|
setup_network(){
|
||||||
|
test -n "$BROWSER" || return 0
|
||||||
|
mount -a
|
||||||
|
udhcpc 1>>/var/log/network.log 2>>/var/log/network.log &
|
||||||
|
echo 0 > /proc/sys/kernel/printk
|
||||||
|
}
|
||||||
|
|
||||||
|
setup_binaries
|
||||||
|
setup_browser_dev
|
||||||
|
setup_hook_dirs
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,3 @@
|
||||||
|
#!/bin/sh
|
||||||
|
read -p "$(printf "\033[0m")[?] [38;5;165m$1: $(printf "\033[0m")" answer
|
||||||
|
echo "$answer"
|
|
@ -0,0 +1,26 @@
|
||||||
|
#!/bin/awk -f
|
||||||
|
|
||||||
|
BEGIN {
|
||||||
|
for (i = 1; i < ARGC; i++) {
|
||||||
|
options[i] = ARGV[i]
|
||||||
|
}
|
||||||
|
ARGC = 0
|
||||||
|
selected = 1
|
||||||
|
n = length(options)
|
||||||
|
|
||||||
|
while (1) {
|
||||||
|
printf "\r "
|
||||||
|
for (i = 1; i <= n; i++) {
|
||||||
|
if (i == selected)
|
||||||
|
printf "\033[44m%s\033[0m ", options[i]
|
||||||
|
else
|
||||||
|
printf "%s ", options[i]
|
||||||
|
}
|
||||||
|
if (c == 0) {
|
||||||
|
getline dir < "/dev/stdin"
|
||||||
|
print dir
|
||||||
|
if (dir == "up" && selected > 1) selected--
|
||||||
|
if (dir == "down" && selected < n) selected++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,30 @@
|
||||||
|
#!/bin/sh
|
||||||
|
#
|
||||||
|
# this daemon allows 'tail -f' on v86 files (which don't persist inode when updated
|
||||||
|
# via javascript)
|
||||||
|
# more info see: https://github.com/copy/v86/issues/1140
|
||||||
|
#
|
||||||
|
# Hopefully as V86 (or my understanding of it) matures, this will be no longer needed
|
||||||
|
|
||||||
|
test -z $2 && { echo "usage: v86pipe <logfile> <namedpipe>"; exit 0; }
|
||||||
|
|
||||||
|
# Start reading from the last line in the log file
|
||||||
|
last_size=0
|
||||||
|
LOG_FILE=$1
|
||||||
|
LOG_PIPE=$2
|
||||||
|
|
||||||
|
test -f $LOG_FILE || touch $LOG_FILE
|
||||||
|
test -p $LOG_PIPE || mkfifo $LOG_PIPE
|
||||||
|
|
||||||
|
while true; do
|
||||||
|
# Get the current size of the file using wc -c (count bytes)
|
||||||
|
current_size=$(wc -c < $LOG_FILE)
|
||||||
|
test $current_size = $last_size || {
|
||||||
|
cat $LOG_FILE > $LOG_PIPE
|
||||||
|
truncate -s 0 $LOG_FILE
|
||||||
|
}
|
||||||
|
last_size=$current_size
|
||||||
|
|
||||||
|
# Sleep for a moment to avoid excessive CPU usage
|
||||||
|
sleep 0.2
|
||||||
|
done
|
|
@ -0,0 +1,62 @@
|
||||||
|
#!/bin/sh
|
||||||
|
#
|
||||||
|
# a minimalistic terminal muxer
|
||||||
|
|
||||||
|
# Save the original stdout and stderr file descriptors for later restoration
|
||||||
|
exec 3>&1 4>&2
|
||||||
|
|
||||||
|
# Function to check if a session is already running on the given VT
|
||||||
|
is_session_running() {
|
||||||
|
vt_number=$1
|
||||||
|
|
||||||
|
# Check if any process is running on /dev/tty<vt_number>
|
||||||
|
fuser /dev/tty"$vt_number" >/dev/null 2>&1
|
||||||
|
return $?
|
||||||
|
}
|
||||||
|
|
||||||
|
# Function to mute the output of a session
|
||||||
|
mute_session() {
|
||||||
|
vt_number=$1
|
||||||
|
if is_session_running "$vt_number"; then
|
||||||
|
# Redirect stdout and stderr of the session to /dev/null
|
||||||
|
exec > /dev/null 2>&1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# Function to unmute the current session (restore stdout and stderr)
|
||||||
|
unmute_session() {
|
||||||
|
exec 1>&3 2>&4 # Restore stdout and stderr from file descriptors 3 and 4
|
||||||
|
}
|
||||||
|
|
||||||
|
# Function to start a new session if not already running
|
||||||
|
start_or_switch_session() {
|
||||||
|
vt_number=$1
|
||||||
|
|
||||||
|
# Mute all other sessions except the one we're switching to
|
||||||
|
for vt in $(seq 1 12); do # Assuming you have up to 12 VTs, adjust as needed
|
||||||
|
if [ "$vt" != "$vt_number" ]; then
|
||||||
|
mute_session "$vt"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
if is_session_running "$vt_number"; then
|
||||||
|
echo "Switching to existing session on VT$vt_number"
|
||||||
|
unmute_session # Unmute the session we're switching to
|
||||||
|
chvt "$vt_number"
|
||||||
|
else
|
||||||
|
echo "Starting a new session on VT$vt_number"
|
||||||
|
openvt -c "$vt_number" -- /bin/sh &
|
||||||
|
sleep 1 # Give the session a moment to start
|
||||||
|
unmute_session # Unmute the new session
|
||||||
|
chvt "$vt_number"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# Ensure a session number is provided
|
||||||
|
if [ "$#" -ne 1 ]; then
|
||||||
|
echo "Usage: $0 <session_number>"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Start or switch to the session
|
||||||
|
start_or_switch_session $1
|
|
@ -47,6 +47,7 @@ AFRAME.registerComponent('launcher-optional', {
|
||||||
"icons": [
|
"icons": [
|
||||||
{
|
{
|
||||||
"src": "https://css.gg/add-r.svg",
|
"src": "https://css.gg/add-r.svg",
|
||||||
|
"src": "data:image/svg+xml;base64,PHN2ZwogIHdpZHRoPSIyNCIKICBoZWlnaHQ9IjI0IgogIHZpZXdCb3g9IjAgMCAyNCAyNCIKICBmaWxsPSJub25lIgogIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIKPgogIDxwYXRoCiAgICBkPSJNMTIgNkMxMi41NTIzIDYgMTMgNi40NDc3MiAxMyA3VjExSDE3QzE3LjU1MjMgMTEgMTggMTEuNDQ3NyAxOCAxMkMxOCAxMi41NTIzIDE3LjU1MjMgMTMgMTcgMTNIMTNWMTdDMTMgMTcuNTUyMyAxMi41NTIzIDE4IDEyIDE4QzExLjQ0NzcgMTggMTEgMTcuNTUyMyAxMSAxN1YxM0g3QzYuNDQ3NzIgMTMgNiAxMi41NTIzIDYgMTJDNiAxMS40NDc3IDYuNDQ3NzIgMTEgNyAxMUgxMVY3QzExIDYuNDQ3NzIgMTEuNDQ3NyA2IDEyIDZaIgogICAgZmlsbD0iY3VycmVudENvbG9yIgogIC8+CiAgPHBhdGgKICAgIGZpbGwtcnVsZT0iZXZlbm9kZCIKICAgIGNsaXAtcnVsZT0iZXZlbm9kZCIKICAgIGQ9Ik01IDIyQzMuMzQzMTUgMjIgMiAyMC42NTY5IDIgMTlWNUMyIDMuMzQzMTUgMy4zNDMxNSAyIDUgMkgxOUMyMC42NTY5IDIgMjIgMy4zNDMxNSAyMiA1VjE5QzIyIDIwLjY1NjkgMjAuNjU2OSAyMiAxOSAyMkg1Wk00IDE5QzQgMTkuNTUyMyA0LjQ0NzcyIDIwIDUgMjBIMTlDMTkuNTUyMyAyMCAyMCAxOS41NTIzIDIwIDE5VjVDMjAgNC40NDc3MiAxOS41NTIzIDQgMTkgNEg1QzQuNDQ3NzIgNCA0IDQuNDQ3NzIgNCA1VjE5WiIKICAgIGZpbGw9ImN1cnJlbnRDb2xvciIKICAvPgo8L3N2Zz4K",
|
||||||
"type": "image/svg+xml",
|
"type": "image/svg+xml",
|
||||||
"sizes": "512x512"
|
"sizes": "512x512"
|
||||||
}
|
}
|
||||||
|
|
|
@ -63,7 +63,10 @@ AFRAME.registerComponent('launcher', {
|
||||||
if( this.data.attach ){
|
if( this.data.attach ){
|
||||||
this.el.object3D.visible = false
|
this.el.object3D.visible = false
|
||||||
if( this.isHand(this.data.attach) ){
|
if( this.isHand(this.data.attach) ){
|
||||||
this.data.attach.addEventListener('model-loaded', () => this.attachMenu() )
|
this.data.attach.addEventListener('model-loaded', () => {
|
||||||
|
this.ready = true
|
||||||
|
this.attachMenu()
|
||||||
|
})
|
||||||
// add button
|
// add button
|
||||||
this.menubutton = this.createMenuButton()
|
this.menubutton = this.createMenuButton()
|
||||||
this.menubutton.object3D.visible = false
|
this.menubutton.object3D.visible = false
|
||||||
|
@ -280,7 +283,7 @@ AFRAME.registerComponent('launcher', {
|
||||||
},
|
},
|
||||||
|
|
||||||
tick: function(){
|
tick: function(){
|
||||||
if( this.data.open ){
|
if( this.ready && this.data.open ){
|
||||||
let indexTipPosition = document.querySelector('#right-hand[hand-tracking-controls]').components['hand-tracking-controls'].indexTipPosition
|
let indexTipPosition = document.querySelector('#right-hand[hand-tracking-controls]').components['hand-tracking-controls'].indexTipPosition
|
||||||
this.el.object3D.getWorldPosition(this.worldPosition)
|
this.el.object3D.getWorldPosition(this.worldPosition)
|
||||||
const lookingAtPalm = this.data.attach.components['hand-tracking-controls'].wristObject3D.rotation.z > 2.0
|
const lookingAtPalm = this.data.attach.components['hand-tracking-controls'].wristObject3D.rotation.z > 2.0
|
||||||
|
|
|
@ -34,7 +34,8 @@ AFRAME.utils.require = function(arr_or_obj,opts){
|
||||||
if( AFRAME.required[id] ) return // already loaded before
|
if( AFRAME.required[id] ) return // already loaded before
|
||||||
AFRAME.required[id] = true
|
AFRAME.required[id] = true
|
||||||
|
|
||||||
if( !document.head.querySelector(`script#${id}`) ){
|
if( !document.body.querySelector(`script#${id}`) &&
|
||||||
|
!document.body.querySelector(`link#${id}`) ){
|
||||||
let {type} = parseURI(package)
|
let {type} = parseURI(package)
|
||||||
let p = new Promise( (resolve,reject) => {
|
let p = new Promise( (resolve,reject) => {
|
||||||
switch(type){
|
switch(type){
|
||||||
|
@ -43,14 +44,15 @@ AFRAME.utils.require = function(arr_or_obj,opts){
|
||||||
script.onload = () => setTimeout( () => resolve(id), 50 )
|
script.onload = () => setTimeout( () => resolve(id), 50 )
|
||||||
script.onerror = (e) => reject(e)
|
script.onerror = (e) => reject(e)
|
||||||
script.src = package
|
script.src = package
|
||||||
document.head.appendChild(script)
|
document.body.appendChild(script)
|
||||||
break;
|
break;
|
||||||
case "css": let link = document.createElement("link")
|
case "css": let link = document.createElement("link")
|
||||||
link.id = id
|
link.id = id
|
||||||
link.href = package
|
link.href = package
|
||||||
link.rel = 'stylesheet'
|
link.rel = 'stylesheet'
|
||||||
document.head.appendChild(link)
|
link.onload = () => setTimeout( () => resolve(id), 50 )
|
||||||
resolve(id)
|
link.onerror = (e) => reject(e)
|
||||||
|
document.body.appendChild(link)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
45
com/save.js
45
com/save.js
|
@ -3,10 +3,13 @@ AFRAME.registerComponent('save', {
|
||||||
foo: { type:"string"}
|
foo: { type:"string"}
|
||||||
},
|
},
|
||||||
|
|
||||||
init: function () {
|
init: async function () {
|
||||||
this.el.object3D.visible = false
|
this.el.object3D.visible = false
|
||||||
|
await AFRAME.utils.require(this.dependencies)
|
||||||
|
},
|
||||||
|
|
||||||
//this.el.innerHTML = ` `
|
dependencies:{
|
||||||
|
'xhook': 'https://jpillora.com/xhook/dist/xhook.min.js'
|
||||||
},
|
},
|
||||||
|
|
||||||
events:{
|
events:{
|
||||||
|
@ -17,6 +20,28 @@ AFRAME.registerComponent('save', {
|
||||||
|
|
||||||
},
|
},
|
||||||
|
|
||||||
|
convert:{
|
||||||
|
|
||||||
|
arrayBufferToBase64: function(buffer){
|
||||||
|
let binary = '';
|
||||||
|
const bytes = new Uint8Array(buffer);
|
||||||
|
const len = bytes.byteLength;
|
||||||
|
for (let i = 0; i < len; i++) binary += String.fromCharCode(bytes[i]);
|
||||||
|
return window.btoa(binary);
|
||||||
|
},
|
||||||
|
|
||||||
|
base64ToArrayBuffer: function(base64) {
|
||||||
|
const binaryString = window.atob(base64);
|
||||||
|
const len = binaryString.length;
|
||||||
|
const bytes = new Uint8Array(len);
|
||||||
|
|
||||||
|
for (let i = 0; i < len; i++) {
|
||||||
|
bytes[i] = binaryString.charCodeAt(i);
|
||||||
|
}
|
||||||
|
return bytes.buffer;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
save: function(){
|
save: function(){
|
||||||
let l = document.querySelector("#left-hand")
|
let l = document.querySelector("#left-hand")
|
||||||
let r = document.querySelector("#right-hand")
|
let r = document.querySelector("#right-hand")
|
||||||
|
@ -33,11 +58,8 @@ AFRAME.registerComponent('save', {
|
||||||
save_state: async function(){
|
save_state: async function(){
|
||||||
if( window.emulator ){
|
if( window.emulator ){
|
||||||
let binaryString = '';
|
let binaryString = '';
|
||||||
const state = await emulator.restore_state(state);
|
const state = await emulator.save_state() //restore_state(state);
|
||||||
uint8Array.forEach(byte => binaryString += String.fromCharCode(byte) );
|
//console.log(this.convert.arrayBufferToBase64(state))
|
||||||
let b64data = btoa(binaryString);
|
|
||||||
console.log(b64data)
|
|
||||||
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -53,8 +75,8 @@ AFRAME.registerComponent('save', {
|
||||||
|
|
||||||
inlineFiles: function(){
|
inlineFiles: function(){
|
||||||
let p = []
|
let p = []
|
||||||
let tags = [ ...document.querySelectorAll('script'),
|
let tags = [ ...document.querySelectorAll('script[src]'),
|
||||||
...document.querySelectorAll('link')
|
...document.querySelectorAll('link[href]')
|
||||||
]
|
]
|
||||||
tags.map( (el) => {
|
tags.map( (el) => {
|
||||||
let remoteFile = el.src || el.href
|
let remoteFile = el.src || el.href
|
||||||
|
@ -67,12 +89,12 @@ AFRAME.registerComponent('save', {
|
||||||
case 'LINK': el2 = document.createElement('style')
|
case 'LINK': el2 = document.createElement('style')
|
||||||
el2.setAttribute("type","text/css")
|
el2.setAttribute("type","text/css")
|
||||||
el2.setAttribute("_href", el.href )
|
el2.setAttribute("_href", el.href )
|
||||||
el2.innerHTML = text
|
el2.innerHTML = `${text}`
|
||||||
el.parentNode.appendChild(el2)
|
el.parentNode.appendChild(el2)
|
||||||
el.remove()
|
el.remove()
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'SCRIPT': el.innerHTML = text
|
case 'SCRIPT': el.innerHTML = `${text.replace(/<\//g,'</')}`
|
||||||
el.setAttribute("_src", el.src)
|
el.setAttribute("_src", el.src)
|
||||||
el.removeAttribute("src")
|
el.removeAttribute("src")
|
||||||
break;
|
break;
|
||||||
|
@ -92,6 +114,7 @@ AFRAME.registerComponent('save', {
|
||||||
"icons": [
|
"icons": [
|
||||||
{
|
{
|
||||||
"src": "https://css.gg/arrow-down-r.svg",
|
"src": "https://css.gg/arrow-down-r.svg",
|
||||||
|
"src": "data:image/svg+xml;base64,PHN2ZwogIHdpZHRoPSIyNCIKICBoZWlnaHQ9IjI0IgogIHZpZXdCb3g9IjAgMCAyNCAyNCIKICBmaWxsPSJub25lIgogIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIKPgogIDxwYXRoCiAgICBkPSJNMTQuODI4NCAxMi4wMjU5TDE2LjI0MjYgMTMuNDQwMkwxMiAxNy42ODI4TDcuNzU3MzMgMTMuNDQwMkw5LjE3MTU1IDEyLjAyNTlMMTEgMTMuODU0NFY2LjMxNzI0SDEzVjEzLjg1NDRMMTQuODI4NCAxMi4wMjU5WiIKICAgIGZpbGw9ImN1cnJlbnRDb2xvciIKICAvPgogIDxwYXRoCiAgICBmaWxsLXJ1bGU9ImV2ZW5vZGQiCiAgICBjbGlwLXJ1bGU9ImV2ZW5vZGQiCiAgICBkPSJNMSA1QzEgMi43OTA4NiAyLjc5MDg2IDEgNSAxSDE5QzIxLjIwOTEgMSAyMyAyLjc5MDg2IDIzIDVWMTlDMjMgMjEuMjA5MSAyMS4yMDkxIDIzIDE5IDIzSDVDMi43OTA4NiAyMyAxIDIxLjIwOTEgMSAxOVY1Wk01IDNIMTlDMjAuMTA0NiAzIDIxIDMuODk1NDMgMjEgNVYxOUMyMSAyMC4xMDQ2IDIwLjEwNDYgMjEgMTkgMjFINUMzLjg5NTQzIDIxIDMgMjAuMTA0NiAzIDE5VjVDMyAzLjg5NTQzIDMuODk1NDMgMyA1IDNaIgogICAgZmlsbD0iY3VycmVudENvbG9yIgogIC8+Cjwvc3ZnPg==",
|
||||||
"type": "image/svg+xml",
|
"type": "image/svg+xml",
|
||||||
"sizes": "512x512"
|
"sizes": "512x512"
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,64 @@
|
||||||
|
AFRAME.registerComponent('selfcontainer', {
|
||||||
|
schema: {
|
||||||
|
foo: { type:"string"}
|
||||||
|
},
|
||||||
|
|
||||||
|
init: async function () {
|
||||||
|
this.installProxyServer()
|
||||||
|
},
|
||||||
|
|
||||||
|
events:{ },
|
||||||
|
|
||||||
|
convert:{
|
||||||
|
|
||||||
|
arrayBufferToBase64: function(buffer){
|
||||||
|
let binary = '';
|
||||||
|
const bytes = new Uint8Array(buffer);
|
||||||
|
const len = bytes.byteLength;
|
||||||
|
for (let i = 0; i < len; i++) binary += String.fromCharCode(bytes[i]);
|
||||||
|
return window.btoa(binary);
|
||||||
|
},
|
||||||
|
|
||||||
|
base64ToArrayBuffer: function(base64) {
|
||||||
|
const binaryString = window.atob(base64);
|
||||||
|
const len = binaryString.length;
|
||||||
|
const bytes = new Uint8Array(len);
|
||||||
|
|
||||||
|
for (let i = 0; i < len; i++) {
|
||||||
|
bytes[i] = binaryString.charCodeAt(i);
|
||||||
|
}
|
||||||
|
return bytes.buffer;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
|
||||||
|
installProxyServer: function(){
|
||||||
|
if( !window.store ) window.store = {}
|
||||||
|
// selfcontain every webrequest to store (and serve if stored)
|
||||||
|
let curry = function(me){
|
||||||
|
return function(request, response, cb){
|
||||||
|
let data = request ? window.store[ request.url ] || false : false
|
||||||
|
if( data ){ // return inline version
|
||||||
|
console.log('selfcontained cache: '+request.url)
|
||||||
|
let res = new Response()
|
||||||
|
res[ data.binary ? 'data' : 'text' ] = data.binary ? () => me.convert.base64ToArrayBuffer(data.text) : data.text
|
||||||
|
cb(res)
|
||||||
|
}else{
|
||||||
|
if( response.text ){
|
||||||
|
data = {text: response.text}
|
||||||
|
}else{
|
||||||
|
data = {binary: true, text: me.convert.arrayBufferToBase64(response.data)}
|
||||||
|
}
|
||||||
|
window.store[ request.url ] = data
|
||||||
|
let $store = document.querySelector('template#store')
|
||||||
|
if( $store ) $store.remove()
|
||||||
|
document.head.innerHTML += `\n<`+`template id="store">\nwindow.store = ${JSON.stringify(window.store,null,2)}\n`+`<`+`/template>`
|
||||||
|
cb(response);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
xhook.after( curry(this) )
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
|
|
@ -2,7 +2,7 @@ AFRAME.registerComponent('window', {
|
||||||
schema:{
|
schema:{
|
||||||
title: {type:'string',"default":"title"},
|
title: {type:'string',"default":"title"},
|
||||||
width: {type:'string'}, // wrap
|
width: {type:'string'}, // wrap
|
||||||
height: {type:'string',"default":'50px'},
|
height: {type:'string',"default":'260px'},
|
||||||
uid: {type:'string'},
|
uid: {type:'string'},
|
||||||
attach: {type:'selector'},
|
attach: {type:'selector'},
|
||||||
dom: {type:'selector'},
|
dom: {type:'selector'},
|
||||||
|
@ -13,6 +13,8 @@ AFRAME.registerComponent('window', {
|
||||||
dependencies:{
|
dependencies:{
|
||||||
dom: "com/dom.js",
|
dom: "com/dom.js",
|
||||||
html: "https://unpkg.com/aframe-htmlmesh@2.1.0/build/aframe-html.js", // html to AFRAME
|
html: "https://unpkg.com/aframe-htmlmesh@2.1.0/build/aframe-html.js", // html to AFRAME
|
||||||
|
winboxjs: "https://unpkg.com/winbox@0.2.82/dist/winbox.bundle.min.js", // deadsimple windows: https://nextapps-de.github.io/winbox
|
||||||
|
//winboxcss: "https://unpkg.com/winbox@0.2.82/dist/css/winbox.min.css", // main theme
|
||||||
},
|
},
|
||||||
|
|
||||||
init: function(){
|
init: function(){
|
||||||
|
@ -32,13 +34,17 @@ AFRAME.registerComponent('window', {
|
||||||
id: this.data.uid || String(Math.random()).substr(4), // important hint for html-mesh
|
id: this.data.uid || String(Math.random()).substr(4), // important hint for html-mesh
|
||||||
root: this.data.attach || document.body,
|
root: this.data.attach || document.body,
|
||||||
mount: this.data.dom,
|
mount: this.data.dom,
|
||||||
|
onresize: () => this.el.emit('window.onresize',{}),
|
||||||
|
onmaximize: () => this.el.emit('window.onmaximize',{}),
|
||||||
oncreate: () => {
|
oncreate: () => {
|
||||||
this.el.emit('window.oncreate',{})
|
this.el.emit('window.oncreate',{})
|
||||||
// resize after the dom content has been rendered & updated
|
// resize after the dom content has been rendered & updated
|
||||||
setTimeout( () => {
|
setTimeout( () => {
|
||||||
winbox.resize( this.el.dom.offsetWidth+'px', this.el.dom.offsetHeight+'px' )
|
winbox.resize( this.el.dom.offsetWidth+'px', this.el.dom.offsetHeight+'px' )
|
||||||
setTimeout( () => this.el.setAttribute("html",`html:#${this.data.uid}; cursor:#cursor`), 1000)
|
setTimeout( () => this.el.setAttribute("html",`html:#${this.data.uid}; cursor:#cursor`), 1000)
|
||||||
this.el.setAttribute("grabbable","")
|
// hint grabbable's obb-collider to track the window-object
|
||||||
|
this.el.components['obb-collider'].data.trackedObject3D = 'components.html.el.object3D.children.0'
|
||||||
|
this.el.components['obb-collider'].update()
|
||||||
},1000)
|
},1000)
|
||||||
},
|
},
|
||||||
onclose: () => {
|
onclose: () => {
|
||||||
|
@ -46,14 +52,15 @@ AFRAME.registerComponent('window', {
|
||||||
this.el.emit('window.onclose',e)
|
this.el.emit('window.onclose',e)
|
||||||
if( e.halt ) return true
|
if( e.halt ) return true
|
||||||
this.data.dom.style.display = 'none';
|
this.data.dom.style.display = 'none';
|
||||||
|
this.data.dom.parentElement.remove()
|
||||||
|
debugger
|
||||||
|
this.el.parentElement.remove( this.el )
|
||||||
return false
|
return false
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
this.data.dom.style.display = '' // show
|
this.data.dom.style.display = '' // show
|
||||||
|
|
||||||
// hint grabbable's obb-collider to track the window-object
|
this.el.setAttribute("grabbable","")
|
||||||
this.el.components['obb-collider'].data.trackedObject3D = 'components.html.el.object3D.children.0'
|
|
||||||
this.el.components['obb-collider'].update()
|
|
||||||
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
Loading…
Reference in New Issue