|
13 | 13 | tools: [ |
14 | 14 | { |
15 | 15 | title: "Asset Studio", |
16 | | - href: "asset-studio.html", |
17 | | - image: "../assets/images/tools/asset-studio.png", |
| 16 | + href: "tools/asset-studio.html", |
| 17 | + image: "assets/images/tools/asset-studio.png", |
18 | 18 | description: "Create sprites, animations, vectors and palettes.", |
19 | 19 | role: "Pixel Smith", |
20 | 20 | mascot: "pixel-smith", |
|
27 | 27 | tools: [ |
28 | 28 | { |
29 | 29 | title: "Object Vector Studio", |
30 | | - href: "object-vector-studio.html", |
31 | | - image: "../assets/images/tools/object-vector-studio.png", |
| 30 | + href: "tools/object-vector-studio.html", |
| 31 | + image: "assets/images/tools/object-vector-studio.png", |
32 | 32 | description: "Create object-ready vector assets and reusable scene pieces.", |
33 | 33 | role: "Pixel Smith", |
34 | 34 | mascot: "pixel-smith", |
35 | 35 | theme: "pixel" |
36 | 36 | }, |
37 | 37 | { |
38 | 38 | title: "World Vector Studio", |
39 | | - href: "world-vector-studio.html", |
40 | | - image: "../assets/images/tools/world-vector-studio.png", |
| 39 | + href: "tools/world-vector-studio.html", |
| 40 | + image: "assets/images/tools/world-vector-studio.png", |
41 | 41 | description: "Shape world layouts, maps, terrain, and scene geometry.", |
42 | 42 | role: "Pixel Smith", |
43 | 43 | mascot: "pixel-smith", |
|
50 | 50 | tools: [ |
51 | 51 | { |
52 | 52 | title: "Palette Manager", |
53 | | - href: "palette-manager.html", |
54 | | - image: "../assets/images/tools/palette-manager.png", |
| 53 | + href: "tools/palette-manager.html", |
| 54 | + image: "assets/images/tools/palette-manager.png", |
55 | 55 | description: "Craft and manage color palettes for your games.", |
56 | 56 | role: "Pixel Smith", |
57 | 57 | mascot: "pixel-smith", |
|
64 | 64 | tools: [ |
65 | 65 | { |
66 | 66 | title: "Game Builder", |
67 | | - href: "game-builder.html", |
68 | | - image: "../assets/images/tools/game-builder.png", |
| 67 | + href: "tools/game-builder.html", |
| 68 | + image: "assets/images/tools/game-builder.png", |
69 | 69 | description: "Assemble components and build your game from scratch.", |
70 | 70 | role: "ForgeBot", |
71 | 71 | mascot: "forgebot", |
|
78 | 78 | tools: [ |
79 | 79 | { |
80 | 80 | title: "Game Design Studio", |
81 | | - href: "game-design-studio.html", |
82 | | - image: "../assets/images/tools/game-design-studio.png", |
| 81 | + href: "tools/game-design-studio.html", |
| 82 | + image: "assets/images/tools/game-design-studio.png", |
83 | 83 | description: "Design gameplay, systems, rules, and player experience.", |
84 | 84 | role: "ForgeBot", |
85 | 85 | mascot: "forgebot", |
|
92 | 92 | tools: [ |
93 | 93 | { |
94 | 94 | title: "Publish Studio", |
95 | | - href: "publisher.html", |
96 | | - image: "../assets/images/tools/publish-studio.png", |
| 95 | + href: "tools/publisher.html", |
| 96 | + image: "assets/images/tools/publish-studio.png", |
97 | 97 | description: "Prepare publishing workflows and release-ready game packages.", |
98 | 98 | role: "ForgeBot", |
99 | 99 | mascot: "forgebot", |
|
106 | 106 | tools: [ |
107 | 107 | { |
108 | 108 | title: "Animation Studio", |
109 | | - href: "animation-studio.html", |
110 | | - image: "../assets/images/tools/animation-studio.png", |
| 109 | + href: "tools/animation-studio.html", |
| 110 | + image: "assets/images/tools/animation-studio.png", |
111 | 111 | description: "Create timing, animation states, and motion workflows.", |
112 | 112 | role: "Spark", |
113 | 113 | mascot: "spark", |
114 | 114 | theme: "pixel" |
115 | 115 | }, |
116 | 116 | { |
117 | 117 | title: "Particle Studio", |
118 | | - href: "particle-studio.html", |
119 | | - image: "../assets/images/tools/particle-studio.png", |
| 118 | + href: "tools/particle-studio.html", |
| 119 | + image: "assets/images/tools/particle-studio.png", |
120 | 120 | description: "Author visual effects, emitters, and particle looks.", |
121 | 121 | role: "Spark", |
122 | 122 | mascot: "spark", |
|
129 | 129 | tools: [ |
130 | 130 | { |
131 | 131 | title: "MIDI Studio", |
132 | | - href: "midi-studio.html", |
133 | | - image: "../assets/images/tools/midi-studio.png", |
| 132 | + href: "tools/midi-studio.html", |
| 133 | + image: "assets/images/tools/midi-studio.png", |
134 | 134 | description: "Build MIDI-driven audio and music interaction flows.", |
135 | 135 | role: "Foundry Bot", |
136 | 136 | mascot: "foundry-bot", |
137 | 137 | theme: "bot" |
138 | 138 | }, |
139 | 139 | { |
140 | 140 | title: "Sound Studio", |
141 | | - href: "sound-studio.html", |
142 | | - image: "../assets/images/tools/sound-studio.png", |
| 141 | + href: "tools/sound-studio.html", |
| 142 | + image: "assets/images/tools/sound-studio.png", |
143 | 143 | description: "Prepare audio, sound effects, and game sound workflows.", |
144 | 144 | role: "Foundry Bot", |
145 | 145 | mascot: "foundry-bot", |
|
152 | 152 | tools: [ |
153 | 153 | { |
154 | 154 | title: "AI Assistant", |
155 | | - href: "ai-assistant.html", |
156 | | - image: "../assets/images/tools/ai-assistant.png", |
| 155 | + href: "tools/ai-assistant.html", |
| 156 | + image: "assets/images/tools/ai-assistant.png", |
157 | 157 | description: "Get guided technical help for game creation workflows.", |
158 | 158 | role: "Foundry Bot", |
159 | 159 | mascot: "foundry-bot", |
|
166 | 166 | tools: [ |
167 | 167 | { |
168 | 168 | title: "Code Studio", |
169 | | - href: "code-studio.html", |
170 | | - image: "../assets/images/tools/code-studio.png", |
| 169 | + href: "tools/code-studio.html", |
| 170 | + image: "assets/images/tools/code-studio.png", |
171 | 171 | description: "Write code, extend systems and build custom logic.", |
172 | 172 | role: "Foundry Bot", |
173 | 173 | mascot: "foundry-bot", |
174 | 174 | theme: "bot" |
175 | 175 | }, |
176 | 176 | { |
177 | 177 | title: "Input Studio", |
178 | | - href: "input-studio.html", |
179 | | - image: "../assets/images/tools/input-studio.png", |
| 178 | + href: "tools/input-studio.html", |
| 179 | + image: "assets/images/tools/input-studio.png", |
180 | 180 | description: "Map player controls and configure input workflows.", |
181 | 181 | role: "Foundry Bot", |
182 | 182 | mascot: "foundry-bot", |
|
189 | 189 | tools: [ |
190 | 190 | { |
191 | 191 | title: "Marketplace", |
192 | | - href: "../marketplace/index.html", |
193 | | - image: "../assets/images/tools/marketplace.png", |
| 192 | + href: "marketplace/index.html", |
| 193 | + image: "assets/images/tools/marketplace.png", |
194 | 194 | description: "Browse community-ready tools, assets, listings, and distribution surfaces.", |
195 | 195 | role: "Community", |
196 | 196 | mascot: "foundry-bot", |
|
203 | 203 | tools: [ |
204 | 204 | { |
205 | 205 | title: "Localization Studio", |
206 | | - href: "localization-studio/index.html", |
207 | | - image: "../assets/images/tools/localization-studio.png", |
| 206 | + href: "tools/localization-studio/index.html", |
| 207 | + image: "assets/images/tools/localization-studio.png", |
208 | 208 | description: "Plan game translation, language coverage, and contributor review workflows.", |
209 | 209 | role: "Community / Media", |
210 | 210 | mascot: "localization-studio", |
|
217 | 217 | tools: [ |
218 | 218 | { |
219 | 219 | title: "Arcade", |
220 | | - href: "../arcade/index.html", |
221 | | - image: "../assets/images/tools/arcade.png", |
| 220 | + href: "arcade/index.html", |
| 221 | + image: "assets/images/tools/arcade.png", |
222 | 222 | description: "Play and review available games from the Game Foundry arcade.", |
223 | 223 | role: "Play", |
224 | 224 | mascot: "forgebot", |
|
231 | 231 | tools: [ |
232 | 232 | { |
233 | 233 | title: "Storage Inspector", |
234 | | - href: "storage-inspector.html", |
235 | | - image: "../assets/images/tools/storage-inspector.png", |
| 234 | + href: "tools/storage-inspector.html", |
| 235 | + image: "assets/images/tools/storage-inspector.png", |
236 | 236 | description: "Inspect local storage, saved state, and tool data.", |
237 | 237 | role: "Foundry Bot", |
238 | 238 | mascot: "foundry-bot", |
|
252 | 252 | "Community & Marketplace": "tool-group-community-marketplace", |
253 | 253 | "Play": "tool-group-play" |
254 | 254 | }; |
| 255 | + const groupSwatchMap = { |
| 256 | + "Build & Create": "swatch-pink", |
| 257 | + "Content & Assets": "swatch-orange", |
| 258 | + "Media & Audio": "swatch-red", |
| 259 | + "AI & Learning": "swatch-purple", |
| 260 | + "Platform & Cloud": "swatch-blue", |
| 261 | + "Development & System": "swatch-gray", |
| 262 | + "Community / Media": "swatch-gold", |
| 263 | + "Community & Marketplace": "swatch-gold", |
| 264 | + "Play": "swatch-green" |
| 265 | + }; |
| 266 | + const badgeMap = { |
| 267 | + "Publish Studio": "publish-studio" |
| 268 | + }; |
255 | 269 | const allTools = toolGroups.flatMap((group) => group.tools.map((tool) => ({ |
256 | 270 | ...tool, |
257 | 271 | group: group.group |
|
261 | 275 | return groupClassMap[groupName] || ""; |
262 | 276 | } |
263 | 277 |
|
| 278 | + function groupSwatch(groupName) { |
| 279 | + return groupSwatchMap[groupName] || "swatch-orange"; |
| 280 | + } |
| 281 | + |
| 282 | + function badgeName(tool) { |
| 283 | + if (badgeMap[tool.title]) { |
| 284 | + return badgeMap[tool.title]; |
| 285 | + } |
| 286 | + return tool.image.split("/").pop().replace(".png", ""); |
| 287 | + } |
| 288 | + |
264 | 289 | function setActiveButton(mode) { |
265 | 290 | if (orderButton) { |
266 | 291 | orderButton.setAttribute("aria-pressed", String(mode !== "grouped")); |
|
303 | 328 |
|
304 | 329 | function createGroupLabel(groupName) { |
305 | 330 | const label = document.createElement("span"); |
306 | | - label.className = "tool-group-label"; |
| 331 | + label.className = "content-cluster"; |
307 | 332 |
|
308 | 333 | const swatch = document.createElement("span"); |
309 | | - swatch.className = "tool-group-swatch"; |
| 334 | + swatch.className = "brand-color-swatch " + groupSwatch(groupName); |
310 | 335 | swatch.setAttribute("role", "img"); |
311 | 336 | swatch.setAttribute("aria-label", groupName + " group color"); |
312 | 337 | swatch.title = groupName + " color"; |
|
320 | 345 |
|
321 | 346 | function createToolCard(tool) { |
322 | 347 | const article = document.createElement("article"); |
323 | | - article.className = `tool-card ${tool.theme} ${groupClass(tool.group)}`; |
| 348 | + article.className = `card ${groupClass(tool.group)}`; |
324 | 349 | article.dataset.mascot = tool.mascot; |
325 | 350 |
|
326 | | - const link = document.createElement("a"); |
327 | | - link.href = tool.href; |
328 | | - |
| 351 | + const media = document.createElement("div"); |
| 352 | + media.className = "card-media"; |
329 | 353 | const image = document.createElement("img"); |
330 | 354 | image.src = tool.image; |
331 | | - image.alt = tool.title; |
| 355 | + image.alt = tool.title + " preview"; |
| 356 | + media.append(image); |
332 | 357 |
|
333 | 358 | const body = document.createElement("div"); |
334 | | - body.className = "body"; |
| 359 | + body.className = "card-body"; |
| 360 | + |
| 361 | + const badgeCluster = createGroupLabel(tool.group); |
| 362 | + const badge = document.createElement("object"); |
| 363 | + badge.data = "assets/images/badges/" + badgeName(tool) + ".png"; |
| 364 | + badge.type = "image/png"; |
| 365 | + badge.width = 48; |
| 366 | + badge.height = 48; |
| 367 | + badge.setAttribute("aria-label", tool.title + " badge"); |
| 368 | + badge.textContent = tool.title + " badge"; |
| 369 | + badgeCluster.append(badge); |
| 370 | + |
| 371 | + const group = document.createElement("div"); |
| 372 | + group.className = "kicker"; |
| 373 | + group.textContent = tool.group; |
335 | 374 |
|
336 | 375 | const title = document.createElement("h3"); |
337 | 376 | title.textContent = tool.title; |
338 | 377 |
|
339 | 378 | const description = document.createElement("p"); |
340 | 379 | description.textContent = tool.description; |
341 | 380 |
|
342 | | - const pill = document.createElement("span"); |
343 | | - pill.className = "pill"; |
344 | | - pill.textContent = "Open page"; |
345 | | - |
346 | | - const group = document.createElement("span"); |
347 | | - group.className = "role"; |
348 | | - group.append(createGroupLabel(tool.group)); |
| 381 | + const link = document.createElement("a"); |
| 382 | + link.className = "btn"; |
| 383 | + link.href = tool.href; |
| 384 | + link.textContent = tool.href.indexOf("tools/") === 0 ? "Open Tool" : "Open Page"; |
349 | 385 |
|
350 | | - body.append(title, description, pill, group); |
351 | | - link.append(image, body); |
352 | | - article.append(link); |
| 386 | + body.append(badgeCluster, group, title, description, link); |
| 387 | + article.append(media, body); |
353 | 388 | return article; |
354 | 389 | } |
355 | 390 |
|
|
366 | 401 | body.className = "accordion-body"; |
367 | 402 |
|
368 | 403 | const grid = document.createElement("div"); |
369 | | - grid.className = "tool-grid"; |
| 404 | + grid.className = "card-grid"; |
370 | 405 |
|
371 | 406 | group.tools.forEach((tool) => { |
372 | 407 | grid.append(createToolCard(tool)); |
|
379 | 414 |
|
380 | 415 | function createToolGrid(tools) { |
381 | 416 | const grid = document.createElement("div"); |
382 | | - grid.className = "tool-grid"; |
| 417 | + grid.className = "card-grid"; |
383 | 418 | tools.forEach((tool) => { |
384 | 419 | grid.append(createToolCard(tool)); |
385 | 420 | }); |
|
0 commit comments