parent
0d3e4f7d15
commit
c560655f1f
@ -0,0 +1,24 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Stackline web editor</title>
|
||||
<script type="module" src="index.js"></script>
|
||||
<link rel="stylesheet" href="style.css">
|
||||
</head>
|
||||
<body>
|
||||
<div id="left-pane">
|
||||
|
||||
</div>
|
||||
<div id="middle-pane">
|
||||
<canvas id="main-canvas">
|
||||
Your browser needs to support canvases, sowwy :(
|
||||
</canvas>
|
||||
</div>
|
||||
<div id="right-pane">
|
||||
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
@ -0,0 +1,194 @@
|
||||
import init, {
|
||||
World,
|
||||
Pane,
|
||||
FullTile,
|
||||
Signal,
|
||||
available_tiles,
|
||||
} from "/stackline-wasm/pkg/stackline_wasm.js";
|
||||
|
||||
let promises = [];
|
||||
promises.push(init());
|
||||
|
||||
const canvas = document.getElementById("main-canvas");
|
||||
const ctx = canvas.getContext("2d");
|
||||
|
||||
let font = new FontFace("Stackline Classic", "url(\"/font/StacklineClassic-Medium.otf\")");
|
||||
promises.push(font.load());
|
||||
await Promise.all(promises);
|
||||
|
||||
font = await font.loaded;
|
||||
document.fonts.add(font);
|
||||
|
||||
let world = World.new();
|
||||
let cx = 0;
|
||||
let cy = 0;
|
||||
let zoom = 1;
|
||||
|
||||
let pane = Pane.empty(5, 5);
|
||||
world.set_pane("main", pane);
|
||||
|
||||
let available = available_tiles();
|
||||
console.log(available);
|
||||
for (let n = 0; n < available.length; n++) {
|
||||
world.set(
|
||||
n % 5,
|
||||
~~(n / 5),
|
||||
new FullTile(available[n])
|
||||
);
|
||||
}
|
||||
|
||||
console.log(world.toString());
|
||||
|
||||
resize();
|
||||
window.addEventListener("resize", resize);
|
||||
window.requestAnimationFrame(loop);
|
||||
|
||||
function draw() {
|
||||
let zoom_factor = Math.ceil(Math.pow(2, zoom));
|
||||
let tile_size = 10 * zoom_factor;
|
||||
ctx.fillStyle = "#202027";
|
||||
ctx.fillRect(0, 0, canvas.width, canvas.height);
|
||||
|
||||
let panes = [];
|
||||
|
||||
for (let name of world.panes()) {
|
||||
let pane = world.get_pane(name);
|
||||
|
||||
ctx.strokeStyle = "rgba(128, 128, 128, 0.5)";
|
||||
ctx.lineWidth = zoom_factor;
|
||||
|
||||
panes.push({
|
||||
x: pane.x,
|
||||
y: pane.y,
|
||||
width: pane.width,
|
||||
height: pane.height
|
||||
});
|
||||
|
||||
ctx.strokeRect(
|
||||
Math.round(pane.x * tile_size + cx + canvas.width / 2) - zoom_factor * 1.5,
|
||||
Math.round(pane.y * tile_size + cy + canvas.height / 2) - zoom_factor * 1.5,
|
||||
Math.round(pane.width * tile_size) + zoom_factor * 3,
|
||||
Math.round(pane.height * tile_size) + zoom_factor * 3,
|
||||
);
|
||||
|
||||
pane.free();
|
||||
}
|
||||
|
||||
let from_y = Math.floor((-cy - canvas.height / 2) / tile_size);
|
||||
let to_y = Math.ceil((-cy + canvas.height / 2) / tile_size);
|
||||
let from_x = Math.floor((-cx - canvas.width / 2) / tile_size);
|
||||
let to_x = Math.ceil((-cx + canvas.width / 2) / tile_size);
|
||||
|
||||
let width = to_x - from_x + 1;
|
||||
let height = to_y - from_y + 1;
|
||||
|
||||
// TODO: memoize
|
||||
let chars = world.draw(-from_x, -from_y, width, height);
|
||||
ctx.textAlign = "left";
|
||||
ctx.textBaseline = "top";
|
||||
ctx.font = `${tile_size}px Stackline Classic`;
|
||||
|
||||
for (let y = from_y; y <= to_y; y++) {
|
||||
for (let x = from_x; x <= to_x; x++) {
|
||||
let x2 = x * tile_size + cx + canvas.width / 2;
|
||||
let y2 = y * tile_size + cy + canvas.height / 2;
|
||||
|
||||
let index = 3 * (width * (y - from_y) + x - from_x);
|
||||
|
||||
let ch = String.fromCharCode(chars[index]);
|
||||
let fg = to_color(chars[index + 1]);
|
||||
let bg = chars[index + 2] === 0 ? null : to_color(chars[index + 2]);
|
||||
|
||||
if (ch !== " ") {
|
||||
if (bg) {
|
||||
ctx.fillStyle = `rgba(${bg.join(",")})`;
|
||||
ctx.fillRect(
|
||||
Math.round(x2),
|
||||
Math.round(y2),
|
||||
Math.round(x2 + tile_size) - Math.round(x2),
|
||||
Math.round(y2 + tile_size) - Math.round(y2),
|
||||
);
|
||||
}
|
||||
ctx.fillStyle = `rgba(${fg.join(",")})`;
|
||||
ctx.fillText(
|
||||
ch,
|
||||
Math.round(x2),
|
||||
Math.round(y2),
|
||||
);
|
||||
} else {
|
||||
// Draw grid
|
||||
let inside = false;
|
||||
|
||||
for (let pane of panes) {
|
||||
if (x >= pane.x && x < pane.x + pane.width && y >= pane.y && y < pane.y + pane.height) {
|
||||
inside = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
ctx.fillStyle = inside ? "#606060" : "#404040";
|
||||
ctx.fillRect(
|
||||
Math.round(x2 + tile_size / 2) - zoom_factor,
|
||||
Math.round(y2 + tile_size / 2) - zoom_factor,
|
||||
Math.max(zoom_factor, 2.0),
|
||||
Math.max(zoom_factor, 2.0)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function resize() {
|
||||
canvas.width = canvas.clientWidth;
|
||||
canvas.height = canvas.clientHeight;
|
||||
|
||||
draw();
|
||||
}
|
||||
|
||||
function loop() {
|
||||
draw();
|
||||
window.requestAnimationFrame(loop);
|
||||
}
|
||||
|
||||
let mouse_x = 0, mouse_y = 0;
|
||||
let mouse_down = false;
|
||||
|
||||
canvas.addEventListener("mousedown", (evt) => {
|
||||
mouse_x = evt.clientX;
|
||||
mouse_y = evt.clientY;
|
||||
mouse_down = true;
|
||||
});
|
||||
|
||||
canvas.addEventListener("mousemove", (evt) => {
|
||||
if (mouse_down) {
|
||||
// TODO: numerically stable solution
|
||||
cx += evt.clientX - mouse_x;
|
||||
cy += evt.clientY - mouse_y;
|
||||
|
||||
mouse_x = evt.clientX;
|
||||
mouse_y = evt.clientY;
|
||||
}
|
||||
});
|
||||
|
||||
canvas.addEventListener("mouseup", (evt) => {
|
||||
mouse_down = false;
|
||||
});
|
||||
|
||||
canvas.addEventListener("mouseleave", (evt) => {
|
||||
mouse_down = false;
|
||||
});
|
||||
|
||||
canvas.addEventListener("wheel", (event) => {
|
||||
const ZOOM_STRENGTH = -0.005;
|
||||
zoom += event.deltaY * ZOOM_STRENGTH;
|
||||
zoom = Math.min(Math.max(zoom, 0.0), 4.0);
|
||||
});
|
||||
|
||||
function to_color(num) {
|
||||
let alpha = (num >> 24) & 0xff;
|
||||
let red = (num >> 16) & 0xff;
|
||||
let green = (num >> 8) & 0xff;
|
||||
let blue = num & 0xff;
|
||||
|
||||
return [red, green, blue, alpha];
|
||||
}
|
@ -0,0 +1,21 @@
|
||||
body {
|
||||
margin: 0;
|
||||
height: 100vh;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: stretch;
|
||||
overflow-y: hidden;
|
||||
}
|
||||
|
||||
#left-pane, #right-pane {
|
||||
max-width: 25vw;
|
||||
}
|
||||
|
||||
#middle-pane {
|
||||
flex-grow: 1;
|
||||
}
|
||||
|
||||
#main-canvas {
|
||||
width: 100%;
|
||||
height: 100vh;
|
||||
}
|
Binary file not shown.
@ -0,0 +1,108 @@
|
||||
Stackline Classic
|
||||
Shad Amethyst
|
||||
Medium
|
||||
11:11:10:9:-1:0:10
|
||||
65:AAPAzBhGCMEf4wRgnjgAAA==
|
||||
77:ABwZxj3G6MkYIwRgnjgAAA==
|
||||
66:AB/hgjBGCP4YIwRgn+AAAA==
|
||||
67:AAfhwjAGAMAYAwBwh+AAAA==
|
||||
68:AB/hgjBGCMEYIwRgn+AAAA==
|
||||
69:AB/xgjAGAPgYAwBgn/AAAA==
|
||||
70:AB/xgjAGAPgYAwBgHgAAAA==
|
||||
71:AAfhwjAGAMAY4wRwh+AAAA==
|
||||
72:AB45gjBGCP8YIwRgnjgAAA==
|
||||
73:AAPAMAYAwBgDAGAMA8AAAA==
|
||||
74:AAHgGAMAYAwBgjBGB4AAAA==
|
||||
75:AB5xhDCGIPgYgwhhHnAAAA==
|
||||
76:AB4BgDAGAMAYAwBgn/AAAA==
|
||||
78:AB5xhDiHkNoZwxhhHnAAAA==
|
||||
79:AAfhxjBGCMEYIwRxh+AAAA==
|
||||
80:AB/BhDCGEPwYAwBgHgAAAA==
|
||||
81:AAfhxjBGCMEZIzRzh/ADAA==
|
||||
82:AB/hgjBGCP4ZAxBhHjAAAA==
|
||||
83:AAfhwjAGAH4AYAxDh+AAAA==
|
||||
84:AA/xMgYAwBgDAGAMA8AAAA==
|
||||
85:AB45gjBGCMEYIwRgh+AAAA==
|
||||
86:AB45gjBGCMEYIYgaAYAAAA==
|
||||
87:AB45gjBGCMkZIyQ1A0AAAA==
|
||||
88:ABxxhBkBwBAHATBDHHAAAA==
|
||||
89:AB45gjBHEHQHAGAMA8AAAA==
|
||||
90:AB/yDAMAwDAMAwBgn/AAAA==
|
||||
112:AAAAAD8DEGIMQfAwBgHgAA==
|
||||
62:AAAAYAYAYAcBgGAYAAAAAA==
|
||||
60:AAAAGAYBgOAGAGAGAAAAAA==
|
||||
43:AAEAIAQAgf8CAEAIAQAAAA==
|
||||
9532:AACAEAIAQP+BACAEAIAAAA==
|
||||
9474:AACAEAIAQAgBACAEAIAAAA==
|
||||
9472:AAAAAAAAAP+AAAAAAAAAAA==
|
||||
118:AAAAAD3DEGIMQcgeAYAAAA==
|
||||
115:AAAAAA4DIGAHADAmA4AAAA==
|
||||
8853:AA/jBkRIiX0iJETBj+AAAA==
|
||||
8854:AA/jBkBICX0gJATBj+AAAA==
|
||||
8855:AA/jBlFJSRElJRTBj+AAAA==
|
||||
8856:AA/jBkFISREkJQTBj+AAAA==
|
||||
8857:AA/jBllKSREkpTTBj+AAAA==
|
||||
45:AAAAAAAAAf8AAAAAAAAAAA==
|
||||
124:AAEAIAQAgBACAEAIAQAAAA==
|
||||
109:AAAAAH2GSMkZIyRknrgAAA==
|
||||
110:AAAAAD8DEGIMQYgxD3AAAA==
|
||||
111:AAAAAA8DEGIMQYgxA8AAAA==
|
||||
113:AAAAAA+DIGQMgPACAEAcAA==
|
||||
114:AAAAAB0B0DAGAMAYB4AAAA==
|
||||
11363:AR/BlDSHEPwYBwBgHgAAAA==
|
||||
9013:AAAAAAAEEMYNgOAIAQAAAA==
|
||||
116:AAAAYAwD4DAGAMAaAYAAAA==
|
||||
117:AAAAADiDEGIMQYgxA8AAAA==
|
||||
94:AAEAIA4DYMYQQAAAAAAAAA==
|
||||
97:AAAAAA8CEAIHwcgxA9AAAA==
|
||||
98:AAABwBgDAHwMQYgxD8AAAA==
|
||||
99:AAAAAA8DEGAMAYAxA8AAAA==
|
||||
100:AAAADgCAED4MQYgxA/AAAA==
|
||||
101:AAAAAA8DEGIPwYAxA8AAAA==
|
||||
102:AAAAOAyBgDAPAMAYB4AAAA==
|
||||
103:AAAAAA/DEGIMQPgBBCB4AA==
|
||||
104:AAABwBgDAHwMQYgxDnAAAA==
|
||||
108:AAAA4AwBgDAGAMAYAYAAAA==
|
||||
107:AAABwBnDEHQNAZAxDnAAAA==
|
||||
105:AAAAMAYAABgDAGAMAcAAAA==
|
||||
106:AAAAGAMAAAwBgDAGBMBwAA==
|
||||
119:AAAAAHjmCMEZIyQ1A8AAAA==
|
||||
120:AAAAADmDIDgCAOAmDOAAAA==
|
||||
121:AAAAAD3DEGIGgGAEAcAAAA==
|
||||
122:AAAAAB/CMAwDAMAYh/AAAA==
|
||||
9673:AAAA+CCF0LoXQgg+AAAAAA==
|
||||
9675:AAAA+CCEEIIQQgg+AAAAAA==
|
||||
9677:AAAA+CCFUKoVQgg+AAAAAA==
|
||||
9678:AAAA+CCF0KoXQgg+AAAAAA==
|
||||
9676:AAAAqCCAAIIAAggqAAAAAA==
|
||||
9679:AAAA+D+H8P4fw/g+AAAAAA==
|
||||
9680:AAAA+DyHkPIeQ8g+AAAAAA==
|
||||
9681:AAAA+CeE8J4Twng+AAAAAA==
|
||||
9682:AAAA+CCEEP4fw/g+AAAAAA==
|
||||
9683:AAAA+D+H8P4QQgg+AAAAAA==
|
||||
9684:AAAA+CeE8J4QQgg+AAAAAA==
|
||||
9685:AAAA+CeE8P4fw/g+AAAAAA==
|
||||
9686:AAAA4DwHgPAeA8A4AAAAAA==
|
||||
9687:AAAAOAeA8B4DwHgOAAAAAA==
|
||||
9716:AAAA+CSEkPIQQgg+AAAAAA==
|
||||
9717:AAAA+CCEEPISQkg+AAAAAA==
|
||||
9718:AAAA+CCEEJ4SQkg+AAAAAA==
|
||||
9719:AAAA+CSEkJ4QQgg+AAAAAA==
|
||||
9655:AAABgCwEYIMRgsBgAAAAAA==
|
||||
9661:AAAB/CCCIEQFAKAIAQAAAA==
|
||||
9665:AAAABgNBiMEGIDQBgAAAAA==
|
||||
9651:AAAAIAQBQCgIgRBBD+AAAA==
|
||||
8593:AAEAcB8GsJICAEAIAQAAAA==
|
||||
8592:AAAAYBgGAf8YAYAYAAAAAA==
|
||||
8594:AAAAMAMAMf8AwDAMAAAAAA==
|
||||
8595:AAEAIAQAgJIawfAcAQAAAA==
|
||||
8280:AAOAIAQICccgIEAIA4AAAA==
|
||||
8860:AA/jBkBL6QEvpATBj+AAAA==
|
||||
63:AAPAjAGAMAwDAAAMAYAAAA==
|
||||
191:AAGAMAAAwDAMAYAxA8AAAA==
|
||||
934:AAEAIA4CoFQKgOAIAQAAAA==
|
||||
42826:AAAAAA4CIf8IgOAAAAAAAA==
|
||||
10689:AA/jBkhIiQkiJITBj+AAAA==
|
||||
10688:AA/jBkJIiSEiJCTBj+AAAA==
|
||||
8805:AA/jBkhIiQkiJOTBj+AAAA==
|
||||
8804:AA/jBkJIiSEiJOTBj+AAAA==
|
Loading…
Reference in new issue