Skip to content

Commit 91d7ac3

Browse files
committed
Add browser-based prototype for Factory Launch
1 parent 839ceb3 commit 91d7ac3

19 files changed

Lines changed: 1414 additions & 1 deletion

README.md

Lines changed: 39 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,39 @@
1-
# Factory_Launch
1+
# Factory Launch
2+
3+
Factory Launch is a research-driven resource management and automation prototype inspired by **Factorio** and **Immortality Factory**. The project now includes a browser-playable build that can be hosted on GitHub Pages for quick playtesting alongside the original Python simulation code.
4+
5+
## What's Included
6+
7+
- **Static Web Client**`index.html`, `css/`, and `js/` provide a standalone build that runs entirely in the browser. The interface lets you gather resources, contribute to research, fuel coal drills, manage clustering bonuses, and operate the starter stone smelter.
8+
- **Simulation Logic in JavaScript** – Modular ES6 scripts (`js/gameState.js`, `js/machines.js`, `js/storage.js`, and `js/constants.js`) mirror the original game systems and drive the UI. Everything runs locally with no server dependencies, making it ideal for GitHub Pages hosting.
9+
- **Python Core Simulation (Legacy)** – The earlier Python game-state package and tests remain in place for reference and future backend tooling.
10+
11+
## Getting Started
12+
13+
Open `index.html` directly in a browser or serve the repository with any static web host. For GitHub Pages, place the repository on a branch configured for Pages (for example `main` or `gh-pages`) and enable Pages in the repository settings—the client works without any build step.
14+
15+
Local development using a lightweight HTTP server:
16+
17+
```bash
18+
python -m http.server 8000
19+
# then visit http://localhost:8000
20+
```
21+
22+
## Gameplay Overview
23+
24+
1. **Manual Gathering** – Use the gather buttons to collect the starting stone, coal, iron, and copper required for the first research node.
25+
2. **Research Progression** – Contribute resources to unlock coal-powered drills and the stone smelter. Progress bars reflect how close you are to completing the initial tech.
26+
3. **Coal-Powered Drills** – Configure each drill to mine a specific resource, adjust the cluster size (1x1, 2x2, 3x3) to earn production bonuses, and refuel them with coal.
27+
4. **Stone Smelter** – Switch between iron and copper plate recipes and keep the smelter powered with coal to transform raw ore into processed materials.
28+
5. **Storage & Inventory** – The UI surfaces player inventory and the starting storage chests, honoring stack limits of 50 (player) and 999 (chests).
29+
30+
## Automated Tests
31+
32+
The Python simulation is still covered by a pytest suite:
33+
34+
```bash
35+
pip install -r requirements-dev.txt
36+
pytest
37+
```
38+
39+
The tests validate drill clustering, smelting throughput, research costs, and inventory limits in the Python reference implementation.

css/styles.css

