diff --git a/components/ui/ButtonGroup.tsx b/components/ui/ButtonGroup.tsx
index 83e0642..60caac6 100644
--- a/components/ui/ButtonGroup.tsx
+++ b/components/ui/ButtonGroup.tsx
@@ -15,7 +15,8 @@ export default function ButtonGroup({ className, children, ...rest }: Props) {
*]:flex-1 [&>*]:rounded-none",
// keep focus rings visible inside the clipped container
From 9f97ce9666701b415623f9411d6cdf909dc41be1 Mon Sep 17 00:00:00 2001
From: Gilles <43683714+corp-0@users.noreply.github.com>
Date: Thu, 9 Jul 2026 13:50:12 -0400
Subject: [PATCH 2/7] fix: dead buttons on local mobile test
---
next.config.js | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/next.config.js b/next.config.js
index a365f31..cf9e4b0 100644
--- a/next.config.js
+++ b/next.config.js
@@ -2,6 +2,10 @@
module.exports = {
reactCompiler: true,
+ // Dev only: lets phones on the home network open the dev server via the
+ // machine's LAN IP. Without this Next blocks its /_next dev resources for
+ // non-localhost origins and pages render but never hydrate (dead buttons).
+ allowedDevOrigins: ["192.168.1.*"],
images: {
remotePatterns: [
{
From 0779b70f9176def080f2c56e40d69f13c9f89672 Mon Sep 17 00:00:00 2001
From: Gilles <43683714+corp-0@users.noreply.github.com>
Date: Thu, 9 Jul 2026 13:50:31 -0400
Subject: [PATCH 3/7] chore: new test for responsiveness
---
cypress/e2e/responsive.cy.ts | 123 +++++++++++++++++++++++++++++++++++
1 file changed, 123 insertions(+)
create mode 100644 cypress/e2e/responsive.cy.ts
diff --git a/cypress/e2e/responsive.cy.ts b/cypress/e2e/responsive.cy.ts
new file mode 100644
index 0000000..fe2d92e
--- /dev/null
+++ b/cypress/e2e/responsive.cy.ts
@@ -0,0 +1,123 @@
+/*
+ * Test if any route has unintended horizontal overflow at most common screens
+ */
+const WIDTHS = [320, 393, 640, 768, 1024];
+
+type Offender = { tag: string; cls: string; left: number; right: number };
+
+/** Elements sticking out horizontally at the current viewport width. */
+function findOverflowingElements(win: Window): Offender[] {
+ const doc = win.document;
+ const vw = doc.documentElement.clientWidth;
+ const offenders: Offender[] = [];
+
+ for (const el of Array.from(doc.querySelectorAll("body *"))) {
+ const rect = el.getBoundingClientRect();
+ if (rect.width === 0 && rect.height === 0) continue;
+ if (rect.right <= vw + 1 && rect.left >= -1) continue;
+
+ // Fixed overlays (parallax space, the clown's cage) clip themselves.
+ if (win.getComputedStyle(el).position === "fixed") continue;
+
+ // Skip elements an ancestor already clips or scrolls horizontally
+ let ancestor = el.parentElement;
+ let clipped = false;
+ while (ancestor && ancestor !== doc.body) {
+ if (/(hidden|clip|auto|scroll)/.test(win.getComputedStyle(ancestor).overflowX)) {
+ clipped = true;
+ break;
+ }
+ ancestor = ancestor.parentElement;
+ }
+ if (clipped) continue;
+
+ const cls = typeof el.className === "string" ? el.className : "";
+ offenders.push({
+ tag: el.tagName.toLowerCase(),
+ cls: cls.slice(0, 100),
+ left: Math.round(rect.left),
+ right: Math.round(rect.right),
+ });
+ }
+ return offenders;
+}
+
+function assertNoHorizontalOverflow(route: string) {
+ for (const width of WIDTHS) {
+ cy.viewport(width, 850);
+ // let the resize propagate and media queries re-evaluate
+ cy.wait(100);
+ cy.window().then((win) => {
+ const offenders = findOverflowingElements(win);
+ expect(
+ offenders,
+ `${route} @ ${width}px elements past the viewport edge:\n` +
+ JSON.stringify(offenders, null, 2),
+ ).to.have.length(0);
+ expect(
+ win.document.documentElement.scrollWidth,
+ `${route} @ ${width}px page scroll width`,
+ ).to.be.at.most(width + 1);
+ });
+ }
+}
+
+describe("Responsive layout", () => {
+ it("home has no horizontal overflow at any width", () => {
+ cy.visit("/");
+ cy.contains("h1", "Unitystation!").should("be.visible");
+ assertNoHorizontalOverflow("/");
+ });
+
+ it("download has no horizontal overflow at any width", () => {
+ cy.visit("/download");
+ cy.contains("h1", "Download Pudu Launcher").should("be.visible");
+ assertNoHorizontalOverflow("/download");
+ });
+
+ it("blog has no horizontal overflow at any width", () => {
+ cy.intercept("GET", /changelog\.unitystation\.org\/posts\/\?page=1$/, {
+ fixture: "blogPosts-page1.json",
+ }).as("postsPage1");
+ cy.intercept("GET", /changelog\.unitystation\.org\/posts\/\?page=2$/, {
+ fixture: "blogPosts-page2.json",
+ }).as("postsPage2");
+
+ cy.visit("/blog");
+ cy.wait("@postsPage1");
+ // materialise the infinite-scroll page before scanning
+ cy.scrollTo("bottom");
+ cy.wait("@postsPage2");
+ assertNoHorizontalOverflow("/blog");
+ });
+
+ it("changelog has no horizontal overflow at any width", () => {
+ cy.intercept("GET", /changelog\.unitystation\.org\/all-changes/, {
+ fixture: "changelog-page1.json",
+ }).as("changelog");
+
+ cy.visit("/changelog");
+ cy.wait("@changelog");
+ assertNoHorizontalOverflow("/changelog");
+ });
+
+ it("ledger has no horizontal overflow at any width", () => {
+ cy.intercept("GET", /ledger\.unitystation\.org\/movements\/$/, {
+ fixture: "ledger-page1.json",
+ }).as("ledgerPage1");
+
+ cy.visit("/ledger");
+ cy.wait("@ledgerPage1");
+ assertNoHorizontalOverflow("/ledger");
+ });
+
+ for (const route of ["/login", "/register", "/reset-password"]) {
+ it(`${route} has no horizontal overflow at any width`, () => {
+ cy.visit(route);
+ cy.get("h1").should("be.visible");
+ assertNoHorizontalOverflow(route);
+ });
+ }
+});
+
+export {};
From 92eb833c1e1548ac40ee7e194f59b0a29d4a15d3 Mon Sep 17 00:00:00 2001
From: Gilles <43683714+corp-0@users.noreply.github.com>
Date: Thu, 9 Jul 2026 13:51:16 -0400
Subject: [PATCH 4/7] fix: more mobile only fixes
---
components/home/Hero.tsx | 3 +--
components/home/RotatingTagline.tsx | 2 +-
2 files changed, 2 insertions(+), 3 deletions(-)
diff --git a/components/home/Hero.tsx b/components/home/Hero.tsx
index 89a89f8..e368278 100644
--- a/components/home/Hero.tsx
+++ b/components/home/Hero.tsx
@@ -40,8 +40,7 @@ export default function Hero() {
- {/* screenshot feed */}
-
diff --git a/components/home/RotatingTagline.tsx b/components/home/RotatingTagline.tsx
index 429bab2..985f45c 100644
--- a/components/home/RotatingTagline.tsx
+++ b/components/home/RotatingTagline.tsx
@@ -32,7 +32,7 @@ export default function RotatingTagline() {
}, []);
return (
-
+
{tagline}
);
From 616bf6e54988e7cb32f12d4ed9e5297ca0829a7e Mon Sep 17 00:00:00 2001
From: Gilles <43683714+corp-0@users.noreply.github.com>
Date: Thu, 9 Jul 2026 14:11:25 -0400
Subject: [PATCH 5/7] fix: test on ci failing
---
cypress/e2e/responsive.cy.ts | 1 +
1 file changed, 1 insertion(+)
diff --git a/cypress/e2e/responsive.cy.ts b/cypress/e2e/responsive.cy.ts
index fe2d92e..9e8e793 100644
--- a/cypress/e2e/responsive.cy.ts
+++ b/cypress/e2e/responsive.cy.ts
@@ -85,6 +85,7 @@ describe("Responsive layout", () => {
cy.visit("/blog");
cy.wait("@postsPage1");
+ cy.contains("h2", "Station reactor now explodes properly").should("be.visible");
// materialise the infinite-scroll page before scanning
cy.scrollTo("bottom");
cy.wait("@postsPage2");
From 21ad79a688d32d99e230f4fc63eff0127e10f37e Mon Sep 17 00:00:00 2001
From: MaxIsJoe <34368774+MaxIsJoe@users.noreply.github.com>
Date: Wed, 5 Aug 2026 11:42:47 +0300
Subject: [PATCH 6/7] Better screenshot feed (#139)
* Better screenshot feed
* Update ScreenshotFeed.tsx
* Update ScreenshotFeed.tsx
---
components/home/ScreenshotFeed.tsx | 9 ++-------
1 file changed, 2 insertions(+), 7 deletions(-)
diff --git a/components/home/ScreenshotFeed.tsx b/components/home/ScreenshotFeed.tsx
index 50898ec..23db43b 100644
--- a/components/home/ScreenshotFeed.tsx
+++ b/components/home/ScreenshotFeed.tsx
@@ -3,7 +3,6 @@
import classNames from "classnames";
import { useEffect, useState } from "react";
import PanelBar from "../ui/PanelBar";
-import StatusLight from "../ui/StatusLight";
const HERO_IMAGES: string[] = [
"https://cdn.unitystation.org/Website-Statics/heroImages/bar-engine.png",
@@ -57,11 +56,6 @@ export default function ScreenshotFeed() {
className="absolute -right-4 -top-4 hidden h-full w-full rounded-lg border border-seam bg-raised sm:block"
/>
-
-
- In-game screenshots
-
-
{HERO_IMAGES.map((src, i) =>
loaded.has(i) ? (
@@ -77,7 +71,7 @@ export default function ScreenshotFeed() {
/>
) : null,
)}
-
+
{/* Status bar: frame picker + counter */}
@@ -104,6 +98,7 @@ export default function ScreenshotFeed() {
/>
))}
+
In-game screenshots
{String(frame + 1).padStart(2, "0")} /{" "}
{String(HERO_IMAGES.length).padStart(2, "0")}
From 5b8212dbfb1645952712811a145811396a16f35d Mon Sep 17 00:00:00 2001
From: MaxIsJoe <34368774+MaxIsJoe@users.noreply.github.com>
Date: Wed, 5 Aug 2026 12:45:25 +0300
Subject: [PATCH 7/7] Expanded "About Unitystation" section (#140)
* add an underline to sectionintro
* Expanded "about unitystation"
* Update home.cy.ts
---
components/home/AboutSection.tsx | 15 +++++++++++----
components/ui/SectionIntro.tsx | 2 +-
cypress/e2e/home.cy.ts | 2 +-
3 files changed, 13 insertions(+), 6 deletions(-)
diff --git a/components/home/AboutSection.tsx b/components/home/AboutSection.tsx
index b48b3bf..2eb6a45 100644
--- a/components/home/AboutSection.tsx
+++ b/components/home/AboutSection.tsx
@@ -3,14 +3,21 @@ import SectionIntro from "../../components/ui/SectionIntro";
export default function AboutSection() {
return (
-
+
+
);
diff --git a/components/ui/SectionIntro.tsx b/components/ui/SectionIntro.tsx
index f9ca58a..681bfff 100644
--- a/components/ui/SectionIntro.tsx
+++ b/components/ui/SectionIntro.tsx
@@ -29,7 +29,7 @@ export default function SectionIntro({
-
{kicker}
+
{kicker}
{
});
it("renders the about and community sections", () => {
- cy.contains("What is Unitystation?").should("exist");
+ cy.contains("What is Space Station 13?").should("exist");
cy.contains("Pick a job and keep the station running.").should("exist");
cy.contains("h2", "Join the community playtest!").scrollIntoView().should("be.visible");
cy.contains("a", "Join the Discord").should(