@guinetik/gcanvas 1.0.4 → 1.0.5
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/dist/CNAME +1 -0
- package/dist/animations.html +31 -0
- package/dist/basic.html +38 -0
- package/dist/baskara.html +31 -0
- package/dist/bezier.html +35 -0
- package/dist/beziersignature.html +29 -0
- package/dist/blackhole.html +28 -0
- package/dist/blob.html +35 -0
- package/dist/coordinates.html +698 -0
- package/dist/cube3d.html +23 -0
- package/dist/demos.css +303 -0
- package/dist/dino.html +42 -0
- package/dist/easing.html +28 -0
- package/dist/events.html +195 -0
- package/dist/fluent.html +647 -0
- package/dist/fluid-simple.html +22 -0
- package/dist/fluid.html +37 -0
- package/dist/fractals.html +36 -0
- package/dist/gameobjects.html +626 -0
- package/dist/gcanvas.es.js +517 -0
- package/dist/gcanvas.es.min.js +1 -1
- package/dist/gcanvas.umd.js +1 -1
- package/dist/gcanvas.umd.min.js +1 -1
- package/dist/genart.html +26 -0
- package/dist/gendream.html +26 -0
- package/dist/group.html +36 -0
- package/dist/home.html +587 -0
- package/dist/hyperbolic001.html +23 -0
- package/dist/hyperbolic002.html +23 -0
- package/dist/hyperbolic003.html +23 -0
- package/dist/hyperbolic004.html +23 -0
- package/dist/hyperbolic005.html +22 -0
- package/dist/index.html +398 -0
- package/dist/isometric.html +34 -0
- package/dist/js/animations.js +452 -0
- package/dist/js/basic.js +204 -0
- package/dist/js/baskara.js +751 -0
- package/dist/js/bezier.js +692 -0
- package/dist/js/beziersignature.js +241 -0
- package/dist/js/blackhole/accretiondisk.obj.js +379 -0
- package/dist/js/blackhole/blackhole.obj.js +318 -0
- package/dist/js/blackhole/index.js +409 -0
- package/dist/js/blackhole/particle.js +56 -0
- package/dist/js/blackhole/starfield.obj.js +218 -0
- package/dist/js/blob.js +2276 -0
- package/dist/js/coordinates.js +840 -0
- package/dist/js/cube3d.js +789 -0
- package/dist/js/dino.js +1420 -0
- package/dist/js/easing.js +477 -0
- package/dist/js/fluent.js +183 -0
- package/dist/js/fluid-simple.js +253 -0
- package/dist/js/fluid.js +527 -0
- package/dist/js/fractals.js +932 -0
- package/dist/js/fractalworker.js +93 -0
- package/dist/js/gameobjects.js +176 -0
- package/dist/js/genart.js +268 -0
- package/dist/js/gendream.js +209 -0
- package/dist/js/group.js +140 -0
- package/dist/js/hyperbolic001.js +310 -0
- package/dist/js/hyperbolic002.js +388 -0
- package/dist/js/hyperbolic003.js +319 -0
- package/dist/js/hyperbolic004.js +345 -0
- package/dist/js/hyperbolic005.js +340 -0
- package/dist/js/info-toggle.js +25 -0
- package/dist/js/isometric.js +863 -0
- package/dist/js/kerr.js +1547 -0
- package/dist/js/lavalamp.js +590 -0
- package/dist/js/layout.js +354 -0
- package/dist/js/mondrian.js +285 -0
- package/dist/js/opacity.js +275 -0
- package/dist/js/painter.js +484 -0
- package/dist/js/particles-showcase.js +514 -0
- package/dist/js/particles.js +299 -0
- package/dist/js/patterns.js +397 -0
- package/dist/js/penrose/artifact.js +69 -0
- package/dist/js/penrose/blackhole.js +121 -0
- package/dist/js/penrose/constants.js +73 -0
- package/dist/js/penrose/game.js +943 -0
- package/dist/js/penrose/lore.js +278 -0
- package/dist/js/penrose/penrosescene.js +892 -0
- package/dist/js/penrose/ship.js +216 -0
- package/dist/js/penrose/sounds.js +211 -0
- package/dist/js/penrose/voidparticle.js +55 -0
- package/dist/js/penrose/voidscene.js +258 -0
- package/dist/js/penrose/voidship.js +144 -0
- package/dist/js/penrose/wormhole.js +46 -0
- package/dist/js/pipeline.js +555 -0
- package/dist/js/plane3d.js +256 -0
- package/dist/js/platformer.js +1579 -0
- package/dist/js/scene.js +304 -0
- package/dist/js/scenes.js +320 -0
- package/dist/js/schrodinger.js +410 -0
- package/dist/js/schwarzschild.js +1015 -0
- package/dist/js/shapes.js +628 -0
- package/dist/js/space/alien.js +171 -0
- package/dist/js/space/boom.js +98 -0
- package/dist/js/space/boss.js +353 -0
- package/dist/js/space/buff.js +73 -0
- package/dist/js/space/bullet.js +102 -0
- package/dist/js/space/constants.js +85 -0
- package/dist/js/space/game.js +1884 -0
- package/dist/js/space/hud.js +112 -0
- package/dist/js/space/laserbeam.js +179 -0
- package/dist/js/space/lightning.js +277 -0
- package/dist/js/space/minion.js +192 -0
- package/dist/js/space/missile.js +212 -0
- package/dist/js/space/player.js +430 -0
- package/dist/js/space/powerup.js +90 -0
- package/dist/js/space/starfield.js +58 -0
- package/dist/js/space/starpower.js +90 -0
- package/dist/js/spacetime.js +559 -0
- package/dist/js/sphere3d.js +229 -0
- package/dist/js/sprite.js +473 -0
- package/dist/js/starfaux/config.js +118 -0
- package/dist/js/starfaux/enemy.js +353 -0
- package/dist/js/starfaux/hud.js +78 -0
- package/dist/js/starfaux/index.js +482 -0
- package/dist/js/starfaux/laser.js +182 -0
- package/dist/js/starfaux/player.js +468 -0
- package/dist/js/starfaux/terrain.js +560 -0
- package/dist/js/study001.js +275 -0
- package/dist/js/study002.js +366 -0
- package/dist/js/study003.js +331 -0
- package/dist/js/study004.js +389 -0
- package/dist/js/study005.js +209 -0
- package/dist/js/study006.js +194 -0
- package/dist/js/study007.js +192 -0
- package/dist/js/study008.js +413 -0
- package/dist/js/svgtween.js +204 -0
- package/dist/js/tde/accretiondisk.js +471 -0
- package/dist/js/tde/blackhole.js +219 -0
- package/dist/js/tde/blackholescene.js +209 -0
- package/dist/js/tde/config.js +59 -0
- package/dist/js/tde/index.js +820 -0
- package/dist/js/tde/jets.js +290 -0
- package/dist/js/tde/lensedstarfield.js +154 -0
- package/dist/js/tde/tdestar.js +297 -0
- package/dist/js/tde/tidalstream.js +372 -0
- package/dist/js/tde_old/blackhole.obj.js +354 -0
- package/dist/js/tde_old/debris.obj.js +791 -0
- package/dist/js/tde_old/flare.obj.js +239 -0
- package/dist/js/tde_old/index.js +448 -0
- package/dist/js/tde_old/star.obj.js +812 -0
- package/dist/js/tetris/config.js +157 -0
- package/dist/js/tetris/grid.js +286 -0
- package/dist/js/tetris/index.js +1195 -0
- package/dist/js/tetris/renderer.js +634 -0
- package/dist/js/tetris/tetrominos.js +280 -0
- package/dist/js/tiles.js +312 -0
- package/dist/js/tweendemo.js +79 -0
- package/dist/js/visibility.js +102 -0
- package/dist/kerr.html +28 -0
- package/dist/lavalamp.html +27 -0
- package/dist/layouts.html +37 -0
- package/dist/logo.svg +4 -0
- package/dist/loop.html +84 -0
- package/dist/mondrian.html +32 -0
- package/dist/og_image.png +0 -0
- package/dist/opacity.html +36 -0
- package/dist/painter.html +39 -0
- package/dist/particles-showcase.html +28 -0
- package/dist/particles.html +24 -0
- package/dist/patterns.html +33 -0
- package/dist/penrose-game.html +31 -0
- package/dist/pipeline.html +737 -0
- package/dist/plane3d.html +24 -0
- package/dist/platformer.html +43 -0
- package/dist/scene.html +33 -0
- package/dist/scenes.html +96 -0
- package/dist/schrodinger.html +27 -0
- package/dist/schwarzschild.html +27 -0
- package/dist/shapes.html +16 -0
- package/dist/space.html +85 -0
- package/dist/spacetime.html +27 -0
- package/dist/sphere3d.html +24 -0
- package/dist/sprite.html +18 -0
- package/dist/starfaux.html +22 -0
- package/dist/study001.html +23 -0
- package/dist/study002.html +23 -0
- package/dist/study003.html +23 -0
- package/dist/study004.html +23 -0
- package/dist/study005.html +22 -0
- package/dist/study006.html +24 -0
- package/dist/study007.html +24 -0
- package/dist/study008.html +22 -0
- package/dist/svgtween.html +29 -0
- package/dist/tde.html +28 -0
- package/dist/tetris3d.html +25 -0
- package/dist/tiles.html +28 -0
- package/dist/transforms.html +400 -0
- package/dist/tween.html +45 -0
- package/dist/visibility.html +33 -0
- package/package.json +1 -1
package/dist/gcanvas.es.js
CHANGED
|
@@ -5111,6 +5111,337 @@ _name = new WeakMap();
|
|
|
5111
5111
|
_signature = new WeakMap();
|
|
5112
5112
|
_coordinates = new WeakMap();
|
|
5113
5113
|
let Tensor = _Tensor;
|
|
5114
|
+
const CONFIG$1 = {
|
|
5115
|
+
tokens: {
|
|
5116
|
+
// Supported operator aliases. Words are case-insensitive.
|
|
5117
|
+
unaryNot: ["!", "~", "¬", "NOT"],
|
|
5118
|
+
and: ["&", "∧", "AND"],
|
|
5119
|
+
nand: ["NAND"],
|
|
5120
|
+
or: ["|", "∨", "OR"],
|
|
5121
|
+
nor: ["NOR"],
|
|
5122
|
+
xor: ["^", "⊕", "XOR"],
|
|
5123
|
+
xnor: ["XNOR"]
|
|
5124
|
+
},
|
|
5125
|
+
precedence: {
|
|
5126
|
+
// Higher number = higher precedence
|
|
5127
|
+
OR: 1,
|
|
5128
|
+
NOR: 1,
|
|
5129
|
+
XOR: 2,
|
|
5130
|
+
XNOR: 2,
|
|
5131
|
+
AND: 3,
|
|
5132
|
+
NAND: 3,
|
|
5133
|
+
NOT: 4
|
|
5134
|
+
},
|
|
5135
|
+
constants: {
|
|
5136
|
+
true: ["1", "TRUE"],
|
|
5137
|
+
false: ["0", "FALSE"]
|
|
5138
|
+
}
|
|
5139
|
+
};
|
|
5140
|
+
function toBool(v) {
|
|
5141
|
+
return Boolean(v);
|
|
5142
|
+
}
|
|
5143
|
+
function upper(s) {
|
|
5144
|
+
return String(s).toUpperCase();
|
|
5145
|
+
}
|
|
5146
|
+
function tokenize(src) {
|
|
5147
|
+
const out = [];
|
|
5148
|
+
const s = String(src ?? "");
|
|
5149
|
+
let i = 0;
|
|
5150
|
+
const isWs = (c) => c === " " || c === "\n" || c === " " || c === "\r";
|
|
5151
|
+
const isAlpha = (c) => c >= "A" && c <= "Z" || c >= "a" && c <= "z" || c === "_";
|
|
5152
|
+
const isAlnum = (c) => isAlpha(c) || c >= "0" && c <= "9";
|
|
5153
|
+
while (i < s.length) {
|
|
5154
|
+
const c = s[i];
|
|
5155
|
+
if (isWs(c)) {
|
|
5156
|
+
i++;
|
|
5157
|
+
continue;
|
|
5158
|
+
}
|
|
5159
|
+
if (c === "(") {
|
|
5160
|
+
out.push({ type: "lp", value: c });
|
|
5161
|
+
i++;
|
|
5162
|
+
continue;
|
|
5163
|
+
}
|
|
5164
|
+
if (c === ")") {
|
|
5165
|
+
out.push({ type: "rp", value: c });
|
|
5166
|
+
i++;
|
|
5167
|
+
continue;
|
|
5168
|
+
}
|
|
5169
|
+
if (c === "!" || c === "~" || c === "¬" || c === "&" || c === "∧" || c === "|" || c === "∨" || c === "^" || c === "⊕") {
|
|
5170
|
+
out.push({ type: "op", value: c });
|
|
5171
|
+
i++;
|
|
5172
|
+
continue;
|
|
5173
|
+
}
|
|
5174
|
+
if (isAlpha(c) || c >= "0" && c <= "9") {
|
|
5175
|
+
let j = i + 1;
|
|
5176
|
+
while (j < s.length && isAlnum(s[j])) j++;
|
|
5177
|
+
const raw = s.slice(i, j);
|
|
5178
|
+
const u = upper(raw);
|
|
5179
|
+
if (CONFIG$1.constants.true.includes(u) || CONFIG$1.constants.false.includes(u)) {
|
|
5180
|
+
out.push({ type: "const", value: u });
|
|
5181
|
+
} else if (CONFIG$1.tokens.unaryNot.includes(u) || CONFIG$1.tokens.and.includes(u) || CONFIG$1.tokens.nand.includes(u) || CONFIG$1.tokens.or.includes(u) || CONFIG$1.tokens.nor.includes(u) || CONFIG$1.tokens.xor.includes(u) || CONFIG$1.tokens.xnor.includes(u)) {
|
|
5182
|
+
out.push({ type: "op", value: u });
|
|
5183
|
+
} else {
|
|
5184
|
+
out.push({ type: "ident", value: raw });
|
|
5185
|
+
}
|
|
5186
|
+
i = j;
|
|
5187
|
+
continue;
|
|
5188
|
+
}
|
|
5189
|
+
throw new Error(`[BooleanAlgebra] Unexpected character "${c}" at ${i}`);
|
|
5190
|
+
}
|
|
5191
|
+
return out;
|
|
5192
|
+
}
|
|
5193
|
+
function normalizeOperator(op) {
|
|
5194
|
+
const u = upper(op);
|
|
5195
|
+
if (CONFIG$1.tokens.unaryNot.map(upper).includes(u)) return "NOT";
|
|
5196
|
+
if (CONFIG$1.tokens.and.map(upper).includes(u)) return "AND";
|
|
5197
|
+
if (CONFIG$1.tokens.nand.map(upper).includes(u)) return "NAND";
|
|
5198
|
+
if (CONFIG$1.tokens.or.map(upper).includes(u)) return "OR";
|
|
5199
|
+
if (CONFIG$1.tokens.nor.map(upper).includes(u)) return "NOR";
|
|
5200
|
+
if (CONFIG$1.tokens.xor.map(upper).includes(u)) return "XOR";
|
|
5201
|
+
if (CONFIG$1.tokens.xnor.map(upper).includes(u)) return "XNOR";
|
|
5202
|
+
throw new Error(`[BooleanAlgebra] Unknown operator "${op}"`);
|
|
5203
|
+
}
|
|
5204
|
+
function precedence(opName) {
|
|
5205
|
+
return CONFIG$1.precedence[opName] ?? 0;
|
|
5206
|
+
}
|
|
5207
|
+
function parseTokens(tokens) {
|
|
5208
|
+
let idx = 0;
|
|
5209
|
+
const peek = () => tokens[idx];
|
|
5210
|
+
const next = () => tokens[idx++];
|
|
5211
|
+
function parsePrimary() {
|
|
5212
|
+
const t = next();
|
|
5213
|
+
if (!t) throw new Error("[BooleanAlgebra] Unexpected end of input");
|
|
5214
|
+
if (t.type === "const") {
|
|
5215
|
+
const u = upper(t.value);
|
|
5216
|
+
return { type: "const", value: CONFIG$1.constants.true.includes(u) };
|
|
5217
|
+
}
|
|
5218
|
+
if (t.type === "ident") {
|
|
5219
|
+
return { type: "var", name: t.value };
|
|
5220
|
+
}
|
|
5221
|
+
if (t.type === "lp") {
|
|
5222
|
+
const expr = parseExpr(0);
|
|
5223
|
+
const r = next();
|
|
5224
|
+
if (!r || r.type !== "rp") {
|
|
5225
|
+
throw new Error("[BooleanAlgebra] Missing closing ')'");
|
|
5226
|
+
}
|
|
5227
|
+
return expr;
|
|
5228
|
+
}
|
|
5229
|
+
if (t.type === "op") {
|
|
5230
|
+
const opName = normalizeOperator(t.value);
|
|
5231
|
+
if (opName !== "NOT") {
|
|
5232
|
+
throw new Error(`[BooleanAlgebra] Unexpected binary operator "${t.value}"`);
|
|
5233
|
+
}
|
|
5234
|
+
return { type: "not", left: parsePrimary() };
|
|
5235
|
+
}
|
|
5236
|
+
throw new Error(`[BooleanAlgebra] Unexpected token "${t.type}"`);
|
|
5237
|
+
}
|
|
5238
|
+
function parseExpr(minPrec) {
|
|
5239
|
+
let left = parsePrimary();
|
|
5240
|
+
while (true) {
|
|
5241
|
+
const t = peek();
|
|
5242
|
+
if (!t || t.type !== "op") break;
|
|
5243
|
+
const opName = normalizeOperator(t.value);
|
|
5244
|
+
if (opName === "NOT") break;
|
|
5245
|
+
const prec = precedence(opName);
|
|
5246
|
+
if (prec < minPrec) break;
|
|
5247
|
+
next();
|
|
5248
|
+
const right = parseExpr(prec + 1);
|
|
5249
|
+
const type = opName === "AND" ? "and" : opName === "OR" ? "or" : opName === "XOR" ? "xor" : opName === "NAND" ? "nand" : opName === "NOR" ? "nor" : "xnor";
|
|
5250
|
+
left = { type, left, right };
|
|
5251
|
+
}
|
|
5252
|
+
return left;
|
|
5253
|
+
}
|
|
5254
|
+
const ast = parseExpr(0);
|
|
5255
|
+
if (idx < tokens.length) {
|
|
5256
|
+
throw new Error("[BooleanAlgebra] Unexpected trailing tokens");
|
|
5257
|
+
}
|
|
5258
|
+
return ast;
|
|
5259
|
+
}
|
|
5260
|
+
function evalAst(ast, env) {
|
|
5261
|
+
switch (ast.type) {
|
|
5262
|
+
case "const":
|
|
5263
|
+
return Boolean(ast.value);
|
|
5264
|
+
case "var": {
|
|
5265
|
+
const v = (env == null ? void 0 : env[ast.name]) ?? false;
|
|
5266
|
+
return toBool(v);
|
|
5267
|
+
}
|
|
5268
|
+
case "not":
|
|
5269
|
+
return !evalAst(ast.left, env);
|
|
5270
|
+
case "and":
|
|
5271
|
+
return evalAst(ast.left, env) && evalAst(ast.right, env);
|
|
5272
|
+
case "nand":
|
|
5273
|
+
return !(evalAst(ast.left, env) && evalAst(ast.right, env));
|
|
5274
|
+
case "or":
|
|
5275
|
+
return evalAst(ast.left, env) || evalAst(ast.right, env);
|
|
5276
|
+
case "nor":
|
|
5277
|
+
return !(evalAst(ast.left, env) || evalAst(ast.right, env));
|
|
5278
|
+
case "xor": {
|
|
5279
|
+
const a = evalAst(ast.left, env);
|
|
5280
|
+
const b = evalAst(ast.right, env);
|
|
5281
|
+
return a && !b || !a && b;
|
|
5282
|
+
}
|
|
5283
|
+
case "xnor": {
|
|
5284
|
+
const a = evalAst(ast.left, env);
|
|
5285
|
+
const b = evalAst(ast.right, env);
|
|
5286
|
+
return a === b;
|
|
5287
|
+
}
|
|
5288
|
+
default:
|
|
5289
|
+
throw new Error(`[BooleanAlgebra] Unknown AST node type "${ast.type}"`);
|
|
5290
|
+
}
|
|
5291
|
+
}
|
|
5292
|
+
function collectVars(ast, out) {
|
|
5293
|
+
if (!ast) return;
|
|
5294
|
+
if (ast.type === "var" && ast.name) out.add(ast.name);
|
|
5295
|
+
if (ast.left) collectVars(ast.left, out);
|
|
5296
|
+
if (ast.right) collectVars(ast.right, out);
|
|
5297
|
+
}
|
|
5298
|
+
function grayOrder(n) {
|
|
5299
|
+
const size = 1 << n;
|
|
5300
|
+
const out = new Array(size);
|
|
5301
|
+
for (let i = 0; i < size; i++) {
|
|
5302
|
+
out[i] = i ^ i >> 1;
|
|
5303
|
+
}
|
|
5304
|
+
return out;
|
|
5305
|
+
}
|
|
5306
|
+
class BooleanAlgebra {
|
|
5307
|
+
/**
|
|
5308
|
+
* Basic gates.
|
|
5309
|
+
* @param {boolean|number} a
|
|
5310
|
+
* @param {boolean|number} b
|
|
5311
|
+
* @returns {boolean}
|
|
5312
|
+
*/
|
|
5313
|
+
static and(a, b) {
|
|
5314
|
+
return toBool(a) && toBool(b);
|
|
5315
|
+
}
|
|
5316
|
+
/**
|
|
5317
|
+
* @param {boolean|number} a
|
|
5318
|
+
* @param {boolean|number} b
|
|
5319
|
+
* @returns {boolean}
|
|
5320
|
+
*/
|
|
5321
|
+
static nand(a, b) {
|
|
5322
|
+
return !(toBool(a) && toBool(b));
|
|
5323
|
+
}
|
|
5324
|
+
/**
|
|
5325
|
+
* @param {boolean|number} a
|
|
5326
|
+
* @param {boolean|number} b
|
|
5327
|
+
* @returns {boolean}
|
|
5328
|
+
*/
|
|
5329
|
+
static or(a, b) {
|
|
5330
|
+
return toBool(a) || toBool(b);
|
|
5331
|
+
}
|
|
5332
|
+
/**
|
|
5333
|
+
* @param {boolean|number} a
|
|
5334
|
+
* @param {boolean|number} b
|
|
5335
|
+
* @returns {boolean}
|
|
5336
|
+
*/
|
|
5337
|
+
static nor(a, b) {
|
|
5338
|
+
return !(toBool(a) || toBool(b));
|
|
5339
|
+
}
|
|
5340
|
+
/**
|
|
5341
|
+
* @param {boolean|number} a
|
|
5342
|
+
* @param {boolean|number} b
|
|
5343
|
+
* @returns {boolean}
|
|
5344
|
+
*/
|
|
5345
|
+
static xor(a, b) {
|
|
5346
|
+
const aa = toBool(a);
|
|
5347
|
+
const bb = toBool(b);
|
|
5348
|
+
return aa && !bb || !aa && bb;
|
|
5349
|
+
}
|
|
5350
|
+
/**
|
|
5351
|
+
* @param {boolean|number} a
|
|
5352
|
+
* @param {boolean|number} b
|
|
5353
|
+
* @returns {boolean}
|
|
5354
|
+
*/
|
|
5355
|
+
static xnor(a, b) {
|
|
5356
|
+
return toBool(a) === toBool(b);
|
|
5357
|
+
}
|
|
5358
|
+
/**
|
|
5359
|
+
* @param {boolean|number} a
|
|
5360
|
+
* @returns {boolean}
|
|
5361
|
+
*/
|
|
5362
|
+
static not(a) {
|
|
5363
|
+
return !toBool(a);
|
|
5364
|
+
}
|
|
5365
|
+
/**
|
|
5366
|
+
* Parse an expression string into an AST.
|
|
5367
|
+
*
|
|
5368
|
+
* Supported operators:
|
|
5369
|
+
* - NOT: `!`, `~`, `¬`, `NOT`
|
|
5370
|
+
* - AND: `&`, `∧`, `AND`
|
|
5371
|
+
* - OR: `|`, `∨`, `OR`
|
|
5372
|
+
* - XOR: `^`, `⊕`, `XOR`
|
|
5373
|
+
* - NAND/NOR/XNOR as words (case-insensitive)
|
|
5374
|
+
*
|
|
5375
|
+
* Constants: `0/1`, `false/true` (case-insensitive)
|
|
5376
|
+
*
|
|
5377
|
+
* @param {string} expr
|
|
5378
|
+
* @returns {BooleanAst}
|
|
5379
|
+
*/
|
|
5380
|
+
static parse(expr) {
|
|
5381
|
+
return parseTokens(tokenize(expr));
|
|
5382
|
+
}
|
|
5383
|
+
/**
|
|
5384
|
+
* Evaluate an expression string or AST against an environment.
|
|
5385
|
+
* @param {string|BooleanAst} expr
|
|
5386
|
+
* @param {BooleanEnv} env
|
|
5387
|
+
* @returns {boolean}
|
|
5388
|
+
*/
|
|
5389
|
+
static evaluate(expr, env = {}) {
|
|
5390
|
+
const ast = typeof expr === "string" ? BooleanAlgebra.parse(expr) : expr;
|
|
5391
|
+
return evalAst(ast, env);
|
|
5392
|
+
}
|
|
5393
|
+
/**
|
|
5394
|
+
* Get sorted variable names used by an expression.
|
|
5395
|
+
* @param {string|BooleanAst} expr
|
|
5396
|
+
* @returns {string[]}
|
|
5397
|
+
*/
|
|
5398
|
+
static variables(expr) {
|
|
5399
|
+
const ast = typeof expr === "string" ? BooleanAlgebra.parse(expr) : expr;
|
|
5400
|
+
const vars = /* @__PURE__ */ new Set();
|
|
5401
|
+
collectVars(ast, vars);
|
|
5402
|
+
return [...vars].sort((a, b) => a.localeCompare(b));
|
|
5403
|
+
}
|
|
5404
|
+
/**
|
|
5405
|
+
* Gray-code ordering for n bits.
|
|
5406
|
+
* @param {number} n
|
|
5407
|
+
* @returns {number[]}
|
|
5408
|
+
*/
|
|
5409
|
+
static grayCode(n) {
|
|
5410
|
+
return grayOrder(n);
|
|
5411
|
+
}
|
|
5412
|
+
/**
|
|
5413
|
+
* Build a truth table for an expression.
|
|
5414
|
+
* @param {string|BooleanAst} expr
|
|
5415
|
+
* @param {string[]} [variables] - Optional variable ordering. If omitted, derived from expression.
|
|
5416
|
+
* @param {{ order?: "binary"|"gray" }} [options]
|
|
5417
|
+
* @returns {{
|
|
5418
|
+
* variables: string[],
|
|
5419
|
+
* order: "binary"|"gray",
|
|
5420
|
+
* rows: Array<{ index: number, inputs: Record<string, boolean>, output: boolean }>
|
|
5421
|
+
* }}
|
|
5422
|
+
*/
|
|
5423
|
+
static truthTable(expr, variables, options = {}) {
|
|
5424
|
+
const ast = typeof expr === "string" ? BooleanAlgebra.parse(expr) : expr;
|
|
5425
|
+
const vars = variables && variables.length > 0 ? [...variables] : BooleanAlgebra.variables(ast);
|
|
5426
|
+
const n = vars.length;
|
|
5427
|
+
const size = 1 << n;
|
|
5428
|
+
const order = options.order === "gray" ? "gray" : "binary";
|
|
5429
|
+
const indices = order === "gray" ? grayOrder(n) : Array.from({ length: size }, (_, i) => i);
|
|
5430
|
+
const rows = indices.map((idx) => {
|
|
5431
|
+
const inputs = {};
|
|
5432
|
+
for (let bit = 0; bit < n; bit++) {
|
|
5433
|
+
const mask = 1 << n - 1 - bit;
|
|
5434
|
+
inputs[vars[bit]] = Boolean(idx & mask);
|
|
5435
|
+
}
|
|
5436
|
+
return {
|
|
5437
|
+
index: idx,
|
|
5438
|
+
inputs,
|
|
5439
|
+
output: evalAst(ast, inputs)
|
|
5440
|
+
};
|
|
5441
|
+
});
|
|
5442
|
+
return { variables: vars, order, rows };
|
|
5443
|
+
}
|
|
5444
|
+
}
|
|
5114
5445
|
function flammEmbedding(r, rHorizon, M) {
|
|
5115
5446
|
if (r <= rHorizon) return 0;
|
|
5116
5447
|
return Math.sqrt(8 * M * (r - rHorizon));
|
|
@@ -16579,6 +16910,190 @@ class Sprite extends GameObject {
|
|
|
16579
16910
|
return `[Sprite frames=${this.totalFrames} current=${this.currentFrame} playing=${this.isPlaying}]`;
|
|
16580
16911
|
}
|
|
16581
16912
|
}
|
|
16913
|
+
class SpriteSheet extends Sprite {
|
|
16914
|
+
/**
|
|
16915
|
+
* Creates a new SpriteSheet
|
|
16916
|
+
* @param {Game} game - The game instance
|
|
16917
|
+
* @param {Object} options - Configuration options
|
|
16918
|
+
* @param {string} options.src - URL/path to the spritesheet image
|
|
16919
|
+
* @param {number} options.frameWidth - Width of each frame in pixels
|
|
16920
|
+
* @param {number} options.frameHeight - Height of each frame in pixels
|
|
16921
|
+
* @param {number} options.columns - Number of columns in the spritesheet
|
|
16922
|
+
* @param {number} options.rows - Number of rows in the spritesheet
|
|
16923
|
+
* @param {number} [options.frameCount] - Total frames (defaults to columns * rows)
|
|
16924
|
+
* @param {number} [options.startFrame=0] - First frame index to use
|
|
16925
|
+
* @param {number} [options.frameRate=12] - Frames per second
|
|
16926
|
+
* @param {boolean} [options.loop=true] - Whether to loop the animation
|
|
16927
|
+
* @param {boolean} [options.autoPlay=false] - Whether to start playing automatically
|
|
16928
|
+
* @param {boolean} [options.smoothing=false] - Image smoothing (false for pixel art)
|
|
16929
|
+
*/
|
|
16930
|
+
constructor(game, options = {}) {
|
|
16931
|
+
super(game, {
|
|
16932
|
+
frameRate: options.frameRate || 12,
|
|
16933
|
+
loop: options.loop !== void 0 ? options.loop : true,
|
|
16934
|
+
autoPlay: false,
|
|
16935
|
+
// Don't autoplay until loaded
|
|
16936
|
+
...options
|
|
16937
|
+
});
|
|
16938
|
+
this._src = options.src;
|
|
16939
|
+
this._frameWidth = options.frameWidth;
|
|
16940
|
+
this._frameHeight = options.frameHeight;
|
|
16941
|
+
this._columns = options.columns;
|
|
16942
|
+
this._rows = options.rows;
|
|
16943
|
+
this._frameCount = options.frameCount || options.columns * options.rows;
|
|
16944
|
+
this._startFrame = options.startFrame || 0;
|
|
16945
|
+
this._smoothing = options.smoothing !== void 0 ? options.smoothing : false;
|
|
16946
|
+
this._autoPlayAfterLoad = options.autoPlay || false;
|
|
16947
|
+
this._loaded = false;
|
|
16948
|
+
this._loading = false;
|
|
16949
|
+
this._image = null;
|
|
16950
|
+
this._frameCanvases = [];
|
|
16951
|
+
this.width = this._frameWidth;
|
|
16952
|
+
this.height = this._frameHeight;
|
|
16953
|
+
}
|
|
16954
|
+
/**
|
|
16955
|
+
* Static factory method that creates and loads a SpriteSheet
|
|
16956
|
+
* @param {Game} game - The game instance
|
|
16957
|
+
* @param {Object} options - Configuration options (same as constructor)
|
|
16958
|
+
* @returns {Promise<SpriteSheet>} Loaded SpriteSheet instance
|
|
16959
|
+
*/
|
|
16960
|
+
static async create(game, options) {
|
|
16961
|
+
const sheet = new SpriteSheet(game, options);
|
|
16962
|
+
await sheet.load();
|
|
16963
|
+
return sheet;
|
|
16964
|
+
}
|
|
16965
|
+
/**
|
|
16966
|
+
* Loads the spritesheet image and creates frame shapes
|
|
16967
|
+
* @returns {Promise<SpriteSheet>} This instance for chaining
|
|
16968
|
+
*/
|
|
16969
|
+
async load() {
|
|
16970
|
+
if (this._loaded || this._loading) {
|
|
16971
|
+
return this;
|
|
16972
|
+
}
|
|
16973
|
+
this._loading = true;
|
|
16974
|
+
try {
|
|
16975
|
+
this._image = await this._loadImage(this._src);
|
|
16976
|
+
await this._sliceFrames();
|
|
16977
|
+
this._loaded = true;
|
|
16978
|
+
this._loading = false;
|
|
16979
|
+
if (this._autoPlayAfterLoad) {
|
|
16980
|
+
this.play();
|
|
16981
|
+
}
|
|
16982
|
+
return this;
|
|
16983
|
+
} catch (error) {
|
|
16984
|
+
this._loading = false;
|
|
16985
|
+
console.error("SpriteSheet.load failed:", error);
|
|
16986
|
+
throw error;
|
|
16987
|
+
}
|
|
16988
|
+
}
|
|
16989
|
+
/**
|
|
16990
|
+
* Loads an image from a URL
|
|
16991
|
+
* @private
|
|
16992
|
+
* @param {string} src - Image URL
|
|
16993
|
+
* @returns {Promise<HTMLImageElement>}
|
|
16994
|
+
*/
|
|
16995
|
+
_loadImage(src) {
|
|
16996
|
+
return new Promise((resolve, reject) => {
|
|
16997
|
+
const img = new Image();
|
|
16998
|
+
img.onload = () => resolve(img);
|
|
16999
|
+
img.onerror = (e) => reject(new Error(`Failed to load image: ${src}`));
|
|
17000
|
+
img.src = src;
|
|
17001
|
+
});
|
|
17002
|
+
}
|
|
17003
|
+
/**
|
|
17004
|
+
* Slices the spritesheet into individual frame canvases
|
|
17005
|
+
* @private
|
|
17006
|
+
*/
|
|
17007
|
+
async _sliceFrames() {
|
|
17008
|
+
const { _image: img, _frameWidth: fw, _frameHeight: fh, _columns: cols } = this;
|
|
17009
|
+
this.clearFrames();
|
|
17010
|
+
this._frameCanvases = [];
|
|
17011
|
+
for (let i = this._startFrame; i < this._startFrame + this._frameCount; i++) {
|
|
17012
|
+
const col = i % cols;
|
|
17013
|
+
const row = Math.floor(i / cols);
|
|
17014
|
+
const sx = col * fw;
|
|
17015
|
+
const sy = row * fh;
|
|
17016
|
+
const frameCanvas = document.createElement("canvas");
|
|
17017
|
+
frameCanvas.width = fw;
|
|
17018
|
+
frameCanvas.height = fh;
|
|
17019
|
+
const ctx = frameCanvas.getContext("2d");
|
|
17020
|
+
ctx.imageSmoothingEnabled = this._smoothing;
|
|
17021
|
+
ctx.drawImage(img, sx, sy, fw, fh, 0, 0, fw, fh);
|
|
17022
|
+
this._frameCanvases.push(frameCanvas);
|
|
17023
|
+
const frameShape = new ImageShape(frameCanvas, {
|
|
17024
|
+
width: fw,
|
|
17025
|
+
height: fh,
|
|
17026
|
+
anchor: "center",
|
|
17027
|
+
smoothing: this._smoothing
|
|
17028
|
+
});
|
|
17029
|
+
this.addFrame(frameShape);
|
|
17030
|
+
}
|
|
17031
|
+
}
|
|
17032
|
+
/**
|
|
17033
|
+
* Gets whether the spritesheet is loaded
|
|
17034
|
+
* @returns {boolean}
|
|
17035
|
+
*/
|
|
17036
|
+
get loaded() {
|
|
17037
|
+
return this._loaded;
|
|
17038
|
+
}
|
|
17039
|
+
/**
|
|
17040
|
+
* Gets whether the spritesheet is currently loading
|
|
17041
|
+
* @returns {boolean}
|
|
17042
|
+
*/
|
|
17043
|
+
get loading() {
|
|
17044
|
+
return this._loading;
|
|
17045
|
+
}
|
|
17046
|
+
/**
|
|
17047
|
+
* Gets the frame width
|
|
17048
|
+
* @returns {number}
|
|
17049
|
+
*/
|
|
17050
|
+
get frameWidth() {
|
|
17051
|
+
return this._frameWidth;
|
|
17052
|
+
}
|
|
17053
|
+
/**
|
|
17054
|
+
* Gets the frame height
|
|
17055
|
+
* @returns {number}
|
|
17056
|
+
*/
|
|
17057
|
+
get frameHeight() {
|
|
17058
|
+
return this._frameHeight;
|
|
17059
|
+
}
|
|
17060
|
+
/**
|
|
17061
|
+
* Gets the number of columns in the spritesheet
|
|
17062
|
+
* @returns {number}
|
|
17063
|
+
*/
|
|
17064
|
+
get columns() {
|
|
17065
|
+
return this._columns;
|
|
17066
|
+
}
|
|
17067
|
+
/**
|
|
17068
|
+
* Gets the number of rows in the spritesheet
|
|
17069
|
+
* @returns {number}
|
|
17070
|
+
*/
|
|
17071
|
+
get rows() {
|
|
17072
|
+
return this._rows;
|
|
17073
|
+
}
|
|
17074
|
+
/**
|
|
17075
|
+
* Override update to skip if not loaded
|
|
17076
|
+
* @param {number} dt - Delta time
|
|
17077
|
+
*/
|
|
17078
|
+
update(dt) {
|
|
17079
|
+
if (!this._loaded) return;
|
|
17080
|
+
super.update(dt);
|
|
17081
|
+
}
|
|
17082
|
+
/**
|
|
17083
|
+
* Override draw to skip if not loaded
|
|
17084
|
+
*/
|
|
17085
|
+
draw() {
|
|
17086
|
+
if (!this._loaded) return;
|
|
17087
|
+
super.draw();
|
|
17088
|
+
}
|
|
17089
|
+
/**
|
|
17090
|
+
* Creates a string representation
|
|
17091
|
+
* @returns {string}
|
|
17092
|
+
*/
|
|
17093
|
+
toString() {
|
|
17094
|
+
return `[SpriteSheet src="${this._src}" frames=${this._frameCount} loaded=${this._loaded}]`;
|
|
17095
|
+
}
|
|
17096
|
+
}
|
|
16582
17097
|
class Text extends GameObjectShapeWrapper {
|
|
16583
17098
|
/**
|
|
16584
17099
|
* Create a Text component
|
|
@@ -25473,6 +25988,7 @@ export {
|
|
|
25473
25988
|
Arc,
|
|
25474
25989
|
Arrow,
|
|
25475
25990
|
BezierShape,
|
|
25991
|
+
BooleanAlgebra,
|
|
25476
25992
|
Button,
|
|
25477
25993
|
Camera2D,
|
|
25478
25994
|
Camera3D,
|
|
@@ -25559,6 +26075,7 @@ export {
|
|
|
25559
26075
|
Sphere,
|
|
25560
26076
|
Sphere3D,
|
|
25561
26077
|
Sprite,
|
|
26078
|
+
SpriteSheet,
|
|
25562
26079
|
Square,
|
|
25563
26080
|
Star,
|
|
25564
26081
|
StateMachine,
|