thrunium 1.2.0-rc.2 → 1.2.0-rc.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +4 -1
- package/dist/cli.mjs +187 -77
- package/dist/thrunium.js +2 -2
- package/dist/thrunium.min.js +2 -2
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -64,7 +64,10 @@ from `game.json` (`entry`, else the first of `game.ts`, `game.js`, `src/game.ts`
|
|
|
64
64
|
`src/game.js`; the title is `name`, else the folder name). A hand-written
|
|
65
65
|
`index.html` is used as written, and having both it and `entry` is an error.
|
|
66
66
|
`import './style.css'` from game code is bundled and linked, with `url()` fonts and
|
|
67
|
-
images; remote `@import` stays remote.
|
|
67
|
+
images; remote `@import` stays remote. A generated page takes a title, description,
|
|
68
|
+
favicon, link-preview image, address and language from `page` in `game.json`, and
|
|
69
|
+
the contents of an optional `head.html` and `body.html` (see the "Dev server and
|
|
70
|
+
builds" guide). None of these mix with a hand-written `index.html`.
|
|
68
71
|
|
|
69
72
|
`dev` never uses the CDN. For a project with a module entry
|
|
70
73
|
(a generated page, or `<script type="module" src=...>` importing `thrunium`), `build` has two engine
|
package/dist/cli.mjs
CHANGED
|
@@ -155,20 +155,28 @@ function hasEngineTag(html) {
|
|
|
155
155
|
function escapeHtml(text) {
|
|
156
156
|
return text.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """);
|
|
157
157
|
}
|
|
158
|
-
function generatePage(title, entry) {
|
|
158
|
+
function generatePage(title, entry, opts = {}) {
|
|
159
|
+
const head = (opts.headTags ?? []).map((tag) => ` ${tag}
|
|
160
|
+
`).join("") + (opts.headExtra ? `${HEAD_PLACEHOLDER}
|
|
161
|
+
` : "");
|
|
162
|
+
const body = opts.bodyExtra ? `${BODY_PLACEHOLDER}
|
|
163
|
+
` : "";
|
|
159
164
|
return `<!DOCTYPE html>
|
|
160
|
-
<html lang="en">
|
|
165
|
+
<html lang="${escapeHtml(opts.lang ?? "en")}">
|
|
161
166
|
<head>
|
|
162
167
|
<meta charset="utf-8">
|
|
163
168
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
164
169
|
<title>${escapeHtml(title)}</title>
|
|
165
|
-
</head>
|
|
170
|
+
${head}</head>
|
|
166
171
|
<body style="margin: 0; padding: 0;">
|
|
167
|
-
<script type="module" src="${escapeHtml(entry)}"></script>
|
|
172
|
+
${body} <script type="module" src="${escapeHtml(entry)}"></script>
|
|
168
173
|
</body>
|
|
169
174
|
</html>
|
|
170
175
|
`;
|
|
171
176
|
}
|
|
177
|
+
function fillExtras(html, extras) {
|
|
178
|
+
return html.replace(HEAD_PLACEHOLDER, () => extras.head).replace(BODY_PLACEHOLDER, () => extras.body);
|
|
179
|
+
}
|
|
172
180
|
function transformHtml(html, opts) {
|
|
173
181
|
let out = html;
|
|
174
182
|
const hasHead = /<\/head\s*>/i.test(html);
|
|
@@ -198,23 +206,98 @@ function transformHtml(html, opts) {
|
|
|
198
206
|
}
|
|
199
207
|
return out;
|
|
200
208
|
}
|
|
201
|
-
var SCRIPT_TAG, ATTRIBUTE, ENGINE_SRC;
|
|
209
|
+
var SCRIPT_TAG, ATTRIBUTE, ENGINE_SRC, HEAD_PLACEHOLDER, BODY_PLACEHOLDER;
|
|
202
210
|
var init_html = __esm({
|
|
203
211
|
"cli/html.ts"() {
|
|
204
212
|
"use strict";
|
|
205
213
|
SCRIPT_TAG = /<script\b[^>]*>/gi;
|
|
206
214
|
ATTRIBUTE = /([^\s"'<>\/=]+)(?:\s*=\s*(?:"([^"]*)"|'([^']*)'|([^\s"'=<>`]+)))?/g;
|
|
207
215
|
ENGINE_SRC = /(^|\/)thrunium(\.min)?\.js([?#]|$)/;
|
|
216
|
+
HEAD_PLACEHOLDER = "<!--thrunium:head-->";
|
|
217
|
+
BODY_PLACEHOLDER = "<!--thrunium:body-->";
|
|
218
|
+
}
|
|
219
|
+
});
|
|
220
|
+
|
|
221
|
+
// cli/page.ts
|
|
222
|
+
import { existsSync as existsSync2, statSync } from "node:fs";
|
|
223
|
+
import { isAbsolute, join as join2, normalize } from "node:path";
|
|
224
|
+
function checkAsset(root, field, value) {
|
|
225
|
+
if (HTTP_URL.test(value)) return value;
|
|
226
|
+
const problem = (why) => new UserError(`"page.${field}" in game.json must be an http(s) URL or a relative path to a file in the project (${why}): ${value}`);
|
|
227
|
+
if (/^[a-z][a-z0-9+.-]*:/i.test(value) || value.startsWith("//")) throw problem("unsupported address");
|
|
228
|
+
if (/[?#]/.test(value)) throw problem("no ? or # suffix");
|
|
229
|
+
if (isAbsolute(value) || normalize(value).split(/[\\/]/).includes("..")) throw problem("outside the project");
|
|
230
|
+
const path = join2(root, value);
|
|
231
|
+
if (!existsSync2(path) || !statSync(path).isFile()) throw problem("file not found");
|
|
232
|
+
return value.replace(/^(\.\/)+/, "");
|
|
233
|
+
}
|
|
234
|
+
function readPageSettings(root, value) {
|
|
235
|
+
if (value === void 0) return {};
|
|
236
|
+
if (typeof value !== "object" || value === null || Array.isArray(value)) {
|
|
237
|
+
throw new UserError('"page" in game.json must be an object.');
|
|
238
|
+
}
|
|
239
|
+
const raw = value;
|
|
240
|
+
const settings = {};
|
|
241
|
+
for (const field of FIELDS) {
|
|
242
|
+
const v = raw[field];
|
|
243
|
+
if (v === void 0) continue;
|
|
244
|
+
if (typeof v !== "string") throw new UserError(`"page.${field}" in game.json must be a string.`);
|
|
245
|
+
if (v !== "") settings[field] = v;
|
|
246
|
+
}
|
|
247
|
+
if (settings.icon !== void 0) settings.icon = checkAsset(root, "icon", settings.icon);
|
|
248
|
+
if (settings.image !== void 0) settings.image = checkAsset(root, "image", settings.image);
|
|
249
|
+
if (settings.url !== void 0 && !(HTTP_URL.test(settings.url) && URL.canParse(settings.url))) {
|
|
250
|
+
throw new UserError(`"page.url" in game.json must be an absolute http(s) URL: ${settings.url}`);
|
|
251
|
+
}
|
|
252
|
+
return settings;
|
|
253
|
+
}
|
|
254
|
+
function pageHeadTags(settings, title) {
|
|
255
|
+
const { description, icon, url } = settings;
|
|
256
|
+
const image = settings.image !== void 0 && url !== void 0 && !HTTP_URL.test(settings.image) ? new URL(settings.image, url).href : settings.image;
|
|
257
|
+
const attr = escapeHtml;
|
|
258
|
+
const tags = [];
|
|
259
|
+
if (description !== void 0) tags.push(`<meta name="description" content="${attr(description)}">`);
|
|
260
|
+
if (url !== void 0) tags.push(`<link rel="canonical" href="${attr(url)}">`);
|
|
261
|
+
if (icon !== void 0) {
|
|
262
|
+
const ext = /\.[^./?#]+$/.exec(icon)?.[0].toLowerCase() ?? "";
|
|
263
|
+
const type = ICON_TYPES[ext];
|
|
264
|
+
tags.push(`<link rel="icon" href="${attr(icon)}"${type ? ` type="${type}"` : ""}>`);
|
|
265
|
+
}
|
|
266
|
+
if (description !== void 0 || image !== void 0 || url !== void 0) {
|
|
267
|
+
tags.push('<meta property="og:type" content="website">');
|
|
268
|
+
tags.push(`<meta property="og:title" content="${attr(title)}">`);
|
|
269
|
+
if (description !== void 0) tags.push(`<meta property="og:description" content="${attr(description)}">`);
|
|
270
|
+
if (image !== void 0) tags.push(`<meta property="og:image" content="${attr(image)}">`);
|
|
271
|
+
if (url !== void 0) tags.push(`<meta property="og:url" content="${attr(url)}">`);
|
|
272
|
+
tags.push(`<meta name="twitter:card" content="${image !== void 0 ? "summary_large_image" : "summary"}">`);
|
|
273
|
+
}
|
|
274
|
+
return tags;
|
|
275
|
+
}
|
|
276
|
+
var FIELDS, HTTP_URL, ICON_TYPES;
|
|
277
|
+
var init_page = __esm({
|
|
278
|
+
"cli/page.ts"() {
|
|
279
|
+
"use strict";
|
|
280
|
+
init_errors();
|
|
281
|
+
init_html();
|
|
282
|
+
FIELDS = ["title", "description", "icon", "image", "url", "lang"];
|
|
283
|
+
HTTP_URL = /^https?:\/\//i;
|
|
284
|
+
ICON_TYPES = {
|
|
285
|
+
".png": "image/png",
|
|
286
|
+
".svg": "image/svg+xml",
|
|
287
|
+
".ico": "image/x-icon",
|
|
288
|
+
".gif": "image/gif",
|
|
289
|
+
".webp": "image/webp"
|
|
290
|
+
};
|
|
208
291
|
}
|
|
209
292
|
});
|
|
210
293
|
|
|
211
294
|
// cli/project.ts
|
|
212
|
-
import { existsSync as
|
|
213
|
-
import { basename, isAbsolute, join as
|
|
295
|
+
import { existsSync as existsSync3, readFileSync as readFileSync2, statSync as statSync2 } from "node:fs";
|
|
296
|
+
import { basename, isAbsolute as isAbsolute2, join as join3, normalize as normalize2, resolve } from "node:path";
|
|
214
297
|
function resolveEngineMode(root, flag) {
|
|
215
298
|
if (flag) return flag;
|
|
216
|
-
const manifest =
|
|
217
|
-
if (!
|
|
299
|
+
const manifest = join3(root, "package.json");
|
|
300
|
+
if (!existsSync3(manifest)) return "cdn";
|
|
218
301
|
let pkg;
|
|
219
302
|
try {
|
|
220
303
|
pkg = JSON.parse(readFileSync2(manifest, "utf8"));
|
|
@@ -227,11 +310,11 @@ function resolveEngineMode(root, flag) {
|
|
|
227
310
|
throw new UserError(`Invalid "thrunium.engine" in package.json: ${JSON.stringify(value)}. Use "cdn" or "bundle".`);
|
|
228
311
|
}
|
|
229
312
|
function isFile(path) {
|
|
230
|
-
return
|
|
313
|
+
return existsSync3(path) && statSync2(path).isFile();
|
|
231
314
|
}
|
|
232
315
|
function readGameJson(root) {
|
|
233
|
-
const file =
|
|
234
|
-
if (!
|
|
316
|
+
const file = join3(root, "game.json");
|
|
317
|
+
if (!existsSync3(file)) return null;
|
|
235
318
|
let json;
|
|
236
319
|
try {
|
|
237
320
|
json = JSON.parse(readFileSync2(file, "utf8"));
|
|
@@ -241,51 +324,77 @@ function readGameJson(root) {
|
|
|
241
324
|
if (typeof json !== "object" || json === null || Array.isArray(json)) {
|
|
242
325
|
throw new UserError("game.json must contain a JSON object.");
|
|
243
326
|
}
|
|
244
|
-
const { name, entry } = json;
|
|
327
|
+
const { name, entry, page } = json;
|
|
245
328
|
if (name !== void 0 && typeof name !== "string") throw new UserError('"name" in game.json must be a string.');
|
|
246
329
|
if (entry !== void 0 && typeof entry !== "string") throw new UserError('"entry" in game.json must be a string.');
|
|
247
|
-
return { name, entry };
|
|
330
|
+
return { name, entry, page };
|
|
248
331
|
}
|
|
249
332
|
function validateEntry(root, entry) {
|
|
250
|
-
const inside = !
|
|
333
|
+
const inside = !isAbsolute2(entry) && !normalize2(entry).split(/[\\/]/).includes("..");
|
|
251
334
|
if (!inside) throw new UserError(`"entry" in game.json must be a relative path inside the project: ${entry}`);
|
|
252
335
|
if (!ENTRY_EXTENSIONS.test(entry)) {
|
|
253
336
|
throw new UserError(`"entry" in game.json must end in .ts, .js, .mts or .mjs: ${entry}`);
|
|
254
337
|
}
|
|
255
|
-
if (!isFile(
|
|
338
|
+
if (!isFile(join3(root, entry))) throw new UserError(`"entry" in game.json points to ${entry}, which does not exist.`);
|
|
256
339
|
}
|
|
257
|
-
function
|
|
340
|
+
function hasKey(file, key) {
|
|
258
341
|
try {
|
|
259
342
|
const json = JSON.parse(readFileSync2(file, "utf8"));
|
|
260
|
-
return typeof json === "object" && json !== null && !Array.isArray(json) &&
|
|
343
|
+
return typeof json === "object" && json !== null && !Array.isArray(json) && key in json;
|
|
261
344
|
} catch {
|
|
262
345
|
return false;
|
|
263
346
|
}
|
|
264
347
|
}
|
|
348
|
+
function readExtra(root, file) {
|
|
349
|
+
const path = join3(root, file);
|
|
350
|
+
return isFile(path) ? readFileSync2(path, "utf8").replace(/^\uFEFF/, "").trimEnd() : "";
|
|
351
|
+
}
|
|
265
352
|
function resolvePage(root) {
|
|
266
|
-
const indexPath =
|
|
267
|
-
if (
|
|
268
|
-
|
|
353
|
+
const indexPath = join3(root, "index.html");
|
|
354
|
+
if (existsSync3(indexPath)) {
|
|
355
|
+
const gameJson = join3(root, "game.json");
|
|
356
|
+
if (hasKey(gameJson, "entry")) {
|
|
269
357
|
throw new UserError('game.json has "entry", but index.html also exists and is used instead. Remove one of them.');
|
|
270
358
|
}
|
|
271
|
-
|
|
359
|
+
if (hasKey(gameJson, "page")) {
|
|
360
|
+
throw new UserError(
|
|
361
|
+
'game.json has "page", but index.html also exists and is used instead. Move the settings into index.html or delete it.'
|
|
362
|
+
);
|
|
363
|
+
}
|
|
364
|
+
for (const file of ["head.html", "body.html"]) {
|
|
365
|
+
if (isFile(join3(root, file))) {
|
|
366
|
+
throw new UserError(
|
|
367
|
+
`${file} exists, but index.html also exists and is used instead. Move its contents into index.html or delete it.`
|
|
368
|
+
);
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
return { html: readFileSync2(indexPath, "utf8"), htmlSource: "file", extras: { head: "", body: "" } };
|
|
272
372
|
}
|
|
273
373
|
const game = readGameJson(root);
|
|
274
374
|
let entry = game?.entry;
|
|
275
375
|
if (entry !== void 0) validateEntry(root, entry);
|
|
276
|
-
else entry = DEFAULT_ENTRIES.find((candidate) => isFile(
|
|
376
|
+
else entry = DEFAULT_ENTRIES.find((candidate) => isFile(join3(root, candidate)));
|
|
277
377
|
if (entry === void 0) {
|
|
278
378
|
throw new UserError(
|
|
279
379
|
`No game found: add game.ts or game.js (or set "entry" in game.json), or an index.html. Looked for: ${DEFAULT_ENTRIES.join(", ")}.`
|
|
280
380
|
);
|
|
281
381
|
}
|
|
282
|
-
|
|
382
|
+
const settings = readPageSettings(root, game?.page);
|
|
383
|
+
const title = settings.title ?? game?.name ?? basename(resolve(root));
|
|
384
|
+
const extras = { head: readExtra(root, "head.html"), body: readExtra(root, "body.html") };
|
|
385
|
+
const html = generatePage(title, entry, {
|
|
386
|
+
lang: settings.lang,
|
|
387
|
+
headTags: pageHeadTags(settings, title),
|
|
388
|
+
headExtra: extras.head !== "",
|
|
389
|
+
bodyExtra: extras.body !== ""
|
|
390
|
+
});
|
|
391
|
+
return { html, htmlSource: "generated", extras };
|
|
283
392
|
}
|
|
284
393
|
function loadProject(root, engineFlag) {
|
|
285
|
-
const { html, htmlSource } = resolvePage(root);
|
|
394
|
+
const { html, htmlSource, extras } = resolvePage(root);
|
|
286
395
|
const entries = findModuleEntries(html);
|
|
287
396
|
for (const entry of entries) {
|
|
288
|
-
if (!
|
|
397
|
+
if (!existsSync3(join3(root, entry))) {
|
|
289
398
|
throw new UserError(`Entry file ${entry} (from ${htmlSource === "file" ? "index.html" : "game.json"}) does not exist.`);
|
|
290
399
|
}
|
|
291
400
|
}
|
|
@@ -293,7 +402,7 @@ function loadProject(root, engineFlag) {
|
|
|
293
402
|
if (usesModules && hasEngineTag(html)) {
|
|
294
403
|
throw new UserError("Remove the Thrunium <script> tag from index.html; thrunium adds it for you.");
|
|
295
404
|
}
|
|
296
|
-
return { root, html, htmlSource, entries, usesModules, engineMode: resolveEngineMode(root, engineFlag) };
|
|
405
|
+
return { root, html, htmlSource, extras, entries, usesModules, engineMode: resolveEngineMode(root, engineFlag) };
|
|
297
406
|
}
|
|
298
407
|
function thruniumPlugin() {
|
|
299
408
|
return {
|
|
@@ -334,6 +443,7 @@ var init_project = __esm({
|
|
|
334
443
|
init_engine();
|
|
335
444
|
init_errors();
|
|
336
445
|
init_html();
|
|
446
|
+
init_page();
|
|
337
447
|
DEFAULT_ENTRIES = ["game.ts", "game.js", "src/game.ts", "src/game.js"];
|
|
338
448
|
ENTRY_EXTENSIONS = /\.(ts|js|mts|mjs)$/;
|
|
339
449
|
ASSET_EXTENSIONS = [".woff", ".woff2", ".ttf", ".otf", ".png", ".jpg", ".jpeg", ".gif", ".svg", ".webp"];
|
|
@@ -381,11 +491,11 @@ __export(dev_exports, {
|
|
|
381
491
|
startDev: () => startDev
|
|
382
492
|
});
|
|
383
493
|
import { spawn } from "node:child_process";
|
|
384
|
-
import { existsSync as
|
|
494
|
+
import { existsSync as existsSync4, readdirSync, realpathSync, statSync as statSync3, watch } from "node:fs";
|
|
385
495
|
import { readFile } from "node:fs/promises";
|
|
386
496
|
import { createServer } from "node:http";
|
|
387
497
|
import { isIP } from "node:net";
|
|
388
|
-
import { basename as basename2, extname, isAbsolute as
|
|
498
|
+
import { basename as basename2, extname, isAbsolute as isAbsolute3, join as join4, normalize as normalize3, relative, resolve as resolve2, sep } from "node:path";
|
|
389
499
|
import { parseArgs } from "node:util";
|
|
390
500
|
import { context as esbuildContext, formatMessages } from "esbuild";
|
|
391
501
|
function openBrowser(url) {
|
|
@@ -423,10 +533,10 @@ async function listen(server, port, host) {
|
|
|
423
533
|
async function startDev(opts) {
|
|
424
534
|
const root = resolve2(opts.root);
|
|
425
535
|
const host = opts.host ?? "localhost";
|
|
426
|
-
const outDir =
|
|
536
|
+
const outDir = join4(root, "dist");
|
|
427
537
|
const realRoot = realpathSync(root);
|
|
428
538
|
const outTmp = outDir + ".tmp";
|
|
429
|
-
const virtualOut =
|
|
539
|
+
const virtualOut = join4(root, ".thrunium-dev");
|
|
430
540
|
loadProject(root);
|
|
431
541
|
const clients = /* @__PURE__ */ new Set();
|
|
432
542
|
let lastError = null;
|
|
@@ -541,12 +651,15 @@ data: ${JSON.stringify(data)}
|
|
|
541
651
|
const project = loadProject(root);
|
|
542
652
|
const entryMap = new Map(project.entries.map((e, i) => [e, `${BUNDLE_PREFIX}${i}.js`]));
|
|
543
653
|
const styles = project.entries.flatMap((_, i) => bundles.has(`${i}.css`) ? [`${BUNDLE_PREFIX}${i}.css`] : []);
|
|
544
|
-
const html =
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
654
|
+
const html = fillExtras(
|
|
655
|
+
transformHtml(project.html, {
|
|
656
|
+
engineTag: project.usesModules ? ENGINE_TAG : null,
|
|
657
|
+
entryMap,
|
|
658
|
+
inject: RELOAD_CLIENT,
|
|
659
|
+
styles
|
|
660
|
+
}),
|
|
661
|
+
project.extras
|
|
662
|
+
);
|
|
550
663
|
res.writeHead(200, { ...noCache, "content-type": MIME[".html"] }).end(html);
|
|
551
664
|
return;
|
|
552
665
|
}
|
|
@@ -565,15 +678,15 @@ data: ${JSON.stringify(data)}
|
|
|
565
678
|
res.writeHead(200, { ...noCache, "content-type": type }).end(contents);
|
|
566
679
|
return;
|
|
567
680
|
}
|
|
568
|
-
const file =
|
|
681
|
+
const file = normalize3(join4(root, pathname));
|
|
569
682
|
const rel = relative(root, file);
|
|
570
683
|
if (/[\\\0]/.test(pathname) || // backslashes act as separators on Windows; NUL is never valid
|
|
571
|
-
rel.split(/[\\/]/).some((part) => part.startsWith(".")) || rel === "" || rel === ".." || rel.startsWith(".." + sep) ||
|
|
684
|
+
rel.split(/[\\/]/).some((part) => part.startsWith(".")) || rel === "" || rel === ".." || rel.startsWith(".." + sep) || isAbsolute3(rel) || !existsSync4(file) || !statSync3(file).isFile()) {
|
|
572
685
|
res.writeHead(404).end();
|
|
573
686
|
return;
|
|
574
687
|
}
|
|
575
688
|
const realRel = relative(realRoot, realpathSync(file));
|
|
576
|
-
if (realRel === ".." || realRel.startsWith(".." + sep) ||
|
|
689
|
+
if (realRel === ".." || realRel.startsWith(".." + sep) || isAbsolute3(realRel)) {
|
|
577
690
|
res.writeHead(404).end();
|
|
578
691
|
return;
|
|
579
692
|
}
|
|
@@ -585,7 +698,7 @@ data: ${JSON.stringify(data)}
|
|
|
585
698
|
for (const dir of [outDir, outTmp]) if (abs === dir || abs.startsWith(dir + sep)) return true;
|
|
586
699
|
if (owned.has(abs)) return true;
|
|
587
700
|
try {
|
|
588
|
-
return
|
|
701
|
+
return statSync3(abs).isDirectory();
|
|
589
702
|
} catch {
|
|
590
703
|
return false;
|
|
591
704
|
}
|
|
@@ -593,15 +706,10 @@ data: ${JSON.stringify(data)}
|
|
|
593
706
|
let timer;
|
|
594
707
|
let closed = false;
|
|
595
708
|
let pending = Promise.resolve();
|
|
596
|
-
let indexChanged = false;
|
|
597
709
|
const flush = async () => {
|
|
598
|
-
const checkEntries = indexChanged;
|
|
599
|
-
indexChanged = false;
|
|
600
710
|
try {
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
if (next.join("\n") !== entries.join("\n")) await startBundler(next);
|
|
604
|
-
}
|
|
711
|
+
const next = findModuleEntries(loadProject(root).html);
|
|
712
|
+
if (next.join("\n") !== entries.join("\n")) await startBundler(next);
|
|
605
713
|
} catch (err) {
|
|
606
714
|
broadcastError(err instanceof Error ? err.message : String(err));
|
|
607
715
|
return;
|
|
@@ -620,20 +728,20 @@ data: ${JSON.stringify(data)}
|
|
|
620
728
|
};
|
|
621
729
|
const watchers = /* @__PURE__ */ new Map();
|
|
622
730
|
const skippedTop = (name) => {
|
|
623
|
-
const abs =
|
|
731
|
+
const abs = join4(root, name);
|
|
624
732
|
return name === "node_modules" || name.startsWith(".") || abs === outDir || abs === outTmp;
|
|
625
733
|
};
|
|
626
734
|
const onWatchError = (path) => (err) => {
|
|
627
735
|
watchers.get(path)?.close();
|
|
628
736
|
watchers.delete(path);
|
|
629
|
-
if (
|
|
737
|
+
if (existsSync4(path)) console.error(`thrunium: file watching stopped for ${path}: ${err.message}`);
|
|
630
738
|
};
|
|
631
739
|
const rescan = () => {
|
|
632
740
|
if (closed) return;
|
|
633
741
|
const dirs = /* @__PURE__ */ new Set();
|
|
634
742
|
try {
|
|
635
743
|
for (const entry of readdirSync(root, { withFileTypes: true })) {
|
|
636
|
-
if (entry.isDirectory() && !skippedTop(entry.name)) dirs.add(
|
|
744
|
+
if (entry.isDirectory() && !skippedTop(entry.name)) dirs.add(join4(root, entry.name));
|
|
637
745
|
}
|
|
638
746
|
} catch {
|
|
639
747
|
return;
|
|
@@ -650,7 +758,7 @@ data: ${JSON.stringify(data)}
|
|
|
650
758
|
const w = watch(dir, { recursive: true }, (_event, filename) => {
|
|
651
759
|
if (!filename) return schedule();
|
|
652
760
|
const name = filename.toString();
|
|
653
|
-
if (name === basename2(dir) && !
|
|
761
|
+
if (name === basename2(dir) && !existsSync4(join4(dir, name))) return;
|
|
654
762
|
if (!ignored(resolve2(dir, name))) schedule();
|
|
655
763
|
});
|
|
656
764
|
w.on("error", onWatchError(dir));
|
|
@@ -662,9 +770,8 @@ data: ${JSON.stringify(data)}
|
|
|
662
770
|
const rootWatcher = watch(root, (event, filename) => {
|
|
663
771
|
if (event === "rename") rescan();
|
|
664
772
|
const abs = filename ? resolve2(root, filename.toString()) : root;
|
|
665
|
-
const pageInput = !filename ||
|
|
773
|
+
const pageInput = !filename || PAGE_INPUTS.some((file) => abs === join4(root, file));
|
|
666
774
|
if (!pageInput && ignored(abs)) return;
|
|
667
|
-
if (pageInput) indexChanged = true;
|
|
668
775
|
schedule();
|
|
669
776
|
});
|
|
670
777
|
rootWatcher.on("error", onWatchError(root));
|
|
@@ -741,7 +848,7 @@ ${USAGE}`);
|
|
|
741
848
|
});
|
|
742
849
|
await server.close();
|
|
743
850
|
}
|
|
744
|
-
var USAGE, MIME, ENGINE_TAG, BUNDLE_PREFIX, WATCH_DEBOUNCE_MS, PORT_ATTEMPTS;
|
|
851
|
+
var USAGE, MIME, ENGINE_TAG, BUNDLE_PREFIX, PAGE_INPUTS, WATCH_DEBOUNCE_MS, PORT_ATTEMPTS;
|
|
745
852
|
var init_dev = __esm({
|
|
746
853
|
"cli/dev.ts"() {
|
|
747
854
|
"use strict";
|
|
@@ -781,6 +888,7 @@ Options:
|
|
|
781
888
|
};
|
|
782
889
|
ENGINE_TAG = '<script src="/__thrunium/engine/thrunium.js"></script>';
|
|
783
890
|
BUNDLE_PREFIX = "/__thrunium/bundle/";
|
|
891
|
+
PAGE_INPUTS = ["index.html", "game.json", "head.html", "body.html"];
|
|
784
892
|
WATCH_DEBOUNCE_MS = 50;
|
|
785
893
|
PORT_ATTEMPTS = 11;
|
|
786
894
|
}
|
|
@@ -792,14 +900,14 @@ __export(build_exports, {
|
|
|
792
900
|
build: () => build,
|
|
793
901
|
runBuild: () => runBuild
|
|
794
902
|
});
|
|
795
|
-
import { existsSync as
|
|
796
|
-
import { dirname as dirname2, isAbsolute as
|
|
903
|
+
import { existsSync as existsSync5, mkdirSync, readdirSync as readdirSync2, readFileSync as readFileSync3, renameSync, rmSync, statSync as statSync4, writeFileSync, copyFileSync } from "node:fs";
|
|
904
|
+
import { dirname as dirname2, isAbsolute as isAbsolute4, join as join5, relative as relative2, resolve as resolve3, sep as sep2 } from "node:path";
|
|
797
905
|
import { parseArgs as parseArgs2 } from "node:util";
|
|
798
906
|
import { build as esbuild, formatMessages as formatMessages2 } from "esbuild";
|
|
799
907
|
function listFiles(root, dir, skipDirs) {
|
|
800
908
|
const files = [];
|
|
801
909
|
for (const entry of readdirSync2(dir, { withFileTypes: true })) {
|
|
802
|
-
const abs =
|
|
910
|
+
const abs = join5(dir, entry.name);
|
|
803
911
|
if (entry.name.startsWith(".") || entry.name === "node_modules" || skipDirs.has(abs)) continue;
|
|
804
912
|
if (entry.isDirectory()) files.push(...listFiles(root, abs, skipDirs));
|
|
805
913
|
else if (entry.isFile() && !SKIPPED_NAMES.test(entry.name)) files.push(relative2(root, abs));
|
|
@@ -810,7 +918,7 @@ async function runBuild(opts) {
|
|
|
810
918
|
const root = resolve3(opts.root);
|
|
811
919
|
const outDir = resolve3(root, opts.outDir ?? "dist");
|
|
812
920
|
const rel = relative2(root, outDir);
|
|
813
|
-
if (rel === "" || rel === ".." || rel.startsWith(".." + sep2) ||
|
|
921
|
+
if (rel === "" || rel === ".." || rel.startsWith(".." + sep2) || isAbsolute4(rel)) {
|
|
814
922
|
throw new UserError(`The output folder must be inside the project and not the project itself: ${outDir}`);
|
|
815
923
|
}
|
|
816
924
|
const project = loadProject(root, opts.engine);
|
|
@@ -827,7 +935,7 @@ async function runBuild(opts) {
|
|
|
827
935
|
const entryMap = /* @__PURE__ */ new Map();
|
|
828
936
|
const styles = [];
|
|
829
937
|
if (project.usesModules) {
|
|
830
|
-
const outAbs =
|
|
938
|
+
const outAbs = join5(root, ".thrunium-out");
|
|
831
939
|
const result = await esbuild({
|
|
832
940
|
...baseBuildOptions(root),
|
|
833
941
|
entryPoints: project.entries,
|
|
@@ -864,25 +972,26 @@ async function runBuild(opts) {
|
|
|
864
972
|
engineTag = '<script src="thrunium.min.js"></script>';
|
|
865
973
|
written.set("thrunium.min.js", readFileSync3(engineFile("thrunium.min.js")));
|
|
866
974
|
const map = engineFile("thrunium.min.js") + ".map";
|
|
867
|
-
if (
|
|
975
|
+
if (existsSync5(map)) written.set("thrunium.min.js.map", readFileSync3(map));
|
|
868
976
|
} else {
|
|
869
977
|
engineTag = cdnScriptTag(engineVersion(), integrity);
|
|
870
978
|
}
|
|
871
979
|
}
|
|
872
980
|
const tmp = outDir + ".tmp";
|
|
873
|
-
written.set("index.html", transformHtml(project.html, { engineTag, entryMap, inject: null, styles }));
|
|
981
|
+
written.set("index.html", fillExtras(transformHtml(project.html, { engineTag, entryMap, inject: null, styles }), project.extras));
|
|
874
982
|
rmSync(tmp, { recursive: true, force: true });
|
|
875
983
|
try {
|
|
876
984
|
const skipDirs = /* @__PURE__ */ new Set([outDir, tmp]);
|
|
877
985
|
for (const file of listFiles(root, root, skipDirs)) {
|
|
878
986
|
const key = file.split(sep2).join("/");
|
|
879
987
|
if (written.has(key) || consumed.has(resolve3(root, file))) continue;
|
|
880
|
-
|
|
988
|
+
if (project.htmlSource === "generated" && PAGE_PARTS.has(key)) continue;
|
|
989
|
+
const dest = join5(tmp, file);
|
|
881
990
|
mkdirSync(dirname2(dest), { recursive: true });
|
|
882
|
-
copyFileSync(
|
|
991
|
+
copyFileSync(join5(root, file), dest);
|
|
883
992
|
}
|
|
884
993
|
for (const [file, contents] of written) {
|
|
885
|
-
const dest =
|
|
994
|
+
const dest = join5(tmp, file);
|
|
886
995
|
mkdirSync(dirname2(dest), { recursive: true });
|
|
887
996
|
writeFileSync(dest, contents);
|
|
888
997
|
}
|
|
@@ -893,12 +1002,12 @@ async function runBuild(opts) {
|
|
|
893
1002
|
throw err;
|
|
894
1003
|
}
|
|
895
1004
|
const files = listAll(outDir, outDir).sort();
|
|
896
|
-
for (const f of files) console.log(` ${f} ${formatSize(
|
|
1005
|
+
for (const f of files) console.log(` ${f} ${formatSize(statSync4(join5(outDir, f)).size)}`);
|
|
897
1006
|
return { outDir, files };
|
|
898
1007
|
}
|
|
899
1008
|
function listAll(base, dir) {
|
|
900
1009
|
return readdirSync2(dir, { withFileTypes: true }).flatMap(
|
|
901
|
-
(e) => e.isDirectory() ? listAll(base,
|
|
1010
|
+
(e) => e.isDirectory() ? listAll(base, join5(dir, e.name)) : [relative2(base, join5(dir, e.name)).split(sep2).join("/")]
|
|
902
1011
|
);
|
|
903
1012
|
}
|
|
904
1013
|
function formatSize(bytes) {
|
|
@@ -930,7 +1039,7 @@ ${USAGE2}`);
|
|
|
930
1039
|
}
|
|
931
1040
|
await runBuild({ root: process.cwd(), outDir: values.out, engine: values.engine });
|
|
932
1041
|
}
|
|
933
|
-
var USAGE2, SKIPPED_NAMES;
|
|
1042
|
+
var USAGE2, SKIPPED_NAMES, PAGE_PARTS;
|
|
934
1043
|
var init_build = __esm({
|
|
935
1044
|
"cli/build.ts"() {
|
|
936
1045
|
"use strict";
|
|
@@ -946,6 +1055,7 @@ Options:
|
|
|
946
1055
|
--help, -h Show this help
|
|
947
1056
|
`;
|
|
948
1057
|
SKIPPED_NAMES = /^(package\.json|package-lock\.json|npm-shrinkwrap\.json|pnpm-lock\.yaml|pnpm-workspace\.yaml|yarn\.lock|bun\.lockb?|bunfig\.toml|tsconfig.*\.json|.*\.ts)$/;
|
|
1058
|
+
PAGE_PARTS = /* @__PURE__ */ new Set(["head.html", "body.html"]);
|
|
949
1059
|
}
|
|
950
1060
|
});
|
|
951
1061
|
|
|
@@ -960,8 +1070,8 @@ __export(init_exports, {
|
|
|
960
1070
|
spawnInstall: () => spawnInstall
|
|
961
1071
|
});
|
|
962
1072
|
import { spawn as spawn2 } from "node:child_process";
|
|
963
|
-
import { cpSync, existsSync as
|
|
964
|
-
import { basename as basename3, join as
|
|
1073
|
+
import { cpSync, existsSync as existsSync6, mkdirSync as mkdirSync2, readdirSync as readdirSync3, readFileSync as readFileSync4, renameSync as renameSync2, statSync as statSync5, writeFileSync as writeFileSync2 } from "node:fs";
|
|
1074
|
+
import { basename as basename3, join as join6, resolve as resolve4 } from "node:path";
|
|
965
1075
|
import { parseArgs as parseArgs3 } from "node:util";
|
|
966
1076
|
function detectPackageManager(userAgent) {
|
|
967
1077
|
const [name, version] = (userAgent?.split(" ")[0] ?? "").split("/");
|
|
@@ -983,25 +1093,25 @@ function spawnInstall(cmd, args, cwd) {
|
|
|
983
1093
|
}
|
|
984
1094
|
async function runInit(opts) {
|
|
985
1095
|
const dir = resolve4(opts.dir);
|
|
986
|
-
if (
|
|
987
|
-
if (!
|
|
1096
|
+
if (existsSync6(dir)) {
|
|
1097
|
+
if (!statSync5(dir).isDirectory() || readdirSync3(dir).length > 0) {
|
|
988
1098
|
throw new UserError(`${dir} already exists and is not an empty folder.`);
|
|
989
1099
|
}
|
|
990
1100
|
} else {
|
|
991
1101
|
mkdirSync2(dir, { recursive: true });
|
|
992
1102
|
}
|
|
993
|
-
cpSync(
|
|
994
|
-
if (opts.pm.name === "pnpm") cpSync(
|
|
995
|
-
renameSync2(
|
|
1103
|
+
cpSync(join6(packageRoot(), "templates", opts.template), dir, { recursive: true });
|
|
1104
|
+
if (opts.pm.name === "pnpm") cpSync(join6(packageRoot(), "templates", "pnpm"), dir, { recursive: true });
|
|
1105
|
+
renameSync2(join6(dir, "gitignore"), join6(dir, ".gitignore"));
|
|
996
1106
|
const name = basename3(dir).toLowerCase().replace(/[^a-z0-9-]/g, "-");
|
|
997
1107
|
for (const file of TEXT_FILES) {
|
|
998
|
-
const path =
|
|
1108
|
+
const path = join6(dir, file);
|
|
999
1109
|
const text = readFileSync4(path, "utf8").replace(/\{\{name\}\}/g, name).replace(/\{\{version\}\}/g, engineVersion());
|
|
1000
1110
|
writeFileSync2(path, text);
|
|
1001
1111
|
}
|
|
1002
1112
|
const pinPnpm = opts.pm.name === "pnpm" && opts.pm.version;
|
|
1003
1113
|
if (pinPnpm || opts.pm.name === "npm") {
|
|
1004
|
-
const path =
|
|
1114
|
+
const path = join6(dir, "package.json");
|
|
1005
1115
|
const pkg = JSON.parse(readFileSync4(path, "utf8"));
|
|
1006
1116
|
if (pinPnpm) pkg.packageManager = `pnpm@${opts.pm.version}`;
|
|
1007
1117
|
if (opts.pm.name === "npm") pkg.allowScripts = { esbuild: true };
|
package/dist/thrunium.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/*! THRUNIUM v1.2.0-rc.
|
|
1
|
+
/*! THRUNIUM v1.2.0-rc.3 | (c) Infobits ApS | MIT License */
|
|
2
2
|
"use strict";
|
|
3
3
|
(() => {
|
|
4
4
|
var __defProp = Object.defineProperty;
|
|
@@ -2222,7 +2222,7 @@
|
|
|
2222
2222
|
}
|
|
2223
2223
|
|
|
2224
2224
|
// src/index.ts
|
|
2225
|
-
T.version = "1.2.0-rc.
|
|
2225
|
+
T.version = "1.2.0-rc.3";
|
|
2226
2226
|
T.pageLoad = pageLoad;
|
|
2227
2227
|
T.ready = ready;
|
|
2228
2228
|
T.throwError = throwError;
|
package/dist/thrunium.min.js
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
/*! THRUNIUM v1.2.0-rc.
|
|
2
|
-
"use strict";(()=>{var H=Object.defineProperty;var _=(s,e)=>{for(var t in e)H(s,t,{get:e[t],enumerable:!0})};window.THRUNIUM||(window.THRUNIUM={});var n=window.THRUNIUM;function b(){n.pageLoaded=!0}function x(s){let e=!1,t=()=>{e||(e=!0,s())};if(document.readyState==="complete"){t();return}document.addEventListener("DOMContentLoaded",t,!1),window.addEventListener("load",t,!1)}function m(s){console.error(s),n.error=!0}function E(){let s=navigator.userAgent||navigator.vendor||"";return/(android|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|midp|mmp|mobile.+firefox|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows ce|xda|xiino|android|ipad|playbook|silk/i.test(s)||/1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\-(n|u)|c55\/|capi|ccwa|cdm\-|cell|chtm|cldc|cmd\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\-s|devi|dica|dmob|do(c|p)o|ds(12|\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\-|_)|g1 u|g560|gene|gf\-5|g\-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd\-(m|p|t)|hei\-|hi(pt|ta)|hp( i|ip)|hs\-c|ht(c(\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\-(20|go|ma)|i230|iac( |\-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc\-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|\-[a-w])|libw|lynx|m1\-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m\-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\-2|po(ck|rt|se)|prox|psio|pt\-g|qa\-a|qc(07|12|21|32|60|\-[2-7]|i\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\-|oo|p\-)|sdk\/|se(c(\-|0|1)|47|mc|nd|ri)|sgh\-|shar|sie(\-|m)|sk\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\-|v\-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\-|tdg\-|tel(i|m)|tim\-|t\-mo|to(pl|sh)|ts(70|m\-|m3|m5)|tx\-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas\-|your|zeto|zte\-/i.test(s.substr(0,4))}function L(){return/iPad|iPhone|iPod/.test(navigator.userAgent)&&!("MSStream"in window)}function R(s,e,t=!1){return t?Math.random()*(e-s)+s:Math.floor(Math.random()*(e-s+1))+s}function M(){n.container=null,n.gameObject=null,n.error=!1,n.pageLoaded=!1,n.fontsLoaded=!1,x(b),typeof document!="undefined"&&document.fonts&&document.fonts.ready?document.fonts.ready.then(()=>{n.fontsLoaded=!0}):n.fontsLoaded=!0}var C;C=Symbol.toStringTag;var p=class{constructor(e,t){this[C]="THRUNIUM.Game";this.scale=1;this.fitScale=1;this.delta=0;this.fps=0;this.runSpeed=0;this.lastRun=null;this.gameRunning=!1;this.showFPS=!1;this.namespace="";this.mouseX=0;this.mouseY=0;this.state="startup";this.startState=null;this.states=[];this.backgroundColor="#fff";this.assets=[];this.assetsLoaded=!1;this.loadedAssets=0;this.assetsToLoad=0;this.font="Arial";this.textSize="30px";this.click=()=>{};this.mousedown=()=>{};this.mouseup=()=>{};this.mousemove=()=>{};this.touch=()=>{};this.touchstart=()=>{};this.touchend=()=>{};this.keydown=()=>{};this.keyup=()=>{};this.deviceorientation=()=>{};this.devicemotion=()=>{};this.rezise=()=>{};this._deviceorientation=e=>{this.deviceorientation(e)};this._devicemotion=e=>{this.devicemotion(e)};this._mousetouchmove=e=>{e.preventDefault(),this.getMouseCords(e),this.mousemove(e)};this._touchstart=e=>{e.preventDefault(),this.getMouseCords(e),this.touch(e),this.touchstart(e)};this._touchend=e=>{e.preventDefault(),this.getMouseCords(e),this.click(e),this.touchend(e)};this._resize=e=>{var i,o;this.updateFitScale(),this.updateScale();let t=(o=(i=n.Elem)==null?void 0:i.elemsList)!=null?o:[];for(let r=0;r<t.length;r++)t[r].resize();this.rezise(e)};this.assetLoaded=()=>{this.loadedAssets++};this.initAssetSpriteMap=(e=>function(){let t=e.assets,i=n.Sprite,o=new i(this);t[this.dataset.index]=o,o.setSpriteMap(Number(this.dataset.spriteWidth),Number(this.dataset.spriteHeight)),e.loadedAssets++})(this);this.gameLoop=()=>{if(!this.lastRun){this.lastRun=Date.now(),this.requestFrame(this.gameLoop);return}this.delta=(Date.now()-this.lastRun)/1e3,this.lastRun=Date.now(),this.fps=1/this.delta,this.runSpeed=Math.round(this.fps/60*100)/100,this.ctx.clearRect(0,0,this.width,this.height),this.canvas.style.cursor="default",this.drawRect(0,0,this.width,this.height),this.setFillColor(this.backgroundColor),this.fill(),this.state=="startup"?this.startup():this.states[this.state](),this.showFPS&&this.drawFPS(),this.gameRunning&&!n.error&&this.requestFrame(this.gameLoop)};this.width=e,this.height=t,this.contruct()}getMouseCords(e){let t=e;if(t.clientX===void 0){let a=e;a.touches&&a.touches[0]?t=a.touches[0]:a.changedTouches&&a.changedTouches[0]&&(t=a.changedTouches[0])}let i=this.canvas.getBoundingClientRect(),o=this.canvas.scrollWidth/this.width,r=this.canvas.scrollHeight/this.height;this.mouseX=(t.clientX-i.left)/o,this.mouseY=(t.clientY-i.top)/r}updateScale(){this.scale=window.devicePixelRatio*this.fitScale,this.canvas.width=this.width*this.scale,this.canvas.height=this.height*this.scale,this.ctx.scale(this.scale,this.scale)}updateFitScale(){this.width/this.height>window.innerWidth/window.innerHeight?this.fitScale=window.innerWidth/this.width:this.fitScale=window.innerHeight/this.height;let e=this.width*this.fitScale+"px",t=this.height*this.fitScale+"px";this.canvas.style.width=e,this.canvas.style.height=t;let i=n.container;i.style.width=e,i.style.height=t}contruct(){document.body.style.background="#333";let e=document.createElement("div");e.style.position="relative",e.style.display="block",e.style.margin="auto",n.container=e,n.gameObject=this,document.body.appendChild(e),this.canvas=document.createElement("canvas"),e.appendChild(this.canvas),this.ctx=this.canvas.getContext("2d"),this.canvas.style.display="block",this.canvas.style.margin="auto",this._resize(),window.addEventListener("resize",this._resize,!1),this.ctx.imageSmoothingEnabled=!1}init(){this.assetsLoaded||this.loadAssets(),this._resize(),this.canvas.addEventListener("click",this.click,!1),this.canvas.addEventListener("mousedown",this.mousedown,!1),this.canvas.addEventListener("mouseup",this.mouseup,!1),this.canvas.addEventListener("touchstart",this._touchstart,!1),this.canvas.addEventListener("touchend",this._touchend,!1),document.addEventListener("keydown",this.keydown,!1),document.addEventListener("keyup",this.keyup,!1),this.canvas.addEventListener("touchmove",this._mousetouchmove,!1),this.canvas.addEventListener("mousemove",this._mousetouchmove,!1),window.addEventListener("deviceorientation",this._deviceorientation),window.addEventListener("devicemotion",this._devicemotion)}loadAssets(){this.assetsToLoad=this.assets.length;let e=[],t=e;for(let i=0;i<this.assets.length;i++){let o=this.assets[i],r,a,d=null;if(typeof o=="string")a=o,r=a;else if(typeof o=="object"&&o!==null){let h=o;a=h.src,r=h.index,h.spriteMap!==void 0&&(d=h.spriteMap)}else{console.error("ASSETS - Unknown entry");continue}let c=this.getFileExtension(a);t[r]=null;let l;if(this.isImage(c))l=new Image;else if(this.isAudio(c))l=new Audio;else{console.error("ASSETS - Unknown file type: "+c+" for file "+a);continue}t[r]=l,l.dataset.index=r,d!==null&&(l.dataset.spriteWidth=String(d.width),l.dataset.spriteHeight=String(d.height)),l.onload=d!==null?this.initAssetSpriteMap:this.assetLoaded,l.src=a}this.assets=e,this.assetsLoaded=!0}getFileExtension(e){return/[.]/.exec(e)?/[^.]+$/.exec(e)[0]:void 0}isImage(e){return["jpg","jpeg","png","gif","xbm"].includes(e)}isAudio(e){return["mp3","wav","ogg","aac"].includes(e)}setFillColor(e){this.ctx.fillStyle=e}fill(){this.ctx.fill()}setStrokeColor(e){this.ctx.strokeStyle=e}stroke(){this.ctx.stroke()}drawLine(e,t,i,o,r){this.ctx.beginPath(),r&&(this.ctx.lineWidth=r),this.ctx.moveTo(e,t),this.ctx.lineTo(i,o),this.ctx.stroke(),this.ctx.closePath()}drawText(e,t,i){this.ctx.font=this.textSize+" "+this.font,this.ctx.fillText(e,t,i)}drawRect(e,t,i,o,r){let a=this.ctx;a.beginPath(),r?(a.moveTo(e+r,t),a.lineTo(e+i-r,t),a.quadraticCurveTo(e+i,t,e+i,t+r),a.lineTo(e+i,t+o-r),a.quadraticCurveTo(e+i,t+o,e+i-r,t+o),a.lineTo(e+r,t+o),a.quadraticCurveTo(e,t+o,e,t+o-r),a.lineTo(e,t+r),a.quadraticCurveTo(e,t,e+r,t)):a.rect(e,t,i,o),a.closePath()}drawCircle(e,t,i){this.ctx.beginPath(),this.ctx.arc(e,t,i,0,2*Math.PI),this.ctx.closePath()}drawImage(e,t,i,o=null,r=null){this.ctx.beginPath(),o!==null&&r!==null?this.ctx.drawImage(e,t,i,o,r):this.ctx.drawImage(e,t,i),this.ctx.closePath()}start(){this.gameRunning=!0,this.requestFrame(this.gameLoop)}stop(){this.gameRunning=!1}requestFrame(e){typeof window.requestAnimFrame=="function"?window.requestAnimFrame(e):requestAnimationFrame(e)}startup(){this.drawRect(0,0,this.width,this.height),this.setFillColor("#000"),this.fill(),this.ctx.font="25px Arial",this.ctx.textAlign="center",this.ctx.textBaseline="bottom",this.setFillColor("#fff"),this.ctx.fillText("Loading game",this.width/2,this.height/2-10),this.drawRect(this.width/2-100,this.height/2,200,20,10),this.setStrokeColor("#fff"),this.stroke();let e=200/this.assetsToLoad*this.loadedAssets;e<20&&(e=20),this.drawRect(this.width/2-100,this.height/2,e,20,10),this.setFillColor("#fff"),this.fill(),this.assetsToLoad==this.loadedAssets&&n.pageLoaded&&n.fontsLoaded&&(this._resize(),this.state=this.startState)}drawFPS(){this.ctx.fillStyle="gray",this.ctx.font="normal 16pt Arial",this.ctx.textAlign="left",this.ctx.textBaseline="top",this.ctx.fillText(Math.round(this.fps)+" fps - scale: "+this.scale,5,5)}};var f=class{constructor(e,t){this.x=e,this.y=t}get[Symbol.toStringTag](){return"THRUNIUM.Vector"}clone(){return new n.Vector(this.x,this.y)}equal(e){return this.x==e.x&&this.y==e.y}scale(e){this.x*=e,this.y*=e}scaleX(e){this.x*=e}scaleY(e){this.y*=e}add(e){this.x+=e.x,this.y+=e.y}addX(e){this.x+=e.x}addY(e){this.y+=e.y}subtract(e){this.x-=e.x,this.y-=e.y}subtractX(e){this.x-=e.x}subtractY(e){this.y-=e.y}divide(e){this.x/=e.x,this.y/=e.y}divideX(e){this.x/=e.x}divideY(e){this.y/=e.y}multiply(e){this.x*=e.x,this.y*=e.y}multiplyX(e){this.x*=e.x}multiplyY(e){this.y*=e.y}invert(){this.x*=-1,this.y*=-1}invertX(){this.x*=-1}invertY(){this.y*=-1}normalize(){let e=Math.sqrt(this.x*this.x+this.y*this.y);e!==0&&(this.x/=e,this.y/=e)}limit(e){this.x>e.x&&(this.x=e.x),this.y>e.y&&(this.y=e.y),this.x<e.x*-1&&(this.x=e.x*-1),this.y<e.y*-1&&(this.y=e.y*-1)}limitLength(e){}};var u={isCircle(s){return s.x!==void 0&&s.y!==void 0&&s.radius!==void 0},isRect(s){return s.x!==void 0&&s.y!==void 0&&s.width!==void 0&&s.height!==void 0},fixPos(s){return s.pos===void 0||s.pos.x===void 0&&s.pos.y===void 0||(s.x=s.pos.x,s.y=s.pos.y),s},rect(s,e){let t=u.fixPos(s),i=u.fixPos(e);if(!u.isRect(t)||!u.isRect(i))return m("One of the objects is not defined correctly as a rect"),!1;let[o,r,a,d]=[t.x,t.y,t.width,t.height],[c,l,h,T]=[i.x,i.y,i.width,i.height];return!(o+a/2<c-h/2||o-a/2>c+h/2||r+d/2<l-T/2||r-d/2>l+T/2)},circle(s,e){let t=u.fixPos(s),i=u.fixPos(e);if(!u.isCircle(t)||!u.isCircle(i))return m("One of the objects is not defined correctly as a circle"),!1;let o=t.x-i.x,r=t.y-i.y;return Math.sqrt(o*o+r*r)<t.radius+i.radius},circleRect(s,e){let t=u.fixPos(s),i=u.fixPos(e);if(!u.isCircle(t)||!u.isRect(i))return m("One of the objects is not defined correctly as a circle or rect"),!1;let o=Math.abs(t.x-i.x),r=Math.abs(t.y-i.y),a=i.width/2,d=i.height/2,c=t.radius;if(o>=a+c||r>=d+c)return!1;if(o<a||r<d)return!0;let l=o-a,h=r-d;return l*l+h*h<=c*c}};var P=()=>n.gameObject,q;q=Symbol.toStringTag;var g=class{constructor(e){this[q]="THRUNIUM.Sprite";this.angle=0;this.currentSprite=null;this.animTimeDur=100;this.frameTimeLast=0;this.animLoop=!1;this.animCallback=()=>{};this.image=e,this.fullWidth=e.width,this.fullHeight=e.height,this.spriteWidth=e.width,this.spriteHeight=e.height}setAngle(e){this.angle=e}setLoop(e){this.animLoop=e}setAnimCallback(e){this.animCallback=e}setAnimTime(e){this.animTimeDur=e}setSpriteMap(e,t){this.spriteWidth=e,this.spriteHeight=t}draw(e=0,t,i,o,r){let a=e*this.spriteWidth%this.fullWidth,d=Math.floor(e*this.spriteWidth/this.fullWidth)*this.spriteHeight,c=o===void 0?this.spriteWidth:o,l=r===void 0?this.spriteHeight:r,h=P().ctx;h.beginPath(),h.save(),h.translate(t,i),h.rotate(this.angle*Math.PI/180),h.drawImage(this.image,a,d,this.spriteWidth,this.spriteHeight,-c/2,-l/2,c,l),h.restore(),h.closePath()}drawAnim(e,t,i,o,r,a){var l;this.currentSprite==null&&(this.currentSprite=e);let d=this.animTimeDur/(t-e+1),c=Date.now();c-this.frameTimeLast>d&&(this.currentSprite<t?this.currentSprite++:this.animLoop?this.currentSprite=e:(this.currentSprite=null,this.animCallback()),this.frameTimeLast=c),this.draw((l=this.currentSprite)!=null?l:void 0,i,o,r,a)}};var w=()=>n.gameObject,v=class{constructor(e,t,i){this.style={};this.hoverStyle={};this.hoverOverrides={};this._tag="THRUNIUM.Elem."+e,this.x=t,this.y=i,this.elem=document.createElement(e),this.elem.addEventListener("mouseenter",()=>this.updateStyle(this.hoverStyle),!1),this.elem.addEventListener("mouseleave",()=>this.updateStyle(this.style),!1),this.setStyle("display","block"),this.setStyle("position","absolute"),this.setStyle("color","#000"),this.setStyle("backgroundColor","#fff"),this.setStyle("fontFamily",w().font),this.setStyle("borderRadius","5px"),this.resize(),S.elemsList.push(this),n.container.appendChild(this.elem)}get[Symbol.toStringTag](){return this._tag}setPos(e,t){this.x=e,this.y=t,this.resize()}resize(){let e=w().fitScale;this.setStyle("left",this.x*e+"px"),this.setStyle("top",this.y*e+"px"),this.setStyle("transformOrigin","top left"),this.setStyle("transform","scale("+e+")")}addEventListener(e,t,i){this.elem.addEventListener(e,t,i)}updateStyle(e){for(let t in e)this.elem.style[t]=e[t]}setStyle(e,t){this.style[e]=t,this.hoverOverrides[e]||(this.hoverStyle[e]=t),this.updateStyle(this.style)}setHoverStyle(e,t){this.hoverStyle[e]=t,this.hoverOverrides[e]=!0}show(){this.setStyle("display","block")}hide(){this.setStyle("display","none")}};function F(s,e,t){let i=new v("button",e,t);return i.elem.textContent=s,i.elem.style.border="none",i}function O(s,e,t){let i=w(),o=document.createElement("input");return o.style.position="absolute",o.style.left=s*i.scale*i.fitScale+"px",o.style.top=e*i.scale*i.fitScale+"px",o.style.border="2px solid #000",o.style.borderRadius="5px",o.style.color="#000",o.style.backgroundColor="#fff",o.style.fontFamily=i.font,o.style.fontSize=i.textSize,o.type=t.type?t.type:"text",t.placeholder&&(o.placeholder=t.placeholder),n.container.appendChild(o),o}var S={elemsList:[],Elem:v,Button:F,Input:O};function y(s){var r,a,d,c;let e=(r=s.success)!=null?r:(l=>console.log(l)),t=(a=s.error)!=null?a:(()=>{}),i=(d=s.contentType)!=null?d:"application/x-www-form-urlencoded",o=new XMLHttpRequest;return o.withCredentials=(c=s.withCredentials)!=null?c:!1,o.onreadystatechange=function(){o.readyState===4&&(o.status===200?e(o):t(o))},o.open(s.type,s.url,!0),i!==!1&&o.setRequestHeader("Content-Type",i),o.send(s.data),o}function I(s){return s.replace(/[%;\x00-\x1f\x7f]/g,encodeURIComponent).replace(/^ +| +$/g,e=>e.replace(/ /g,"%20"))}function z(s,e){let t=new Date;t.setTime(t.getTime()+365*24*60*60*1e3);let i="expires="+t.toUTCString();return document.cookie=s+"="+I(String(e))+";"+i+";path="+document.location.pathname,!0}function j(s){let e=s+"=";for(let t of document.cookie.split(";"))if(t=t.replace(/^ +/,""),t.indexOf(e)===0){let i=t.substring(e.length);try{return decodeURIComponent(i)}catch(o){return i}}return null}var A={set:z,get:j};var k={};_(k,{_options:()=>G,_receiveMessage:()=>B,accessRequested:()=>D,loginPopup:()=>W,reqToken:()=>V,reqUserToken:()=>Y,request:()=>K,setReqToken:()=>N,timeout:()=>X,userToken:()=>U});var V=null,U=null,X=null,W=null,D=!1,G={succes:s=>console.log(s),error:s=>console.log(s)};function N(s){n.Storage.reqToken=s}function Y(s){n.Storage._options.succes=s.succes,n.Storage._options.error=s.error,y({url:"https://api.thrungames.com/request/user-token",type:"post",data:"requestToken="+n.Storage.reqToken,succes:function(e){var i,o,r,a;let t=JSON.parse(e.response);t.access=="0"&&!n.Storage.accessRequested?(window.addEventListener("message",n.Storage._receiveMessage,!1),window.parent.postMessage({reqToken:n.Storage.reqToken},document.origin),n.Storage.timeout=setTimeout(function(){let d=screen.width?(screen.width-400)/2:0,l="height=500,width=400,top="+(screen.height?(screen.height-500)/2:0)+",left="+d+",scrollbars=yes,resizable",h="https://api.thrungames.com/user/access?token="+n.Storage.reqToken;n.Storage.loginPopup=window.open(h,"Approval of game",l)},200)):t.access=="1"?(n.Storage.userToken=window.event.data.userToken,(o=(i=n.Storage._options).succes)==null||o.call(i,{type:"userAccepted",event:e})):(a=(r=n.Storage._options).error)==null||a.call(r,{type:"ajaxFailed",event:e})},error:function(e){var t,i;(i=(t=n.Storage._options).error)==null||i.call(t,{type:"ajaxFailed",event:e})}})}function B(s){var t,i,o;let e=window.event;e.origin!=="https://www.thrungames.com/"&&e.origin!=="https://www.thrungames.com/"||(clearTimeout((t=n.Storage.timeout)!=null?t:void 0),n.Storage.accessRequested=!0,e.data.state==1?n.Storage.reqUserToken(n.Storage._options):(o=(i=n.Storage._options).error)==null||o.call(i,{type:"userRejected",event:s}))}function K(s){}n.version="1.2.0-rc.2";n.pageLoad=b;n.ready=x;n.throwError=m;n.mobileAndTabletcheck=E;n.iOScheck=L;n.getRandom=R;M();n.Game=p;n.Vector=f;n.Collider=Object.assign(n.Collider||{},u);n.Sprite=g;n.Elem=Object.assign(n.Elem||{},S);n.ajax=y;n.Storage=Object.assign(n.Storage||{},A,k);window.requestAnimFrame=typeof window.requestAnimationFrame=="function"?window.requestAnimationFrame.bind(window):s=>window.setTimeout(()=>s(Date.now()),1e3/60);})();
|
|
1
|
+
/*! THRUNIUM v1.2.0-rc.3 | (c) Infobits ApS | MIT License */
|
|
2
|
+
"use strict";(()=>{var H=Object.defineProperty;var _=(s,e)=>{for(var t in e)H(s,t,{get:e[t],enumerable:!0})};window.THRUNIUM||(window.THRUNIUM={});var n=window.THRUNIUM;function b(){n.pageLoaded=!0}function x(s){let e=!1,t=()=>{e||(e=!0,s())};if(document.readyState==="complete"){t();return}document.addEventListener("DOMContentLoaded",t,!1),window.addEventListener("load",t,!1)}function m(s){console.error(s),n.error=!0}function E(){let s=navigator.userAgent||navigator.vendor||"";return/(android|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|midp|mmp|mobile.+firefox|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows ce|xda|xiino|android|ipad|playbook|silk/i.test(s)||/1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\-(n|u)|c55\/|capi|ccwa|cdm\-|cell|chtm|cldc|cmd\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\-s|devi|dica|dmob|do(c|p)o|ds(12|\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\-|_)|g1 u|g560|gene|gf\-5|g\-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd\-(m|p|t)|hei\-|hi(pt|ta)|hp( i|ip)|hs\-c|ht(c(\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\-(20|go|ma)|i230|iac( |\-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc\-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|\-[a-w])|libw|lynx|m1\-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m\-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\-2|po(ck|rt|se)|prox|psio|pt\-g|qa\-a|qc(07|12|21|32|60|\-[2-7]|i\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\-|oo|p\-)|sdk\/|se(c(\-|0|1)|47|mc|nd|ri)|sgh\-|shar|sie(\-|m)|sk\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\-|v\-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\-|tdg\-|tel(i|m)|tim\-|t\-mo|to(pl|sh)|ts(70|m\-|m3|m5)|tx\-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas\-|your|zeto|zte\-/i.test(s.substr(0,4))}function L(){return/iPad|iPhone|iPod/.test(navigator.userAgent)&&!("MSStream"in window)}function R(s,e,t=!1){return t?Math.random()*(e-s)+s:Math.floor(Math.random()*(e-s+1))+s}function M(){n.container=null,n.gameObject=null,n.error=!1,n.pageLoaded=!1,n.fontsLoaded=!1,x(b),typeof document!="undefined"&&document.fonts&&document.fonts.ready?document.fonts.ready.then(()=>{n.fontsLoaded=!0}):n.fontsLoaded=!0}var C;C=Symbol.toStringTag;var p=class{constructor(e,t){this[C]="THRUNIUM.Game";this.scale=1;this.fitScale=1;this.delta=0;this.fps=0;this.runSpeed=0;this.lastRun=null;this.gameRunning=!1;this.showFPS=!1;this.namespace="";this.mouseX=0;this.mouseY=0;this.state="startup";this.startState=null;this.states=[];this.backgroundColor="#fff";this.assets=[];this.assetsLoaded=!1;this.loadedAssets=0;this.assetsToLoad=0;this.font="Arial";this.textSize="30px";this.click=()=>{};this.mousedown=()=>{};this.mouseup=()=>{};this.mousemove=()=>{};this.touch=()=>{};this.touchstart=()=>{};this.touchend=()=>{};this.keydown=()=>{};this.keyup=()=>{};this.deviceorientation=()=>{};this.devicemotion=()=>{};this.rezise=()=>{};this._deviceorientation=e=>{this.deviceorientation(e)};this._devicemotion=e=>{this.devicemotion(e)};this._mousetouchmove=e=>{e.preventDefault(),this.getMouseCords(e),this.mousemove(e)};this._touchstart=e=>{e.preventDefault(),this.getMouseCords(e),this.touch(e),this.touchstart(e)};this._touchend=e=>{e.preventDefault(),this.getMouseCords(e),this.click(e),this.touchend(e)};this._resize=e=>{var i,o;this.updateFitScale(),this.updateScale();let t=(o=(i=n.Elem)==null?void 0:i.elemsList)!=null?o:[];for(let r=0;r<t.length;r++)t[r].resize();this.rezise(e)};this.assetLoaded=()=>{this.loadedAssets++};this.initAssetSpriteMap=(e=>function(){let t=e.assets,i=n.Sprite,o=new i(this);t[this.dataset.index]=o,o.setSpriteMap(Number(this.dataset.spriteWidth),Number(this.dataset.spriteHeight)),e.loadedAssets++})(this);this.gameLoop=()=>{if(!this.lastRun){this.lastRun=Date.now(),this.requestFrame(this.gameLoop);return}this.delta=(Date.now()-this.lastRun)/1e3,this.lastRun=Date.now(),this.fps=1/this.delta,this.runSpeed=Math.round(this.fps/60*100)/100,this.ctx.clearRect(0,0,this.width,this.height),this.canvas.style.cursor="default",this.drawRect(0,0,this.width,this.height),this.setFillColor(this.backgroundColor),this.fill(),this.state=="startup"?this.startup():this.states[this.state](),this.showFPS&&this.drawFPS(),this.gameRunning&&!n.error&&this.requestFrame(this.gameLoop)};this.width=e,this.height=t,this.contruct()}getMouseCords(e){let t=e;if(t.clientX===void 0){let a=e;a.touches&&a.touches[0]?t=a.touches[0]:a.changedTouches&&a.changedTouches[0]&&(t=a.changedTouches[0])}let i=this.canvas.getBoundingClientRect(),o=this.canvas.scrollWidth/this.width,r=this.canvas.scrollHeight/this.height;this.mouseX=(t.clientX-i.left)/o,this.mouseY=(t.clientY-i.top)/r}updateScale(){this.scale=window.devicePixelRatio*this.fitScale,this.canvas.width=this.width*this.scale,this.canvas.height=this.height*this.scale,this.ctx.scale(this.scale,this.scale)}updateFitScale(){this.width/this.height>window.innerWidth/window.innerHeight?this.fitScale=window.innerWidth/this.width:this.fitScale=window.innerHeight/this.height;let e=this.width*this.fitScale+"px",t=this.height*this.fitScale+"px";this.canvas.style.width=e,this.canvas.style.height=t;let i=n.container;i.style.width=e,i.style.height=t}contruct(){document.body.style.background="#333";let e=document.createElement("div");e.style.position="relative",e.style.display="block",e.style.margin="auto",n.container=e,n.gameObject=this,document.body.appendChild(e),this.canvas=document.createElement("canvas"),e.appendChild(this.canvas),this.ctx=this.canvas.getContext("2d"),this.canvas.style.display="block",this.canvas.style.margin="auto",this._resize(),window.addEventListener("resize",this._resize,!1),this.ctx.imageSmoothingEnabled=!1}init(){this.assetsLoaded||this.loadAssets(),this._resize(),this.canvas.addEventListener("click",this.click,!1),this.canvas.addEventListener("mousedown",this.mousedown,!1),this.canvas.addEventListener("mouseup",this.mouseup,!1),this.canvas.addEventListener("touchstart",this._touchstart,!1),this.canvas.addEventListener("touchend",this._touchend,!1),document.addEventListener("keydown",this.keydown,!1),document.addEventListener("keyup",this.keyup,!1),this.canvas.addEventListener("touchmove",this._mousetouchmove,!1),this.canvas.addEventListener("mousemove",this._mousetouchmove,!1),window.addEventListener("deviceorientation",this._deviceorientation),window.addEventListener("devicemotion",this._devicemotion)}loadAssets(){this.assetsToLoad=this.assets.length;let e=[],t=e;for(let i=0;i<this.assets.length;i++){let o=this.assets[i],r,a,d=null;if(typeof o=="string")a=o,r=a;else if(typeof o=="object"&&o!==null){let h=o;a=h.src,r=h.index,h.spriteMap!==void 0&&(d=h.spriteMap)}else{console.error("ASSETS - Unknown entry");continue}let c=this.getFileExtension(a);t[r]=null;let l;if(this.isImage(c))l=new Image;else if(this.isAudio(c))l=new Audio;else{console.error("ASSETS - Unknown file type: "+c+" for file "+a);continue}t[r]=l,l.dataset.index=r,d!==null&&(l.dataset.spriteWidth=String(d.width),l.dataset.spriteHeight=String(d.height)),l.onload=d!==null?this.initAssetSpriteMap:this.assetLoaded,l.src=a}this.assets=e,this.assetsLoaded=!0}getFileExtension(e){return/[.]/.exec(e)?/[^.]+$/.exec(e)[0]:void 0}isImage(e){return["jpg","jpeg","png","gif","xbm"].includes(e)}isAudio(e){return["mp3","wav","ogg","aac"].includes(e)}setFillColor(e){this.ctx.fillStyle=e}fill(){this.ctx.fill()}setStrokeColor(e){this.ctx.strokeStyle=e}stroke(){this.ctx.stroke()}drawLine(e,t,i,o,r){this.ctx.beginPath(),r&&(this.ctx.lineWidth=r),this.ctx.moveTo(e,t),this.ctx.lineTo(i,o),this.ctx.stroke(),this.ctx.closePath()}drawText(e,t,i){this.ctx.font=this.textSize+" "+this.font,this.ctx.fillText(e,t,i)}drawRect(e,t,i,o,r){let a=this.ctx;a.beginPath(),r?(a.moveTo(e+r,t),a.lineTo(e+i-r,t),a.quadraticCurveTo(e+i,t,e+i,t+r),a.lineTo(e+i,t+o-r),a.quadraticCurveTo(e+i,t+o,e+i-r,t+o),a.lineTo(e+r,t+o),a.quadraticCurveTo(e,t+o,e,t+o-r),a.lineTo(e,t+r),a.quadraticCurveTo(e,t,e+r,t)):a.rect(e,t,i,o),a.closePath()}drawCircle(e,t,i){this.ctx.beginPath(),this.ctx.arc(e,t,i,0,2*Math.PI),this.ctx.closePath()}drawImage(e,t,i,o=null,r=null){this.ctx.beginPath(),o!==null&&r!==null?this.ctx.drawImage(e,t,i,o,r):this.ctx.drawImage(e,t,i),this.ctx.closePath()}start(){this.gameRunning=!0,this.requestFrame(this.gameLoop)}stop(){this.gameRunning=!1}requestFrame(e){typeof window.requestAnimFrame=="function"?window.requestAnimFrame(e):requestAnimationFrame(e)}startup(){this.drawRect(0,0,this.width,this.height),this.setFillColor("#000"),this.fill(),this.ctx.font="25px Arial",this.ctx.textAlign="center",this.ctx.textBaseline="bottom",this.setFillColor("#fff"),this.ctx.fillText("Loading game",this.width/2,this.height/2-10),this.drawRect(this.width/2-100,this.height/2,200,20,10),this.setStrokeColor("#fff"),this.stroke();let e=200/this.assetsToLoad*this.loadedAssets;e<20&&(e=20),this.drawRect(this.width/2-100,this.height/2,e,20,10),this.setFillColor("#fff"),this.fill(),this.assetsToLoad==this.loadedAssets&&n.pageLoaded&&n.fontsLoaded&&(this._resize(),this.state=this.startState)}drawFPS(){this.ctx.fillStyle="gray",this.ctx.font="normal 16pt Arial",this.ctx.textAlign="left",this.ctx.textBaseline="top",this.ctx.fillText(Math.round(this.fps)+" fps - scale: "+this.scale,5,5)}};var f=class{constructor(e,t){this.x=e,this.y=t}get[Symbol.toStringTag](){return"THRUNIUM.Vector"}clone(){return new n.Vector(this.x,this.y)}equal(e){return this.x==e.x&&this.y==e.y}scale(e){this.x*=e,this.y*=e}scaleX(e){this.x*=e}scaleY(e){this.y*=e}add(e){this.x+=e.x,this.y+=e.y}addX(e){this.x+=e.x}addY(e){this.y+=e.y}subtract(e){this.x-=e.x,this.y-=e.y}subtractX(e){this.x-=e.x}subtractY(e){this.y-=e.y}divide(e){this.x/=e.x,this.y/=e.y}divideX(e){this.x/=e.x}divideY(e){this.y/=e.y}multiply(e){this.x*=e.x,this.y*=e.y}multiplyX(e){this.x*=e.x}multiplyY(e){this.y*=e.y}invert(){this.x*=-1,this.y*=-1}invertX(){this.x*=-1}invertY(){this.y*=-1}normalize(){let e=Math.sqrt(this.x*this.x+this.y*this.y);e!==0&&(this.x/=e,this.y/=e)}limit(e){this.x>e.x&&(this.x=e.x),this.y>e.y&&(this.y=e.y),this.x<e.x*-1&&(this.x=e.x*-1),this.y<e.y*-1&&(this.y=e.y*-1)}limitLength(e){}};var u={isCircle(s){return s.x!==void 0&&s.y!==void 0&&s.radius!==void 0},isRect(s){return s.x!==void 0&&s.y!==void 0&&s.width!==void 0&&s.height!==void 0},fixPos(s){return s.pos===void 0||s.pos.x===void 0&&s.pos.y===void 0||(s.x=s.pos.x,s.y=s.pos.y),s},rect(s,e){let t=u.fixPos(s),i=u.fixPos(e);if(!u.isRect(t)||!u.isRect(i))return m("One of the objects is not defined correctly as a rect"),!1;let[o,r,a,d]=[t.x,t.y,t.width,t.height],[c,l,h,T]=[i.x,i.y,i.width,i.height];return!(o+a/2<c-h/2||o-a/2>c+h/2||r+d/2<l-T/2||r-d/2>l+T/2)},circle(s,e){let t=u.fixPos(s),i=u.fixPos(e);if(!u.isCircle(t)||!u.isCircle(i))return m("One of the objects is not defined correctly as a circle"),!1;let o=t.x-i.x,r=t.y-i.y;return Math.sqrt(o*o+r*r)<t.radius+i.radius},circleRect(s,e){let t=u.fixPos(s),i=u.fixPos(e);if(!u.isCircle(t)||!u.isRect(i))return m("One of the objects is not defined correctly as a circle or rect"),!1;let o=Math.abs(t.x-i.x),r=Math.abs(t.y-i.y),a=i.width/2,d=i.height/2,c=t.radius;if(o>=a+c||r>=d+c)return!1;if(o<a||r<d)return!0;let l=o-a,h=r-d;return l*l+h*h<=c*c}};var P=()=>n.gameObject,q;q=Symbol.toStringTag;var g=class{constructor(e){this[q]="THRUNIUM.Sprite";this.angle=0;this.currentSprite=null;this.animTimeDur=100;this.frameTimeLast=0;this.animLoop=!1;this.animCallback=()=>{};this.image=e,this.fullWidth=e.width,this.fullHeight=e.height,this.spriteWidth=e.width,this.spriteHeight=e.height}setAngle(e){this.angle=e}setLoop(e){this.animLoop=e}setAnimCallback(e){this.animCallback=e}setAnimTime(e){this.animTimeDur=e}setSpriteMap(e,t){this.spriteWidth=e,this.spriteHeight=t}draw(e=0,t,i,o,r){let a=e*this.spriteWidth%this.fullWidth,d=Math.floor(e*this.spriteWidth/this.fullWidth)*this.spriteHeight,c=o===void 0?this.spriteWidth:o,l=r===void 0?this.spriteHeight:r,h=P().ctx;h.beginPath(),h.save(),h.translate(t,i),h.rotate(this.angle*Math.PI/180),h.drawImage(this.image,a,d,this.spriteWidth,this.spriteHeight,-c/2,-l/2,c,l),h.restore(),h.closePath()}drawAnim(e,t,i,o,r,a){var l;this.currentSprite==null&&(this.currentSprite=e);let d=this.animTimeDur/(t-e+1),c=Date.now();c-this.frameTimeLast>d&&(this.currentSprite<t?this.currentSprite++:this.animLoop?this.currentSprite=e:(this.currentSprite=null,this.animCallback()),this.frameTimeLast=c),this.draw((l=this.currentSprite)!=null?l:void 0,i,o,r,a)}};var w=()=>n.gameObject,v=class{constructor(e,t,i){this.style={};this.hoverStyle={};this.hoverOverrides={};this._tag="THRUNIUM.Elem."+e,this.x=t,this.y=i,this.elem=document.createElement(e),this.elem.addEventListener("mouseenter",()=>this.updateStyle(this.hoverStyle),!1),this.elem.addEventListener("mouseleave",()=>this.updateStyle(this.style),!1),this.setStyle("display","block"),this.setStyle("position","absolute"),this.setStyle("color","#000"),this.setStyle("backgroundColor","#fff"),this.setStyle("fontFamily",w().font),this.setStyle("borderRadius","5px"),this.resize(),S.elemsList.push(this),n.container.appendChild(this.elem)}get[Symbol.toStringTag](){return this._tag}setPos(e,t){this.x=e,this.y=t,this.resize()}resize(){let e=w().fitScale;this.setStyle("left",this.x*e+"px"),this.setStyle("top",this.y*e+"px"),this.setStyle("transformOrigin","top left"),this.setStyle("transform","scale("+e+")")}addEventListener(e,t,i){this.elem.addEventListener(e,t,i)}updateStyle(e){for(let t in e)this.elem.style[t]=e[t]}setStyle(e,t){this.style[e]=t,this.hoverOverrides[e]||(this.hoverStyle[e]=t),this.updateStyle(this.style)}setHoverStyle(e,t){this.hoverStyle[e]=t,this.hoverOverrides[e]=!0}show(){this.setStyle("display","block")}hide(){this.setStyle("display","none")}};function F(s,e,t){let i=new v("button",e,t);return i.elem.textContent=s,i.elem.style.border="none",i}function O(s,e,t){let i=w(),o=document.createElement("input");return o.style.position="absolute",o.style.left=s*i.scale*i.fitScale+"px",o.style.top=e*i.scale*i.fitScale+"px",o.style.border="2px solid #000",o.style.borderRadius="5px",o.style.color="#000",o.style.backgroundColor="#fff",o.style.fontFamily=i.font,o.style.fontSize=i.textSize,o.type=t.type?t.type:"text",t.placeholder&&(o.placeholder=t.placeholder),n.container.appendChild(o),o}var S={elemsList:[],Elem:v,Button:F,Input:O};function y(s){var r,a,d,c;let e=(r=s.success)!=null?r:(l=>console.log(l)),t=(a=s.error)!=null?a:(()=>{}),i=(d=s.contentType)!=null?d:"application/x-www-form-urlencoded",o=new XMLHttpRequest;return o.withCredentials=(c=s.withCredentials)!=null?c:!1,o.onreadystatechange=function(){o.readyState===4&&(o.status===200?e(o):t(o))},o.open(s.type,s.url,!0),i!==!1&&o.setRequestHeader("Content-Type",i),o.send(s.data),o}function I(s){return s.replace(/[%;\x00-\x1f\x7f]/g,encodeURIComponent).replace(/^ +| +$/g,e=>e.replace(/ /g,"%20"))}function z(s,e){let t=new Date;t.setTime(t.getTime()+365*24*60*60*1e3);let i="expires="+t.toUTCString();return document.cookie=s+"="+I(String(e))+";"+i+";path="+document.location.pathname,!0}function j(s){let e=s+"=";for(let t of document.cookie.split(";"))if(t=t.replace(/^ +/,""),t.indexOf(e)===0){let i=t.substring(e.length);try{return decodeURIComponent(i)}catch(o){return i}}return null}var A={set:z,get:j};var k={};_(k,{_options:()=>G,_receiveMessage:()=>B,accessRequested:()=>D,loginPopup:()=>W,reqToken:()=>V,reqUserToken:()=>Y,request:()=>K,setReqToken:()=>N,timeout:()=>X,userToken:()=>U});var V=null,U=null,X=null,W=null,D=!1,G={succes:s=>console.log(s),error:s=>console.log(s)};function N(s){n.Storage.reqToken=s}function Y(s){n.Storage._options.succes=s.succes,n.Storage._options.error=s.error,y({url:"https://api.thrungames.com/request/user-token",type:"post",data:"requestToken="+n.Storage.reqToken,succes:function(e){var i,o,r,a;let t=JSON.parse(e.response);t.access=="0"&&!n.Storage.accessRequested?(window.addEventListener("message",n.Storage._receiveMessage,!1),window.parent.postMessage({reqToken:n.Storage.reqToken},document.origin),n.Storage.timeout=setTimeout(function(){let d=screen.width?(screen.width-400)/2:0,l="height=500,width=400,top="+(screen.height?(screen.height-500)/2:0)+",left="+d+",scrollbars=yes,resizable",h="https://api.thrungames.com/user/access?token="+n.Storage.reqToken;n.Storage.loginPopup=window.open(h,"Approval of game",l)},200)):t.access=="1"?(n.Storage.userToken=window.event.data.userToken,(o=(i=n.Storage._options).succes)==null||o.call(i,{type:"userAccepted",event:e})):(a=(r=n.Storage._options).error)==null||a.call(r,{type:"ajaxFailed",event:e})},error:function(e){var t,i;(i=(t=n.Storage._options).error)==null||i.call(t,{type:"ajaxFailed",event:e})}})}function B(s){var t,i,o;let e=window.event;e.origin!=="https://www.thrungames.com/"&&e.origin!=="https://www.thrungames.com/"||(clearTimeout((t=n.Storage.timeout)!=null?t:void 0),n.Storage.accessRequested=!0,e.data.state==1?n.Storage.reqUserToken(n.Storage._options):(o=(i=n.Storage._options).error)==null||o.call(i,{type:"userRejected",event:s}))}function K(s){}n.version="1.2.0-rc.3";n.pageLoad=b;n.ready=x;n.throwError=m;n.mobileAndTabletcheck=E;n.iOScheck=L;n.getRandom=R;M();n.Game=p;n.Vector=f;n.Collider=Object.assign(n.Collider||{},u);n.Sprite=g;n.Elem=Object.assign(n.Elem||{},S);n.ajax=y;n.Storage=Object.assign(n.Storage||{},A,k);window.requestAnimFrame=typeof window.requestAnimationFrame=="function"?window.requestAnimationFrame.bind(window):s=>window.setTimeout(()=>s(Date.now()),1e3/60);})();
|
|
3
3
|
//# sourceMappingURL=thrunium.min.js.map
|