Skip to content

Commit 8baaf33

Browse files
committed
Add mobile responsive styles, new scenarios, and visual improvements
- Mobile responsive CSS: proper layout for small screens and landscape - Two new scenarios: Convoy (escort tanker) and Duel (frigate combat) - Improved minimap viewport indicator with filled highlight - Gravity deflection arrows on course preview paths
1 parent df5eb91 commit 8baaf33

File tree

4 files changed

+213
-8
lines changed

4 files changed

+213
-8
lines changed

src/client/renderer.ts

Lines changed: 40 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -724,6 +724,31 @@ export class Renderer {
724724
ctx.stroke();
725725
ctx.setLineDash([]);
726726

727+
// Show gravity deflection indicators along the path
728+
for (const grav of course.gravityEffects) {
729+
if (grav.strength === 'weak') continue; // weak has its own toggle UI
730+
const gp = hexToPixel(grav.hex, HEX_SIZE);
731+
const dp = hexToPixel(hexAdd(grav.hex, HEX_DIRECTIONS[grav.direction]), HEX_SIZE);
732+
const angle = Math.atan2(dp.y - gp.y, dp.x - gp.x);
733+
const arrowLen = 7;
734+
const ax = gp.x + Math.cos(angle) * arrowLen;
735+
const ay = gp.y + Math.sin(angle) * arrowLen;
736+
ctx.strokeStyle = 'rgba(255, 200, 50, 0.6)';
737+
ctx.lineWidth = 1.5;
738+
ctx.beginPath();
739+
ctx.moveTo(gp.x, gp.y);
740+
ctx.lineTo(ax, ay);
741+
ctx.stroke();
742+
// Arrowhead
743+
const headLen = 4;
744+
ctx.beginPath();
745+
ctx.moveTo(ax, ay);
746+
ctx.lineTo(ax - headLen * Math.cos(angle - 0.5), ay - headLen * Math.sin(angle - 0.5));
747+
ctx.moveTo(ax, ay);
748+
ctx.lineTo(ax - headLen * Math.cos(angle + 0.5), ay - headLen * Math.sin(angle + 0.5));
749+
ctx.stroke();
750+
}
751+
727752
// Ghost ship at destination
728753
if (!course.crashed) {
729754
this.drawShipIcon(ctx, to.x, to.y, ship.owner, 0.4, 0);
@@ -1534,14 +1559,21 @@ export class Renderer {
15341559
const vpW = vpBR.x - vpTL.x;
15351560
const vpH = vpBR.y - vpTL.y;
15361561

1537-
ctx.strokeStyle = 'rgba(255, 255, 255, 0.4)';
1538-
ctx.lineWidth = 1;
1539-
ctx.strokeRect(
1540-
Math.max(mmX, vpTL.x),
1541-
Math.max(mmY, vpTL.y),
1542-
Math.min(vpW, mmW),
1543-
Math.min(vpH, mmH),
1544-
);
1562+
// Clip viewport rect to minimap bounds
1563+
const clampedX = Math.max(mmX + 1, vpTL.x);
1564+
const clampedY = Math.max(mmY + 1, vpTL.y);
1565+
const clampedR = Math.min(mmX + mmW - 1, vpTL.x + vpW);
1566+
const clampedB = Math.min(mmY + mmH - 1, vpTL.y + vpH);
1567+
const clampedW = clampedR - clampedX;
1568+
const clampedH = clampedB - clampedY;
1569+
1570+
if (clampedW > 2 && clampedH > 2) {
1571+
ctx.fillStyle = 'rgba(79, 195, 247, 0.06)';
1572+
ctx.fillRect(clampedX, clampedY, clampedW, clampedH);
1573+
ctx.strokeStyle = 'rgba(79, 195, 247, 0.5)';
1574+
ctx.lineWidth = 1;
1575+
ctx.strokeRect(clampedX, clampedY, clampedW, clampedH);
1576+
}
15451577

15461578
ctx.restore();
15471579
}

src/shared/map-data.ts

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -317,6 +317,54 @@ export const SCENARIOS: Record<string, ScenarioDefinition> = {
317317
},
318318
],
319319
},
320+
convoy: {
321+
name: 'Convoy',
322+
description: 'Escort a tanker from Mars to Venus — pirates intercept',
323+
players: [
324+
{
325+
// Convoy: tanker + corvette escort, starting from Mars
326+
ships: [
327+
{ type: 'tanker', position: { q: 10, r: 8 }, velocity: { dq: 0, dr: 0 } },
328+
{ type: 'corvette', position: { q: 10, r: 8 }, velocity: { dq: 0, dr: 0 } },
329+
],
330+
targetBody: 'Venus',
331+
homeBody: 'Mars',
332+
escapeWins: false,
333+
},
334+
{
335+
// Pirates: 2 corsairs lurking in the asteroid belt
336+
ships: [
337+
{ type: 'corsair', position: { q: 3, r: 3 }, velocity: { dq: 0, dr: 0 }, startLanded: false },
338+
{ type: 'corsair', position: { q: -2, r: 5 }, velocity: { dq: 0, dr: 0 }, startLanded: false },
339+
],
340+
targetBody: '',
341+
homeBody: '',
342+
escapeWins: false,
343+
},
344+
],
345+
},
346+
duel: {
347+
name: 'Duel',
348+
description: 'Frigates clash near Mercury — last ship standing wins',
349+
players: [
350+
{
351+
ships: [
352+
{ type: 'frigate', position: { q: 5, r: -3 }, velocity: { dq: 0, dr: 0 }, startLanded: false },
353+
],
354+
targetBody: '',
355+
homeBody: 'Mercury',
356+
escapeWins: false,
357+
},
358+
{
359+
ships: [
360+
{ type: 'frigate', position: { q: 9, r: -1 }, velocity: { dq: 0, dr: 0 }, startLanded: false },
361+
],
362+
targetBody: '',
363+
homeBody: 'Mercury',
364+
escapeWins: false,
365+
},
366+
],
367+
},
320368
};
321369

