/// import { Debounce } from "./debounce.js"; import { PlaygroundConsole } from "./playground_console.js"; import { CodeRunner } from "./code_runner.js"; import { AssetEditor } from "./asset_editor.js"; import { AssetProvider } from "./asset_provider.js"; import { Gamelib } from "./gamelib.js"; import { KarlkoderCodec } from "./karlkoder_codec.js"; import { promptUpload } from "./prompt_upload.js"; import { GamelibCompleter } from "./gamelib_completer.js"; import { TextCompleter } from "./text_completer.js"; import { ConsoleInput } from "./console_input.js"; import { downloadFile, slugify } from "./utils.js"; import { HtmlExporter } from "./html_exporter.js"; const editor = ace.edit("editor"); editor.setTheme("ace/theme/gruvbox"); editor.session.setMode("ace/mode/javascript"); const langTools = ace.require("ace/ext/language_tools"); editor.setOptions({ enableBasicAutocompletion: true, enableLiveAutocompletion: true, copyWithEmptySelection: true, }); langTools.setCompleters([new GamelibCompleter(), new TextCompleter()]); editor.setValue(sessionStorage.getItem("code") ?? editor.getValue(), -1); const playgroundConsole = new PlaygroundConsole( document.querySelector("#console-code"), editor, ); addEventListener("DOMContentLoaded", () => { playgroundConsole.getAdapter().log("Karlkode 1.0"); }); const assetProvider = new AssetProvider(); const assetEditor = new AssetEditor(document.querySelector("#asset-editor-container"), []); const htmlExporter = new HtmlExporter(assetProvider); const gamelib = new Gamelib( playgroundConsole.getAdapter(), assetProvider, document.querySelector("canvas"), ); globalThis.karlkoder = { lib() { return gamelib.getAdapter(); }, }; const codeRunner = new CodeRunner(playgroundConsole.getAdapter(), gamelib); new ConsoleInput(document.querySelector("#console-input"), playgroundConsole, codeRunner); const runButton = document.querySelector("#run-button"); const toggleAssetEditorButton = document.querySelector("#toggle-asset-editor-button"); const projectName = document.querySelector("#project-name"); const saveButton = document.querySelector("#save-button"); const loadButton = document.querySelector("#load-button"); const exportButton = document.querySelector("#export-button"); const sessionSaveDebounce = new Debounce(1000); editor.addEventListener("change", () => { sessionSaveDebounce.run(() => { sessionStorage.setItem("code", editor.getValue()); }); }); if (sessionStorage.getItem("project-name")) { projectName.value = sessionStorage.getItem("project-name"); } projectName.onchange = () => { sessionStorage.setItem("project-name", projectName.value); }; loadButton.onclick = async () => { const files = await promptUpload(".karlkode", false); if (files.length === 0) { return; } if (files.length > 1) { throw new Error( `unreachable: something went wrong ! files.length > 1 : files.length = ${files.length}`, ); } const items = KarlkoderCodec.de( await fetch(URL.createObjectURL(files[0])).then((x) => x.bytes()), ); const assets = items .filter((x) => x.tag === "asset") .map((x) => { delete x.tag; return x; }); const code = items.find((x) => x.tag === "code"); delete code.tag; assetEditor.importAssets( assets.map(({ name, mime, content }) => { const file = new File([content], name, { type: mime }); return { name, file }; }), ); projectName.value = code.name; const dec = new TextDecoder(); editor.setValue(dec.decode(code.content)); }; runButton.onclick = async () => { const code = editor.getValue(); const assets = await assetEditor.getAssets(); gamelib.assetProvider.injectAssets(assets); codeRunner.setCode(code); codeRunner.toggle(); document.querySelector("canvas").focus(); if (codeRunner.isRunning) { runButton.textContent = "✋ Stop"; runButton.classList.add("running"); } else { runButton.textContent = "🏃 Run"; runButton.classList.remove("running"); } }; exportButton.onclick = async () => { const html = await htmlExporter.export(projectName.value, editor.getValue()); downloadFile(slugify(projectName.value) || "project", html, ".html", "text/html"); }; async function saveKarlKoder() { downloadFile( slugify(projectName.value) || "project", await KarlkoderCodec.en( projectName.value, editor.getValue(), await assetEditor.getAssets(), ), ".karlkode", ); } saveButton.onclick = () => saveKarlKoder(); addEventListener("keydown", (ev) => { if (ev.ctrlKey && ev.key === "s") { ev.preventDefault(); saveKarlKoder(); } }); toggleAssetEditorButton.addEventListener("click", () => assetEditor.toggleEditor());