Lines changed: 222 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,222 @@
1+
:root {
2+
--bg: #0e1016;
3+
--bg-panel: #171b26;
4+
--accent: #ffae42;
5+
--accent-dark: #d98b1a;
6+
--text: #f4f5f7;
7+
--muted: #9aa0b5;
8+
--success: #4caf50;
9+
--danger: #ff6b6b;
10+
font-size: 16px;
11+
}
12+
13+
* {
14+
box-sizing: border-box;
15+
}
16+
17+
body {
18+
margin: 0;
19+
font-family: "Segoe UI", system-ui, -apple-system, sans-serif;
20+
background: radial-gradient(circle at top, #1f2a44, #0e1016 60%);
21+
color: var(--text);
22+
min-height: 100vh;
23+
display: flex;
24+
flex-direction: column;
25+
}
26+
27+
.app-header,
28+
.app-footer {
29+
text-align: center;
30+
padding: 1.5rem 1rem;
31+
background: rgba(15, 19, 29, 0.8);
32+
backdrop-filter: blur(6px);
33+
border-bottom: 1px solid rgba(255, 255, 255, 0.05);
34+
}
35+
36+
.app-footer {
37+
border-top: 1px solid rgba(255, 255, 255, 0.05);
38+
border-bottom: none;
39+
}
40+
41+
.layout {
42+
flex: 1;
43+
display: grid;
44+
gap: 1.25rem;
45+
padding: 1.5rem;
46+
grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
47+
}
48+
49+
.panel {
50+
background: rgba(23, 27, 38, 0.95);
51+
border-radius: 12px;
52+
padding: 1rem 1.25rem 1.5rem;
53+
box-shadow: 0 18px 40px rgba(0, 0, 0, 0.25);
54+
display: flex;
55+
flex-direction: column;
56+
gap: 1rem;
57+
}
58+
59+
.panel h2 {
60+
margin: 0;
61+
font-size: 1.4rem;
62+
letter-spacing: 0.02em;
63+
}
64+
65+
button {
66+
background: rgba(255, 255, 255, 0.08);
67+
border: 1px solid rgba(255, 255, 255, 0.08);
68+
color: var(--text);
69+
border-radius: 8px;
70+
padding: 0.5rem 0.75rem;
71+
cursor: pointer;
72+
transition: transform 0.15s ease, background 0.2s ease, border 0.2s ease;
73+
}
74+
75+
button:hover {
76+
transform: translateY(-1px);
77+
background: rgba(255, 255, 255, 0.12);
78+
}
79+
80+
button.primary {
81+
background: var(--accent);
82+
border-color: var(--accent-dark);
83+
color: #1b1e27;
84+
font-weight: 600;
85+
}
86+
87+
button.primary:disabled {
88+
background: rgba(255, 255, 255, 0.2);
89+
border-color: rgba(255, 255, 255, 0.2);
90+
color: rgba(255, 255, 255, 0.6);
91+
cursor: not-allowed;
92+
}
93+
94+
.inventory-grid,
95+
.storage-grid {
96+
display: grid;
97+
grid-template-columns: repeat(auto-fill, minmax(120px, 1fr));
98+
gap: 0.75rem;
99+
}
100+
101+
.inventory-item,
102+
.storage-item {
103+
background: rgba(255, 255, 255, 0.04);
104+
border-radius: 10px;
105+
padding: 0.75rem;
106+
display: flex;
107+
flex-direction: column;
108+
gap: 0.35rem;
109+
border: 1px solid rgba(255, 255, 255, 0.06);
110+
}
111+
112+
.inventory-item h3,
113+
.storage-item h3 {
114+
margin: 0;
115+
font-size: 1rem;
116+
text-transform: capitalize;
117+
}
118+
119+
.inventory-item .meta,
120+
.storage-item .meta {
121+
font-size: 0.8rem;
122+
color: var(--muted);
123+
}
124+
125+
.gather-buttons {
126+
display: flex;
127+
flex-wrap: wrap;
128+
gap: 0.5rem;
129+
}
130+
131+
.machine-card {
132+
background: rgba(255, 255, 255, 0.05);
133+
border: 1px solid rgba(255, 255, 255, 0.06);
134+
border-radius: 10px;
135+
padding: 0.75rem;
136+
margin-bottom: 0.75rem;
137+
display: grid;
138+
gap: 0.5rem;
139+
}
140+
141+
.machine-card header {
142+
display: flex;
143+
justify-content: space-between;
144+
align-items: baseline;
145+
}
146+
147+
.machine-card h3 {
148+
margin: 0;
149+
}
150+
151+
.machine-card select,
152+
.machine-card input {
153+
width: 100%;
154+
padding: 0.35rem 0.5rem;
155+
border-radius: 6px;
156+
border: 1px solid rgba(255, 255, 255, 0.1);
157+
background: rgba(0, 0, 0, 0.2);
158+
color: var(--text);
159+
}
160+
161+
.machine-card .status {
162+
font-size: 0.85rem;
163+
color: var(--muted);
164+
}
165+
166+
.machine-card .status span {
167+
display: inline-flex;
168+
align-items: center;
169+
gap: 0.25rem;
170+
}
171+
172+
.machine-card .status .active {
173+
color: var(--success);
174+
}
175+
176+
.machine-card .status .inactive {
177+
color: var(--danger);
178+
}
179+
180+
.event-log-item {
181+
font-size: 0.85rem;
182+
padding: 0.35rem 0;
183+
border-bottom: 1px solid rgba(255, 255, 255, 0.04);
184+
color: var(--muted);
185+
}
186+
187+
.research-status {
188+
display: grid;
189+
gap: 0.5rem;
190+
font-size: 0.95rem;
191+
background: rgba(255, 255, 255, 0.04);
192+
padding: 0.75rem;
193+
border-radius: 10px;
194+
}
195+
196+
.progress {
197+
height: 8px;
198+
border-radius: 99px;
199+
overflow: hidden;
200+
background: rgba(255, 255, 255, 0.08);
201+
}
202+
203+
.progress-bar {
204+
height: 100%;
205+
width: 0%;
206+
background: linear-gradient(135deg, var(--accent), var(--accent-dark));
207+
transition: width 0.3s ease;
208+
}
209+
210+
.badge {
211+
padding: 0.15rem 0.4rem;
212+
border-radius: 999px;
213+
font-size: 0.7rem;
214+
background: rgba(255, 255, 255, 0.08);
215+
border: 1px solid rgba(255, 255, 255, 0.1);
216+
}
217+
218+
@media (max-width: 768px) {
219+
.layout {
220+
grid-template-columns: 1fr;
221+
}
222+
}

factory_launch/__init__.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
"""Factory Launch core game logic package."""
2+
3+
from .game_state import GameState
4+
from .research import ResearchNode, TechTree
5+
from .machines import CoalDrill, StoneSmelter
6+
from .storage import Inventory, StorageChest
7+
8+
__all__ = [
9+
"GameState",
10+
"ResearchNode",
11+
"TechTree",
12+
"CoalDrill",
13+
"StoneSmelter",
14+
"Inventory",
15+
"StorageChest",
16+
]

factory_launch/constants.py

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
"""Game balance constants."""
2+
3+
COAL_DRILL_COAL_PER_SECOND = 0.1 # 1 coal per 10 seconds
4+
COAL_DRILL_OUTPUT_PER_SECOND = 1.0
5+
6+
SMELTER_COAL_PER_SECOND = 0.2 # 1 coal per 5 seconds
7+
SMELTER_OUTPUT_PER_SECOND = 1.0
8+
9+
PLAYER_STACK_LIMIT = 50
10+
CHEST_STACK_LIMIT = 999
11+
12+
RESOURCE_TYPES = (
13+
"stone",
14+
"coal",
15+
"iron",
16+
"copper",
17+
"iron_plates",
18+
"copper_plates",
19+
)
20+
21+
SMELTER_RECIPES = {
22+
"stone": {"iron_plates": 1},
23+
"iron": {"iron_plates": 1},
24+
"copper": {"copper_plates": 1},
25+
}

0 commit comments

Comments
 (0)