vermiparous
This commit is contained in:
parent
a4f2da333f
commit
2514cd3669
@ -14,6 +14,8 @@
|
||||
<main>
|
||||
<div class="column" style="flex: 1">
|
||||
<div id="buttons">
|
||||
<button id="import-button">🙏 Import</button>
|
||||
|
||||
<a
|
||||
href="docs/index.html"
|
||||
target="_blank"
|
||||
@ -42,6 +44,12 @@
|
||||
>
|
||||
Export as HTML
|
||||
</div>
|
||||
<div
|
||||
id="save-karlkoder"
|
||||
class="dropdown-option"
|
||||
>
|
||||
Export as Karlkoder File
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
28
src/index.js
28
src/index.js
@ -7,6 +7,8 @@ import { SpriteEditor } from "./sprite_editor.js";
|
||||
import { SpriteProvider } from "./sprite_provider.js";
|
||||
import { Gamelib } from "./gamelib.js";
|
||||
import { CodeStopper } from "./code_stopper.js";
|
||||
import { Vermiparous } from "./vermiparous.js";
|
||||
import { promptUpload } from "./prompt_upload.js";
|
||||
|
||||
const playgroundConsole = new PlaygroundConsole(
|
||||
document.querySelector("#console-code"),
|
||||
@ -38,11 +40,13 @@ editor.session.setMode("ace/mode/javascript");
|
||||
|
||||
editor.setValue(sessionStorage.getItem("code") ?? editor.getValue(), -1);
|
||||
|
||||
const importButton = document.querySelector("#import-button");
|
||||
const runButton = document.querySelector("#run-button");
|
||||
const saveButton = document.querySelector("#save-button");
|
||||
const saveDropdown = document.querySelector("#save-dropdown");
|
||||
const saveJsButton = document.querySelector("#save-js");
|
||||
const saveHtmlButton = document.querySelector("#save-html");
|
||||
const saveKarlkoderButton = document.querySelector("#save-karlkoder");
|
||||
const toggleSpriteEditorButton = document.querySelector("#toggle-sprite-editor-button");
|
||||
|
||||
const sessionSaveDebounce = new Debounce(1000);
|
||||
@ -52,6 +56,17 @@ editor.addEventListener("change", (ev) => {
|
||||
});
|
||||
});
|
||||
|
||||
importButton.onclick = async (ev) => {
|
||||
const files = await promptUpload("", false);
|
||||
if (files.length === 0) {
|
||||
return;
|
||||
}
|
||||
if (files.length > 1) {
|
||||
throw new Error("unreachable: something went wrong !");
|
||||
}
|
||||
const item = Vermiparous.de(await fetch(URL.createObjectURL(files[0])).then((x) => x.bytes()));
|
||||
};
|
||||
|
||||
runButton.onclick = (ev) => {
|
||||
const code = editor.getValue();
|
||||
|
||||
@ -148,6 +163,19 @@ ${js}
|
||||
downloadFile(html, "text/html", ".html");
|
||||
};
|
||||
|
||||
saveKarlkoderButton.onclick = (ev) => {
|
||||
downloadFile(
|
||||
Vermiparous.en(
|
||||
editor.getValue()
|
||||
.split("\n")
|
||||
.map((line) => " ".repeat(12) + line).join("\n"),
|
||||
spriteEditor.sprites,
|
||||
),
|
||||
"",
|
||||
".karlkode",
|
||||
);
|
||||
};
|
||||
|
||||
toggleSpriteEditorButton.addEventListener("click", () => {
|
||||
const cont = document.querySelector("#sprite-editor-container");
|
||||
if (cont.style.getPropertyValue("display") === "none") {
|
||||
|
19
src/prompt_upload.js
Normal file
19
src/prompt_upload.js
Normal file
@ -0,0 +1,19 @@
|
||||
export function promptUpload(accept, multiple) {
|
||||
return new Promise((resolve) => {
|
||||
const input = document.createElement("input");
|
||||
input.type = "file";
|
||||
input.accept = accept;
|
||||
input.multiple = multiple;
|
||||
input.style = "display: none;";
|
||||
input.addEventListener("cancel", () => {
|
||||
resolve([]);
|
||||
input.remove();
|
||||
});
|
||||
input.addEventListener("change", () => {
|
||||
resolve(input.files);
|
||||
input.remove();
|
||||
});
|
||||
document.body.append(input);
|
||||
input.click();
|
||||
});
|
||||
}
|
@ -1,3 +1,5 @@
|
||||
import { promptUpload } from "./prompt_upload.js";
|
||||
|
||||
export class SpriteEditor {
|
||||
constructor(rootEl, sprites) {
|
||||
this.list = rootEl.querySelector("#sprite-editor-sprite-list");
|
||||
@ -13,39 +15,26 @@ export class SpriteEditor {
|
||||
this.renderList();
|
||||
}
|
||||
|
||||
promptUpload() {
|
||||
const input = document.createElement("input");
|
||||
input.type = "file";
|
||||
input.accept = "image/*";
|
||||
input.multiple = true;
|
||||
input.style = "display: none;";
|
||||
input.addEventListener("cancel", () => {
|
||||
input.remove();
|
||||
});
|
||||
input.addEventListener("change", async () => {
|
||||
for (const file of input.files) {
|
||||
const rootName = file.name;
|
||||
let fullName = file.name;
|
||||
for (let i = 0; this.sprites.some((x) => x.name === fullName); ++i) {
|
||||
const extensionIdx = rootName.split("").findLastIndex((x) => x === ".");
|
||||
let name = rootName;
|
||||
let extension = "";
|
||||
if (extensionIdx !== -1) {
|
||||
name = rootName.slice(0, extensionIdx);
|
||||
extension = rootName.slice(extensionIdx);
|
||||
}
|
||||
fullName = `${name}-${i}${extension}`;
|
||||
async promptUpload() {
|
||||
for (const file of await promptUpload("image/*", true)) {
|
||||
const rootName = file.name;
|
||||
let fullName = file.name;
|
||||
for (let i = 0; this.sprites.some((x) => x.name === fullName); ++i) {
|
||||
const extensionIdx = rootName.split("").findLastIndex((x) => x === ".");
|
||||
let name = rootName;
|
||||
let extension = "";
|
||||
if (extensionIdx !== -1) {
|
||||
name = rootName.slice(0, extensionIdx);
|
||||
extension = rootName.slice(extensionIdx);
|
||||
}
|
||||
this.addSprite({
|
||||
name: fullName,
|
||||
mime: file.type,
|
||||
bytes: await fetch(URL.createObjectURL(file)).then((x) => x.bytes()),
|
||||
});
|
||||
fullName = `${name}-${i}${extension}`;
|
||||
}
|
||||
input.remove();
|
||||
});
|
||||
document.body.append(input);
|
||||
input.click();
|
||||
this.addSprite({
|
||||
name: fullName,
|
||||
mime: file.type,
|
||||
bytes: await fetch(URL.createObjectURL(file)).then((x) => x.bytes()),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
addSprite({ name, bytes, mime }) {
|
||||
|
@ -2,43 +2,30 @@ const KEYWORDS = ["asset", "code"];
|
||||
const MIN_KW_LENGTH = Math.min(...KEYWORDS.map((x) => x.length));
|
||||
const SEMICOLON_CHARCODE = ";".charCodeAt(0);
|
||||
|
||||
function isKeyword(buffer: number[]) {
|
||||
const kw = String.fromCharCode(...buffer);
|
||||
function isKeyword(buffer) {
|
||||
const kw = buffer.map((x) => String.fromCharCode(x)).join("");
|
||||
return KEYWORDS.includes(kw);
|
||||
}
|
||||
|
||||
function strToBytes(str: string): number[] {
|
||||
function strToBytes(str) {
|
||||
return str.split("").map((x) => x.charCodeAt(0));
|
||||
}
|
||||
|
||||
type EncAsset = {
|
||||
name: string;
|
||||
mime: string;
|
||||
content: Uint8Array;
|
||||
};
|
||||
|
||||
type DecAssic = {
|
||||
tag: "code" | "asset";
|
||||
name: string;
|
||||
mime: string;
|
||||
content: Uint8Array;
|
||||
};
|
||||
|
||||
export class Vermiparous {
|
||||
private constructor() {}
|
||||
static en(code: string, assets: EncAsset[]): Uint8Array {
|
||||
const ret: number[] = [];
|
||||
static en(code, assets) {
|
||||
const ret = [];
|
||||
for (const asset of assets) {
|
||||
console.log(asset);
|
||||
ret.push(...strToBytes("asset"));
|
||||
ret.push(...strToBytes(asset.name.length.toString()));
|
||||
ret.push(...strToBytes(";"));
|
||||
ret.push(...strToBytes(asset.mime.length.toString()));
|
||||
ret.push(...strToBytes(";"));
|
||||
ret.push(...strToBytes(asset.content.length.toString()));
|
||||
ret.push(...strToBytes(asset.bytes.length.toString()));
|
||||
ret.push(...strToBytes(";"));
|
||||
ret.push(...strToBytes(asset.name));
|
||||
ret.push(...strToBytes(asset.mime));
|
||||
ret.push(...asset.content);
|
||||
ret.push(...asset.bytes);
|
||||
}
|
||||
ret.push(...strToBytes("code"));
|
||||
ret.push(...strToBytes("0;0;"));
|
||||
@ -48,7 +35,7 @@ export class Vermiparous {
|
||||
return new Uint8Array(ret);
|
||||
}
|
||||
|
||||
static de(bytes: Uint8Array): DecAssic[] {
|
||||
static de(bytes) {
|
||||
const ret = [];
|
||||
let buffer = [];
|
||||
let idx = 0;
|
||||
@ -92,7 +79,7 @@ export class Vermiparous {
|
||||
}
|
||||
const [name, mime, content] = consoom;
|
||||
ret.push({
|
||||
tag: String.fromCharCode(...tag) as DecAssic["tag"],
|
||||
tag: String.fromCharCode(...tag),
|
||||
name: String.fromCharCode(...name),
|
||||
mime: String.fromCharCode(...mime),
|
||||
content: new Uint8Array(content),
|
Loading…
x
Reference in New Issue
Block a user