feat(balatro): introduce m6x11 pixel font as primary font face

Add m6x11.ttf and register it via @font-face in styles.css. Use it as
the primary font throughout BalatroGame.js and BalatroViews.js (with
Julius Sans One as fallback), giving the game a consistent pixel-art
aesthetic. Update PreloadScene to warm the new font alongside
YummyCupcakes.
This commit is contained in:
Brian Fertig 2026-07-10 16:30:29 -06:00
parent 7dce7ab271
commit 3a88ebc626
5 changed files with 47 additions and 39 deletions

BIN
assets/fonts/m6x11.ttf Normal file

Binary file not shown.

View File

@ -239,7 +239,7 @@ export default class BalatroGame extends Phaser.Scene {
text(x, y, str, size, color = C.ink, opts = {}) { text(x, y, str, size, color = C.ink, opts = {}) {
const t = this.add.text(x, y, str, { const t = this.add.text(x, y, str, {
fontFamily: opts.font || '"Julius Sans One"', fontSize: `${size}px`, color, fontFamily: opts.font || 'm6x11, "Julius Sans One"', fontSize: `${size}px`, color,
align: opts.align || 'left', wordWrap: opts.wrap ? { width: opts.wrap } : undefined, align: opts.align || 'left', wordWrap: opts.wrap ? { width: opts.wrap } : undefined,
fontStyle: opts.bold ? 'bold' : 'normal', fontStyle: opts.bold ? 'bold' : 'normal',
}).setOrigin(opts.ox ?? 0, opts.oy ?? 0); }).setOrigin(opts.ox ?? 0, opts.oy ?? 0);
@ -266,7 +266,7 @@ export default class BalatroGame extends Phaser.Scene {
toast(msg) { toast(msg) {
if (this._toastText) this._toastText.destroy(); if (this._toastText) this._toastText.destroy();
const t = this.add.text(GAME_WIDTH / 2, 640, msg, { const t = this.add.text(GAME_WIDTH / 2, 640, msg, {
fontFamily: '"Julius Sans One"', fontSize: '30px', color: '#ffd2c8', fontFamily: 'm6x11, "Julius Sans One"', fontSize: '30px', color: '#ffd2c8',
backgroundColor: '#301418', padding: { x: 18, y: 10 }, backgroundColor: '#301418', padding: { x: 18, y: 10 },
}).setOrigin(0.5).setDepth(90); }).setOrigin(0.5).setDepth(90);
this.fxLayer.add(t); this.fxLayer.add(t);
@ -326,22 +326,22 @@ export default class BalatroGame extends Phaser.Scene {
if (enh !== 'stone') { if (enh !== 'stone') {
const color = SUIT_COLOR[card.suit]; const color = SUIT_COLOR[card.suit];
const rank = this.add.text(-w / 2 + 10, -h / 2 + 6, RANK_NAMES[card.rank], { const rank = this.add.text(-w / 2 + 10, -h / 2 + 6, RANK_NAMES[card.rank], {
fontFamily: 'Georgia, serif', fontSize: `${Math.round(h * 0.21)}px`, color, fontStyle: 'bold', fontFamily: 'm6x11, Georgia, serif', fontSize: `${Math.round(h * 0.21)}px`, color, fontStyle: 'bold',
}); });
const suitSm = this.add.text(-w / 2 + 12, -h / 2 + 8 + h * 0.21, SUIT_GLYPH[card.suit], { const suitSm = this.add.text(-w / 2 + 12, -h / 2 + 8 + h * 0.21, SUIT_GLYPH[card.suit], {
fontFamily: 'Georgia, serif', fontSize: `${Math.round(h * 0.16)}px`, color, fontFamily: 'm6x11, Georgia, serif', fontSize: `${Math.round(h * 0.16)}px`, color,
}); });
const suitBig = this.add.text(w * 0.16, h * 0.16, SUIT_GLYPH[card.suit], { const suitBig = this.add.text(w * 0.16, h * 0.16, SUIT_GLYPH[card.suit], {
fontFamily: 'Georgia, serif', fontSize: `${Math.round(h * 0.42)}px`, color, fontFamily: 'm6x11, Georgia, serif', fontSize: `${Math.round(h * 0.42)}px`, color,
}).setOrigin(0.5).setAlpha(0.9); }).setOrigin(0.5).setAlpha(0.9);
cont.add([rank, suitSm, suitBig]); cont.add([rank, suitSm, suitBig]);
if (enh === 'wild') { if (enh === 'wild') {
const wl = this.add.text(0, h * 0.38, 'WILD', { fontFamily: '"Julius Sans One"', fontSize: `${Math.round(h * 0.1)}px`, color: '#5a3a10', fontStyle: 'bold' }).setOrigin(0.5); const wl = this.add.text(0, h * 0.38, 'WILD', { fontFamily: 'm6x11, "Julius Sans One"', fontSize: `${Math.round(h * 0.1)}px`, color: '#5a3a10', fontStyle: 'bold' }).setOrigin(0.5);
cont.add(wl); cont.add(wl);
} }
} else { } else {
const st = this.add.text(0, 0, '◼', { fontFamily: 'Georgia, serif', fontSize: `${Math.round(h * 0.32)}px`, color: '#4c4a45' }).setOrigin(0.5); const st = this.add.text(0, 0, '◼', { fontFamily: 'm6x11, Georgia, serif', fontSize: `${Math.round(h * 0.32)}px`, color: '#4c4a45' }).setOrigin(0.5);
const lbl = this.add.text(0, h * 0.3, 'STONE', { fontFamily: '"Julius Sans One"', fontSize: `${Math.round(h * 0.1)}px`, color: '#3d3b37' }).setOrigin(0.5); const lbl = this.add.text(0, h * 0.3, 'STONE', { fontFamily: 'm6x11, "Julius Sans One"', fontSize: `${Math.round(h * 0.1)}px`, color: '#3d3b37' }).setOrigin(0.5);
cont.add([st, lbl]); cont.add([st, lbl]);
} }
if (card.seal) { if (card.seal) {
@ -351,19 +351,19 @@ export default class BalatroGame extends Phaser.Scene {
} }
if (card.edition) { if (card.edition) {
const tag = this.add.text(0, -h / 2 + 4, EDITIONS[card.edition].name.toUpperCase(), { const tag = this.add.text(0, -h / 2 + 4, EDITIONS[card.edition].name.toUpperCase(), {
fontFamily: '"Julius Sans One"', fontSize: `${Math.round(h * 0.07)}px`, color: '#ffffff', fontFamily: 'm6x11, "Julius Sans One"', fontSize: `${Math.round(h * 0.07)}px`, color: '#ffffff',
}).setOrigin(0.5, 0).setAlpha(0.85); }).setOrigin(0.5, 0).setAlpha(0.85);
cont.add(tag); cont.add(tag);
} }
if (card.permaChips) { if (card.permaChips) {
const pc = this.add.text(-w / 2 + 8, h / 2 - 26, `+${card.permaChips}`, { const pc = this.add.text(-w / 2 + 8, h / 2 - 26, `+${card.permaChips}`, {
fontFamily: '"Julius Sans One"', fontSize: `${Math.round(h * 0.09)}px`, color: C.chipsHex, fontFamily: 'm6x11, "Julius Sans One"', fontSize: `${Math.round(h * 0.09)}px`, color: C.chipsHex,
}); });
cont.add(pc); cont.add(pc);
} }
if (debuffed) { if (debuffed) {
const shade = this.add.rectangle(0, 0, w, h, 0x1a1420, 0.62); const shade = this.add.rectangle(0, 0, w, h, 0x1a1420, 0.62);
const xg = this.add.text(0, 0, '✕', { fontFamily: 'Georgia, serif', fontSize: `${Math.round(h * 0.3)}px`, color: '#8a4550' }).setOrigin(0.5); const xg = this.add.text(0, 0, '✕', { fontFamily: 'm6x11, Georgia, serif', fontSize: `${Math.round(h * 0.3)}px`, color: '#8a4550' }).setOrigin(0.5);
cont.add([shade, xg]); cont.add([shade, xg]);
} }
cont.setSize(w, h); cont.setSize(w, h);
@ -387,11 +387,11 @@ export default class BalatroGame extends Phaser.Scene {
g.lineStyle(2, C.rarity[def.rarity], 1); g.strokeRoundedRect(-w / 2, -h / 2, w, h, 10); g.lineStyle(2, C.rarity[def.rarity], 1); g.strokeRoundedRect(-w / 2, -h / 2, w, h, 10);
cont.add(g); cont.add(g);
const name = this.add.text(0, -h / 2 + 15, def.name, { const name = this.add.text(0, -h / 2 + 15, def.name, {
fontFamily: '"Julius Sans One"', fontSize: `${Math.min(17, Math.round(280 / def.name.length))}px`, color: '#141019', fontStyle: 'bold', fontFamily: 'm6x11, "Julius Sans One"', fontSize: `${Math.min(17, Math.round(280 / def.name.length))}px`, color: '#141019', fontStyle: 'bold',
}).setOrigin(0.5); }).setOrigin(0.5);
const desc = typeof def.desc === 'function' ? def.desc(opts.inst || { state: def.initState ? def.initState() : {} }) : def.desc; const desc = typeof def.desc === 'function' ? def.desc(opts.inst || { state: def.initState ? def.initState() : {} }) : def.desc;
const body = this.add.text(0, 8, desc, { const body = this.add.text(0, 8, desc, {
fontFamily: '"Julius Sans One"', fontSize: '15px', color: C.ink, align: 'center', fontFamily: 'm6x11, "Julius Sans One"', fontSize: '15px', color: C.ink, align: 'center',
wordWrap: { width: w - 16 }, wordWrap: { width: w - 16 },
}).setOrigin(0.5); }).setOrigin(0.5);
cont.add([name, body]); cont.add([name, body]);
@ -403,14 +403,14 @@ export default class BalatroGame extends Phaser.Scene {
eg.lineStyle(4, edColor, 0.95); eg.strokeRoundedRect(-w / 2, -h / 2, w, h, 10); eg.lineStyle(4, edColor, 0.95); eg.strokeRoundedRect(-w / 2, -h / 2, w, h, 10);
cont.add(eg); cont.add(eg);
const tag = this.add.text(0, h / 2 - 16, EDITIONS[edition].name.toUpperCase(), { const tag = this.add.text(0, h / 2 - 16, EDITIONS[edition].name.toUpperCase(), {
fontFamily: '"Julius Sans One"', fontSize: '11px', color: '#ffffff', fontFamily: 'm6x11, "Julius Sans One"', fontSize: '11px', color: '#ffffff',
}).setOrigin(0.5).setAlpha(0.9); }).setOrigin(0.5).setAlpha(0.9);
cont.add(tag); cont.add(tag);
if (edition === 'negative') cont.setAlpha(0.8); if (edition === 'negative') cont.setAlpha(0.8);
} }
if (opts.inst && opts.inst.debuffedByBoss) { if (opts.inst && opts.inst.debuffedByBoss) {
cont.add(this.add.rectangle(0, 0, w, h, 0x1a1420, 0.6)); cont.add(this.add.rectangle(0, 0, w, h, 0x1a1420, 0.6));
cont.add(this.add.text(0, 0, 'DISABLED', { fontFamily: '"Julius Sans One"', fontSize: '16px', color: '#c86a6a' }).setOrigin(0.5)); cont.add(this.add.text(0, 0, 'DISABLED', { fontFamily: 'm6x11, "Julius Sans One"', fontSize: '16px', color: '#c86a6a' }).setOrigin(0.5));
} }
cont.setSize(w, h); cont.setSize(w, h);
return cont; return cont;
@ -433,16 +433,16 @@ export default class BalatroGame extends Phaser.Scene {
g.lineStyle(1, tint, 0.6); g.strokeRoundedRect(-w / 2 + 6, -h / 2 + 6, w - 12, h - 12, 8); g.lineStyle(1, tint, 0.6); g.strokeRoundedRect(-w / 2 + 6, -h / 2 + 6, w - 12, h - 12, 8);
cont.add(g); cont.add(g);
const name = this.add.text(0, -h / 2 + 20, def.name, { const name = this.add.text(0, -h / 2 + 20, def.name, {
fontFamily: '"Julius Sans One"', fontSize: `${Math.min(16, Math.round(300 / def.name.length))}px`, fontFamily: 'm6x11, "Julius Sans One"', fontSize: `${Math.min(16, Math.round(300 / def.name.length))}px`,
color: `#${tint.toString(16).padStart(6, '0')}`, fontStyle: 'bold', align: 'center', wordWrap: { width: w - 14 }, color: `#${tint.toString(16).padStart(6, '0')}`, fontStyle: 'bold', align: 'center', wordWrap: { width: w - 14 },
}).setOrigin(0.5, 0); }).setOrigin(0.5, 0);
const descText = kind === 'planet' ? `+1 level: ${HAND_BY_ID[def.hand].name}` : def.desc; const descText = kind === 'planet' ? `+1 level: ${HAND_BY_ID[def.hand].name}` : def.desc;
const body = this.add.text(0, 16, descText, { const body = this.add.text(0, 16, descText, {
fontFamily: '"Julius Sans One"', fontSize: '14px', color: C.ink, align: 'center', wordWrap: { width: w - 18 }, fontFamily: 'm6x11, "Julius Sans One"', fontSize: '14px', color: C.ink, align: 'center', wordWrap: { width: w - 18 },
}).setOrigin(0.5); }).setOrigin(0.5);
cont.add([name, body]); cont.add([name, body]);
const glyph = { tarot: '☽', planet: '✶', spectral: '✧' }[kind]; const glyph = { tarot: '☽', planet: '✶', spectral: '✧' }[kind];
cont.add(this.add.text(0, h / 2 - 22, glyph, { fontFamily: 'Georgia, serif', fontSize: '20px', color: `#${tint.toString(16).padStart(6, '0')}` }).setOrigin(0.5)); cont.add(this.add.text(0, h / 2 - 22, glyph, { fontFamily: 'm6x11, Georgia, serif', fontSize: '20px', color: `#${tint.toString(16).padStart(6, '0')}` }).setOrigin(0.5));
} }
cont.setSize(w, h); cont.setSize(w, h);
return cont; return cont;
@ -460,14 +460,14 @@ export default class BalatroGame extends Phaser.Scene {
this.fxLayer.add(cont); this.fxLayer.add(cont);
let y = PAD; let y = PAD;
const title = this.add.text(PAD, y, info.title, { const title = this.add.text(PAD, y, info.title, {
fontFamily: '"Julius Sans One"', fontSize: '22px', color: info.titleColor || C.ink, fontFamily: 'm6x11, "Julius Sans One"', fontSize: '22px', color: info.titleColor || C.ink,
fontStyle: 'bold', wordWrap: { width: W - PAD * 2 }, fontStyle: 'bold', wordWrap: { width: W - PAD * 2 },
}); });
cont.add(title); cont.add(title);
y += title.height + 4; y += title.height + 4;
if (info.tag) { if (info.tag) {
const tag = this.add.text(PAD, y, info.tag, { const tag = this.add.text(PAD, y, info.tag, {
fontFamily: '"Julius Sans One"', fontSize: '14px', color: info.tagColor || C.muted, fontFamily: 'm6x11, "Julius Sans One"', fontSize: '14px', color: info.tagColor || C.muted,
}); });
cont.add(tag); cont.add(tag);
y += tag.height + 8; y += tag.height + 8;
@ -476,7 +476,7 @@ export default class BalatroGame extends Phaser.Scene {
} }
for (const line of info.lines || []) { for (const line of info.lines || []) {
const t = this.add.text(PAD, y, line.text, { const t = this.add.text(PAD, y, line.text, {
fontFamily: '"Julius Sans One"', fontSize: '16px', color: line.color || C.muted, fontFamily: 'm6x11, "Julius Sans One"', fontSize: '16px', color: line.color || C.muted,
wordWrap: { width: W - PAD * 2 }, wordWrap: { width: W - PAD * 2 },
}); });
cont.add(t); cont.add(t);
@ -701,7 +701,7 @@ export default class BalatroGame extends Phaser.Scene {
g.fillStyle(C.panel, 0.97); g.fillRoundedRect(GAME_WIDTH / 2 - 240, 360, 480, 360, 16); g.fillStyle(C.panel, 0.97); g.fillRoundedRect(GAME_WIDTH / 2 - 240, 360, 480, 360, 16);
g.lineStyle(2, C.panelEdge, 1); g.strokeRoundedRect(GAME_WIDTH / 2 - 240, 360, 480, 360, 16); g.lineStyle(2, C.panelEdge, 1); g.strokeRoundedRect(GAME_WIDTH / 2 - 240, 360, 480, 360, 16);
ov.add([shade, g]); ov.add([shade, g]);
const t = this.add.text(GAME_WIDTH / 2, 400, 'Options', { fontFamily: '"Julius Sans One"', fontSize: '32px', color: C.ink }).setOrigin(0.5); const t = this.add.text(GAME_WIDTH / 2, 400, 'Options', { fontFamily: 'm6x11, "Julius Sans One"', fontSize: '32px', color: C.ink }).setOrigin(0.5);
ov.add(t); ov.add(t);
const mk = (y, label, cb) => { const mk = (y, label, cb) => {
const b = new Button(this, GAME_WIDTH / 2, y, label, cb, { width: 320, height: 56, fontSize: 22 }); const b = new Button(this, GAME_WIDTH / 2, y, label, cb, { width: 320, height: 56, fontSize: 22 });
@ -775,8 +775,8 @@ export default class BalatroGame extends Phaser.Scene {
g.lineStyle(2, C.rarity[def.rarity], 1); g.strokeRoundedRect(px, py, pw, ph, 12); g.lineStyle(2, C.rarity[def.rarity], 1); g.strokeRoundedRect(px, py, pw, ph, 12);
cont.add(g); cont.add(g);
const desc = typeof def.desc === 'function' ? def.desc(inst) : def.desc; const desc = typeof def.desc === 'function' ? def.desc(inst) : def.desc;
cont.add(this.add.text(px + 20, py + 14, `${def.name}${inst.edition ? ` (${EDITIONS[inst.edition].name})` : ''}`, { fontFamily: '"Julius Sans One"', fontSize: '24px', color: C.ink })); cont.add(this.add.text(px + 20, py + 14, `${def.name}${inst.edition ? ` (${EDITIONS[inst.edition].name})` : ''}`, { fontFamily: 'm6x11, "Julius Sans One"', fontSize: '24px', color: C.ink }));
cont.add(this.add.text(px + 20, py + 52, desc, { fontFamily: '"Julius Sans One"', fontSize: '17px', color: C.muted, wordWrap: { width: pw - 40 } })); cont.add(this.add.text(px + 20, py + 52, desc, { fontFamily: 'm6x11, "Julius Sans One"', fontSize: '17px', color: C.muted, wordWrap: { width: pw - 40 } }));
const sell = new Button(this, px + pw - 110, py + ph - 40, `Sell $${inst.sellValue}`, () => { const sell = new Button(this, px + pw - 110, py + ph - 40, `Sell $${inst.sellValue}`, () => {
const r = sellJoker(this.run, inst.uid); const r = sellJoker(this.run, inst.uid);
if (r.ok) { playSound(this, SFX.COINS); this.save(); this.renderView(); } if (r.ok) { playSound(this, SFX.COINS); this.save(); this.renderView(); }
@ -823,11 +823,11 @@ export default class BalatroGame extends Phaser.Scene {
const tint = { tarot: C.tarot, planet: C.planet, spectral: C.spectral }[inst.kind]; const tint = { tarot: C.tarot, planet: C.planet, spectral: C.spectral }[inst.kind];
g.lineStyle(2, tint, 1); g.strokeRoundedRect(px, py, pw, ph, 12); g.lineStyle(2, tint, 1); g.strokeRoundedRect(px, py, pw, ph, 12);
cont.add(g); cont.add(g);
cont.add(this.add.text(px + 20, py + 14, def.name, { fontFamily: '"Julius Sans One"', fontSize: '24px', color: C.ink })); cont.add(this.add.text(px + 20, py + 14, def.name, { fontFamily: 'm6x11, "Julius Sans One"', fontSize: '24px', color: C.ink }));
const descText = inst.kind === 'planet' ? `+1 level: ${HAND_BY_ID[def.hand].name}` : def.desc; const descText = inst.kind === 'planet' ? `+1 level: ${HAND_BY_ID[def.hand].name}` : def.desc;
cont.add(this.add.text(px + 20, py + 52, descText, { fontFamily: '"Julius Sans One"', fontSize: '17px', color: C.muted, wordWrap: { width: pw - 40 } })); cont.add(this.add.text(px + 20, py + 52, descText, { fontFamily: 'm6x11, "Julius Sans One"', fontSize: '17px', color: C.muted, wordWrap: { width: pw - 40 } }));
const needs = def.targets || 0; const needs = def.targets || 0;
if (needs) cont.add(this.add.text(px + 20, py + ph - 96, `Select up to ${needs} card${needs > 1 ? 's' : ''} in hand first`, { fontFamily: '"Julius Sans One"', fontSize: '15px', color: '#a8d8ff' })); if (needs) cont.add(this.add.text(px + 20, py + ph - 96, `Select up to ${needs} card${needs > 1 ? 's' : ''} in hand first`, { fontFamily: 'm6x11, "Julius Sans One"', fontSize: '15px', color: '#a8d8ff' }));
const use = new Button(this, px + pw - 110, py + ph - 40, 'Use', () => { const use = new Button(this, px + pw - 110, py + ph - 40, 'Use', () => {
const r = useConsumable(this.run, inst.uid, this.selected.slice(0, Math.max(needs, 2))); const r = useConsumable(this.run, inst.uid, this.selected.slice(0, Math.max(needs, 2)));
if (!r.ok) { this.toast(r.error); return; } if (!r.ok) { this.toast(r.error); return; }
@ -897,7 +897,7 @@ export default class BalatroGame extends Phaser.Scene {
cont.add(glow); cont.add(glow);
} }
if (run.bossState && run.bossState.forcedUid === card.uid) { if (run.bossState && run.bossState.forcedUid === card.uid) {
const lock = this.add.text(0, -h / 2 - 20, '⛓ forced', { fontFamily: '"Julius Sans One"', fontSize: '15px', color: '#ff8a6a' }).setOrigin(0.5); const lock = this.add.text(0, -h / 2 - 20, '⛓ forced', { fontFamily: 'm6x11, "Julius Sans One"', fontSize: '15px', color: '#ff8a6a' }).setOrigin(0.5);
cont.add(lock); cont.add(lock);
} }
if (!frozen) { if (!frozen) {
@ -1140,7 +1140,7 @@ export default class BalatroGame extends Phaser.Scene {
const x = sprite ? this.fxX(sprite) : 980; const x = sprite ? this.fxX(sprite) : 980;
const y = sprite ? this.fxY(sprite) - 90 : 400; const y = sprite ? this.fxY(sprite) - 90 : 400;
const t = this.add.text(x, y, textStr, { const t = this.add.text(x, y, textStr, {
fontFamily: '"Julius Sans One"', fontSize: '34px', color, fontStyle: 'bold', fontFamily: 'm6x11, "Julius Sans One"', fontSize: '34px', color, fontStyle: 'bold',
stroke: '#141019', strokeThickness: 5, stroke: '#141019', strokeThickness: 5,
}).setOrigin(0.5).setDepth(85); }).setOrigin(0.5).setDepth(85);
this.fxLayer.add(t); this.fxLayer.add(t);
@ -1189,7 +1189,7 @@ export default class BalatroGame extends Phaser.Scene {
const score = res.trace.score; const score = res.trace.score;
// Slam: big score text at the played row. // Slam: big score text at the played row.
const slam = this.add.text(centerX, py - 170, fmtChips(score), { const slam = this.add.text(centerX, py - 170, fmtChips(score), {
fontFamily: '"Julius Sans One"', fontSize: '72px', color: '#ffffff', fontStyle: 'bold', fontFamily: 'm6x11, "Julius Sans One"', fontSize: '72px', color: '#ffffff', fontStyle: 'bold',
stroke: '#c8342c', strokeThickness: 8, stroke: '#c8342c', strokeThickness: 8,
}).setOrigin(0.5).setScale(1.6).setAlpha(0).setDepth(86); }).setOrigin(0.5).setScale(1.6).setAlpha(0).setDepth(86);
this.fxLayer.add(slam); this.fxLayer.add(slam);

View File

@ -64,7 +64,7 @@ function confirmNewRun(scene) {
g.fillStyle(C.panel, 0.97); g.fillRoundedRect(CX - 280, 420, 560, 240, 16); g.fillStyle(C.panel, 0.97); g.fillRoundedRect(CX - 280, 420, 560, 240, 16);
g.lineStyle(2, C.panelEdge, 1); g.strokeRoundedRect(CX - 280, 420, 560, 240, 16); g.lineStyle(2, C.panelEdge, 1); g.strokeRoundedRect(CX - 280, 420, 560, 240, 16);
ov.add([shade, g]); ov.add([shade, g]);
ov.add(scene.add.text(CX, 470, 'Abandon the saved run?', { fontFamily: '"Julius Sans One"', fontSize: '28px', color: C.ink }).setOrigin(0.5)); ov.add(scene.add.text(CX, 470, 'Abandon the saved run?', { fontFamily: 'm6x11, "Julius Sans One"', fontSize: '28px', color: C.ink }).setOrigin(0.5));
const yes = scene.button(CX - 110, 590, 'Yes', () => { scene._savedRun = null; store.write('balatro:run', null); ov.destroy(); scene.setView('deckselect'); }, { width: 160, height: 54, fontSize: 22 }); const yes = scene.button(CX - 110, 590, 'Yes', () => { scene._savedRun = null; store.write('balatro:run', null); ov.destroy(); scene.setView('deckselect'); }, { width: 160, height: 54, fontSize: 22 });
const no = scene.button(CX + 110, 590, 'No', () => ov.destroy(), { width: 160, height: 54, fontSize: 22, variant: 'ghost' }); const no = scene.button(CX + 110, 590, 'No', () => ov.destroy(), { width: 160, height: 54, fontSize: 22, variant: 'ghost' });
ov.add([yes, no]); ov.add([yes, no]);
@ -94,8 +94,8 @@ export function renderDeckSelect(scene) {
bg.lineStyle(1, 0xffffff, 0.25); bg.strokeRoundedRect(-48, -130, 96, 140, 6); bg.lineStyle(1, 0xffffff, 0.25); bg.strokeRoundedRect(-48, -130, 96, 140, 6);
cont.add(bg); cont.add(bg);
} }
cont.add(scene.add.text(0, 52, deck.name, { fontFamily: '"Julius Sans One"', fontSize: '26px', color: C.ink, fontStyle: 'bold' }).setOrigin(0.5)); cont.add(scene.add.text(0, 52, deck.name, { fontFamily: 'm6x11, "Julius Sans One"', fontSize: '26px', color: C.ink, fontStyle: 'bold' }).setOrigin(0.5));
cont.add(scene.add.text(0, 108, deck.desc, { fontFamily: '"Julius Sans One"', fontSize: '17px', color: C.muted, align: 'center', wordWrap: { width: w - 30 } }).setOrigin(0.5)); cont.add(scene.add.text(0, 108, deck.desc, { fontFamily: 'm6x11, "Julius Sans One"', fontSize: '17px', color: C.muted, align: 'center', wordWrap: { width: w - 30 } }).setOrigin(0.5));
cont.setSize(w, h); cont.setSize(w, h);
scene.add2(cont); scene.add2(cont);
scene.addHoverTilt(cont); scene.addHoverTilt(cont);
@ -248,7 +248,7 @@ export function renderShop(scene) {
g.lineStyle(3, 0xffffff, 0.5); g.strokeRoundedRect(-90, -120, 180, 240, 12); g.lineStyle(3, 0xffffff, 0.5); g.strokeRoundedRect(-90, -120, 180, 240, 12);
g.fillStyle(0x141019, 0.35); g.fillRoundedRect(-90, -30, 180, 60, 0); g.fillStyle(0x141019, 0.35); g.fillRoundedRect(-90, -30, 180, 60, 0);
cont.add(g); cont.add(g);
cont.add(scene.add.text(0, 0, def.name.replace(' Pack', '\nPack'), { fontFamily: '"Julius Sans One"', fontSize: '22px', color: '#ffffff', align: 'center', fontStyle: 'bold' }).setOrigin(0.5)); cont.add(scene.add.text(0, 0, def.name.replace(' Pack', '\nPack'), { fontFamily: 'm6x11, "Julius Sans One"', fontSize: '22px', color: '#ffffff', align: 'center', fontStyle: 'bold' }).setOrigin(0.5));
} }
cont.setSize(180, 240); cont.setSize(180, 240);
scene.add2(cont); scene.add2(cont);
@ -284,8 +284,8 @@ export function renderShop(scene) {
g.lineStyle(3, C.voucher, 1); g.strokeRoundedRect(-95, -125, 190, 250, 10); g.lineStyle(3, C.voucher, 1); g.strokeRoundedRect(-95, -125, 190, 250, 10);
g.lineStyle(1, C.voucher, 0.5); g.strokeRoundedRect(-85, -115, 170, 230, 8); g.lineStyle(1, C.voucher, 0.5); g.strokeRoundedRect(-85, -115, 170, 230, 8);
cont.add(g); cont.add(g);
cont.add(scene.add.text(0, -80, v.name, { fontFamily: '"Julius Sans One"', fontSize: '22px', color: '#7ce0c0', align: 'center', fontStyle: 'bold', wordWrap: { width: 170 } }).setOrigin(0.5)); cont.add(scene.add.text(0, -80, v.name, { fontFamily: 'm6x11, "Julius Sans One"', fontSize: '22px', color: '#7ce0c0', align: 'center', fontStyle: 'bold', wordWrap: { width: 170 } }).setOrigin(0.5));
cont.add(scene.add.text(0, 20, v.desc, { fontFamily: '"Julius Sans One"', fontSize: '16px', color: C.ink, align: 'center', wordWrap: { width: 165 } }).setOrigin(0.5)); cont.add(scene.add.text(0, 20, v.desc, { fontFamily: 'm6x11, "Julius Sans One"', fontSize: '16px', color: C.ink, align: 'center', wordWrap: { width: 165 } }).setOrigin(0.5));
} }
cont.setSize(190, 250); cont.setSize(190, 250);
scene.add2(cont); scene.add2(cont);

View File

@ -261,9 +261,10 @@ export default class PreloadScene extends Phaser.Scene {
}); });
} }
// Warm the handwritten Scrabble notepad font so its first paint isn't a // Warm the handwritten Scrabble notepad font and Balatro's pixel font so
// fallback face. Best effort — never block startup on it. // their first paint isn't a fallback face. Best effort — never block
try { await Promise.race([document.fonts.load('48px YummyCupcakes'), new Promise(r => setTimeout(r, 1500))]); } catch { /* ignore */ } // startup on them.
try { await Promise.race([Promise.all([document.fonts.load('48px YummyCupcakes'), document.fonts.load('48px m6x11')]), new Promise(r => setTimeout(r, 1500))]); } catch { /* ignore */ }
await auth.refresh(); await auth.refresh();
this.scene.start('Landing'); this.scene.start('Landing');

View File

@ -26,6 +26,13 @@
font-style: normal; font-style: normal;
} }
@font-face {
font-family: 'm6x11';
src: url('assets/fonts/m6x11.ttf') format('truetype');
font-weight: normal;
font-style: normal;
}
html, body { html, body {
margin: 0; margin: 0;
padding: 0; padding: 0;