← back to Neon Baguette Battle
Bigger, faster baguette missile + alternate 1P controls (arrows to move, Space/Cmd/Ctrl to fire)
4fcd312841a805533db920504f28e3b7f3c4ab71 · 2026-08-31 13:29:46 -0700 · Steve Abrams
- Missile: velocity 11->19, size/hitbox 22->34, 1.5x render scale, faster spin, longer trail
- Array-based control maps; 1-player P1 also drives with arrows (up=jump, down=block)
- New 'fire' action (Space, Left/Right Command, Control): launches missile if meter full, else whack
- Menu hint + README document the alternate scheme
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Files touched
Diff
commit 4fcd312841a805533db920504f28e3b7f3c4ab71
Author: Steve Abrams <steve@designerwallcoverings.com>
Date: Mon Aug 31 13:29:46 2026 -0700
Bigger, faster baguette missile + alternate 1P controls (arrows to move, Space/Cmd/Ctrl to fire)
- Missile: velocity 11->19, size/hitbox 22->34, 1.5x render scale, faster spin, longer trail
- Array-based control maps; 1-player P1 also drives with arrows (up=jump, down=block)
- New 'fire' action (Space, Left/Right Command, Control): launches missile if meter full, else whack
- Menu hint + README document the alternate scheme
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
---
README.md | 5 +++++
index.html | 47 +++++++++++++++++++++++++++--------------------
2 files changed, 32 insertions(+), 20 deletions(-)
diff --git a/README.md b/README.md
index 5f3583d..a6da8e9 100644
--- a/README.md
+++ b/README.md
@@ -37,6 +37,11 @@ also click a card to choose P1's fighter. `Enter`/`Space` or **START FIGHT** beg
| Pause | `P` | |
| Mute (audio + voice) | `M` | |
+**1-player alternate scheme (P1):** you can also play with the **arrow keys**
+(`←`/`→` move, `↑` jump, `↓` block) and **fire** with **`Space`**, **`⌘`
+Command**, or **`Ctrl`** — fire launches the baguette missile when the meter is
+full, otherwise it does a whack. (In 2-player the arrows belong to Player 2.)
+
## Features
- **Real combat**: startup/active/recovery attack frames, blocking with chip
damage, knockback, hit-stun, a build-up special meter, and a **launched
diff --git a/index.html b/index.html
index 872a307..e7c2b4f 100644
--- a/index.html
+++ b/index.html
@@ -126,7 +126,7 @@
</table>
</div>
</div>
- <div class="tiny">Press <span class="key">P</span> to pause · <span class="key">M</span> mute</div>
+ <div class="tiny">1-Player also: <span class="key">←</span><span class="key">→</span> move · <span class="key">↑</span> jump · <span class="key">↓</span> block · <span class="key">Space</span>/<span class="key">⌘</span>/<span class="key">Ctrl</span> fire · <span class="key">P</span> pause · <span class="key">M</span> mute</div>
</div>
<!-- CHARACTER SELECT -->
@@ -264,8 +264,12 @@
// ---------- Input ----------
const keys = {};
- const P1MAP = { left:'a', right:'d', jump:'w', block:'s', poke:'f', swing:'g', blast:'h' };
- const P2MAP = { left:'arrowleft', right:'arrowright', jump:'arrowup', block:'arrowdown', poke:',', swing:'.', blast:'/' };
+ // maps are arrays so an action can have several keys. 'fire' = launch missile if meter full, else whack.
+ const P1_ATTACK = { poke:['f'], swing:['g'], blast:['h'], fire:[' ','meta','control'] };
+ const P1MAP_1P = { left:['a','arrowleft'], right:['d','arrowright'], jump:['w','arrowup'], block:['s','arrowdown'], ...P1_ATTACK };
+ const P1MAP_2P = { left:['a'], right:['d'], jump:['w'], block:['s'], ...P1_ATTACK }; // arrows belong to P2 in 2P
+ const P2MAP = { left:['arrowleft'], right:['arrowright'], jump:['arrowup'], block:['arrowdown'], poke:[','], swing:['.'], blast:['/'] };
+ let p1map = P1MAP_1P;
addEventListener('keydown', e => {
const k = e.key.toLowerCase();
if (['arrowup','arrowdown','arrowleft','arrowright',' ','/'].includes(k)) e.preventDefault();
@@ -398,19 +402,21 @@
controlHuman(map){
if (this.state==='hurt'||this.state==='ko') return;
- const left = keys[map.left], right = keys[map.right];
+ const down = a => a && a.some(k => keys[k]);
+ const hit = a => { if (!a) return false; let h=false; for (const k of a){ if (keys['_pressed_'+k]){ keys['_pressed_'+k]=false; h=true; } } return h; };
const speed = this.spd;
- const canMove = !this.attack;
- if (canMove){
- if (left && !right){ this.vx = -speed; this.facing = -1; }
- else if (right && !left){ this.vx = speed; this.facing = 1; }
+ const L = down(map.left), R = down(map.right);
+ if (!this.attack){
+ if (L && !R){ this.vx = -speed; this.facing = -1; }
+ else if (R && !L){ this.vx = speed; this.facing = 1; }
}
- if (keys[map.block] && this.onGround && !this.attack){ this.state = 'block'; }
+ if (down(map.block) && this.onGround && !this.attack){ this.state = 'block'; }
else if (this.state==='block'){ this.state = 'idle'; }
- if (pressed(map.jump) && this.onGround && !this.attack){ this.vy = -16; this.onGround = false; Audio.jump(); }
- if (pressed(map.poke)) this.startAttack('poke');
- if (pressed(map.swing)) this.startAttack('swing');
- if (pressed(map.blast)) this.startAttack('blast');
+ if (hit(map.jump) && this.onGround && !this.attack){ this.vy = -16; this.onGround = false; Audio.jump(); }
+ if (hit(map.poke)) this.startAttack('poke');
+ if (hit(map.swing)) this.startAttack('swing');
+ if (hit(map.blast)) this.startAttack('blast');
+ if (hit(map.fire)) this.startAttack(this.meter >= 100 ? 'blast' : 'swing'); // Space / ⌘ / Ctrl
}
controlAI(foe){
@@ -672,7 +678,7 @@
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.62,
- vx: owner.facing*11, r: 22, owner, life: 90, t:0, rot: 0 });
+ vx: owner.facing*19, r: 34, owner, life: 90, t:0, rot: 0 }); // fast + big
}
function spawnSpark(x,y,color,n){
for (let i=0;i<n;i++){
@@ -682,7 +688,7 @@
}
function updateProjectiles(f1,f2){
for (const b of blasts){
- b.t++; b.x += b.vx; b.rot += 0.5*Math.sign(b.vx); b.life--;
+ b.t++; b.x += b.vx; b.rot += 0.7*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){
@@ -700,11 +706,11 @@
g.save();
// 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
+ for (let i=1;i<=6;i++){ g.globalAlpha = 0.30/i; g.beginPath(); g.arc(b.x-b.vx*i*0.9, b.y, 12-i, 0, Math.PI*2); g.fill(); }
+ // the big 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.translate(b.x, b.y); g.rotate(b.rot); g.scale(1.5, 1.5);
+ drawBaguetteWeapon(g, -33, 0, 0, 66, true); // centered on flight path
g.restore();
}
for (const s of sparks){
@@ -1061,6 +1067,7 @@
}
function beginSelectedMatch(){
if (!(p1Ready && p2Ready)) return;
+ p1map = (mode==='2p') ? P1MAP_2P : P1MAP_1P; // 1P: P1 also gets arrows + space/⌘
f1 = new Fighter(W*0.32,'p1', ROSTER[p1Idx], true);
f2 = new Fighter(W*0.68,'p2', ROSTER[p2Idx], mode==='2p');
f1.rounds=0; f2.rounds=0; roundNum=1;
@@ -1171,7 +1178,7 @@
roundTimer += dt; roundTime = Math.max(0, 60 - roundTimer/60*60*0); // handled below
roundTime = Math.max(0, 60 - roundTimer/60);
// control
- if (f1.human) f1.controlHuman(P1MAP); else f1.controlAI(f2);
+ if (f1.human) f1.controlHuman(p1map); else f1.controlAI(f2);
if (f2.human) f2.controlHuman(P2MAP); else f2.controlAI(f1);
f1.update(f2); f2.update(f1);
resolveHits(f1,f2); resolveHits(f2,f1);
← d93d9ac Redesign fighters as Frenchmen in berets wielding baguettes;
·
back to Neon Baguette Battle
·
Play La Marseillaise on load + cobblestone street floor stre 125754f →