← back to Neon Baguette Battle
Redesign fighters as Frenchmen in berets wielding baguettes; special now launches the baguette as a spinning missile (Baguette Missile)
d93d9acb84950f48ccc4a7a784ab22e181e1d6f6 · 2026-08-31 13:17:47 -0700 · Steve Abrams
- Fighters redrawn: beret + Breton-striped shirt + moustache, holding a baguette weapon (jab/whack animate the baguette)
- Special (H // ) launches the baguette as a spinning projectile instead of a crumb ball
- Character-select mini-portraits redrawn as little Frenchmen
- Voice + HUD + controls + copy updated (Baguette Missile)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Files touched
M .gitignoreM README.mdD fight2p.pngM index.htmlD screenshot.pngD select.png
Diff
commit d93d9acb84950f48ccc4a7a784ab22e181e1d6f6
Author: Steve Abrams <steve@designerwallcoverings.com>
Date: Mon Aug 31 13:17:47 2026 -0700
Redesign fighters as Frenchmen in berets wielding baguettes; special now launches the baguette as a spinning missile (Baguette Missile)
- Fighters redrawn: beret + Breton-striped shirt + moustache, holding a baguette weapon (jab/whack animate the baguette)
- Special (H // ) launches the baguette as a spinning projectile instead of a crumb ball
- Character-select mini-portraits redrawn as little Frenchmen
- Voice + HUD + controls + copy updated (Baguette Missile)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
---
.gitignore | 3 +
README.md | 13 +--
fight2p.png | Bin 303502 -> 0 bytes
index.html | 281 +++++++++++++++++++++++++++++++--------------------------
screenshot.png | Bin 304810 -> 0 bytes
select.png | Bin 279933 -> 0 bytes
6 files changed, 161 insertions(+), 136 deletions(-)
diff --git a/.gitignore b/.gitignore
index 1924158..f9eb2e0 100644
--- a/.gitignore
+++ b/.gitignore
@@ -6,3 +6,6 @@ tmp/
dist/
build/
.next/
+
+# scratch test screenshots
+*.png
diff --git a/README.md b/README.md
index 03b00a5..5f3583d 100644
--- a/README.md
+++ b/README.md
@@ -1,9 +1,10 @@
# Baguette Battle — Neon Paris 🥖⚔️
-A playable browser fighting game. Two artisanal baguettes duel beneath a neon
-Eiffel Tower while pies, french rolls, and croissants fly across the arena.
-Single self-contained `index.html` — no build step, no dependencies, no assets.
-Open it in any modern browser and play.
+A playable browser fighting game. Two mustachioed **Frenchmen in berets** duel
+with **baguettes** beneath a neon Eiffel Tower — jab, whack, block, and **launch
+your baguette like a spinning missile** — while pies, french rolls, and
+croissants fly across the arena. Single self-contained `index.html` — no build
+step, no dependencies, no assets. Open it in any modern browser and play.
Built from a Model Arena challenge ("a game where baguettes in Paris fight each
other"). The starting artifact (Qwen2.5-local) was just a title card with an
@@ -38,8 +39,8 @@ also click a card to choose P1's fighter. `Enter`/`Space` or **START FIGHT** beg
## Features
- **Real combat**: startup/active/recovery attack frames, blocking with chip
- damage, knockback, hit-stun, a build-up special meter, and a **Crumb Blast**
- projectile.
+ damage, knockback, hit-stun, a build-up special meter, and a **launched
+ baguette missile** (spinning projectile) once the meter is full.
- **CPU opponent** with an approach/attack/block/retreat/blast state machine.
- **Flying food hazards**: pies (cream splat, big damage), french rolls (fast),
and croissants arc in from off-screen and hit either fighter.
diff --git a/fight2p.png b/fight2p.png
deleted file mode 100644
index c8b8f2b..0000000
Binary files a/fight2p.png and /dev/null differ
diff --git a/index.html b/index.html
index a39ff66..872a307 100644
--- a/index.html
+++ b/index.html
@@ -98,8 +98,8 @@
<div class="screen" id="menu">
<h1>BAGUETTE BATTLE</h1>
<div class="sub"><span class="flag"></span> Neon Paris Combat Arena <span class="flag"></span></div>
- <p>Two artisanal baguettes settle their differences beneath a neon Eiffel Tower.
- Poke, swing, block, and unleash the <b>Crumb Blast</b>. Best of 3 rounds wins.</p>
+ <p>Two Parisians settle their differences with baguettes beneath a neon Eiffel Tower.
+ Poke, whack, block — then <b>launch your baguette like a missile</b>. Best of 3 rounds wins.</p>
<div class="btns">
<button class="primary" id="btn1p">1 PLAYER · vs CPU</button>
<button id="btn2p">2 PLAYERS · local</button>
@@ -110,9 +110,9 @@
<tr><td>Move</td><td><span class="key">A</span><span class="key">D</span></td></tr>
<tr><td>Jump</td><td><span class="key">W</span></td></tr>
<tr><td>Block</td><td><span class="key">S</span></td></tr>
- <tr><td>Poke</td><td><span class="key">F</span></td></tr>
- <tr><td>Swing</td><td><span class="key">G</span></td></tr>
- <tr><td>Crumb Blast</td><td><span class="key">H</span></td></tr>
+ <tr><td>Jab (baguette)</td><td><span class="key">F</span></td></tr>
+ <tr><td>Whack (baguette)</td><td><span class="key">G</span></td></tr>
+ <tr><td>Launch baguette 🚀</td><td><span class="key">H</span></td></tr>
</table>
</div>
<div class="ctl p2"><h3>🥖 Player 2</h3>
@@ -120,9 +120,9 @@
<tr><td>Move</td><td><span class="key">←</span><span class="key">→</span></td></tr>
<tr><td>Jump</td><td><span class="key">↑</span></td></tr>
<tr><td>Block</td><td><span class="key">↓</span></td></tr>
- <tr><td>Poke</td><td><span class="key">,</span></td></tr>
- <tr><td>Swing</td><td><span class="key">.</span></td></tr>
- <tr><td>Crumb Blast</td><td><span class="key">/</span></td></tr>
+ <tr><td>Jab (baguette)</td><td><span class="key">,</span></td></tr>
+ <tr><td>Whack (baguette)</td><td><span class="key">.</span></td></tr>
+ <tr><td>Launch baguette 🚀</td><td><span class="key">/</span></td></tr>
</table>
</div>
</div>
@@ -250,7 +250,7 @@
taunt: () => say(rnd(["Take zat!","Ooh la la!","On garde!","Zut alors!","Eat my baguette!","Ha! Too slow, mon ami!"]), {pitch:1.15}),
hurt: () => say(rnd(["Oh non!","Mon dieu!","Sacrebleu!","Ze pain!","Aïe!"]), {pitch:1.25, rate:1.05}),
block: () => say(rnd(["Non non non!","Not today!"]), {pitch:1.15}),
- blast: () => say("Crumb blast! Boom!", {rate:0.9, pitch:1.0, force:true}),
+ blast: () => say(rnd(["Baguette missile! Allez!","Fire ze baguette!","Incoming! Ha ha!"]), {rate:0.95, pitch:1.05, force:true}),
round: () => say("Allez!", {force:true, pitch:1.1}),
fight: () => say("Fight, mon ami!", {force:true, pitch:1.15}),
ko: () => say("Oh la la! Magnifique!", {force:true, pitch:1.05}),
@@ -531,118 +531,132 @@
if (koFall>0){ g.rotate(koFall*Math.PI*0.5*0.9); g.translate(0, koFall*10); }
g.rotate(lean*Math.PI/180);
- // ---- baguette body ----
- const bx=0, by=-this.h, bw=this.w, bh=this.h;
+ // ===== Frenchman with beret, wielding a baguette =====
+ const legPhase = this.state==='walk' ? Math.sin(this.animT) : 0;
+ const armExt = this.armSwing;
+ const skin='#e8b892', skinDk='#c98f68', trouser='#242a42', shoe='#141414';
+ const shirt = hurtFlash ? '#ffffff' : '#f2efe6';
+ const hipY=-46, shoY=-86, headR=14, headCY=-104;
+
+ // ---- legs + shoes ----
+ g.lineCap='round';
+ g.strokeStyle=trouser; g.lineWidth=13;
+ g.beginPath(); g.moveTo(-8,hipY); g.lineTo(-9 - legPhase*7, -3); g.stroke();
+ g.beginPath(); g.moveTo( 8,hipY); g.lineTo( 9 + legPhase*7, -3); g.stroke();
+ g.strokeStyle=shoe; g.lineWidth=7;
+ g.beginPath(); g.moveTo(-9-legPhase*7,-2); g.lineTo(-14-legPhase*7,-1); g.stroke();
+ g.beginPath(); g.moveTo( 9+legPhase*7,-2); g.lineTo( 14+legPhase*7,-1); g.stroke();
+
+ // ---- back arm (behind torso) ----
+ const backHy = shoY+12+22+Math.sin(this.animT)*2;
+ g.strokeStyle=shirt; g.lineWidth=8; g.lineCap='round';
+ g.beginPath(); g.moveTo(-this.w*0.16, shoY+12); g.lineTo(-this.w*0.16-6, backHy); g.stroke();
+ g.fillStyle=skin; g.beginPath(); g.arc(-this.w*0.16-6, backHy, 4,0,Math.PI*2); g.fill();
+
+ // ---- torso: Breton-striped shirt ----
+ const tw=this.w*0.8, tx=-tw/2, ty=shoY, thh=hipY-shoY+6;
g.save();
- g.translate(0,0);
- // body glow
- g.shadowColor = c.glow; g.shadowBlur = hurtFlash?26:14;
- roundRectPath(g, -bw/2, by, bw, bh, bw/2);
- const grd = g.createLinearGradient(-bw/2,0,bw/2,0);
- grd.addColorStop(0, c.crustDk); grd.addColorStop(0.5, c.crust); grd.addColorStop(1, c.crustDk);
- g.fillStyle = hurtFlash ? '#ffffff' : grd; g.fill();
- g.shadowBlur = 0;
- // crust rim
- g.lineWidth = 3; g.strokeStyle = 'rgba(90,55,15,.7)'; g.stroke();
-
- // baguette diagonal score marks
+ g.shadowColor=c.glow; g.shadowBlur=hurtFlash?24:12;
+ roundRectPath(g, tx, ty, tw, thh, 9); g.fillStyle=shirt; g.fill();
+ g.shadowBlur=0;
if (!hurtFlash){
- g.strokeStyle = 'rgba(120,72,20,.85)'; g.lineWidth = 3;
- for (let i=0;i<5;i++){
- const yy = by + 22 + i*(bh-40)/4;
- g.beginPath();
- g.moveTo(-bw*0.22, yy);
- g.quadraticCurveTo(0, yy-8, bw*0.24, yy-3);
- g.stroke();
- }
- // flour speckles
- g.fillStyle = 'rgba(255,248,230,.5)';
- for (let i=0;i<8;i++){
- const sx=(Math.sin(i*12.9+this.side.length)*0.5)*bw*0.7;
- const sy=by+18+((i*37)%(bh-30));
- g.beginPath(); g.arc(sx, sy, 1.6, 0, Math.PI*2); g.fill();
- }
+ g.save(); roundRectPath(g, tx, ty, tw, thh, 9); g.clip();
+ g.fillStyle=c.accent;
+ for (let sy=ty+5; sy<ty+thh; sy+=10) g.fillRect(tx, sy, tw, 5);
+ g.restore();
}
+ g.lineWidth=2; g.strokeStyle='rgba(0,0,0,.28)'; roundRectPath(g, tx, ty, tw, thh, 9); g.stroke();
g.restore();
- // ---- beret ----
- g.save();
- g.translate(0, by+4);
- g.fillStyle = c.beret;
- g.beginPath(); g.ellipse(2, 0, bw*0.42, 12, 0, 0, Math.PI*2); g.fill();
- g.beginPath(); g.arc(2, -6, bw*0.34, Math.PI, 0); g.fill();
- g.fillStyle = '#1a1a1a'; g.beginPath(); g.arc(bw*0.30, -8, 2.5, 0, Math.PI*2); g.fill(); // stalk
- g.restore();
+ // ---- neckerchief ----
+ g.fillStyle=c.beret;
+ g.beginPath(); g.moveTo(-8, shoY+2); g.lineTo(8, shoY+2); g.lineTo(0, shoY+13); g.closePath(); g.fill();
- // ---- face ----
- const eyeY = by + 34;
- g.fillStyle = '#20140a';
- // eyes
- g.beginPath(); g.ellipse(-9, eyeY, 4, 6, 0, 0, Math.PI*2); g.fill();
- g.beginPath(); g.ellipse( 9, eyeY, 4, 6, 0, 0, Math.PI*2); g.fill();
- if (this.state!=='ko'){
- g.fillStyle='#fff';
- g.beginPath(); g.arc(-8, eyeY-2, 1.6,0,Math.PI*2); g.fill();
- g.beginPath(); g.arc(10, eyeY-2, 1.6,0,Math.PI*2); g.fill();
- }
- // angry brows
- g.strokeStyle='#20140a'; g.lineWidth=3; g.beginPath();
- g.moveTo(-15, eyeY-9); g.lineTo(-4, eyeY-5);
- g.moveTo( 15, eyeY-9); g.lineTo( 4, eyeY-5); g.stroke();
- // mouth
- g.beginPath();
- if (this.state==='ko'){ g.arc(0, eyeY+20, 6, 0, Math.PI, true); }
- else if (this.state==='hurt'){ g.arc(0, eyeY+18, 7, 0, Math.PI*2); }
- else if (this.attack){ g.arc(0, eyeY+16, 6, 0, Math.PI*2); }
- else { g.arc(0, eyeY+20, 8, 0.15*Math.PI, 0.85*Math.PI); }
- g.stroke();
-
- // ---- scarf (accent) ----
- g.fillStyle = c.accent;
- g.fillRect(-bw/2, by+bh*0.52, bw, 10);
- g.fillRect(bw/2-14, by+bh*0.52, 10, 26);
-
- // ---- arms ----
- const armExt = this.armSwing;
- g.strokeStyle = c.crustDk; g.lineWidth = 8; g.lineCap='round';
- // back arm
- g.beginPath(); g.moveTo(-bw*0.35, by+bh*0.45); g.lineTo(-bw*0.35-8, by+bh*0.62); g.stroke();
- // front arm (attacking)
- const shoulderX = bw*0.35, shoulderY = by+bh*0.44;
- let handX, handY;
- if (this.state==='swing'){
- const ang = -0.7 + armExt*2.0;
- handX = shoulderX + Math.cos(ang)*(46+armExt*34);
- handY = shoulderY + Math.sin(ang)*(46+armExt*34);
+ // ---- front arm + baguette weapon ----
+ const sx=this.w*0.2, sy=shoY+10;
+ let hx, hy, bang;
+ if (this.state==='swing'){ // overhead whack that sweeps down
+ bang = -2.1 + armExt*2.7;
+ hx = sx + 6 + Math.cos(bang)*6; hy = sy + 2 + Math.sin(bang)*6;
} else if (this.state==='poke' || (this.attack&&this.attack.type==='blast')){
- handX = shoulderX + (34 + armExt*30);
- handY = shoulderY + 6;
+ hx = sx + 12 + armExt*26; hy = sy + 8; bang = -0.12; // thrust / throw
} else if (this.state==='block'){
- handX = shoulderX - 6; handY = shoulderY + 4;
+ hx = sx - 2; hy = sy + 4; bang = -1.45; // raised guard
} else {
- handX = shoulderX + 6 + Math.sin(this.animT)*2; handY = shoulderY + 20;
+ hx = sx + 8 + Math.sin(this.animT)*2; hy = sy + 16; bang = -0.15; // held ready
}
- g.beginPath(); g.moveTo(shoulderX, shoulderY); g.lineTo(handX, handY); g.stroke();
- // little baguette-crumb fist
- g.fillStyle = c.crust; g.beginPath(); g.arc(handX, handY, 7, 0, Math.PI*2); g.fill();
+ g.strokeStyle=shirt; g.lineWidth=9; g.lineCap='round';
+ g.beginPath(); g.moveTo(sx, sy); g.lineTo(hx, hy); g.stroke();
+ const hideBag = this.attack && this.attack.type==='blast'; // baguette is airborne as a missile
+ if (!hideBag) drawBaguetteWeapon(g, hx, hy, bang, 46, true);
+ g.fillStyle=skin; g.beginPath(); g.arc(hx, hy, 5, 0, Math.PI*2); g.fill();
- // block shield shimmer
+ // block shimmer
if (this.state==='block'){
- g.strokeStyle='rgba(180,225,255,.8)'; g.lineWidth=3;
- g.beginPath(); g.arc(bw*0.2, by+bh*0.5, bw*0.6, -0.7, 0.7); g.stroke();
+ g.strokeStyle='rgba(180,225,255,.85)'; g.lineWidth=3;
+ g.beginPath(); g.arc(this.w*0.12, shoY+thh*0.4, this.w*0.55, -0.7, 0.7); g.stroke();
}
- // ---- legs ----
- g.strokeStyle=c.crustDk; g.lineWidth=8;
- const legPhase = this.state==='walk'? Math.sin(this.animT):0;
- g.beginPath(); g.moveTo(-10, by+bh-6); g.lineTo(-12 - legPhase*8, by+bh+10); g.stroke();
- g.beginPath(); g.moveTo( 10, by+bh-6); g.lineTo( 12 + legPhase*8, by+bh+10); g.stroke();
+ // ---- head ----
+ g.save();
+ g.translate(2, headCY);
+ g.fillStyle=skin; g.fillRect(-4, headR-5, 8, 8); // neck
+ g.fillStyle = hurtFlash ? '#ffffff' : skin; // face
+ g.beginPath(); g.arc(0,0,headR,0,Math.PI*2); g.fill();
+ g.strokeStyle=skinDk; g.lineWidth=1.5; g.stroke();
+ g.fillStyle=skin; g.beginPath(); g.arc(-headR+2, 2, 3, 0, Math.PI*2); g.fill(); // ear
+ if (this.state==='ko'){
+ g.strokeStyle='#20140a'; g.lineWidth=2;
+ for (const ex of [4,10]){ g.beginPath(); g.moveTo(ex-2,-5); g.lineTo(ex+2,-1); g.moveTo(ex+2,-5); g.lineTo(ex-2,-1); g.stroke(); }
+ } else {
+ g.fillStyle='#20140a';
+ g.beginPath(); g.arc(5,-3,2,0,Math.PI*2); g.fill();
+ g.beginPath(); g.arc(11,-3,2,0,Math.PI*2); g.fill();
+ g.strokeStyle='#20140a'; g.lineWidth=2.5;
+ g.beginPath(); g.moveTo(1,-8); g.lineTo(8,-5); g.moveTo(8,-6); g.lineTo(14,-8); g.stroke(); // brows
+ }
+ // grand moustache
+ g.strokeStyle='#3b2415'; g.lineWidth=3; g.lineCap='round';
+ g.beginPath(); g.moveTo(1,6); g.quadraticCurveTo(5,3,9,5);
+ g.moveTo(9,5); g.quadraticCurveTo(12,3,15,7); g.stroke();
+ // mouth
+ g.strokeStyle='#20140a'; g.lineWidth=2; g.beginPath();
+ if (this.state==='hurt') g.arc(7, 9, 3.5, 0, Math.PI*2);
+ else if (this.attack) g.arc(7, 9, 3, 0, Math.PI*2);
+ else g.arc(7, 8, 4, 0.1*Math.PI, 0.9*Math.PI);
+ g.stroke();
+ // ---- beret (hat) ----
+ g.fillStyle=c.beret;
+ g.beginPath(); g.ellipse(1, -headR+3, headR*0.98, 5.5, 0, 0, Math.PI*2); g.fill();
+ g.beginPath(); g.arc(1, -headR-2, headR*0.86, Math.PI, 0); g.fill();
+ g.fillStyle='#1a1a1a'; g.beginPath(); g.arc(headR*0.55, -headR-3, 2.2, 0, Math.PI*2); g.fill(); // stalk
+ g.restore();
g.restore(); // bob/ko
g.restore(); // translate/scale
}
}
+ // draws a baguette starting at (x,y) extending length `len` along +x, rotated by `angle`
+ function drawBaguetteWeapon(g, x, y, angle, len, glow){
+ g.save();
+ g.translate(x,y); g.rotate(angle);
+ const bw = 9;
+ g.shadowColor='#ffcf6b'; g.shadowBlur = glow?10:0;
+ roundRectPath(g, 0, -bw/2, len, bw, bw/2);
+ const grd = g.createLinearGradient(0,-bw/2,0,bw/2);
+ grd.addColorStop(0,'#e9c079'); grd.addColorStop(.5,'#d9a441'); grd.addColorStop(1,'#a9761f');
+ g.fillStyle = grd; g.fill();
+ g.shadowBlur = 0;
+ g.lineWidth = 1.5; g.strokeStyle = 'rgba(90,55,15,.65)'; g.stroke();
+ // score marks
+ g.strokeStyle = 'rgba(110,66,18,.8)'; g.lineWidth = 1.6;
+ for (let i=1;i<4;i++){ const xx = len*i/4; g.beginPath(); g.moveTo(xx-3,-2); g.quadraticCurveTo(xx, -bw*0.6, xx+3,-1); g.stroke(); }
+ // rounded tips highlight
+ g.fillStyle='rgba(255,245,220,.35)'; g.beginPath(); g.ellipse(len-3,0,2.5,bw*0.28,0,0,Math.PI*2); g.fill();
+ g.restore();
+ }
+
function roundRectPath(g,x,y,w,h,r){
r = Math.min(r, w/2, h/2);
g.beginPath();
@@ -657,8 +671,8 @@
// ---------- Projectiles & particles ----------
let blasts = [], sparks = [], hazards = [], hazardTimer = 140, shake = 0;
function spawnBlast(owner){
- blasts.push({ x: owner.x + owner.facing*owner.w*0.5, y: owner.y - owner.h*0.5,
- vx: owner.facing*10, r: 16, owner, life: 90, t:0 });
+ blasts.push({ x: owner.x + owner.facing*owner.w*0.5, y: owner.y - owner.h*0.62,
+ vx: owner.facing*11, r: 22, owner, life: 90, t:0, rot: 0 });
}
function spawnSpark(x,y,color,n){
for (let i=0;i<n;i++){
@@ -668,7 +682,7 @@
}
function updateProjectiles(f1,f2){
for (const b of blasts){
- b.t++; b.x += b.vx; b.life--;
+ b.t++; b.x += b.vx; b.rot += 0.5*Math.sign(b.vx); b.life--;
const foe = b.owner === f1 ? f2 : f1;
const hb = foe.hurtbox();
if (b.x+b.r > hb.x && b.x-b.r < hb.x+hb.w && b.y+b.r>hb.y && b.y-b.r<hb.y+hb.h){
@@ -684,14 +698,13 @@
for (const b of blasts){
const c = b.owner.colors;
g.save();
- g.globalAlpha = 0.9;
- g.shadowColor = c.glow; g.shadowBlur = 24;
- const grd = g.createRadialGradient(b.x,b.y,2,b.x,b.y,b.r);
- grd.addColorStop(0,'#fff'); grd.addColorStop(0.4,c.crust); grd.addColorStop(1,c.glow);
- g.fillStyle = grd;
- g.beginPath(); g.arc(b.x,b.y,b.r,0,Math.PI*2); g.fill();
- // trailing crumbs
- for (let i=1;i<=3;i++){ g.globalAlpha=0.4/i; g.beginPath(); g.arc(b.x-b.vx*i*1.6,b.y,b.r*(1-i*0.2),0,Math.PI*2); g.fill(); }
+ // motion trail
+ g.fillStyle = c.glow;
+ for (let i=1;i<=4;i++){ g.globalAlpha = 0.28/i; g.beginPath(); g.arc(b.x-b.vx*i*1.5, b.y, 7-i, 0, Math.PI*2); g.fill(); }
+ // the spinning baguette missile
+ g.globalAlpha = 1;
+ g.translate(b.x, b.y); g.rotate(b.rot);
+ drawBaguetteWeapon(g, -24, 0, 0, 48, true); // centered on flight path
g.restore();
}
for (const s of sparks){
@@ -933,7 +946,7 @@
if (val>=100){ g.shadowColor=c.glow; g.shadowBlur=10; }
g.fillRect(bx,y,bw,h); g.shadowBlur=0;
if (val>=100){ g.fillStyle=c.accent; g.font='700 9px Georgia'; g.textAlign=flip?'right':'left';
- g.fillText('CRUMB BLAST READY', flip?x+w:x, y+18); g.textAlign='left'; }
+ g.fillText('BAGUETTE MISSILE READY', flip?x+w:x, y+18); g.textAlign='left'; }
}
function drawPips(g,x,y,n,flip){
for (let i=0;i<2;i++){
@@ -959,23 +972,31 @@
function drawMini(g, c){
g.clearRect(0,0,56,70);
- g.save(); g.translate(28, 37);
- const bw = 24, bh = 52;
- roundRectPath(g, -bw/2, -bh/2, bw, bh, bw/2);
- const grd = g.createLinearGradient(-bw/2,0,bw/2,0);
- grd.addColorStop(0,c.crustDk); grd.addColorStop(.5,c.crust); grd.addColorStop(1,c.crustDk);
- g.fillStyle = grd; g.fill();
- g.lineWidth = 2; g.strokeStyle = 'rgba(90,55,15,.7)'; g.stroke();
- g.strokeStyle = 'rgba(120,72,20,.85)'; g.lineWidth = 2;
- for (let i=0;i<4;i++){ const yy = -bh/2+11+i*11; g.beginPath(); g.moveTo(-5,yy); g.quadraticCurveTo(0,yy-4,6,yy-1); g.stroke(); }
- g.fillStyle = c.beret; g.beginPath(); g.ellipse(1,-bh/2+1,bw*0.5,4.5,0,0,Math.PI*2); g.fill();
- g.beginPath(); g.arc(1,-bh/2-3,bw*0.4,Math.PI,0); g.fill();
- g.fillStyle = '#20140a';
- g.beginPath(); g.arc(-4.5,-bh/2+15,2.2,0,Math.PI*2); g.fill();
- g.beginPath(); g.arc(4.5,-bh/2+15,2.2,0,Math.PI*2); g.fill();
- g.strokeStyle='#20140a'; g.lineWidth=2; g.beginPath();
- g.moveTo(-8,-bh/2+9); g.lineTo(-2,-bh/2+12); g.moveTo(8,-bh/2+9); g.lineTo(2,-bh/2+12); g.stroke();
- g.fillStyle = c.accent; g.fillRect(-bw/2, bh*0.16, bw, 4);
+ g.save(); g.translate(28, 64); // feet near bottom
+ const skin='#e8b892';
+ // legs
+ g.strokeStyle='#242a42'; g.lineWidth=6; g.lineCap='round';
+ g.beginPath(); g.moveTo(-5,-20); g.lineTo(-6,-2); g.stroke();
+ g.beginPath(); g.moveTo( 5,-20); g.lineTo( 6,-2); g.stroke();
+ // striped torso
+ const tw=20, th=22, tx=-tw/2, ty=-44;
+ roundRectPath(g,tx,ty,tw,th,5); g.fillStyle='#f2efe6'; g.fill();
+ g.save(); roundRectPath(g,tx,ty,tw,th,5); g.clip(); g.fillStyle=c.accent;
+ for (let sy=ty+3; sy<ty+th; sy+=6) g.fillRect(tx,sy,tw,3); g.restore();
+ g.lineWidth=1.4; g.strokeStyle='rgba(0,0,0,.25)'; roundRectPath(g,tx,ty,tw,th,5); g.stroke();
+ // arm + held baguette
+ g.strokeStyle='#f2efe6'; g.lineWidth=5; g.beginPath(); g.moveTo(6,-40); g.lineTo(13,-34); g.stroke();
+ drawBaguetteWeapon(g, 13, -34, -0.15, 22, false);
+ g.fillStyle=skin; g.beginPath(); g.arc(13,-34,3,0,Math.PI*2); g.fill();
+ // head
+ g.save(); g.translate(0,-50);
+ g.fillStyle=skin; g.beginPath(); g.arc(0,0,9,0,Math.PI*2); g.fill();
+ g.strokeStyle='#3b2415'; g.lineWidth=2; g.lineCap='round';
+ g.beginPath(); g.moveTo(-4,3); g.quadraticCurveTo(-1,1,0,3); g.moveTo(0,3); g.quadraticCurveTo(1,1,4,3); g.stroke(); // moustache
+ g.fillStyle='#20140a'; g.beginPath(); g.arc(-3,-1,1.4,0,7); g.fill(); g.beginPath(); g.arc(3,-1,1.4,0,7); g.fill();
+ g.fillStyle=c.beret; g.beginPath(); g.ellipse(0,-8,10,3.5,0,0,Math.PI*2); g.fill();
+ g.beginPath(); g.arc(1,-11,8,Math.PI,0); g.fill();
+ g.restore();
g.restore();
}
diff --git a/screenshot.png b/screenshot.png
deleted file mode 100644
index 0a9643b..0000000
Binary files a/screenshot.png and /dev/null differ
diff --git a/select.png b/select.png
deleted file mode 100644
index 4c871e9..0000000
Binary files a/select.png and /dev/null differ
← b93e403 Add two-player character select: 6 baguette fighters with Sp
·
back to Neon Baguette Battle
·
Bigger, faster baguette missile + alternate 1P controls (arr 4fcd312 →