pre-mortem 0.1.5 → 0.1.7
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/pre-mortem.gif +0 -0
- package/dist/pre-mortem.mjs +45 -46
- package/dist/pre-mortem.umd.js +8 -8
- package/package.json +6 -1
- package/index.html +0 -39
- package/public/control-freak.png +0 -0
- package/public/logo.png +0 -0
- package/public/pre-mortem-icon.png +0 -0
- package/public/pre-mortem.gif +0 -0
- package/public/pre-mortem.mp4 +0 -0
- package/public/prima-donna.png +0 -0
- package/public/quet-quitter.png +0 -0
- package/public/slack-spammer.png +0 -0
- package/public/slacker.png +0 -0
- package/src/blocks.ts +0 -182
- package/src/game.ts +0 -366
- package/src/gamestate.ts +0 -176
- package/src/index.ts +0 -30
- package/src/ui.ts +0 -634
- package/tsconfig.json +0 -21
- package/vite.config.ts +0 -20
package/dist/pre-mortem.gif
CHANGED
|
Binary file
|
package/dist/pre-mortem.mjs
CHANGED
|
@@ -2,7 +2,7 @@ var m = Object.defineProperty;
|
|
|
2
2
|
var b = (r, t, e) => t in r ? m(r, t, { enumerable: !0, configurable: !0, writable: !0, value: e }) : r[t] = e;
|
|
3
3
|
var l = (r, t, e) => b(r, typeof t != "symbol" ? t + "" : t, e);
|
|
4
4
|
import c from "matter-js";
|
|
5
|
-
var
|
|
5
|
+
var g = /* @__PURE__ */ ((r) => (r.BOOTSTRAP = "bootstrap", r.VC = "vc", r.SLACKER = "slacker", r.CONTROL_FREAK = "control_freak", r.PRIMA_DONNA = "prima_donna", r.QUIET_QUITTER = "quiet_quitter", r.SLACK_SPAMMER = "slack_spammer", r))(g || {});
|
|
6
6
|
const p = {
|
|
7
7
|
bootstrap: {
|
|
8
8
|
w: 132,
|
|
@@ -168,30 +168,29 @@ const p = {
|
|
|
168
168
|
label: s
|
|
169
169
|
};
|
|
170
170
|
if (e === "vc") {
|
|
171
|
-
const n = i.w,
|
|
172
|
-
{ x: 0 + a, y:
|
|
171
|
+
const n = i.w, u = i.h, h = Math.random() * 15, d = Math.random() * 15, a = (Math.random() - 0.5) * 20, f = [
|
|
172
|
+
{ x: 0 + a, y: h },
|
|
173
173
|
// TL
|
|
174
|
-
{ x: n + a, y:
|
|
174
|
+
{ x: n + a, y: d },
|
|
175
175
|
// TR
|
|
176
|
-
{ x: n, y:
|
|
176
|
+
{ x: n, y: u },
|
|
177
177
|
// BR
|
|
178
|
-
{ x: 0, y:
|
|
178
|
+
{ x: 0, y: u }
|
|
179
179
|
// BL
|
|
180
180
|
];
|
|
181
181
|
return c.Bodies.fromVertices(r, t, [f], o);
|
|
182
182
|
} else if (e === "slacker" || e === "control_freak" || e === "prima_donna" || e === "quiet_quitter" || e === "slack_spammer") {
|
|
183
|
-
const
|
|
183
|
+
const n = "https://raw.githubusercontent.com/Booby-Boobs/pre-mortem/main/public/", u = {
|
|
184
|
+
slacker: `${n}slacker.png`,
|
|
185
|
+
control_freak: `${n}control-freak.png`,
|
|
186
|
+
prima_donna: `${n}prima-donna.png`,
|
|
187
|
+
quiet_quitter: `${n}quet-quitter.png`,
|
|
188
|
+
slack_spammer: `${n}slack-spammer.png`
|
|
189
|
+
}, h = {
|
|
184
190
|
...o,
|
|
185
191
|
render: {
|
|
186
192
|
sprite: {
|
|
187
|
-
texture:
|
|
188
|
-
slacker: "./slacker.png",
|
|
189
|
-
control_freak: "./control-freak.png",
|
|
190
|
-
prima_donna: "./prima-donna.png",
|
|
191
|
-
quiet_quitter: "./quet-quitter.png",
|
|
192
|
-
// User typo kept
|
|
193
|
-
slack_spammer: "./slack-spammer.png"
|
|
194
|
-
}[e],
|
|
193
|
+
texture: u[e],
|
|
195
194
|
xScale: i.w / 512 * 2,
|
|
196
195
|
// Approximate
|
|
197
196
|
yScale: i.h / 512 * 2
|
|
@@ -200,7 +199,7 @@ const p = {
|
|
|
200
199
|
strokeStyle: "#ffffff"
|
|
201
200
|
}
|
|
202
201
|
};
|
|
203
|
-
return e === "quiet_quitter" ? c.Bodies.circle(r, t, i.w / 2,
|
|
202
|
+
return e === "quiet_quitter" ? c.Bodies.circle(r, t, i.w / 2, h) : e === "control_freak" ? c.Bodies.trapezoid(r, t, i.w, i.h, 0.5, h) : e === "prima_donna" ? c.Bodies.polygon(r, t, 5, i.w / 2, h) : e === "slack_spammer" ? c.Bodies.polygon(r, t, 6, i.w / 2, h) : c.Bodies.rectangle(r, t, i.w, i.h, h);
|
|
204
203
|
} else
|
|
205
204
|
return c.Bodies.rectangle(r, t, i.w, i.h, o);
|
|
206
205
|
};
|
|
@@ -358,9 +357,9 @@ class w {
|
|
|
358
357
|
}
|
|
359
358
|
initRenderLoop() {
|
|
360
359
|
c.Events.on(this.render, "afterRender", () => {
|
|
361
|
-
const t = this.render.context, e = this.width / 2, i = 400, s = 700, o = 100, n = { x: e - i / 2, y: o, w: i, h: this.height - o },
|
|
360
|
+
const t = this.render.context, e = this.width / 2, i = 400, s = 700, o = 100, n = { x: e - i / 2, y: o, w: i, h: this.height - o }, u = { x: e - s / 2, y: o - 50, w: s, h: this.height - o + 100 };
|
|
362
361
|
if (t.beginPath(), t.setLineDash([10, 10]), t.lineWidth = 2, t.strokeStyle = "rgba(255, 255, 255, 0.3)", t.strokeRect(n.x, n.y, n.w, n.h), t.font = '10px "Inter", sans-serif', t.fillStyle = "rgba(255, 255, 255, 0.3)", t.textAlign = "center", t.fillText("ACCURATE VALUATION ZONE", e, n.y - 15), !this.currentQuote) {
|
|
363
|
-
const
|
|
362
|
+
const d = [
|
|
364
363
|
{ text: `WE ARE A
|
|
365
364
|
FAMILY`, author: "- CEO" },
|
|
366
365
|
{ text: `CHANGE THE
|
|
@@ -380,15 +379,15 @@ GROWTH`, author: "- Investor" },
|
|
|
380
379
|
{ text: `PIVOT
|
|
381
380
|
TO AI`, author: "- Board" }
|
|
382
381
|
];
|
|
383
|
-
this.currentQuote =
|
|
382
|
+
this.currentQuote = d[Math.floor(Math.random() * d.length)];
|
|
384
383
|
}
|
|
385
384
|
t.save(), t.translate(e, n.y + n.h / 3), t.rotate(-Math.PI / 12), t.textAlign = "center", t.textBaseline = "middle", t.font = '900 48px "Inter", sans-serif', t.fillStyle = "rgba(255, 255, 255, 0.05)";
|
|
386
|
-
const
|
|
385
|
+
const h = this.currentQuote.text.split(`
|
|
387
386
|
`);
|
|
388
|
-
|
|
389
|
-
if (!
|
|
390
|
-
const a =
|
|
391
|
-
t.save(), t.translate(
|
|
387
|
+
h.forEach((d, a) => t.fillText(d, 0, a * 50)), t.font = 'italic 700 24px "Inter", sans-serif', t.fillStyle = "rgba(255, 255, 255, 0.04)", t.fillText(this.currentQuote.author, 0, h.length * 50 + 10), t.restore(), t.beginPath(), t.setLineDash([]), t.lineWidth = 1, t.strokeStyle = "rgba(255, 50, 50, 0.2)", t.strokeRect(u.x, u.y, u.w, u.h), t.font = 'bold 13px "Inter", sans-serif', t.textAlign = "center", t.textBaseline = "middle", t.fillStyle = "#FFFFFF", this.engine.world.bodies.forEach((d) => {
|
|
388
|
+
if (!d.label || d.label.includes("Body") || d.isStatic) return;
|
|
389
|
+
const a = d.gameData, f = a && a.vested;
|
|
390
|
+
t.save(), t.translate(d.position.x, d.position.y), t.rotate(d.angle), f ? (t.shadowColor = "#00ff7f", t.shadowBlur = 10, t.fillStyle = "#00ff7f", t.fillText(d.label + " ✓", 0, 0)) : (t.shadowColor = "black", t.shadowBlur = 4, t.fillStyle = "#FFFFFF", t.fillText(d.label, 0, 0)), t.restore();
|
|
392
391
|
});
|
|
393
392
|
});
|
|
394
393
|
}
|
|
@@ -403,13 +402,13 @@ TO AI`, author: "- Board" }
|
|
|
403
402
|
const n = o.gameData;
|
|
404
403
|
if (Math.abs(o.position.x - e) > s / 2 || o.position.y > this.height + 50) {
|
|
405
404
|
c.Composite.remove(this.engine.world, o);
|
|
406
|
-
const
|
|
407
|
-
this.gameState.penalty(5e4,
|
|
405
|
+
const h = ["VC Scolding!", "Server Outage!", "GDPR Violation!", "TechCrunch Hit Piece!", "IP Lawsuit!"];
|
|
406
|
+
this.gameState.penalty(5e4, h[Math.floor(Math.random() * h.length)]);
|
|
408
407
|
return;
|
|
409
408
|
}
|
|
410
409
|
if (n && !n.vested) {
|
|
411
|
-
const
|
|
412
|
-
|
|
410
|
+
const h = o.speed < 0.15 && Math.abs(o.angularVelocity) < 0.05, d = Math.abs(o.position.x - e) < i / 2;
|
|
411
|
+
h && d ? (n.vestTimer += this.runner.delta, n.vestTimer > 1e3 && (n.vested = !0, this.gameState.addValuation(n.value))) : n.vestTimer = 0;
|
|
413
412
|
}
|
|
414
413
|
});
|
|
415
414
|
});
|
|
@@ -433,9 +432,9 @@ TO AI`, author: "- Board" }
|
|
|
433
432
|
break;
|
|
434
433
|
case 2:
|
|
435
434
|
(s = this.onCrisis) == null || s.call(this, "LEGACY DEPRECATION", "CTO: 'Deprecating v1 API!' (Ghost Blocks)");
|
|
436
|
-
const
|
|
437
|
-
if (
|
|
438
|
-
const a =
|
|
435
|
+
const u = this.engine.world.bodies.filter((a) => !a.isStatic);
|
|
436
|
+
if (u.length > 3) {
|
|
437
|
+
const a = u[Math.floor(Math.random() * u.length)];
|
|
439
438
|
a.isSensor = !0, setTimeout(() => {
|
|
440
439
|
a.isSensor = !1;
|
|
441
440
|
}, 4e3);
|
|
@@ -448,11 +447,11 @@ TO AI`, author: "- Board" }
|
|
|
448
447
|
break;
|
|
449
448
|
case 4:
|
|
450
449
|
(n = this.onCrisis) == null || n.call(this, "VIRAL SPIKE", "DevOps: 'Traffic Spike!' (Earthquake)");
|
|
451
|
-
let
|
|
452
|
-
const
|
|
450
|
+
let h = 0;
|
|
451
|
+
const d = setInterval(() => {
|
|
453
452
|
this.engine.world.bodies.forEach((a) => {
|
|
454
453
|
a.isStatic || c.Body.applyForce(a, a.position, { x: (Math.random() - 0.5) * 0.05, y: (Math.random() - 0.5) * 0.05 });
|
|
455
|
-
}), ++
|
|
454
|
+
}), ++h > 20 && clearInterval(d);
|
|
456
455
|
}, 100);
|
|
457
456
|
break;
|
|
458
457
|
}
|
|
@@ -463,15 +462,15 @@ TO AI`, author: "- Board" }
|
|
|
463
462
|
spawnBlock(t) {
|
|
464
463
|
if (!this.gameState.isPlaying()) return;
|
|
465
464
|
if (Math.random() < 1 / 15) {
|
|
466
|
-
const o = [
|
|
465
|
+
const o = [g.SLACKER, g.CONTROL_FREAK, g.PRIMA_DONNA, g.QUIET_QUITTER, g.SLACK_SPAMMER];
|
|
467
466
|
t = o[Math.floor(Math.random() * o.length)];
|
|
468
467
|
}
|
|
469
|
-
t ===
|
|
468
|
+
t === g.BOOTSTRAP ? this.gameState.spendMoney(5e3) : t === g.VC && this.gameState.addMoney(75e3);
|
|
470
469
|
const e = this.width / 2 + (Math.random() - 0.5) * 40, i = y(e, S, t);
|
|
471
470
|
let s = this.spawnVertical ? 90 * (Math.PI / 180) : 0;
|
|
472
|
-
t ===
|
|
471
|
+
t === g.VC && (s += (Math.random() - 0.5) * (30 * (Math.PI / 180))), c.Body.setAngle(i, s), i.gameData = {
|
|
473
472
|
type: t,
|
|
474
|
-
value: t ===
|
|
473
|
+
value: t === g.VC ? 5e7 : t === g.BOOTSTRAP ? 5e6 : 0,
|
|
475
474
|
vested: !1,
|
|
476
475
|
vestTimer: 0
|
|
477
476
|
}, c.Composite.add(this.engine.world, i);
|
|
@@ -694,10 +693,10 @@ class k {
|
|
|
694
693
|
t.className = "uj-controls";
|
|
695
694
|
const e = document.createElement("button");
|
|
696
695
|
e.className = "uj-btn uj-btn-solid", e.innerText = `Build Solid
|
|
697
|
-
(Costs $5k)`, e.onclick = () => this.options.onSpawn(
|
|
696
|
+
(Costs $5k)`, e.onclick = () => this.options.onSpawn(g.BOOTSTRAP);
|
|
698
697
|
const i = document.createElement("button");
|
|
699
698
|
i.className = "uj-btn uj-btn-hype", i.innerText = `Hype Up
|
|
700
|
-
(Grants $75k)`, i.onclick = () => this.options.onSpawn(
|
|
699
|
+
(Grants $75k)`, i.onclick = () => this.options.onSpawn(g.VC), t.appendChild(e), t.appendChild(i), this.container.appendChild(t);
|
|
701
700
|
}
|
|
702
701
|
createSystemButtons() {
|
|
703
702
|
const t = document.createElement("div");
|
|
@@ -864,10 +863,10 @@ class k {
|
|
|
864
863
|
populateGlossaryLists() {
|
|
865
864
|
var i, s;
|
|
866
865
|
const t = document.getElementById("uj-solid-list"), e = document.getElementById("uj-hype-list");
|
|
867
|
-
t && e && ((i = p[
|
|
866
|
+
t && e && ((i = p[g.BOOTSTRAP].possibleLabels) == null || i.forEach((o) => {
|
|
868
867
|
const n = document.createElement("li");
|
|
869
868
|
n.textContent = o, t.appendChild(n);
|
|
870
|
-
}), (s = p[
|
|
869
|
+
}), (s = p[g.VC].possibleLabels) == null || s.forEach((o) => {
|
|
871
870
|
const n = document.createElement("li");
|
|
872
871
|
n.textContent = o, e.appendChild(n);
|
|
873
872
|
}));
|
|
@@ -885,7 +884,7 @@ class k {
|
|
|
885
884
|
currency: "USD",
|
|
886
885
|
notation: "compact",
|
|
887
886
|
maximumFractionDigits: 1
|
|
888
|
-
}), o = t.isBankrupt() ? "uj-stat-value danger" : "uj-stat-value", n = t.getNextStageThreshold(),
|
|
887
|
+
}), o = t.isBankrupt() ? "uj-stat-value danger" : "uj-stat-value", n = t.getNextStageThreshold(), u = n > 0 ? `<small style="font-size:12px; opacity:0.7">Next: ${i.format(n)}</small>` : "";
|
|
889
888
|
this.hudElement.innerHTML = `
|
|
890
889
|
<div class="uj-stat-label">Stage</div>
|
|
891
890
|
<div class="uj-stat-value">${t.stage}</div>
|
|
@@ -893,7 +892,7 @@ class k {
|
|
|
893
892
|
<div class="uj-stat-label">Valuation</div>
|
|
894
893
|
<div class="uj-stat-value" style="color: #00ff7f">
|
|
895
894
|
${e.format(t.valuation)}<br>
|
|
896
|
-
${
|
|
895
|
+
${u}
|
|
897
896
|
</div>
|
|
898
897
|
|
|
899
898
|
<div class="uj-stat-label">Runway</div>
|
|
@@ -981,7 +980,7 @@ class k {
|
|
|
981
980
|
}, 4e3);
|
|
982
981
|
}
|
|
983
982
|
}
|
|
984
|
-
class
|
|
983
|
+
class R {
|
|
985
984
|
constructor(t, e = {}) {
|
|
986
985
|
l(this, "game");
|
|
987
986
|
l(this, "ui");
|
|
@@ -999,7 +998,7 @@ class T {
|
|
|
999
998
|
}
|
|
1000
999
|
}
|
|
1001
1000
|
export {
|
|
1002
|
-
|
|
1001
|
+
R as PreMortem,
|
|
1003
1002
|
w as PreMortemGame,
|
|
1004
1003
|
k as UIManager
|
|
1005
1004
|
};
|
package/dist/pre-mortem.umd.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
(function(
|
|
1
|
+
(function(p,o){typeof exports=="object"&&typeof module<"u"?o(exports,require("matter-js")):typeof define=="function"&&define.amd?define(["exports","matter-js"],o):(p=typeof globalThis<"u"?globalThis:p||self,o(p.PreMortem={},p.Matter))})(this,function(p,o){"use strict";var E=Object.defineProperty;var C=(p,o,d)=>o in p?E(p,o,{enumerable:!0,configurable:!0,writable:!0,value:d}):p[o]=d;var l=(p,o,d)=>C(p,typeof o!="symbol"?o+"":o,d);var d=(c=>(c.BOOTSTRAP="bootstrap",c.VC="vc",c.SLACKER="slacker",c.CONTROL_FREAK="control_freak",c.PRIMA_DONNA="prima_donna",c.QUIET_QUITTER="quiet_quitter",c.SLACK_SPAMMER="slack_spammer",c))(d||{});const f={bootstrap:{w:132,h:44,color:"#555555",density:.005,friction:.8,restitution:0,label:"Refactoring",possibleLabels:["Refactoring","Unit Tests","Bug Fixes","User Support","Documentation","Security Audit","Compliance","Cleanup","Optimization","CI/CD Pipeline","Code Review","DB Tuning","API Design","Accessibility","Localization","Error Logs","Backups","Legacy Code","Hiring","Customer Love","Bossware","YAML Hell","DNS Propagation","Regex","npm audit","GDPR / SOC2","Migration","Certificate Expiry","On-Call","Technical Debt","Works on my machine","Yak Shaving"]},vc:{w:120,h:40,color:"#FF00FF",density:5e-4,friction:.3,restitution:.6,label:"AI Blockchain",possibleLabels:["GenAI","Blockchain","Web3","Metaverse","NFTs","Viral Growth","Pivot","Synergy","Disruption","Thought Leader","Influencers","Hyper-Scale","Quantum","Big Data","Growth Hack","Paradigm Shift","10x Engineer","Visionary","Series B Pitch","Exit Strategy","Vibe Coding","Founder Mode","Prompt Engineering","AGI","AI Wrapper","Unlimited PTO","Radical Candor","Community Led","Pre-Revenue","Fractional CxO"]},slacker:{w:64,h:64,color:"#FFFFFF",density:.01,friction:1,restitution:.1,label:"The Slacker",possibleLabels:["The Slacker"]},control_freak:{w:64,h:64,color:"#FF0000",density:.012,friction:.5,restitution:.2,label:"Control Freak",possibleLabels:["Control Freak"]},prima_donna:{w:56,h:56,color:"#FFFF00",density:.008,friction:.1,restitution:1.2,label:"Prima Donna",possibleLabels:["Prima Donna"]},quiet_quitter:{w:48,h:48,color:"#00FFFF",density:.005,friction:.01,restitution:.9,label:"Quiet Quitter",possibleLabels:["Quiet Quitter"]},slack_spammer:{w:60,h:60,color:"#00FF00",density:.01,friction:.4,restitution:.4,label:"Slack Spammer",possibleLabels:["Slack Spammer"]}},y=c=>{const t=f[c].possibleLabels||[];return t[Math.floor(Math.random()*t.length)]},v=(c,t,e)=>{const i=f[e],s=y(e),a={density:i.density,friction:i.friction,restitution:i.restitution,render:{fillStyle:i.color,strokeStyle:"#000",lineWidth:2},label:s};if(e==="vc"){const n=i.w,g=i.h,u=Math.random()*15,h=Math.random()*15,r=(Math.random()-.5)*20,m=[{x:0+r,y:u},{x:n+r,y:h},{x:n,y:g},{x:0,y:g}];return o.Bodies.fromVertices(c,t,[m],a)}else if(e==="slacker"||e==="control_freak"||e==="prima_donna"||e==="quiet_quitter"||e==="slack_spammer"){const n="https://raw.githubusercontent.com/Booby-Boobs/pre-mortem/main/public/",g={slacker:`${n}slacker.png`,control_freak:`${n}control-freak.png`,prima_donna:`${n}prima-donna.png`,quiet_quitter:`${n}quet-quitter.png`,slack_spammer:`${n}slack-spammer.png`},u={...a,render:{sprite:{texture:g[e],xScale:i.w/512*2,yScale:i.h/512*2},lineWidth:3,strokeStyle:"#ffffff"}};return e==="quiet_quitter"?o.Bodies.circle(c,t,i.w/2,u):e==="control_freak"?o.Bodies.trapezoid(c,t,i.w,i.h,.5,u):e==="prima_donna"?o.Bodies.polygon(c,t,5,i.w/2,u):e==="slack_spammer"?o.Bodies.polygon(c,t,6,i.w/2,u):o.Bodies.rectangle(c,t,i.w,i.h,u)}else return o.Bodies.rectangle(c,t,i.w,i.h,a)};class w{constructor(t){l(this,"runway");l(this,"valuation",0);l(this,"stage");l(this,"status","playing");l(this,"lastPenaltyReason","");l(this,"config");l(this,"currentStageIndex",0);l(this,"listeners",[]);if(this.config=t,this.runway=t.initialRunway,!this.config.stages||this.config.stages.length===0)throw new Error("Game must have at least one stage defined.");this.config.stages.sort((e,i)=>e.threshold-i.threshold),this.currentStageIndex=0,this.stage=this.config.stages[0].name,this.checkStage()}setPaused(t){t?this.status==="playing"&&(this.status="paused"):this.status==="paused"&&(this.status="playing"),this.notify()}togglePause(){this.setPaused(this.status==="playing")}tick(t){if(this.status!=="playing")return;const e=Math.min(t,.1),i=this.getDynamicBurnRate();this.runway-=i*e,this.runway<=0&&(this.runway=0,this.status="bankrupt");const s=this.config.stages[this.config.stages.length-1];this.valuation>=s.threshold&&this.status==="playing"&&(this.status="exited"),this.checkStage(),this.notify()}getDynamicBurnRate(){return this.config.stages[this.currentStageIndex].burnRate}addValuation(t){this.valuation+=t,this.checkStage(),this.notify()}spendMoney(t){this.runway-=t,this.notify()}addMoney(t){this.runway+=t,this.notify()}setCollapsed(){this.status==="playing"&&(this.status="collapsed",this.notify())}getNextStageThreshold(){return this.currentStageIndex<this.config.stages.length-1?this.config.stages[this.currentStageIndex+1].threshold:this.config.stages[this.config.stages.length-1].threshold}penalty(t,e){this.runway-=t,this.lastPenaltyReason=e,this.runway<0&&(this.runway=0,this.status="bankrupt"),this.notify("penalty")}checkStage(){let t=0;for(let e=0;e<this.config.stages.length&&this.valuation>=this.config.stages[e].threshold;e++)t=e;if(t!==this.currentStageIndex){if(t>this.currentStageIndex){const e=this.config.stages[t].fundingBonus||0;e>0&&(this.addMoney(e),this.notify("funding:"+e))}this.currentStageIndex=t,this.stage=this.config.stages[t].name}}subscribe(t){this.listeners.push(t)}notify(t){this.listeners.forEach(e=>e(t))}isPlaying(){return this.status==="playing"}isBankrupt(){return this.status==="bankrupt"}}class b{constructor(t,e={}){l(this,"engine");l(this,"render");l(this,"runner");l(this,"container");l(this,"width");l(this,"height");l(this,"mouseConstraint");l(this,"currentQuote",null);l(this,"chaosTimer",1e4);l(this,"chaosInterval",9e4);l(this,"onCrisis");l(this,"gameState");l(this,"spawnVertical",!1);this.container=t,this.width=e.width||t.clientWidth||800,this.height=e.height||t.clientHeight||600,this.onCrisis=e.onCrisis,this.chaosInterval=e.chaosInterval||9e4,this.chaosTimer=e.chaosInterval?e.chaosInterval:1e4;const i=[{name:"Seed Round",threshold:0,burnRate:2e3},{name:"Series A",threshold:1e8,burnRate:1e4,fundingBonus:25e4},{name:"Series B",threshold:25e7,burnRate:25e3,fundingBonus:5e5},{name:"Series C",threshold:5e8,burnRate:5e4,fundingBonus:1e6},{name:"Series D",threshold:7e8,burnRate:75e3,fundingBonus:2e6},{name:"Series E",threshold:85e7,burnRate:1e5,fundingBonus:5e6},{name:"Unicorn Status",threshold:1e9,burnRate:15e4,fundingBonus:1e7}];this.gameState=new w({initialRunway:e.initialRunway||2e5,stages:e.stages||i}),this.engine=o.Engine.create(),this.render=o.Render.create({element:this.container,engine:this.engine,options:{width:this.width,height:this.height,wireframes:!1,background:"#1a1a1a"}}),this.runner=o.Runner.create(),this.initWorld(),this.initMouse(),this.initRenderLoop(),this.initGameLoop(),this.initControls(),this.gameState.subscribe(()=>{this.gameState.status==="paused"?this.runner.enabled=!1:this.gameState.status==="playing"&&(this.runner.enabled=!0)})}initControls(){window.addEventListener("keydown",t=>{(t.key==="r"||t.key==="R")&&this.gameState.isPlaying()&&this.rotateHeldBody()})}rotateHeldBody(){const t=this.mouseConstraint.body;t&&o.Body.rotate(t,45*(Math.PI/180))}initWorld(){const{width:t,height:e}=this,i=60,s=o.Bodies.rectangle(t/2,e-i/2,t,i,{isStatic:!0,render:{fillStyle:"#333"}});o.Composite.add(this.engine.world,[s])}initMouse(){const t=o.Mouse.create(this.render.canvas);this.mouseConstraint=o.MouseConstraint.create(this.engine,{mouse:t,constraint:{stiffness:.2,render:{visible:!1}}}),o.Composite.add(this.engine.world,this.mouseConstraint),this.render.mouse=t}start(){o.Render.run(this.render),o.Runner.run(this.runner,this.engine)}stop(){o.Render.stop(this.render),o.Runner.stop(this.runner)}initRenderLoop(){o.Events.on(this.render,"afterRender",()=>{const t=this.render.context,e=this.width/2,i=400,s=700,a=100,n={x:e-i/2,y:a,w:i,h:this.height-a},g={x:e-s/2,y:a-50,w:s,h:this.height-a+100};if(t.beginPath(),t.setLineDash([10,10]),t.lineWidth=2,t.strokeStyle="rgba(255, 255, 255, 0.3)",t.strokeRect(n.x,n.y,n.w,n.h),t.font='10px "Inter", sans-serif',t.fillStyle="rgba(255, 255, 255, 0.3)",t.textAlign="center",t.fillText("ACCURATE VALUATION ZONE",e,n.y-15),!this.currentQuote){const h=[{text:`WE ARE A
|
|
2
2
|
FAMILY`,author:"- CEO"},{text:`CHANGE THE
|
|
3
3
|
WORLD`,author:"- Founder"},{text:`DISRUPT
|
|
4
4
|
EVERYTHING`,author:"- VC"},{text:`MOVE FAST
|
|
@@ -7,8 +7,8 @@ CANDOR`,author:"- HR"},{text:`UNLIMITED
|
|
|
7
7
|
PTO`,author:"- Recruiter"},{text:`VISIONARY
|
|
8
8
|
LEADER`,author:"- LinkedIn"},{text:`10X
|
|
9
9
|
GROWTH`,author:"- Investor"},{text:`PIVOT
|
|
10
|
-
TO AI`,author:"- Board"}];this.currentQuote=
|
|
11
|
-
`);
|
|
10
|
+
TO AI`,author:"- Board"}];this.currentQuote=h[Math.floor(Math.random()*h.length)]}t.save(),t.translate(e,n.y+n.h/3),t.rotate(-Math.PI/12),t.textAlign="center",t.textBaseline="middle",t.font='900 48px "Inter", sans-serif',t.fillStyle="rgba(255, 255, 255, 0.05)";const u=this.currentQuote.text.split(`
|
|
11
|
+
`);u.forEach((h,r)=>t.fillText(h,0,r*50)),t.font='italic 700 24px "Inter", sans-serif',t.fillStyle="rgba(255, 255, 255, 0.04)",t.fillText(this.currentQuote.author,0,u.length*50+10),t.restore(),t.beginPath(),t.setLineDash([]),t.lineWidth=1,t.strokeStyle="rgba(255, 50, 50, 0.2)",t.strokeRect(g.x,g.y,g.w,g.h),t.font='bold 13px "Inter", sans-serif',t.textAlign="center",t.textBaseline="middle",t.fillStyle="#FFFFFF",this.engine.world.bodies.forEach(h=>{if(!h.label||h.label.includes("Body")||h.isStatic)return;const r=h.gameData,m=r&&r.vested;t.save(),t.translate(h.position.x,h.position.y),t.rotate(h.angle),m?(t.shadowColor="#00ff7f",t.shadowBlur=10,t.fillStyle="#00ff7f",t.fillText(h.label+" ✓",0,0)):(t.shadowColor="black",t.shadowBlur=4,t.fillStyle="#FFFFFF",t.fillText(h.label,0,0)),t.restore()})})}initGameLoop(){o.Events.on(this.runner,"afterUpdate",()=>{if(!this.gameState.isPlaying())return;const t=this.runner.delta;this.gameState.tick(t/1e3),this.gameState.valuation>=1e6&&(this.chaosTimer-=t,this.chaosTimer<=0&&(this.triggerChaosEvent(),this.chaosTimer=this.chaosInterval));const e=this.width/2,i=400,s=700;this.engine.world.bodies.forEach(a=>{if(a.isStatic)return;const n=a.gameData;if(Math.abs(a.position.x-e)>s/2||a.position.y>this.height+50){o.Composite.remove(this.engine.world,a);const u=["VC Scolding!","Server Outage!","GDPR Violation!","TechCrunch Hit Piece!","IP Lawsuit!"];this.gameState.penalty(5e4,u[Math.floor(Math.random()*u.length)]);return}if(n&&!n.vested){const u=a.speed<.15&&Math.abs(a.angularVelocity)<.05,h=Math.abs(a.position.x-e)<i/2;u&&h?(n.vestTimer+=this.runner.delta,n.vestTimer>1e3&&(n.vested=!0,this.gameState.addValuation(n.value))):n.vestTimer=0}})})}triggerChaosEvent(){var e,i,s,a,n;switch(Math.floor(Math.random()*5)){case 0:(e=this.onCrisis)==null||e.call(this,"STRATEGIC PIVOT","CEO: 'We are pivoting to AI!' (Gravity Shift)"),this.engine.world.gravity.x=.2,setTimeout(()=>{this.engine.world.gravity.x=0},5e3);break;case 1:(i=this.onCrisis)==null||i.call(this,"THE BIG REORG","HR: 'New Org Chart Announced!' (No Friction)"),this.engine.world.bodies.forEach(r=>{r.isStatic||(r.oldFriction=r.friction,r.friction=0,r.frictionStatic=0)}),setTimeout(()=>{this.engine.world.bodies.forEach(r=>{r.isStatic||(r.friction=r.oldFriction||.1,r.frictionStatic=.5)})},5e3);break;case 2:(s=this.onCrisis)==null||s.call(this,"LEGACY DEPRECATION","CTO: 'Deprecating v1 API!' (Ghost Blocks)");const g=this.engine.world.bodies.filter(r=>!r.isStatic);if(g.length>3){const r=g[Math.floor(Math.random()*g.length)];r.isSensor=!0,setTimeout(()=>{r.isSensor=!1},4e3)}break;case 3:(a=this.onCrisis)==null||a.call(this,"FEATURE CREEP","PM: 'Just one more feature...' (1.2x Scaling)"),this.engine.world.bodies.forEach(r=>{r.isStatic||o.Body.scale(r,1.2,1.2)});break;case 4:(n=this.onCrisis)==null||n.call(this,"VIRAL SPIKE","DevOps: 'Traffic Spike!' (Earthquake)");let u=0;const h=setInterval(()=>{this.engine.world.bodies.forEach(r=>{r.isStatic||o.Body.applyForce(r,r.position,{x:(Math.random()-.5)*.05,y:(Math.random()-.5)*.05})}),++u>20&&clearInterval(h)},100);break}}toggleRotation(){this.spawnVertical=!this.spawnVertical}spawnBlock(t){if(!this.gameState.isPlaying())return;if(Math.random()<1/15){const a=[d.SLACKER,d.CONTROL_FREAK,d.PRIMA_DONNA,d.QUIET_QUITTER,d.SLACK_SPAMMER];t=a[Math.floor(Math.random()*a.length)]}t===d.BOOTSTRAP?this.gameState.spendMoney(5e3):t===d.VC&&this.gameState.addMoney(75e3);const e=this.width/2+(Math.random()-.5)*40,i=v(e,S,t);let s=this.spawnVertical?90*(Math.PI/180):0;t===d.VC&&(s+=(Math.random()-.5)*(30*(Math.PI/180))),o.Body.setAngle(i,s),i.gameData={type:t,value:t===d.VC?5e7:t===d.BOOTSTRAP?5e6:0,vested:!1,vestTimer:0},o.Composite.add(this.engine.world,i)}}const S=100;class x{constructor(t,e){l(this,"container");l(this,"options");l(this,"hudElement");this.container=t,this.options=e,this.initStyles(),this.createHUD(),this.createControls(),this.createLegend(),this.createSystemButtons(),this.options.gameState.subscribe(i=>{if(this.updateHUD(),i==="penalty")this.showToast(`-${this.options.gameState.lastPenaltyReason}`,"danger");else if(i!=null&&i.startsWith("funding:")){const s=i.split(":")[1];this.showToast(`+$${parseInt(s).toLocaleString()} Series Funding!`,"info")}}),this.updateHUD()}initStyles(){const t=document.createElement("style");t.textContent=`
|
|
12
12
|
.uj-hud {
|
|
13
13
|
position: absolute;
|
|
14
14
|
top: 20px; /* Restored to top */
|
|
@@ -326,14 +326,14 @@ TO AI`,author:"- Board"}];this.currentQuote=u[Math.floor(Math.random()*u.length)
|
|
|
326
326
|
</div>
|
|
327
327
|
</div>
|
|
328
328
|
</div>
|
|
329
|
-
`,this.container.appendChild(e),this.populateGlossaryLists();const i=()=>{if(e.remove(),t){this.options.gameState.setPaused(!1);const s=document.getElementById("uj-btn-pause");s&&(s.innerText="⏸ PAUSE")}};document.getElementById("uj-glossary-close").onclick=i,e.onclick=s=>{s.target===e&&i()}}populateGlossaryLists(){var i,s;const t=document.getElementById("uj-solid-list"),e=document.getElementById("uj-hype-list");t&&e&&((i=f[d.BOOTSTRAP].possibleLabels)==null||i.forEach(a=>{const
|
|
329
|
+
`,this.container.appendChild(e),this.populateGlossaryLists();const i=()=>{if(e.remove(),t){this.options.gameState.setPaused(!1);const s=document.getElementById("uj-btn-pause");s&&(s.innerText="⏸ PAUSE")}};document.getElementById("uj-glossary-close").onclick=i,e.onclick=s=>{s.target===e&&i()}}populateGlossaryLists(){var i,s;const t=document.getElementById("uj-solid-list"),e=document.getElementById("uj-hype-list");t&&e&&((i=f[d.BOOTSTRAP].possibleLabels)==null||i.forEach(a=>{const n=document.createElement("li");n.textContent=a,t.appendChild(n)}),(s=f[d.VC].possibleLabels)==null||s.forEach(a=>{const n=document.createElement("li");n.textContent=a,e.appendChild(n)}))}createHUD(){this.hudElement=document.createElement("div"),this.hudElement.className="uj-hud",this.container.appendChild(this.hudElement)}updateHUD(){const t=this.options.gameState,e=new Intl.NumberFormat("en-US",{style:"currency",currency:"USD",maximumFractionDigits:0}),i=new Intl.NumberFormat("en-US",{style:"currency",currency:"USD",notation:"compact",maximumFractionDigits:1}),a=t.isBankrupt()?"uj-stat-value danger":"uj-stat-value",n=t.getNextStageThreshold(),g=n>0?`<small style="font-size:12px; opacity:0.7">Next: ${i.format(n)}</small>`:"";this.hudElement.innerHTML=`
|
|
330
330
|
<div class="uj-stat-label">Stage</div>
|
|
331
331
|
<div class="uj-stat-value">${t.stage}</div>
|
|
332
332
|
|
|
333
333
|
<div class="uj-stat-label">Valuation</div>
|
|
334
334
|
<div class="uj-stat-value" style="color: #00ff7f">
|
|
335
335
|
${e.format(t.valuation)}<br>
|
|
336
|
-
${
|
|
336
|
+
${g}
|
|
337
337
|
</div>
|
|
338
338
|
|
|
339
339
|
<div class="uj-stat-label">Runway</div>
|
|
@@ -363,8 +363,8 @@ TO AI`,author:"- Board"}];this.currentQuote=u[Math.floor(Math.random()*u.length)
|
|
|
363
363
|
justify-content: center;
|
|
364
364
|
z-index: 200;
|
|
365
365
|
font-family: 'Inter', sans-serif;
|
|
366
|
-
`;let s="",a="",
|
|
367
|
-
<h1 style="font-size: 48px; color: ${
|
|
366
|
+
`;let s="",a="",n="#fff";switch(t){case"bankrupt":s="HONEST POOR",a="You ran out of runway. The market did not love you.",n="#ff4444";break;case"collapsed":s="SCANDAL!",a="Your tower of lies has collapsed. TechCrunch is mocking you.",n="#ffaa00";break;case"exited":s="VISIONARY FRAUD",a=`You exited with $${(e/1e6).toFixed(1)}M! You are a genius.`,n="#00ff7f";break}i.innerHTML=`
|
|
367
|
+
<h1 style="font-size: 48px; color: ${n}; margin-bottom: 10px;">${s}</h1>
|
|
368
368
|
<p style="font-size: 18px; color #ccc; max-width: 400px; text-align: center;">${a}</p>
|
|
369
369
|
<button onclick="window.location.reload()" style="
|
|
370
370
|
margin-top: 30px;
|
|
@@ -379,4 +379,4 @@ TO AI`,author:"- Board"}];this.currentQuote=u[Math.floor(Math.random()*u.length)
|
|
|
379
379
|
`,this.container.appendChild(i)}showLogo(t){if(!t)return;const e=document.createElement("img");e.src=t,e.className="uj-overlay-logo",this.container.appendChild(e)}showCrisisAlert(t,e){const i=document.createElement("div");i.className="uj-crisis-overlay active";const s=document.createElement("div");s.className="uj-crisis-box",s.innerHTML=`
|
|
380
380
|
<div class="uj-crisis-shout">${t}</div>
|
|
381
381
|
<div class="uj-crisis-desc">${e}</div>
|
|
382
|
-
`,i.appendChild(s),this.container.appendChild(i),setTimeout(()=>s.classList.add("visible"),100),setTimeout(()=>{s.classList.remove("visible"),i.classList.remove("active"),setTimeout(()=>{i.remove()},500)},4e3)}}class k{constructor(t,e={}){l(this,"game");l(this,"ui");this.game=new b(t,{...e,onCrisis:(i,s)=>this.ui.showCrisisAlert(i,s)}),this.ui=new x(t,{onSpawn:i=>this.game.spawnBlock(i),onRotate:()=>this.game.toggleRotation(),gameState:this.game.gameState}),e.logoUrl&&this.ui.showLogo(e.logoUrl)}start(){this.game.start()}}
|
|
382
|
+
`,i.appendChild(s),this.container.appendChild(i),setTimeout(()=>s.classList.add("visible"),100),setTimeout(()=>{s.classList.remove("visible"),i.classList.remove("active"),setTimeout(()=>{i.remove()},500)},4e3)}}class k{constructor(t,e={}){l(this,"game");l(this,"ui");this.game=new b(t,{...e,onCrisis:(i,s)=>this.ui.showCrisisAlert(i,s)}),this.ui=new x(t,{onSpawn:i=>this.game.spawnBlock(i),onRotate:()=>this.game.toggleRotation(),gameState:this.game.gameState}),e.logoUrl&&this.ui.showLogo(e.logoUrl)}start(){this.game.start()}}p.PreMortem=k,p.PreMortemGame=b,p.UIManager=x,Object.defineProperty(p,Symbol.toStringTag,{value:"Module"})});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pre-mortem",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.7",
|
|
4
4
|
"description": "The Exit Simulator: A satirical startup physics game",
|
|
5
5
|
"main": "dist/pre-mortem.umd.js",
|
|
6
6
|
"module": "dist/pre-mortem.mjs",
|
|
@@ -16,6 +16,11 @@
|
|
|
16
16
|
"physics",
|
|
17
17
|
"matter-js"
|
|
18
18
|
],
|
|
19
|
+
"files": [
|
|
20
|
+
"dist",
|
|
21
|
+
"README.md",
|
|
22
|
+
"LICENSE"
|
|
23
|
+
],
|
|
19
24
|
"author": "Boobs",
|
|
20
25
|
"license": "ISC",
|
|
21
26
|
"repository": {
|
package/index.html
DELETED
|
@@ -1,39 +0,0 @@
|
|
|
1
|
-
<!DOCTYPE html>
|
|
2
|
-
<html lang="en">
|
|
3
|
-
<head>
|
|
4
|
-
<meta charset="UTF-8" />
|
|
5
|
-
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
6
|
-
<title>Pre-Mortem - The Exit Simulator</title>
|
|
7
|
-
<style>
|
|
8
|
-
body {
|
|
9
|
-
margin: 0;
|
|
10
|
-
padding: 0;
|
|
11
|
-
background: #000;
|
|
12
|
-
color: #fff;
|
|
13
|
-
font-family: sans-serif;
|
|
14
|
-
overflow: hidden;
|
|
15
|
-
}
|
|
16
|
-
#app {
|
|
17
|
-
width: 100vw;
|
|
18
|
-
height: 100vh;
|
|
19
|
-
position: relative;
|
|
20
|
-
}
|
|
21
|
-
</style>
|
|
22
|
-
</head>
|
|
23
|
-
<body>
|
|
24
|
-
<div id="app"></div>
|
|
25
|
-
<script type="module">
|
|
26
|
-
import { PreMortem } from './src/index.ts';
|
|
27
|
-
|
|
28
|
-
const app = document.getElementById('app');
|
|
29
|
-
// Example Logo: using a placeholder or local asset
|
|
30
|
-
// For demo, we leave it empty or use a placeholder
|
|
31
|
-
const game = new PreMortem(app, {
|
|
32
|
-
logoUrl: './logo.png', // Local logo
|
|
33
|
-
width: window.innerWidth,
|
|
34
|
-
height: window.innerHeight
|
|
35
|
-
});
|
|
36
|
-
game.start();
|
|
37
|
-
</script>
|
|
38
|
-
</body>
|
|
39
|
-
</html>
|
package/public/control-freak.png
DELETED
|
Binary file
|
package/public/logo.png
DELETED
|
Binary file
|
|
Binary file
|
package/public/pre-mortem.gif
DELETED
|
Binary file
|
package/public/pre-mortem.mp4
DELETED
|
Binary file
|
package/public/prima-donna.png
DELETED
|
Binary file
|
package/public/quet-quitter.png
DELETED
|
Binary file
|
package/public/slack-spammer.png
DELETED
|
Binary file
|
package/public/slacker.png
DELETED
|
Binary file
|
package/src/blocks.ts
DELETED
|
@@ -1,182 +0,0 @@
|
|
|
1
|
-
import Matter from 'matter-js';
|
|
2
|
-
|
|
3
|
-
export enum BlockType {
|
|
4
|
-
BOOTSTRAP = 'bootstrap',
|
|
5
|
-
VC = 'vc',
|
|
6
|
-
SLACKER = 'slacker',
|
|
7
|
-
CONTROL_FREAK = 'control_freak',
|
|
8
|
-
PRIMA_DONNA = 'prima_donna',
|
|
9
|
-
QUIET_QUITTER = 'quiet_quitter',
|
|
10
|
-
SLACK_SPAMMER = 'slack_spammer'
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
export interface BlockConfig {
|
|
14
|
-
w: number;
|
|
15
|
-
h: number;
|
|
16
|
-
color: string;
|
|
17
|
-
density: number;
|
|
18
|
-
friction: number;
|
|
19
|
-
restitution: number;
|
|
20
|
-
label: string;
|
|
21
|
-
possibleLabels?: string[];
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
export const BLOCK_DEFINITIONS: Record<BlockType, BlockConfig> = {
|
|
25
|
-
[BlockType.BOOTSTRAP]: {
|
|
26
|
-
w: 132,
|
|
27
|
-
h: 44,
|
|
28
|
-
color: '#555555', // Concrete/Rust
|
|
29
|
-
density: 0.005, // High relative density (Matter.js default is 0.001)
|
|
30
|
-
friction: 0.8,
|
|
31
|
-
restitution: 0.0,
|
|
32
|
-
label: 'Refactoring',
|
|
33
|
-
possibleLabels: [
|
|
34
|
-
// The Work (Old & New)
|
|
35
|
-
'Refactoring', 'Unit Tests', 'Bug Fixes', 'User Support',
|
|
36
|
-
'Documentation', 'Security Audit', 'Compliance', 'Cleanup',
|
|
37
|
-
'Optimization', 'CI/CD Pipeline', 'Code Review', 'DB Tuning',
|
|
38
|
-
'API Design', 'Accessibility', 'Localization', 'Error Logs',
|
|
39
|
-
'Backups', 'Legacy Code', 'Hiring', 'Customer Love',
|
|
40
|
-
'Bossware', 'YAML Hell', 'DNS Propagation', 'Regex', 'npm audit',
|
|
41
|
-
'GDPR / SOC2', 'Migration', 'Certificate Expiry', 'On-Call',
|
|
42
|
-
'Technical Debt', 'Works on my machine', 'Yak Shaving'
|
|
43
|
-
]
|
|
44
|
-
},
|
|
45
|
-
[BlockType.VC]: {
|
|
46
|
-
w: 120,
|
|
47
|
-
h: 40,
|
|
48
|
-
color: '#FF00FF', // Neon Pink
|
|
49
|
-
density: 0.0005, // Slightly heavier (was 0.0001)
|
|
50
|
-
friction: 0.3, // Less slippery (was 0.1)
|
|
51
|
-
restitution: 0.6, // Less bouncy (was 0.9)
|
|
52
|
-
label: 'AI Blockchain',
|
|
53
|
-
possibleLabels: [
|
|
54
|
-
// The Hype (Old & New)
|
|
55
|
-
'GenAI', 'Blockchain', 'Web3', 'Metaverse', 'NFTs',
|
|
56
|
-
'Viral Growth', 'Pivot', 'Synergy', 'Disruption',
|
|
57
|
-
'Thought Leader', 'Influencers', 'Hyper-Scale', 'Quantum',
|
|
58
|
-
'Big Data', 'Growth Hack', 'Paradigm Shift', '10x Engineer',
|
|
59
|
-
'Visionary', 'Series B Pitch', 'Exit Strategy',
|
|
60
|
-
'Vibe Coding', 'Founder Mode', 'Prompt Engineering', 'AGI',
|
|
61
|
-
'AI Wrapper', 'Unlimited PTO', 'Radical Candor', 'Community Led',
|
|
62
|
-
'Pre-Revenue', 'Fractional CxO'
|
|
63
|
-
]
|
|
64
|
-
},
|
|
65
|
-
[BlockType.SLACKER]: {
|
|
66
|
-
w: 64, // 80 * 0.8
|
|
67
|
-
h: 64, // 80 * 0.8
|
|
68
|
-
color: '#FFFFFF',
|
|
69
|
-
density: 0.01,
|
|
70
|
-
friction: 1.0,
|
|
71
|
-
restitution: 0.1,
|
|
72
|
-
label: 'The Slacker',
|
|
73
|
-
possibleLabels: ['The Slacker']
|
|
74
|
-
},
|
|
75
|
-
[BlockType.CONTROL_FREAK]: {
|
|
76
|
-
w: 64, // Square to match image aspect ratio
|
|
77
|
-
h: 64,
|
|
78
|
-
color: '#FF0000', density: 0.012, friction: 0.5, restitution: 0.2,
|
|
79
|
-
label: 'Control Freak', possibleLabels: ['Control Freak']
|
|
80
|
-
},
|
|
81
|
-
[BlockType.PRIMA_DONNA]: {
|
|
82
|
-
w: 56, h: 56, // 70 * 0.8
|
|
83
|
-
color: '#FFFF00', density: 0.008, friction: 0.1, restitution: 1.2,
|
|
84
|
-
label: 'Prima Donna', possibleLabels: ['Prima Donna']
|
|
85
|
-
},
|
|
86
|
-
[BlockType.QUIET_QUITTER]: {
|
|
87
|
-
w: 48, h: 48, // 60 * 0.8
|
|
88
|
-
color: '#00FFFF', density: 0.005, friction: 0.01, restitution: 0.9,
|
|
89
|
-
label: 'Quiet Quitter', possibleLabels: ['Quiet Quitter']
|
|
90
|
-
},
|
|
91
|
-
[BlockType.SLACK_SPAMMER]: {
|
|
92
|
-
w: 60, h: 60, // 75 * 0.8
|
|
93
|
-
color: '#00FF00', density: 0.01, friction: 0.4, restitution: 0.4,
|
|
94
|
-
label: 'Slack Spammer', possibleLabels: ['Slack Spammer']
|
|
95
|
-
}
|
|
96
|
-
};
|
|
97
|
-
|
|
98
|
-
export const getRandomLabel = (type: BlockType): string => {
|
|
99
|
-
const labels = BLOCK_DEFINITIONS[type].possibleLabels || [];
|
|
100
|
-
return labels[Math.floor(Math.random() * labels.length)];
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
export const createBlock = (x: number, y: number, type: BlockType) => {
|
|
104
|
-
const def = BLOCK_DEFINITIONS[type];
|
|
105
|
-
const labelText = getRandomLabel(type);
|
|
106
|
-
|
|
107
|
-
const options = {
|
|
108
|
-
density: def.density,
|
|
109
|
-
friction: def.friction,
|
|
110
|
-
restitution: def.restitution,
|
|
111
|
-
render: {
|
|
112
|
-
fillStyle: def.color,
|
|
113
|
-
strokeStyle: '#000',
|
|
114
|
-
lineWidth: 2,
|
|
115
|
-
},
|
|
116
|
-
label: labelText,
|
|
117
|
-
};
|
|
118
|
-
|
|
119
|
-
if (type === BlockType.VC) {
|
|
120
|
-
// "Long Side Trapezoid" / Distorted Wedge
|
|
121
|
-
// Create an irregular quadrilateral that is annoying to stack
|
|
122
|
-
const w = def.w;
|
|
123
|
-
const h = def.h;
|
|
124
|
-
|
|
125
|
-
// Randomize the top corners to create a slanted roof (Wedge)
|
|
126
|
-
// or skew the sides (Parallelogram)
|
|
127
|
-
const y1 = Math.random() * 15; // Top-Left drop
|
|
128
|
-
const y2 = Math.random() * 15; // Top-Right drop
|
|
129
|
-
const skew = (Math.random() - 0.5) * 20; // skew x
|
|
130
|
-
|
|
131
|
-
const vertices = [
|
|
132
|
-
{ x: 0 + skew, y: y1 }, // TL
|
|
133
|
-
{ x: w + skew, y: y2 }, // TR
|
|
134
|
-
{ x: w, y: h }, // BR
|
|
135
|
-
{ x: 0, y: h } // BL
|
|
136
|
-
];
|
|
137
|
-
|
|
138
|
-
return Matter.Bodies.fromVertices(x, y, [vertices], options);
|
|
139
|
-
return Matter.Bodies.fromVertices(x, y, [vertices], options);
|
|
140
|
-
} else if (type === BlockType.SLACKER ||
|
|
141
|
-
type === BlockType.CONTROL_FREAK ||
|
|
142
|
-
type === BlockType.PRIMA_DONNA ||
|
|
143
|
-
type === BlockType.QUIET_QUITTER ||
|
|
144
|
-
type === BlockType.SLACK_SPAMMER) {
|
|
145
|
-
|
|
146
|
-
const textureMap: Record<string, string> = {
|
|
147
|
-
[BlockType.SLACKER]: './slacker.png',
|
|
148
|
-
[BlockType.CONTROL_FREAK]: './control-freak.png',
|
|
149
|
-
[BlockType.PRIMA_DONNA]: './prima-donna.png',
|
|
150
|
-
[BlockType.QUIET_QUITTER]: './quet-quitter.png', // User typo kept
|
|
151
|
-
[BlockType.SLACK_SPAMMER]: './slack-spammer.png'
|
|
152
|
-
};
|
|
153
|
-
|
|
154
|
-
const spriteOptions = {
|
|
155
|
-
...options,
|
|
156
|
-
render: {
|
|
157
|
-
sprite: {
|
|
158
|
-
texture: textureMap[type],
|
|
159
|
-
xScale: (def.w / 512) * 2, // Approximate
|
|
160
|
-
yScale: (def.h / 512) * 2
|
|
161
|
-
},
|
|
162
|
-
lineWidth: 3,
|
|
163
|
-
strokeStyle: '#ffffff'
|
|
164
|
-
}
|
|
165
|
-
};
|
|
166
|
-
|
|
167
|
-
if (type === BlockType.QUIET_QUITTER) {
|
|
168
|
-
return Matter.Bodies.circle(x, y, def.w / 2, spriteOptions);
|
|
169
|
-
} else if (type === BlockType.CONTROL_FREAK) {
|
|
170
|
-
return Matter.Bodies.trapezoid(x, y, def.w, def.h, 0.5, spriteOptions);
|
|
171
|
-
} else if (type === BlockType.PRIMA_DONNA) {
|
|
172
|
-
return Matter.Bodies.polygon(x, y, 5, def.w / 2, spriteOptions); // Pentagon
|
|
173
|
-
} else if (type === BlockType.SLACK_SPAMMER) {
|
|
174
|
-
return Matter.Bodies.polygon(x, y, 6, def.w / 2, spriteOptions); // Hexagon
|
|
175
|
-
} else {
|
|
176
|
-
// Default Slacker (Square)
|
|
177
|
-
return Matter.Bodies.rectangle(x, y, def.w, def.h, spriteOptions);
|
|
178
|
-
}
|
|
179
|
-
} else {
|
|
180
|
-
return Matter.Bodies.rectangle(x, y, def.w, def.h, options);
|
|
181
|
-
}
|
|
182
|
-
};
|