322370
// Singleton map instance

static/index.html

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,14 @@ <h2 class="scenario-title">Select Scenario</h2>
4343
<div class="scenario-name">Escape</div>
4444
<div class="scenario-desc">3 pilgrim transports flee — enforcers must stop them</div>
4545
</button>
46+
<button class="btn btn-scenario" data-scenario="convoy">
47+
<div class="scenario-name">Convoy</div>
48+
<div class="scenario-desc">Escort a tanker from Mars to Venus — pirates intercept</div>
49+
</button>
50+
<button class="btn btn-scenario" data-scenario="duel">
51+
<div class="scenario-name">Duel</div>
52+
<div class="scenario-desc">Frigates clash near Mercury — last ship standing wins</div>
53+
</button>
4654
<button id="backBtn" class="btn btn-secondary" style="margin-top: 1rem">Back</button>
4755
</div>
4856
</div>

static/style.css

Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -615,3 +615,120 @@ body {
615615
width: 100%;
616616
margin-bottom: 0.5rem;
617617
}
618+
619+
/* Mobile responsive */
620+
@media (max-width: 600px) {
621+
.title {
622+
font-size: 2rem;
623+
letter-spacing: 0.2em;
624+
}
625+
626+
.subtitle {
627+
font-size: 0.75rem;
628+
margin-bottom: 1.5rem;
629+
}
630+
631+
.menu-content {
632+
padding: 1.2rem;
633+
max-width: 300px;
634+
}
635+
636+
.hud-bar {
637+
flex-wrap: wrap;
638+
gap: 0.2rem;
639+
padding: 0.4rem 0.5rem;
640+
font-size: 0.7rem;
641+
}
642+
643+
.hud-bottom {
644+
flex-wrap: wrap;
645+
gap: 0.4rem;
646+
padding: 0.5rem;
647+
}
648+
649+
.status-msg {
650+
font-size: 0.7rem;
651+
width: 100%;
652+
}
653+
654+
.btn-confirm, .btn-attack {
655+
padding: 0.5rem 1.5rem;
656+
font-size: 0.85rem;
657+
}
658+
659+
.btn-ordnance {
660+
padding: 0.5rem 1rem;
661+
font-size: 0.75rem;
662+
}
663+
664+
.ship-list {
665+
top: auto;
666+
bottom: 5rem;
667+
left: 0.3rem;
668+
max-height: 30vh;
669+
overflow-y: auto;
670+
}
671+
672+
.ship-entry {
673+
font-size: 0.6rem;
674+
min-width: 100px;
675+
padding: 0.25rem 0.4rem;
676+
}
677+
678+
.game-log {
679+
top: auto;
680+
bottom: 5rem;
681+
right: 0.3rem;
682+
width: 160px;
683+
max-height: 30vh;
684+
}
685+
686+
.log-entries {
687+
font-size: 0.55rem;
688+
}
689+
690+
.game-code {
691+
font-size: 1.8rem;
692+
letter-spacing: 0.3em;
693+
}
694+
695+
.objective-text {
696+
font-size: 0.6rem;
697+
}
698+
699+
.latency-text {
700+
font-size: 0.55rem;
701+
}
702+
703+
.help-content {
704+
max-width: 280px;
705+
font-size: 0.85rem;
706+
}
707+
708+
.help-key {
709+
min-width: 90px;
710+
}
711+
712+
#gameOver h2 {
713+
font-size: 1.5rem;
714+
}
715+
}
716+
717+
@media (max-height: 500px) {
718+
/* Landscape mobile */
719+
.ship-list {
720+
top: 2.5rem;
721+
bottom: auto;
722+
max-height: 50vh;
723+
}
724+
725+
.game-log {
726+
top: 2.5rem;
727+
bottom: auto;
728+
max-height: 50vh;
729+
}
730+
731+
.hud-bottom {
732+
padding: 0.3rem;
733+
}
734+
}

0 commit comments

Comments
 (0)