Compare commits

...

10 Commits

Author SHA1 Message Date
Jeremy Brandenburger f5f57c3e4d feat: polish gameplay and admin flow 2026-04-03 11:59:24 +02:00
Jeremy Brandenburger c8003cc77c Merge branch 'main' into bugfixes-features 2026-04-03 11:39:53 +02:00
Jeremy Brandenburger e555bbd321 chore: automate release checks 2026-04-03 11:34:59 +02:00
Jeremy Brandenburger 8ea3b14860 docs: add PROJECT_MAP, AGENTS.md; add PROJECT_MAP update rule to CLAUDE.md 2026-04-03 11:14:35 +02:00
Jeremy Brandenburger 6ac0376539 fix: remove black blob pseudo-element, revert sm icon to 22px 2026-03-31 18:45:29 +02:00
Jeremy Brandenburger 765d857cdc fix: larger, brighter icons on dashboard and tables (-md, -sm sizes) 2026-03-31 18:43:32 +02:00
Jeremy Brandenburger b35687d095 fix: larger stratagem icon with glow, readable queue labels 2026-03-31 18:42:48 +02:00
Jeremy Brandenburger 8a5d08b586 fix: speedrun scores, dashboard icons, N+1 queries, typeof guards 2026-03-31 09:05:33 +02:00
Jeremy Brandenburger 2d27d9fe4d feat: stratagem icons, session summary, queue preview, UX polish
- Download 65 SVG icons from community repo (scripts/download-icons.js)
- Gold CSS filter on all icons to match game theme
- Session summary modal with score/accuracy/top stratagems
- Queue preview strip (next 3 stratagems with icons)
- Score popup animation, icon shake on wrong input
- Icons in history, leaderboard, and best-per-stratagem tables
- server.js: icon fields on all stratagems, ELO in lobby-update WS events
2026-03-31 08:48:56 +02:00
Jeremy Brandenburger 0d971745a6 feat: major redesign — ELO system, 4 practice modes, history view, mobile nav
- 4 practice modes: Timed (SVG ring), Endless (3 lives), Category Drill, Speed Run
- Practice settings modal (timer duration, difficulty) with localStorage persistence
- History view: paginated table, SVG score chart, best-times-per-stratagem
- ELO rating system with server-side K=32 calculation and rank tiers PRIVATE–GENERAL
- Post-match result modal with ELO delta and round history
- Challenge modal showing challenger name + ELO (replaces toast)
- Dashboard hero card with ELO rank icon and daily sequence preview
- Leaderboard tabs: Practice Score / ELO / Speed Run
- Mobile hamburger nav drawer with slide-in animation
- DB migration: elo column, mode column, stratagem_stats table
- WS lobby-update now sends {name, elo, rank} objects
- View fade transitions, danger vignette at ≤5s, streak fire glow, combo badge
- Esc/Enter keyboard shortcuts for modals and practice
2026-03-30 18:31:46 +02:00
80 changed files with 5873 additions and 655 deletions
+12
View File
@@ -0,0 +1,12 @@
#!/usr/bin/env bash
set -euo pipefail
if [[ -f package.json && -f scripts/release-sync.cjs && -f scripts/release-verify.cjs ]]; then
npm run --silent release:sync >/dev/null
if [[ -d public ]]; then
while IFS= read -r -d '' file; do
git add -- "$file"
done < <(find public -type f -name '*.html' -print0 2>/dev/null)
fi
npm run --silent release:verify
fi
+39
View File
@@ -0,0 +1,39 @@
# Codex Instructions helldivers
## Pflichtlektüre vor dem ersten Code-Zugriff
Lies **PROJECT_MAP.md** in diesem Verzeichnis sie enthält alle Funktionen, API-Routen, WebSocket-Message-Types, State-Struktur und Datenbank-Details.
## Projekt-Überblick
- **Port:** 3012
- **Typ:** Authenticated Multiplayer App (WebSocket, SQLite, ELO-Rating)
- **Stack:** Node.js / Express, WebSocket (ws), SQLite (better-sqlite3), bcrypt, Helmet, rate-limit, Vanilla JS
- **Features:** Stratagem-Trainer (Timed/Endless/Drill/Speedrun), 1v1-Multiplayer-Matches, ELO-Rangliste, Tages-Challenge, Admin-Panel
## Struktur
```
helldivers/
├── server.js # Express + WebSocket + SQLite (~650 Zeilen)
├── public/app.js # Gesamte Client-Logik (~1840 Zeilen)
├── public/styles.css
├── public/index.html
├── scripts/ # DB-Migrations / Seed
└── data/helldivers.db # SQLite (Scores, Users, History, Sessions)
```
## Git-Workflow
1. Branch: immer `bugfixes-features` für Änderungen
2. Commit: `type: kurze Beschreibung` **keine Co-Authored-By-Zeile**
3. Vor Commit: `CHANGELOG.md` aktualisieren
4. Vor Commit: `PROJECT_MAP.md` aktualisieren, falls Funktionen/Routen/WS-Types geändert wurden
5. `git add` nur einzelne Dateien kein `git add -A`
6. Merge nach `main` nur auf explizite Anweisung
## Sicherheit
- Niemals `data/helldivers.db` committen
## Release-Automation
- **Version ist Single Source of Truth:** `package.json`
- **Cache-Busting nie manuell pflegen** stattdessen `npm run release:sync`
- **Vor jedem Commit zusätzlich:** `npm run release:verify`
- Repo-Hook: `.githooks/pre-commit` führt `release:sync` und `release:verify` automatisch aus
- Für Versionssprünge: `npm run release:bump:patch`, `release:bump:minor` oder `release:bump:major`
+91 -1
View File
@@ -1,4 +1,94 @@
# Changelog helldivers-trainer # Changelog
## [Unreleased]
### Changed
- Release-Automation ergänzt: `npm run release:sync`, `npm run release:verify`, `.githooks/pre-commit` und versionsbasiertes Cache-Busting aus `package.json` helldivers-trainer
- Practice- und Match-Flow wirken jetzt deutlich spielerischer mit Deployment-Countdown, Fokusbereich, direkter Feedback-Anzeige und staerkeren Mobile-HUDs
- Stratagem-Icons wurden breit ueberarbeitet und koennen ueber das neue Wiki-Download-Skript einfacher aktualisiert werden
- Admin-Bereich zeigt mehr Nutzer- und Aktivitaetsdaten, inklusive Sessions, letzter Aktivitaet, Passwort-Reset und Rollenpflege
## [2.1.3] 2026-03-31
### Fixed
- **Schwarzes Blob hinter Stratagem-Icon**: `::before` Pseudoelement ohne `position: relative` am Parent positionierte sich falsch und wurde als schwarzer Kreis gerendert — entfernt
- **Tabellen-Spaltenumbrüche**: `stratagem-icon-sm` wieder auf 22px (von 26px) damit Stratagemnamen in der History-Tabelle nicht umbrechen
---
## [2.1.2] 2026-03-31
### Changed
- **Stratagem main icon**: Größer (86→110px, mobil 70→88px), hellerer Gold-Filter mit `drop-shadow` Glow, leuchtender Kreis-Hintergrund für besseren Kontrast
- **Queue preview**: Icons größer (36→44px), Labels wrappen jetzt über 2 Zeilen statt abzuschneiden, Breite von 60→72px pro Item, Abstufung der Opazität (75%/55%/40% statt 70%/45%)
- **Dashboard/Tabellen-Icons** (`-md` und `-sm`): Größer (40→52px / 22→26px), stärkerer Gold-Filter, höhere Opazität (0.85→1 / 0.7→0.9) für bessere Erkennbarkeit
---
## [2.1.1] 2026-03-31
### Fixed
- **Speedrun scores never saved**: Individual scores were blocked by `if (mode !== 'speedrun')` guard; now saved per-stratagem like other modes. Final bulk-save with invalid `__speedrun__` stratagem name removed (was causing 400 errors).
- **Dashboard recent-sessions icons missing**: `r.icon` was always `undefined` since the server doesn't store icon paths in the DB. Now looks up icon from `state.stratagems` by name.
- **Variable shadowing in `renderDashboard`**: Outer `const r = eloRankFor(...)` was shadowed by `recent.map(r => ...)`. Renamed outer to `myRank`.
- **N+1 DB queries in `broadcastLobbyUpdate`**: Was running one `SELECT elo` per online user. Now batches into a single `WHERE username IN (...)` query.
- **N+1 DB queries in dashboard endpoint**: Same pattern fixed for the `/api/dashboard` online-users list.
- **Unnecessary `typeof` guards**: `typeof u === 'object'` checks in lobby/dashboard removed — `lobby-update` always sends objects, never plain strings.
- **Duplicate `else if (mode === 'endless')` branch in `nextStratagem`**: Was identical to the `else` branch below it; merged.
---
## [2.1.0] 2026-03-31
### Added
- **Stratagem icons**: 65 SVG icons downloaded from community icon set, served as static files under `/icons/`; icon download script at `scripts/download-icons.js`
- **Gold CSS filter** on all stratagem icons to match the game's yellow accent theme
- **Session summary modal**: opens after stopping practice or finishing a drill/speedrun — shows score, completed count, accuracy, best time, and top 5 stratagems
- **Queue preview strip**: shows next 3 upcoming stratagems (with icons) below the active stratagem
- **Score popup animation**: floating `+N pts` text appears on every correct completion
- **Shake animation on wrong input**: stratagem icon shakes on incorrect arrow key
- **Icon complete pulse**: stratagem icon scales + brightens when sequence is completed correctly
- **ELO rank icon** in post-match result header (matches rank tier badge)
- **Inline icons** in history table rows, best-per-stratagem table, and leaderboard
- `scripts/download-icons.js` — automated icon fetcher from GitHub community SVG repo
### Changed
- `index.html` fully rewritten: new elements for icon display, queue, score popup, session summary modal
- `app.js` fully rewritten (~1100 lines): icon helpers, queue builder, popup system, session stats, improved match/lobby flows
- `server.js` STRATAGEMS array: all 65 entries now have `icon` field (or `null` for missing ones)
- `broadcastLobbyUpdate()` now sends `[{name, elo, rank}]` objects with CSS-safe rank labels
- `challenge-received` WS event now includes challenger ELO for display in challenge modal
---
## [2.0.0] 2026-03-30
### Added
- **4 Practice modes**: Timed (configurable 15/30/45s, SVG ring timer), Endless (3 lives), Category Drill (progress bar), Speed Run (all stratagems, total time)
- **Settings modal**: timer duration and difficulty (Easy/Normal/Hard) persisted in localStorage
- **History view**: paginated session table with mode/category filters, SVG polyline score chart, best-time-per-stratagem table
- **ELO rating system**: server-side ELO (K=32) calculated after every match; rank tiers PRIVATE → GENERAL
- **Post-match result modal**: ELO delta display (`before → after +N`), round-by-round history
- **Challenge modal**: incoming challenge shows challenger name and ELO; replaces toast notification
- **Dashboard hero card**: ELO rank badge, rank icon, daily sequence preview arrows, mode column in recent sessions
- **Leaderboard tabs**: Practice Score / ELO Rating / Speed Run with correct column headers per tab
- **Mobile hamburger nav**: slide-in drawer with overlay backdrop, Esc key closes modals
- **DB migration**: `elo` column on users, `mode` column on practice_sessions, `stratagem_stats` table
- **Lobby redesign**: ELO + rank shown per player, 2-column layout (Online + Incoming Challenges)
- View fade transitions on every view switch
- Danger vignette flash at ≤5s timer remaining
- Streak fire glow effect (streak ≥ 5), combo multiplier badge (×N, streak ≥ 2)
- Keyboard shortcuts: `Esc` stops practice / closes modals, `Enter` starts practice
- `aria-label` on all D-pad buttons, modals with `role="dialog"` and `aria-modal="true"`
### Changed
- Full CSS redesign (~700 → ~1200 lines): glassmorphism cards, new design tokens, SVG timer ring, skeleton shimmer, animated modals
- Dashboard online list now shows ELO; lobby shows ELO + rank per player
- WS `lobby-update` now sends `[{name, elo, rank}]` objects instead of plain usernames
- WS `challenge-received` now includes challenger ELO
- Practice leaderboard query joined with `users.elo` for rank badge display
---
## [1.0.0] 2026-03-30 ## [1.0.0] 2026-03-30
+50
View File
@@ -0,0 +1,50 @@
# CLAUDE.md helldivers
## Overview
Port: 3012
Type: Authenticated Multiplayer App (WebSocket, SQLite, ELO-Rating, Bcrypt, Helmet)
## Running
```bash
node server.js # Produktion
npm run dev # Entwicklung
```
## Structure
```
helldivers/
├── server.js # Express + WebSocket (ws) + SQLite (better-sqlite3)
├── public/app.js # Gesamte Client-Logik (~1840 Zeilen)
├── public/styles.css
├── public/index.html
├── scripts/ # DB-Migrations / Seed
└── data/helldivers.db
```
## Deployment
- Runs under PM2 on the host
- Nginx reverse-proxies to port 3012
## Branches
- `main` stable, production-ready code
- `bugfixes-features` active development
## Commit Convention
`type: short description`
Types: `feat`, `fix`, `refactor`, `docs`, `chore`
## PROJECT_MAP.md Pflege
Falls Funktionen, API-Routen, WebSocket-Message-Types oder State-Variablen **hinzugefügt, geändert oder entfernt** werden, muss `PROJECT_MAP.md` **vor dem Commit** aktualisiert werden. Gilt für beide KIs (Claude und Codex) gleichermaßen.
## Changelog
- Nach jeder Änderung `CHANGELOG.md` aktualisieren
- Format: `## [Unreleased]` für laufende Änderungen
## Release Automation
- Version source of truth: `package.json`
- Never update `?v=...` asset parameters manually; use `npm run release:sync`
- Run `npm run release:verify` before commit whenever frontend/server/version files changed
- Repo hook: `.githooks/pre-commit` runs release sync + verification automatically
- Use `npm run release:bump:patch`, `release:bump:minor`, or `release:bump:major` for version bumps
+144
View File
@@ -0,0 +1,144 @@
# Project Map helldivers
## Files
| File | Purpose |
|---|---|
| `server.js` | Express + WebSocket (ws) + SQLite (better-sqlite3) Auth, Scores, Matchmaking |
| `public/app.js` | Gesamte Client-Logik (WebSocket-Client, Practice/Match/Lobby) |
| `public/styles.css` | Alle Styles |
| `public/index.html` | App-Shell |
| `data/helldivers.db` | SQLite-Datenbank (Scores, Users, Sessions, History) |
| `scripts/` | Migrations / Seed-Skripte |
---
## app.js
### State Object
```js
state = {
user, currentView, stratagems,
settings: { timerDuration, difficulty },
practice: {
active, mode, current, queue, progress, timeLeft, timerHandle, startTime,
score, streak, selectedCats, dailyTarget,
lives, // Endless mode
drillPool, drillCompleted, drillTotal, // Drill mode
speedrunStart, speedrunPool, speedrunElapsed, // Speedrun mode
sessionStats: { completed, missed, bestTime, stratagems, mistakes, maxStreak }
},
lobby: { online, incoming, pendingChallenge },
match: { roomId, opponent, matchScores, current, myProgress, oppProgress, roundActive, roundHistory },
leaderboard: { activeTab },
history: { page, total },
ws, wsReconnectTimer
}
```
### Constants
| Constant | Purpose |
|---|---|
| `RING_CIRCUMFERENCE` | `219.9` Kreis-Umfang für Timer-Ring-Canvas (r=35) |
| `ELO_RANKS` | Array `{ min, label, color }` ELO-Rangstufen |
| `STRATAGEMS` | Array aller Stratagems mit `name`, `category`, `icon`, `sequence` |
### Key Functions Settings & Navigation
| Function | Purpose |
|---|---|
| `loadSettings() / saveSettings()` | localStorage-Persistenz für Settings |
| `applySettingsToUI()` | Settings auf UI-Elemente anwenden |
| `showView(name)` | Ansicht wechseln (login/dashboard/practice/leaderboard/history/admin) |
| `focusGameplayArea(id)` | Scrollt den aktiven Gameplay-Bereich gezielt in den Viewport |
| `runGameplayCountdown(label, steps)` | Kurzer Start-Countdown vor Practice- und Match-Runden |
| `showGameplayFeedback(id, text, tone, duration)` | Inline-Feedback fuer Treffer, Fehler und Startphasen |
| `connectWS() / wsSend(type, payload)` | WebSocket-Verbindung + Nachrichten senden |
| `handleWSMessage({ type, payload })` | Eingehende WS-Nachrichten dispatchen |
### Key Functions Practice
| Function | Purpose |
|---|---|
| `initPracticeView()` | Practice-View initialisieren |
| `getPool()` | Stratagem-Pool nach Filter + Modus aufbauen |
| `buildQueue() / renderQueue(queue)` | Warteschlange aufbauen und rendern |
| `nextStratagem()` | Nächstes Stratagem anzeigen |
| `handlePracticeInput(dir)` | Pfeilrichtung auswerten (Treffer/Fehler) |
| `startPracticeTimer() / stopPracticeTimer()` | Timer für Timed-Modus |
| `startSpeedrunTimer()` | Timer für Speedrun-Modus |
| `renderPracticeStratagem()` | Aktuelles Stratagem + Pfeile rendern |
| `renderArrows(containerId, sequence, progress)` | Pfeil-Sequenz rendern |
| `trackPracticeMistake()` | Fehler je Stratagem fuer die Session-Statistik erfassen |
| `updateScoreDisplay() / updateStreakDisplay() / updateLivesDisplay()` | Score-UI |
| `openSessionSummary() / closeSessionSummary()` | Sitzungs-Zusammenfassung Modal |
### Key Functions Lobby & Match
| Function | Purpose |
|---|---|
| `updateLobbyView()` | Online-Nutzer-Liste aktualisieren |
| `sendChallenge(target) / acceptChallenge(from) / declineChallenge(from)` | Herausforderungen verwalten |
| `openChallengeModal(from, elo) / closeChallengeModal()` | Challenge-Dialog |
| `renderMatchRound()` | Aktive Match-Runde rendern |
| `handleMatchInput(dir)` | Match-Eingabe auswerten |
| `renderRoundResult(winner)` | Rundensieger anzeigen |
| `openMatchResultModal({ winner, eloChanges, roundHistory })` | Match-Ergebnis-Modal |
### Key Functions Admin & History
| Function | Purpose |
|---|---|
| `renderAdminOverview(data)` | Admin-Dashboard: Nutzer, Scores, Aktivität |
| `renderAdminUsers(users)` | Nutzertabelle im Admin-Bereich |
| `renderAdminActivity(data)` | Aktivitätslog rendern |
| `renderHistoryChart(sessions)` | Verlaufs-Diagramm (Canvas) |
| `renderHistoryPagination(limit)` | Pagination-Buttons |
| `renderDashboard({ stats, rank, elo, ... })` | Haupt-Dashboard-Kacheln |
---
## server.js
### Besonderheiten
- **SQLite** (better-sqlite3) statt JSON-Dateien
- **WebSocket** (ws-Library) für Multiplayer: Lobby, Challenges, Live-Matches
- **ELO-Rating-System** für 1v1-Matches
### Server-Side State
| Variable | Purpose |
|---|---|
| `userSockets` | `Map<userId, ws>` aktive WebSocket-Verbindungen |
| `pendingChallenges` | `Map<challengerId, targetId>` |
| `rooms` | `Map<roomId, roomState>` aktive Match-Räume |
### API Routes
| Route | Purpose |
|---|---|
| `POST /api/login` | Login (rate-limited) |
| `POST /api/logout` | Logout |
| `GET /api/me` | Session-Info |
| `POST /api/change-password` | Passwort ändern |
| `GET /api/users` | Alle Nutzer (Admin) |
| `POST /api/users` | Nutzer erstellen (Admin) |
| `DELETE /api/users/:username` | Nutzer löschen (Admin) |
| `POST /api/users/:username/reset-password` | Temp-Passwort (Admin) |
| `PATCH /api/users/:username` | Nutzerdaten ändern (Admin) |
| `GET /api/admin/overview` | Admin-Dashboard-Daten |
| `GET /api/admin/activity` | Aktivitätslog (Admin) |
| `GET /api/dashboard` | Dashboard-Daten (Stats, Rank, ELO, Daily) |
| `POST /api/scores/practice` | Practice-Session speichern |
| `GET /api/scores/leaderboard` | Gesamt-Leaderboard |
| `GET /api/scores/leaderboard/elo` | ELO-Rangliste |
| `GET /api/scores/leaderboard/speedrun` | Speedrun-Rangliste |
| `GET /api/scores/me` | Eigene Statistiken |
| `GET /api/history` | Session-Verlauf (paginiert) |
| `GET /api/stats/stratagems` | Stratagem-Trefferquoten |
| `GET /api/stratagems` | Stratagem-Liste (für Client-Sync) |
### WebSocket Message Types (Client → Server)
`join`, `challenge`, `accept_challenge`, `decline_challenge`, `ready`, `input`, `leave_match`
### WebSocket Message Types (Server → Client)
`lobby_update`, `challenge_received`, `challenge_declined`, `match_start`, `round_start`, `round_result`, `match_end`, `opponent_progress`, `error`
## Release Automation
- Version source of truth: `package.json`
- `scripts/release-sync.cjs`: synchronisiert lokale CSS/JS-Referenzen in HTML-Dateien auf die aktuelle Paketversion
- `scripts/release-verify.cjs`: prüft Version-Parameter sowie Pflichtdateien wie `CHANGELOG.md` und `PROJECT_MAP.md` vor Commits
- `.githooks/pre-commit`: führt Release-Sync und Verify automatisch aus
+6 -1
View File
@@ -5,7 +5,12 @@
"main": "server.js", "main": "server.js",
"scripts": { "scripts": {
"start": "node server.js", "start": "node server.js",
"dev": "node --watch server.js" "dev": "node --watch server.js",
"release:sync": "node scripts/release-sync.cjs",
"release:verify": "node scripts/release-verify.cjs",
"release:bump:patch": "npm version patch --no-git-tag-version && npm run release:sync",
"release:bump:minor": "npm version minor --no-git-tag-version && npm run release:sync",
"release:bump:major": "npm version major --no-git-tag-version && npm run release:sync"
}, },
"dependencies": { "dependencies": {
"bcryptjs": "^3.0.3", "bcryptjs": "^3.0.3",
+1199 -175
View File
File diff suppressed because it is too large Load Diff
+67
View File
@@ -0,0 +1,67 @@
{
"Reinforce": "/icons/reinforce.svg",
"Resupply": "/icons/resupply.svg",
"SOS Beacon": "/icons/sos_beacon.svg",
"Hellbomb": "/icons/hellbomb.svg",
"SEAF Artillery": "/icons/seaf_artillery.svg",
"Upload Data": "/icons/upload_data.svg",
"Prospecting Drill": "/icons/prospecting_drill.svg",
"Orbital Illumination Flare": "/icons/orbital_illumination_flare.svg",
"Orbital Gatling Barrage": "/icons/orbital_gatling_barrage.svg",
"Orbital Airburst Strike": "/icons/orbital_airburst_strike.svg",
"Orbital 120MM HE Barrage": "/icons/orbital_120mm_he_barrage.svg",
"Orbital 380MM HE Barrage": "/icons/orbital_380mm_he_barrage.svg",
"Orbital Walking Barrage": "/icons/orbital_walking_barrage.svg",
"Orbital Laser": "/icons/orbital_laser.svg",
"Orbital Railcannon Strike": "/icons/orbital_railcannon_strike.svg",
"Orbital Precision Strike": "/icons/orbital_precision_strike.svg",
"Orbital Gas Strike": "/icons/orbital_gas_strike.svg",
"Orbital EMS Strike": "/icons/orbital_ems_strike.svg",
"Orbital Smoke Strike": "/icons/orbital_smoke_strike.svg",
"Tesla Tower": "/icons/tesla_tower.svg",
"Shield Generator Relay": "/icons/shield_generator_relay.svg",
"HMG Emplacement": "/icons/hmg_emplacement.svg",
"Eagle Strafing Run": "/icons/eagle_strafing_run.svg",
"Eagle Airstrike": "/icons/eagle_airstrike.svg",
"Eagle Cluster Bomb": "/icons/eagle_cluster_bomb.svg",
"Eagle Napalm Airstrike": "/icons/eagle_napalm_airstrike.svg",
"LIFT-850 Jump Pack": "/icons/lift_850_jump_pack.svg",
"Eagle Smoke Strike": "/icons/eagle_smoke_strike.svg",
"Eagle 110MM Rocket Pods": "/icons/eagle_110mm_rocket_pods.svg",
"Eagle 500KG Bomb": "/icons/eagle_500kg_bomb.svg",
"Eagle Rearm": "/icons/eagle_rearm.svg",
"Machine Gun": "/icons/machine_gun.svg",
"Anti-Materiel Rifle": "/icons/anti_materiel_rifle.svg",
"Stalwart": "/icons/stalwart.svg",
"Expendable Anti-Tank": "/icons/expendable_anti_tank.svg",
"Recoilless Rifle": "/icons/recoilless_rifle.svg",
"Flamethrower": "/icons/flamethrower.svg",
"Autocannon": "/icons/autocannon.svg",
"Heavy Machine Gun": "/icons/heavy_machine_gun.svg",
"Airburst Rocket Launcher": "/icons/airburst_rocket_launcher.svg",
"Commando": "/icons/commando.svg",
"Railgun": "/icons/railgun.svg",
"Spear": "/icons/spear.svg",
"Quasar Cannon": "/icons/quasar_cannon.svg",
"Arc Thrower": "/icons/arc_thrower.svg",
"Laser Cannon": "/icons/laser_cannon.svg",
"Grenade Launcher": "/icons/grenade_launcher.svg",
"Supply Pack": "/icons/supply_pack.svg",
"Guard Dog Rover": "/icons/guard_dog_rover.svg",
"Ballistic Shield Backpack": "/icons/ballistic_shield_backpack.svg",
"Shield Generator Pack": "/icons/shield_generator_pack.svg",
"Anti-Personnel Minefield": "/icons/anti_personnel_minefield.svg",
"Incendiary Mines": "/icons/incendiary_mines.svg",
"Anti-Tank Mines": "/icons/anti_tank_mines.svg",
"Machine Gun Sentry": "/icons/machine_gun_sentry.svg",
"Gatling Sentry": "/icons/gatling_sentry.svg",
"Mortar Sentry": "/icons/mortar_sentry.svg",
"Guard Dog": "/icons/guard_dog.svg",
"Autocannon Sentry": "/icons/autocannon_sentry.svg",
"Rocket Sentry": "/icons/rocket_sentry.svg",
"EMS Mortar Sentry": "/icons/ems_mortar_sentry.svg",
"Patriot Exosuit": "/icons/patriot_exosuit.svg",
"Emancipator Exosuit": "/icons/emancipator_exosuit.svg",
"Directional Shield": "/icons/directional_shield.svg",
"Anti-Tank Emplacement": "/icons/anti_tank_emplacement.svg"
}
+15
View File
@@ -0,0 +1,15 @@
<svg viewBox="0 0 256 256" xmlns="http://www.w3.org/2000/svg" xml:space="preserve" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2">
<desc>Traced by Dogo314</desc>
<g transform="translate(-276 -306)">
<path style="fill:none" d="M276 306h256v256H276z"/>
<clipPath id="a">
<path d="M276 306h256v256H276z"/>
</clipPath>
<g clip-path="url(#a)">
<path style="fill:#011419;" transform="translate(0 306)" d="M276 0h256v256H276z"/>
<path d="M2575.238 2482.001 2575 2481v-4h13v-1h5v1h6v-2h-13v-1h-29v1h-4v-2l-4-3h-2l-4 3h-12l-17-3h-6l-4 3h-7c-2 0-3-4-3-10s1-10 3-10h7l4 3h6l17-3h12l4 3h2l4-3v-2h4v1h29v-1h25v1h28v-1h4v2l14 2h3l3-3h5v4l3 2h11l4-2h22l4 2c4 0 9 1 18 4v2c-9 3-14 4-18 4l-4 2h-22l-4-2h-11l-3 2v4h-5l-3-3h-3l-14 2v2h3a2.5 2.5 0 1 1 4 2.999V2490a2 2 0 1 1-4 0v-12h-7a1 1 0 0 0-1 1v3c0 .796-.316 1.559-.879 2.121a3 3 0 0 1-2.121.879h-10l-6 12-5-3 6-11v-4h-6l-2 4h-8a2 2 0 0 0-2-2h-18v21h-4l-.483-2.027a1 1 0 1 0-.463-1.946l-.492-2.066a1 1 0 0 0-.463-1.943l-.492-2.07a1.001 1.001 0 0 0-.462-1.938l-.495-2.078a1 1 0 0 0-.364-1.932q-.048 0-.094.004l-.498-2.091a1 1 0 0 0-.408-1.913zM2630 2478h-1l1 2-.379 1.515a2.002 2.002 0 0 0 1.941 2.485H2634a3 3 0 0 0 3-3v-2a.997.997 0 0 0-1-1h-4c0 2 0 4 1 5-1 0-2-2-2-3l-1-1z" style="fill:#53bcda" transform="translate(-2208 -1992)"/>
<path d="M2545 2348c18.213 0 33 14.787 33 33s-14.787 33-33 33-33-14.787-33-33 14.787-33 33-33m0 4c-16.006 0-29 12.994-29 29s12.994 29 29 29 29-12.994 29-29-12.994-29-29-29m0 7c12.142 0 22 9.858 22 22s-9.858 22-22 22-22-9.858-22-22 9.858-22 22-22m0 4c-9.934 0-18 8.066-18 18s8.066 18 18 18 18-8.066 18-18-8.066-18-18-18m0 6c6.623 0 12 5.377 12 12s-5.377 12-12 12-12-5.377-12-12 5.377-12 12-12m56 14-5-16h9l4 11h4l-4-11h17l6 8h5l38-8 38 8v16l-38 8-38-8h-5l-6 8h-17l4-11h-4l-4 11h-9z" style="fill:#ffe" transform="translate(-2208 -1992)"/>
<path d="M276 15V0h256v15zM518 .82H290v13.36h228z" style="fill:#5abeda" transform="matrix(1 0 0 17.06667 0 306)"/>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.0 KiB

+15
View File
@@ -0,0 +1,15 @@
<svg viewBox="0 0 256 256" xmlns="http://www.w3.org/2000/svg" xml:space="preserve" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2">
<desc>Traced by Dogo314</desc>
<g transform="translate(-276 -306)">
<path style="fill:none" d="M276 306h256v256H276z"/>
<clipPath id="a">
<path d="M276 306h256v256H276z"/>
</clipPath>
<g clip-path="url(#a)">
<path style="fill:#011419;" transform="translate(0 306)" d="M276 0h256v256H276z"/>
<path d="M690 2486h-32v8h-4v7h-15l-3-3v-7h-1v-2h-1.172a2 2 0 0 0-1.414.586l-.535.535a3 3 0 0 1-2.122.879h-2.049c-.466 0-.925-.108-1.341-.317l-1.788-.893a2 2 0 0 0-2.558.679l-4.776 7.163a1 1 0 0 0-.138.797l.467 1.866a1 1 0 0 1-1.258 1.2l-6.998-2.1a1 1 0 0 1-.535-1.527l7.058-10.195a2 2 0 0 0-.535-2.802L611 2482h-12l-3.522 5.635a6 6 0 0 1-4.239 2.759l-10.579 1.512a2 2 0 0 0-1.131.565l-1.943 1.943a2 2 0 0 1-1.414.586h-.344a2 2 0 0 1-1.414-.586l-.828-.828a2 2 0 0 1-.586-1.414v-2.465c0-.453.18-.887.5-1.207l.5-.5v-8l-.766-.766a.8.8 0 0 1-.234-.565v-2.708c0-.607.276-1.182.751-1.561l3.701-2.962a2 2 0 0 1 1.25-.438H615l5-4h7v-1h1v-3h-8v-4h9v-2l1-1h1l1 1v2h2l1-1h6l1 1h3l4-1h9v6h-9l-4-1h-3l-1 1v2h1v1h37l5 5h20l2 2h55l2.071-2.071H787l2 2.071v4l-2 2h-24l-2-2h-56v8h-3l-1-1v-2h-5.038l-.962 2v19h1l2-2h1v1l-3 3h1l2-2h1v1l-3 3h-8l-3-3v-1l-1-1v-1h1l2 2h2zm-110-6v7l15.862-5.047a1 1 0 0 0-.303-1.953zm50.382 9a1 1 0 0 0 .894-.553l.402-.802c.192-.385.117-.85-.188-1.155l-1.197-1.197a1 1 0 0 0-.707-.293h-2.172a1 1 0 0 0-.707.293l-1 1a1 1 0 0 0 0 1.414l1 1a1 1 0 0 0 .707.293zm2.618-26v3h2v-3z" style="fill:#53bcda" transform="translate(-276 -1992)"/>
<path d="M644.22 2394H636v-8h8.22c1.847-16.676 15.104-29.933 31.78-31.78V2342h8v12.22c16.676 1.847 29.933 15.104 31.78 31.78H724v8h-8.22c-1.847 16.676-15.104 29.933-31.78 31.78v8.22h-8v-8.22c-16.676-1.847-29.933-15.104-31.78-31.78m31.78-31.716c-12.255 1.756-21.96 11.461-23.716 23.716H676zM707.716 2386c-1.756-12.255-11.461-21.96-23.716-23.716V2386zM684 2417.716c12.255-1.756 21.96-11.461 23.716-23.716H684zM652.284 2394c1.756 12.255 11.461 21.96 23.716 23.716V2394z" style="fill:#ffe" transform="translate(-276 -1992)"/>
<path d="M276 15V0h256v15zM518 .82H290v13.36h228z" style="fill:#5abeda" transform="matrix(1 0 0 17.06667 0 306)"/>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.3 KiB

+15
View File
@@ -0,0 +1,15 @@
<svg viewBox="0 0 256 256" xmlns="http://www.w3.org/2000/svg" xml:space="preserve" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2">
<desc>Traced by Dogo314</desc>
<g transform="translate(-276 -306)">
<path style="fill:none" d="M276 306h256v256H276z"/>
<clipPath id="a">
<path d="M276 306h256v256H276z"/>
</clipPath>
<g clip-path="url(#a)">
<path style="fill:#091901;" transform="translate(0 306)" d="M276 0h256v256H276z"/>
<path d="M516 1128H292v-18.222L332 1092l36 16 36-16 36 16 36-16 40 17.778z" style="fill:#679452" transform="translate(0 -582)"/>
<path d="M412 1032v8h-16v-8zm32 16a4 4 0 0 1 4 4v12h-88v-12a4 4 0 0 1 4-4zm-100 40.579V1072h119v17.023l-23 10.222-36-16-36 16z" style="fill:#ffe" transform="translate(0 -582)"/>
<path d="M276 15V0h256v15zM518 .82H290v13.36h228z" style="fill:#689452" transform="matrix(1 0 0 17.06667 0 306)"/>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 971 B

+16
View File
@@ -0,0 +1,16 @@
<svg viewBox="0 0 256 256" xmlns="http://www.w3.org/2000/svg" xml:space="preserve" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2">
<desc>Traced by Dogo314</desc>
<g transform="translate(-276 -306)">
<path style="fill:none" d="M276 306h256v256H276z"/>
<clipPath id="a">
<path d="M276 306h256v256H276z"/>
</clipPath>
<g clip-path="url(#a)">
<path style="fill:#091901;" transform="translate(0 306)" d="M276 0h256v256H276z"/>
<path d="M389 676.25V653h15c31.459 0 57 25.541 57 57v15h-72v-8.25h17.485l7.5-7.5h21.139l18.417-12.75-18.417-12.75h-21.139l-7.5-7.5zM430.849 653H485v21h-29.306a63.3 63.3 0 0 0-24.845-21M446 731v21h-42v-21zm15 27 18 21H371l18-21z" style="fill:#679452" transform="translate(-138.667 -520.667)scale(1.33333)"/>
<path d="M2254 932c7.727 0 14 6.273 14 14s-6.273 14-14 14-14-6.273-14-14 6.273-14 14-14m-14 104h-4a4 4 0 0 1-2.828-1.172A4 4 0 0 1 2232 1032v-64c0-1.061.421-2.078 1.172-2.828A4 4 0 0 1 2236 964h36c1.061 0 2.078.421 2.828 1.172A4 4 0 0 1 2276 968v64a4 4 0 0 1-1.172 2.828A4 4 0 0 1 2272 1036h-4v60a4 4 0 0 1-1.172 2.828A4 4 0 0 1 2264 1100h-20a4 4 0 0 1-2.828-1.172A4 4 0 0 1 2240 1096z" style="fill:#ffe" transform="translate(-1932 -582)"/>
<path d="m2618 998.526-10 9.474h-41v-36h41l10 9.474h29l13 8.526-13 8.526z" style="fill:#ffe" transform="matrix(1 0 0 1.05556 -2208 -637)"/>
<path d="M276 15V0h256v15zM518 .82H290v13.36h228z" style="fill:#689452" transform="matrix(1 0 0 17.06667 0 306)"/>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.5 KiB

+15
View File
@@ -0,0 +1,15 @@
<svg viewBox="0 0 256 256" xmlns="http://www.w3.org/2000/svg" xml:space="preserve" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2">
<desc>Traced by Dogo314</desc>
<g transform="translate(-276 -306)">
<path style="fill:none" d="M276 306h256v256H276z"/>
<clipPath id="a">
<path d="M276 306h256v256H276z"/>
</clipPath>
<g clip-path="url(#a)">
<path style="fill:#091901;" transform="translate(0 306)" d="M276 0h256v256H276z"/>
<path d="M516 1128H292v-18.222L332 1092l36 16 36-16 36 16 36-16 40 17.778z" style="fill:#679452" transform="translate(0 -582)"/>
<path d="M412 1032v8h-16v-8zm32 16a4 4 0 0 1 4 4v12h-88v-12a4 4 0 0 1 4-4zm-100 40.579V1072h119v17.023l-23 10.222-36-16-36 16zM409 935l-3 3h-40v-14h40l3 3h37v8zm51 55H352v-29l14-14h40l54 23zm-92 9c0 4.415-3.585 8-8 8s-8-3.585-8-8zm23 0c0 4.415-3.585 8-8 8s-8-3.585-8-8zm23 0c0 4.415-3.585 8-8 8s-8-3.585-8-8zm23 0c0 4.415-3.585 8-8 8s-8-3.585-8-8zm23 0c0 4.415-3.585 8-8 8s-8-3.585-8-8z" style="fill:#ffe" transform="translate(0 -582)"/>
<path d="M276 15V0h256v15zM518 .82H290v13.36h228z" style="fill:#689452" transform="matrix(1 0 0 17.06667 0 306)"/>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.2 KiB

+15
View File
@@ -0,0 +1,15 @@
<svg viewBox="0 0 256 256" xmlns="http://www.w3.org/2000/svg" xml:space="preserve" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2">
<desc>Traced by Dogo314</desc>
<g transform="translate(-276 -306)">
<path style="fill:none" d="M276 306h256v256H276z"/>
<clipPath id="a">
<path d="M276 306h256v256H276z"/>
</clipPath>
<g clip-path="url(#a)">
<path style="fill:#011419;" transform="translate(0 306)" d="M276 0h256v256H276z"/>
<path d="M436 2744h-1v9h-2v2h2v5a4 4 0 0 1-8 0v-5h2v-2h-2v-7h-14l-2 2h-5l-26 34h-3l-19-9v-2l9-18-5-5h-8l-4-4h-21l-19 19h-7l-3-3v-36h9l2-2h34l2 2h3v-4h10l10-10h9v-2h12v2h12l7 7-3 3-7-7h-9v3h8v4h5l3 3h4v-3h8l2 2h66l2-2h4v4h3v2h9l3 3h-12v2h12l-2 2h-10v4h-3v9h-9v-2h-2v2h-2v-2h-2v2h-2v-2h-2v2h-2v-2h-2v2h-2v-2h-2v2h-2v-2h-2v2h-2v-2h-2v2h-2v-2h-2v2h-2v-2h-2v2h-2v-2h-2v2h-2v-2h-2v2h-2v-2h-2v2h-2zm-51 6q-1.5 3 0 6h7a2 2 0 0 0 2-2v-4zm5 9h-13l-2 2-5 10v1.337a3 3 0 0 0 1.41 2.544l4.211 2.632a3 3 0 0 0 4.022-.788L391 2761zm-15-39 4-4v-3h-6l-7 7z" style="fill:#53bcda" transform="translate(0 -2268)"/>
<path d="m312.683 2666.11-1.366-8.22 76.4-12.69 3.232 20.683 31.932-27.941 4.58 27.481 68.079-7.564.92 8.282-75.921 8.436-3.42-20.519-32.068 28.059-4.268-27.317z" style="fill:#fff" transform="translate(0 -2268)"/>
<path d="M276 15V0h256v15zM518 .82H290v13.36h228z" style="fill:#5abeda" transform="matrix(1 0 0 17.06667 0 306)"/>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.4 KiB

+15
View File
@@ -0,0 +1,15 @@
<svg viewBox="0 0 256 256" xmlns="http://www.w3.org/2000/svg" xml:space="preserve" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2">
<desc>Traced by Dogo314</desc>
<g transform="translate(-276 -306)">
<path style="fill:none" d="M276 306h256v256H276z"/>
<clipPath id="a">
<path d="M276 306h256v256H276z"/>
</clipPath>
<g clip-path="url(#a)">
<path style="fill:#011419;" transform="translate(0 306)" d="M276 0h256v256H276z"/>
<path d="M2164 2471v-8h-7v1h-17l-2-2h-2v-3h-5v1h-12l-2-2h-85l-2-4v-8l-1-1h-32l-1 1v8l-1 4h-34a2 2 0 0 0-2 2v2l-.729.486a5.1 5.1 0 0 0-2.271 4.243v.666a6.74 6.74 0 0 0 3 5.605v8a2 2 0 0 0 2 2h12l3 3c6-8 9-10 16-10 8.327 0 16 7 16 13v5h4l1.121-1.121a3 3 0 0 1 2.122-.879h.514a3 3 0 0 0 2.122-.879l.242-.242a3 3 0 0 1 2.122-.879H2022c3 0 8.026-8.162 9-11h12v2l-6.238 14.259a2 2 0 0 0 .937 2.591l8.208 4.104q.093.045.194.071l.002.001A2.413 2.413 0 0 0 2049 2499l-.912-1.824a5.1 5.1 0 0 1-.081-4.391L2052 2484h2v1h2v-6h24v9h3l5-9h17l3-3h9l2-2h12v1h5v-3h2l2-2h17v1z" style="fill:#53bcda" transform="translate(-1656 -1992)"/>
<path d="M2042.25 2410h-25.35v-39h64.35zm50.7-39h17.55c10.762 0 19.5 8.738 19.5 19.5s-8.738 19.5-19.5 19.5h-56.55z" style="fill:#ffe" transform="translate(-1716.615 -2053.795)scale(1.02564)"/>
<path d="M276 15V0h256v15zM518 .82H290v13.36h228z" style="fill:#5abeda" transform="matrix(1 0 0 17.06667 0 306)"/>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.4 KiB

+15
View File
@@ -0,0 +1,15 @@
<svg viewBox="0 0 256 256" xmlns="http://www.w3.org/2000/svg" xml:space="preserve" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2">
<desc>Traced by Dogo314</desc>
<g transform="translate(-276 -306)">
<path style="fill:none" d="M276 306h256v256H276z"/>
<clipPath id="a">
<path d="M276 306h256v256H276z"/>
</clipPath>
<g clip-path="url(#a)">
<path style="fill:#091901;" transform="translate(0 306)" d="M276 0h256v256H276z"/>
<path d="M377 665v-12h27c31.459 0 57 25.541 57 57v15h-54.301a15 15 0 0 0-5.702-9c3.644-2.738 6.003-7.096 6.003-12s-2.359-9.262-6.003-12c3.644-2.738 6.003-7.096 6.003-12 0-8.279-6.721-15-15-15zm29.699 66H449v21h-60v-9h3c7.251 0 13.308-5.157 14.699-12m24.15-78H491v21h-35.306a63.3 63.3 0 0 0-24.845-21M461 758l18 21H359l18-21z" style="fill:#679452" transform="translate(-154.667 -520.667)scale(1.33333)"/>
<path d="M1196 704h-34l23-24h11c6.623 0 12 5.377 12 12s-5.377 12-12 12m-45 0h-15v-24h38zm45 32h-34l23-24h11c6.623 0 12 5.377 12 12s-5.377 12-12 12m-45 0h-15v-24h38zm45 32h-34l23-24h11c6.623 0 12 5.377 12 12s-5.377 12-12 12m-45 0h-15v-24h38z" style="fill:#ffe" transform="translate(-828 -306)"/>
<path d="M276 15V0h256v15zM518 .82H290v13.36h228z" style="fill:#689452" transform="matrix(1 0 0 17.06667 0 306)"/>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.3 KiB

@@ -0,0 +1,15 @@
<svg viewBox="0 0 256 256" xmlns="http://www.w3.org/2000/svg" xml:space="preserve" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2">
<desc>Traced by Dogo314</desc>
<g transform="translate(-276 -306)">
<path style="fill:none" d="M276 306h256v256H276z"/>
<clipPath id="a">
<path d="M276 306h256v256H276z"/>
</clipPath>
<g clip-path="url(#a)">
<path style="fill:#011419;" transform="translate(0 306)" d="M276 0h256v256H276z"/>
<path d="M388 1569.204V1541l17 17h19v24h32v-24h19l17-17v101l-16 16h-68v-84.448zM472 1550h-64l-20-20v-16h104v16zm-24 8v16h-16v-16z" style="fill:#53bcda" transform="translate(0 -1164)"/>
<path d="m3390 1570 46 10v75l-46 27-46-27v-75zm-14 24h-12v8h12zm20 12h-12v36l6 9 6-9zm0-12h-12v8h12zm-20 12h-12v36l6 9 6-9zm40-12h-12v8h12zm0 12h-12v36l6 9 6-9z" style="fill:#ffe" transform="translate(-3036 -1164)"/>
<path d="M276 15V0h256v15zM518 .82H290v13.36h228z" style="fill:#5abeda" transform="matrix(1 0 0 17.06667 0 306)"/>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.0 KiB

+15
View File
@@ -0,0 +1,15 @@
<svg viewBox="0 0 256 256" xmlns="http://www.w3.org/2000/svg" xml:space="preserve" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2">
<desc>Traced by Dogo314</desc>
<g transform="translate(-276 -306)">
<path style="fill:none" d="M276 306h256v256H276z"/>
<clipPath id="a">
<path d="M276 306h256v256H276z"/>
</clipPath>
<g clip-path="url(#a)">
<path style="fill:#011419;" transform="translate(0 306)" d="M276 0h256v256H276z"/>
<path d="M276 15V0h256v15zM518 .82H290v13.36h228z" style="fill:#5abeda" transform="matrix(1 0 0 17.06667 0 306)"/>
<path d="M2939 2444v4h34v3h3v12h-3v1h3v14h-3v3h-3l-3 3h-8l-3 3h-8v13h-1v1h-6v-1h-1v-14h-4v1a6 6 0 0 1-6 6h-4l-8 13v4h-3l-9-5h-14l-2 2h-9v9h-3l-2 2h-4l-2-2v-2h-2v-6a18 18 0 0 0-18-18h-8v-1h-4v-4l2.973-2.973.027-1.027h-41v-33h61v-2h11v-2zm-41 45a2 2 0 0 0-2 2v9a2 2 0 0 0 2 2h10l7-11v-.17a1.83 1.83 0 0 0-1.83-1.83zm36-1.178a1.82 1.82 0 0 0-1.822-1.822H2931a2 2 0 0 0-2 2v1.036c0 1.085.879 1.964 1.964 1.964H2932l2-3z" style="fill:#53bcda" transform="translate(-2484 -1992)"/>
<path d="M2949 2398h-128v-12h72v-8h-72v-12h128c8.831 0 16 7.169 16 16s-7.169 16-16 16m-128-64 24 24h-24zm0 96v-24h24z" style="fill:#ffe" transform="translate(-2485 -1992)"/>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.3 KiB

+15
View File
@@ -0,0 +1,15 @@
<svg viewBox="0 0 256 256" xmlns="http://www.w3.org/2000/svg" xml:space="preserve" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2">
<desc>Traced by Dogo314</desc>
<g transform="translate(-276 -306)">
<path style="fill:none" d="M276 306h256v256H276z"/>
<clipPath id="a">
<path d="M276 306h256v256H276z"/>
</clipPath>
<g clip-path="url(#a)">
<path style="fill:#011419;" transform="translate(0 306)" d="M276 0h256v256H276z"/>
<path d="M388 1569.204V1541l17 17h19v24h32v-24h19l17-17v101l-16 16h-68v-84.448zM472 1550h-64l-20-20v-16h104v16zm-24 8v16h-16v-16z" style="fill:#53bcda" transform="translate(0 -1164)"/>
<path d="m3390 1570 46 10v75l-46 27-46-27v-75zm0 27.167c12.145 0 19.554 7.279 19.554 7.279L3405 1609h15v-15l-4.554 4.554s-9.591-9.721-25.446-9.721-25.446 9.721-25.446 9.721L3360 1594v15h15l-4.554-4.554s7.409-7.279 19.554-7.279m0 34.833 6-23-21 29h15l-6 23 21-29z" style="fill:#ffe" transform="translate(-3036 -1164)"/>
<path d="M276 15V0h256v15zM518 .82H290v13.36h228z" style="fill:#5abeda" transform="matrix(1 0 0 17.06667 0 306)"/>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

+15
View File
@@ -0,0 +1,15 @@
<svg viewBox="0 0 256 256" xmlns="http://www.w3.org/2000/svg" xml:space="preserve" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2">
<desc>Traced by Dogo314</desc>
<g transform="translate(-276 -306)">
<path style="fill:none" d="M276 306h256v256H276z"/>
<clipPath id="a">
<path d="M276 306h256v256H276z"/>
</clipPath>
<g clip-path="url(#a)">
<path style="fill:#190301;" transform="translate(0 306)" d="M276 0h256v256H276z"/>
<path d="M1796 510h-16l-20-20h-12l-16-16h28v-28l16 16v12l20 20zm-49-44h-15l-12-12h15zm5-5-12-12v-15l12 12zm108-15h-16l-20-20h-12l-16-16h28v-28l16 16v12l20 20zm-49-44h-15l-12-12h15zm5-5-12-12v-15l12 12z" style="fill:#ffe" transform="translate(-1380)"/>
<path d="M388 418h-64l-12-12 48-16 16-48 12 12zm37.358-57.956L433 342l27 15v29.686l-24-24v8zM460 453.314V469l29 29 7 28-28-7-29-29h-15.686L404 470.686v-12l-24.342-24.341L397 427l7.345-17.342L428.686 434h12zM356.686 490H327l-15-27 18.044-7.642L340.686 466h-8z" style="fill:#dd6658"/>
<path d="M276 15V0h256v15zM518 .82H290v13.36h228z" style="fill:#e67366" transform="matrix(1 0 0 17.06667 0 306)"/>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.2 KiB

+15
View File
@@ -0,0 +1,15 @@
<svg viewBox="0 0 256 256" xmlns="http://www.w3.org/2000/svg" xml:space="preserve" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2">
<desc>Traced by Dogo314</desc>
<g transform="translate(-276 -306)">
<path style="fill:none" d="M276 306h256v256H276z"/>
<clipPath id="a">
<path d="M276 306h256v256H276z"/>
</clipPath>
<g clip-path="url(#a)">
<path style="fill:#190301;" transform="translate(0 306)" d="M276 0h256v256H276z"/>
<path d="M409.887 396.573 433 342l27 15v112l29 29 7 28-28-7-29-29H327l-15-27 54.573-23.113L400.686 474H444v-43.314zM343.074 418H324l-12-12 15.743-5.248zm27.678-60.257L376 342l12 12v19.074z" style="fill:#dd6658"/>
<path d="M436 466h-32l-32-32 4-16-4-4-20 2-16-18 24-8 8-24 18 16-2 20 4 4 16-4 32 32z" style="fill:#ffe"/>
<path d="M276 15V0h256v15zM518 .82H290v13.36h228z" style="fill:#e67366" transform="matrix(1 0 0 17.06667 0 306)"/>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 984 B

+15
View File
@@ -0,0 +1,15 @@
<svg viewBox="0 0 256 256" xmlns="http://www.w3.org/2000/svg" xml:space="preserve" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2">
<desc>Traced by Dogo314</desc>
<g transform="translate(-276 -306)">
<path style="fill:none" d="M276 306h256v256H276z"/>
<clipPath id="a">
<path d="M276 306h256v256H276z"/>
</clipPath>
<g clip-path="url(#a)">
<path style="fill:#190301;" transform="translate(0 306)" d="M276 0h256v256H276z"/>
<path d="M2065 511h-18l-16-16 2-9-2-2-11 1-8-10 12-5 5-12 10 8-1 11 2 2 9-2 16 16zm74-74h-18l-16-16 2-9-2-2-11 1-8-10 12-5 5-12 10 8-1 11 2 2 9-2 16 16z" style="fill:#ffe" transform="translate(-1656)"/>
<path d="M357.755 490H327l-15-27 85-36 36-85 27 15v27.155l-16.298-13.039-7.82 18.766-18.766 7.82 17.324 21.655 6.869-.625-1.071 4.82L460 443.314V469l29 29 7 28-28-7-29-29h-22v-.314l-21.448-21.448-4.82 1.071.625-6.869-21.655-17.324-7.82 18.766-18.766 7.82zM360 390l16-48 12 12v64h-64l-12-12z" style="fill:#dd6658"/>
<path d="M276 15V0h256v15zM518 .82H290v13.36h228z" style="fill:#e67366" transform="matrix(1 0 0 17.06667 0 306)"/>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.2 KiB

+20
View File
@@ -0,0 +1,20 @@
<svg viewBox="0 0 256 256" xmlns="http://www.w3.org/2000/svg" xml:space="preserve" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2">
<desc>Traced by Dogo314</desc>
<g transform="translate(-276 -306)">
<path style="fill:none" d="M276 306h256v256H276z"/>
<clipPath id="a">
<path d="M276 306h256v256H276z"/>
</clipPath>
<g clip-path="url(#a)">
<path style="fill:#190301;" transform="translate(0 306)" d="M276 0h256v256H276z"/>
<circle cx="1232" cy="490" r="12" style="fill:#ffe" transform="translate(-828)"/>
<circle cx="1232" cy="490" r="12" style="fill:#ffe" transform="translate(-860)"/>
<circle cx="1232" cy="490" r="12" style="fill:#ffe" transform="translate(-892)"/>
<circle cx="1232" cy="490" r="12" style="fill:#ffe" transform="matrix(-1 0 0 1 1692 -56)"/>
<circle cx="1232" cy="490" r="12" style="fill:#ffe" transform="matrix(-1 0 0 1 1692 -88)"/>
<circle cx="1232" cy="490" r="12" style="fill:#ffe" transform="matrix(-1 0 0 1 1692 -120)"/>
<path d="M322.072 481.13 312 463l85-36 36-85 18.13 10.072C444.537 355.344 440 362.146 440 370c0 6.539 3.145 12.35 8.004 16-4.859 3.65-8.004 9.461-8.004 16s3.145 12.35 8.004 16c-4.859 3.65-8.004 9.461-8.004 16 0 11.038 8.962 20 20 20v15l29 29 7 28-28-7-29-29h-15c0-11.038-8.962-20-20-20-6.539 0-12.35 3.145-16 8.004-3.65-4.859-9.461-8.004-16-8.004s-12.35 3.145-16 8.004c-3.65-4.859-9.461-8.004-16-8.004-7.854 0-14.656 4.537-17.928 11.13M360 390l16-48 12 12v64h-64l-12-12z" style="fill:#dd6658"/>
<path d="M276 15V0h256v15zM518 .82H290v13.36h228z" style="fill:#e67366" transform="matrix(1 0 0 17.06667 0 306)"/>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.7 KiB

+15
View File
@@ -0,0 +1,15 @@
<svg viewBox="0 0 256 256" xmlns="http://www.w3.org/2000/svg" xml:space="preserve" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2">
<desc>Traced by Dogo314</desc>
<g transform="translate(-276 -306)">
<path style="fill:none" d="M276 306h256v256H276z"/>
<clipPath id="a">
<path d="M276 306h256v256H276z"/>
</clipPath>
<g clip-path="url(#a)">
<path style="fill:#190301;" transform="translate(0 306)" d="M276 0h256v256H276z"/>
<path d="M1761 109V87l18-18V41l25 25v27l7-20 11.524 32.476L1797 131v-15l7-7-10-10V85l-21 21 10 10v15s-16.579-15.602-22-22m-129.298 0V87l18-18V41l25 25v27l7-20 11.524 32.476L1667.702 131v-15l7-7-10-10V85l-21 21 10 10v15s-16.58-15.602-22-22" style="fill:#ffe" transform="rotate(-45 1321.8 1403.774)scale(.7875)"/>
<path d="M344.64 490H327l-15-27 18.044-7.642 13.548 13.548v20.046zm23.222-50.659L397 427l14.485-34.201 4.107 4.107v20.046l16.668 16.668 2.923.242c6.102.505 21.607.126 24.817.04V469l29 29 7 28-28-7-29-29h-34.86v-33.384zM421.141 370 433 342l27 15v19.93l-33.417-15.913 4.325 8.983zM360 390l16-48 12 12v64h-64l-12-12z" style="fill:#dd6658"/>
<path d="M276 15V0h256v15zM518 .82H290v13.36h228z" style="fill:#e67366" transform="matrix(1 0 0 17.06667 0 306)"/>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.3 KiB

+15
View File
@@ -0,0 +1,15 @@
<svg viewBox="0 0 256 256" xmlns="http://www.w3.org/2000/svg" xml:space="preserve" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2">
<desc>Traced by Dogo314</desc>
<g transform="translate(-28.444 589.487)scale(.98084)">
<path style="fill:none" d="M29-601h261v261H29z"/>
<clipPath id="a">
<path d="M29-601h261v261H29z"/>
</clipPath>
<g clip-path="url(#a)">
<path style="fill:#363426" transform="translate(-252.39 -601)scale(1.01953)" d="M276 0h256v256H276z"/>
<path d="M5074.42 184H5019l-15-27 68.014-28.806A56 56 0 0 0 5065.75 154a55.96 55.96 0 0 0 8.67 30m21.774-79.986L5125 36l27 15v33.865l-9.554 16.724A56.1 56.1 0 0 0 5122 97.75c-9.3 0-18.075 2.262-25.806 6.264m74.671 77.851L5181 192l7 28-28-7-10.135-10.135a56.6 56.6 0 0 0 21-21M5080 112h-64l-12-12 48-16 16-48 12 12zm69.75 42c0 15.316-12.434 27.75-27.75 27.75s-27.75-12.434-27.75-27.75 12.434-27.75 27.75-27.75c2.055 0 4.058.224 5.986.648l-9.77 17.102h29.675a27.7 27.7 0 0 1 1.859 10" style="fill:#c9b269" transform="translate(-5036.031 -601)scale(1.01953)"/>
<path d="M5135.097 132.482a24.54 24.54 0 0 0-12.097-3.167c-13.624 0-24.685 11.061-24.685 24.685s11.061 24.685 24.685 24.685 24.685-11.061 24.685-24.685h8.63c0 18.387-14.928 33.315-33.315 33.315s-33.315-14.928-33.315-33.315 14.928-33.315 33.315-33.315a33.16 33.16 0 0 1 16.362 4.293l.016.011 4.336-7.59 13.81 24.172h-27.619z" style="fill:#ffe" transform="translate(-7378.422 -671.383)scale(1.47656)"/>
<path d="M276 15V0h256v15zM518 .82H290v13.36h228z" style="fill:#c9b269" transform="matrix(1.01953 0 0 17.4 -252.39 -601)"/>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.6 KiB

+15
View File
@@ -0,0 +1,15 @@
<svg viewBox="0 0 256 256" xmlns="http://www.w3.org/2000/svg" xml:space="preserve" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2">
<desc>Traced by Dogo314</desc>
<g transform="translate(-276 -306)">
<path style="fill:none" d="M276 306h256v256H276z"/>
<clipPath id="a">
<path d="M276 306h256v256H276z"/>
</clipPath>
<g clip-path="url(#a)">
<path style="fill:#190301;" transform="translate(0 306)" d="M276 0h256v256H276z"/>
<path d="M683.5 483.25c-9.359 0-17.581-4.909-22.229-12.289 3.658-.618 7.54-3.922 10.079-6.461H653.5c-8.279 0-15-6.721-15-15q0-.509.033-1.008c3.716-.528 7.694-3.906 10.279-6.492H631c-8.279 0-15-6.721-15-15s6.721-15 15-15h17.812c-2.585-2.586-6.563-5.964-10.279-6.492a15 15 0 0 1-.033-1.008c0-8.279 6.721-15 15-15h17.85c-2.539-2.539-6.421-5.843-10.079-6.461 4.648-7.38 12.87-12.289 22.229-12.289s17.581 4.909 22.229 12.289c-3.658.618-7.54 3.922-10.079 6.461h17.85c8.279 0 15 6.721 15 15q0 .509-.033 1.008c-3.716.528-7.694 3.906-10.279 6.492H736c8.279 0 15 6.721 15 15s-6.721 15-15 15h-17.812c2.585 2.586 6.563 5.964 10.279 6.492q.033.5.033 1.008c0 8.279-6.721 15-15 15h-17.85c2.539 2.539 6.421 5.843 10.079 6.461-4.648 7.38-12.87 12.289-22.229 12.289" style="fill:#ffe" transform="translate(-317.067 -17.467)scale(1.06667)"/>
<path d="M342.736 418H324l-12-12 48-16 16-48 12 12v25.174a36.2 36.2 0 0 0-6.48 7.672l-1.99 3.159C366.501 390.255 356 400.911 356 414a23.9 23.9 0 0 0-13.264 4m77.957-46.942L433 342l27 15v39.117a23.9 23.9 0 0 0-15.53-6.112l-1.99-3.159c-4.884-7.757-12.649-13.519-21.787-15.788m44.17 102.805L489 498l7 28-28-7-27.289-27.289a36 36 0 0 0 1.769-2.557l1.99-3.159c8.735-.167 16.334-5.012 20.393-12.132M382.069 490H327l-15-27 24.858-10.528C341.242 458.259 348.187 462 356 462c0 13.089 10.501 23.745 23.53 23.995l1.99 3.159q.268.428.549.846" style="fill:#dd6658"/>
<path d="M276 15V0h256v15zM518 .82H290v13.36h228z" style="fill:#e67366" transform="matrix(1 0 0 17.06667 0 306)"/>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.0 KiB

+22
View File
@@ -0,0 +1,22 @@
<svg viewBox="0 0 256 256" xmlns="http://www.w3.org/2000/svg" xml:space="preserve" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2">
<desc>Traced by Dogo314</desc>
<g transform="translate(-276 -306)">
<path style="fill:none" d="M276 306h256v256H276z"/>
<clipPath id="a">
<path d="M276 306h256v256H276z"/>
</clipPath>
<g clip-path="url(#a)">
<path style="fill:#190301;" transform="translate(0 306)" d="M276 0h256v256H276z"/>
<path style="fill:#ffe" transform="rotate(-45 227.772 916.522)scale(.9974 .92601)" d="M627 744h12v39h-12z"/>
<path style="fill:#ffe" transform="rotate(-45 174.852 938.442)scale(.9974 .92601)" d="M627 744h12v39h-12z"/>
<path style="fill:#ffe" transform="rotate(-45 251.515 879.687)scale(.9974 .92601)" d="M627 744h12v39h-12z"/>
<path style="fill:#ffe" transform="rotate(-45 198.594 901.608)scale(.9974 .92601)" d="M627 744h12v39h-12z"/>
<path style="fill:#ffe" transform="rotate(135 315.357 -193.53)scale(.9974 -.92601)" d="M627 744h12v39h-12z"/>
<path style="fill:#ffe" transform="rotate(135 306.277 -215.45)scale(.9974 -.92601)" d="M627 744h12v39h-12z"/>
<path style="fill:#ffe" transform="rotate(135 311.522 -175.786)scale(.9974 -.92601)" d="M627 744h12v39h-12z"/>
<path style="fill:#ffe" transform="rotate(135 302.443 -197.707)scale(.9974 -.92601)" d="M627 744h12v39h-12z"/>
<path d="M368.042 439.265 397 427l13.455-31.768L460 444.777V469l29 29 7 28-28-7-29-29h-20.223zm62.214-90.786L433 342l27 15v21.223zM352.223 490H327l-15-27 9.289-3.934zM360 390l16-48 12 12v64h-64l-12-12z" style="fill:#dd6658"/>
<path d="M276 15V0h256v15zM518 .82H290v13.36h228z" style="fill:#e67366" transform="matrix(1 0 0 17.06667 0 306)"/>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.8 KiB

+15
View File
@@ -0,0 +1,15 @@
<svg viewBox="0 0 256 256" xmlns="http://www.w3.org/2000/svg" xml:space="preserve" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2">
<desc>Traced by Dogo314</desc>
<g transform="translate(-276 -306)">
<path style="fill:none" d="M276 306h256v256H276z"/>
<clipPath id="a">
<path d="M276 306h256v256H276z"/>
</clipPath>
<g clip-path="url(#a)">
<path style="fill:#011419;" transform="translate(0 306)" d="M276 0h256v256H276z"/>
<path d="M688 1930h-16l-12-12v-24h-24v-28l8-8h16l8-8h24l8 8h16l8 8v28h-24v24zm-16-20c-2.208 0-4 1.792-4 4s1.792 4 4 4 4-1.792 4-4-1.792-4-4-4m20-44h-24v20h24zm-20 32c-2.208 0-4 1.792-4 4s1.792 4 4 4 4-1.792 4-4-1.792-4-4-4m16 0c-2.208 0-4 1.792-4 4s1.792 4 4 4 4-1.792 4-4-1.792-4-4-4m0 12c-2.208 0-4 1.792-4 4s1.792 4 4 4 4-1.792 4-4-1.792-4-4-4m-36-8v26l12 12v14l12 12h-40l12-12v-8l-12-12v-32zm56 0h16v32l-12 12v8l12 12h-40l12-12v-14l12-12z" style="fill:#53bcda" transform="translate(-276 -1440)"/>
<path d="M897 1802h-26l16-16h10c4.415 0 8 3.585 8 8s-3.585 8-8 8m-32 0h-11v-16h27zm182 0h-26l16-16h10c4.415 0 8 3.585 8 8s-3.585 8-8 8m-32 0h-11v-16h27zm-118 24h-26l16-16h10c4.415 0 8 3.585 8 8s-3.585 8-8 8m-32 0h-11v-16h27zm182 0h-26l16-16h10c4.415 0 8 3.585 8 8s-3.585 8-8 8m-32 0h-11v-16h27z" style="fill:#ffe" transform="translate(-550 -1440)"/>
<path d="M276 15V0h256v15zM518 .82H290v13.36h228z" style="fill:#5abeda" transform="matrix(1 0 0 17.06667 0 306)"/>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.5 KiB

+15
View File
@@ -0,0 +1,15 @@
<svg viewBox="0 0 256 256" xmlns="http://www.w3.org/2000/svg" xml:space="preserve" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2">
<desc>Traced by Dogo314</desc>
<g transform="translate(-276 -306)">
<path style="fill:none" d="M276 306h256v256H276z"/>
<clipPath id="a">
<path d="M276 306h256v256H276z"/>
</clipPath>
<g clip-path="url(#a)">
<path style="fill:#091901" transform="translate(0 306)" d="M276 0h256v256H276z"/>
<path d="M404 758h57l18 21H359l10.286-12H404zm-8.675-105H404c31.459 0 57 25.541 57 57v15h-65.675l12-36zM395 731h54v21h-45v-8.485l-9-9zm35.849-78H491v21h-35.306a63.3 63.3 0 0 0-24.845-21" style="fill:#679452" transform="translate(-154.667 -520.667)scale(1.33333)"/>
<path d="M2260 720h-24l32-47-8 39h24l-32 47zm12-16 16-48h12l16 48-16 48v16l12 12v20h-36v-20l12-12v-16l-7.085-21.254 18.21-26.746z" style="fill:#ffe" transform="translate(-1936 -306)"/>
<path d="M276 15V0h256v15zM518 .82H290v13.36h228z" style="fill:#689452" transform="matrix(1 0 0 17.06667 0 306)"/>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

+15
View File
@@ -0,0 +1,15 @@
<svg viewBox="0 0 256 256" xmlns="http://www.w3.org/2000/svg" xml:space="preserve" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2">
<desc>Traced by Dogo314</desc>
<g transform="translate(-276 -306)">
<path style="fill:none" d="M276 306h256v256H276z"/>
<clipPath id="a">
<path d="M276 306h256v256H276z"/>
</clipPath>
<g clip-path="url(#a)">
<path style="fill:#011419;" transform="translate(0 306)" d="M276 0h256v256H276z"/>
<path d="M276 15V0h256v15zM518 .82H290v13.36h228z" style="fill:#5abeda" transform="matrix(1 0 0 17.06667 0 306)"/>
<path d="m1156 2385-8-23h14.435l5.565 16h5.565l-5.565-16h24l8 12h8l56-12 56 12v22l-56 12-56-12h-8l-8 12h-24l5.565-16H1168l-5.565 16H1148z" style="fill:#ffe" transform="translate(-828 -1992)"/>
<path d="M1169 2502v-2h-36l-5-2v-33l5-2h2v-5h4v-7h21l9-6h4v8h8l3 3h5l3 3h39v-2h6v-5h52l5 5h4v6h33l5 2v33l-5 2h-37v2h-8v-2h-43v2h-6v-2h-22v2z" style="fill:#53bcda" transform="translate(-828 -1992)"/>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.0 KiB

+15
View File
@@ -0,0 +1,15 @@
<svg viewBox="0 0 256 256" xmlns="http://www.w3.org/2000/svg" xml:space="preserve" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2">
<desc>Traced by Dogo314</desc>
<g transform="translate(-276 -306)">
<path style="fill:none" d="M276 306h256v256H276z"/>
<clipPath id="a">
<path d="M276 306h256v256H276z"/>
</clipPath>
<g clip-path="url(#a)">
<path style="fill:#011419;" transform="translate(0 306)" d="M276 0h256v256H276z"/>
<path d="M1680 2461a1 1 0 0 1 1-1h10l2 1h2l2-1h7l2 1h4l6-3h32l1-2v-2h5v2h2v-2h2v2h2v-2h2v2l1 2h4l1-2h2v-2h7v2h2v-2h2v2h2v-2h2v2h2v-2h2v2h2v-2h2v2h2v-2h2v2h2v-2h2v2h2v-2h2v4h2v-2h2v2h10l3 3h53l2 2h3l1 1v3l-1 1h-2l-1 1v5h4l2-2v-4h3v3l2 2v2l-2 2h-69v1h1l2 3v5l-1 1h-2v3l-1 1h-4l-1 1h-3v5l-23 16h-6l-1 1h-2l-10-13v-6l-11-18-2-1v-3h-29c-1 4-6 9-8 9h-26a6 6 0 0 1-6-6h-3a1 1 0 0 1-1-1zm189 14v-1l1-1h3l1-1v-1l-1-1h-52l-3 3h-1v2zm-106-3v2l11 17 17-10-7-9zm-49 3v-5h-15a2 2 0 0 0-2 2h-1a3 3 0 0 1 3-3h15l-1-3h-19c-.796 0-1.559.316-2.121.879A3 3 0 0 0 1691 2469v7c0 .796.316 1.559.879 2.121a3 3 0 0 0 2.121.879h16z" style="fill:#53bcda" transform="translate(-1380 -1992)"/>
<path d="m1782 2429-22-22v-22l18-18v-28l25 25v27l8-20 10 33-25 25v-15l7-7-11-11v-14l-21 21 11 11z" style="fill:#ffe" transform="translate(-1380 -1992)"/>
<path d="M276 15V0h256v15zM518 .82H290v13.36h228z" style="fill:#5abeda" transform="matrix(1 0 0 17.06667 0 306)"/>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.4 KiB

+19
View File
@@ -0,0 +1,19 @@
<svg viewBox="0 0 256 256" xmlns="http://www.w3.org/2000/svg" xml:space="preserve" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2">
<desc>Traced by Dogo314</desc>
<g transform="translate(-276 -306)">
<path style="fill:none" d="M276 306h256v256H276z"/>
<clipPath id="a">
<path d="M276 306h256v256H276z"/>
</clipPath>
<g clip-path="url(#a)">
<path style="fill:#091901;" transform="translate(0 306)" d="M276 0h256v256H276z"/>
<path d="M276 15V0h256v15zM518 .82H290v13.36h228z" style="fill:#689452" transform="matrix(1 0 0 17.06667 0 306)"/>
<path d="M377 662v-9h27c31.459 0 57 25.541 57 57v15h-53.045l-10.8-6 16.2-9-16.2-9 16.2-9-16.2-9 16.2-9-17.55-9.75h-8.82l-2.25-2.25zm30.955 69H449v21h-46.445l10.8-6-16.2-9zM377 758h84l18 21H359zm53.849-105H491v21h-35.306a63.3 63.3 0 0 0-24.845-21" style="fill:#679452" transform="translate(-154.667 -520.667)scale(1.33333)"/>
<path d="m358 685-3 3h-47v-16h47l3 3h13l9 5-9 5z" style="fill:#ffe" transform="translate(0 -302)"/>
<path d="m358 685-3 3h-47v-16h47l3 3h13l9 5-9 5z" style="fill:#ffe" transform="translate(0 -278)"/>
<path d="m358 685-3 3h-47v-16h47l3 3h13l9 5-9 5z" style="fill:#ffe" transform="translate(0 -254)"/>
<path d="m358 685-3 3h-47v-16h47l3 3h13l9 5-9 5z" style="fill:#ffe" transform="translate(0 -230)"/>
<path d="m358 685-3 3h-47v-16h47l3 3h13l9 5-9 5z" style="fill:#ffe" transform="translate(0 -206)"/>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.5 KiB

+15
View File
@@ -0,0 +1,15 @@
<svg viewBox="0 0 256 256" xmlns="http://www.w3.org/2000/svg" xml:space="preserve" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2">
<desc>Traced by Dogo314</desc>
<g transform="translate(-276 -306)">
<path style="fill:none" d="M276 306h256v256H276z"/>
<clipPath id="a">
<path d="M276 306h256v256H276z"/>
</clipPath>
<g clip-path="url(#a)">
<path style="fill:#011419;" transform="translate(0 306)" d="M276 0h256v256H276z"/>
<path d="M4037 2483h-7l-3-3h-20v15h-4l-9.297 2.789c-.466.14-.95.211-1.437.211h-7.911q-.355 0-.707-.05L3977 2497l-8 14v4l-1.121 1.121a3 3 0 0 1-2.122.879H3960a3 3 0 0 1-1.8-.6 517 517 0 0 1-4.715-3.568 2.974 2.974 0 0 1-.587-4.175c4.035-5.074 13.102-16.992 13.102-21.657q0-6-6-6h-16l-9-5v-5h-10l-3-3h-11l-.657 22.353c-.191 6.487-5.505 11.647-11.995 11.647H3893a5 5 0 0 1-5-5v-49c0-1.326.527-2.598 1.464-3.536A5 5 0 0 1 3893 2443h9a7 7 0 0 1 7 7h13l2-2h13l4-4v-2h12v2h2v-2h2v2h2v-2h2v2h2v-2h2v2h2v-2h2v2h2v-2h2v2h2v-2h2v2h8l3 3v-3h50l2-2h11l2 2h1l2-2h12l2 2h5l6 4h6v8l-2 1v8h4v1h7v13h-7v1h-17l-3 3h-6.127a5.97 5.97 0 0 1 1.127 3.5c0 3.311-2.689 6-6 6h-8v3.5h8c3.311 0 6 2.689 6 6s-2.689 6-6 6h-8v2h-2.5v-2h-9.5v1h-1v-14h1v1h1v-3.5h-1v1h-1zm-54.5 4.5a1 1 0 1 0 0 2 1 1 0 0 0 0-2m0 5a1 1 0 1 0 0 2 1 1 0 0 0 0-2m10.5-5.5h-8c-1 3-1 5 0 8h8a4 4 0 0 0 2.828-1.172 3.995 3.995 0 0 0 0-5.656A4 4 0 0 0 3993 2487m-11 3a1 1 0 1 0 0 2 1 1 0 0 0 0-2" style="fill:#53bcda" transform="translate(-3588 -1992)"/>
<path d="M4038 2410h-44v-40h44c11.038 0 20 8.962 20 20s-8.962 20-20 20m-92 0v4h-16v-48h16v4h40v40z" style="fill:#ffe" transform="translate(-3590 -1992)"/>
<path d="M276 15V0h256v15zM518 .82H290v13.36h228z" style="fill:#5abeda" transform="matrix(1 0 0 17.06667 0 306)"/>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.8 KiB

+15
View File
@@ -0,0 +1,15 @@
<svg viewBox="0 0 256 256" xmlns="http://www.w3.org/2000/svg" xml:space="preserve" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2">
<desc>Traced by Dogo314</desc>
<g transform="translate(-276 -306)">
<path style="fill:none" d="M276 306h256v256H276z"/>
<clipPath id="a">
<path d="M276 306h256v256H276z"/>
</clipPath>
<g clip-path="url(#a)">
<path style="fill:#011419;" transform="translate(0 306)" d="M276 0h256v256H276z"/>
<path d="M388 1553.443V1541l17 17h19v24h32v-24h19l17-17v101l-16 16h-64v-67.357zm84-3.443h-64l-20-20v-16h104v16zm-24 8v16h-16v-16z" style="fill:#53bcda" transform="translate(0 -1164)"/>
<path d="m1468 1554 8 24h12v-16l20 31v58l-20 31v-16h-12l-8 24h-16l-8-24h-12v16l-20-31v-58l20-31v16h12l8-24zm-8 49h20l8-5-8-5h-20l-3-3h-25v16h25zm0 24h20l8-5-8-5h-20l-3-3h-25v16h25zm0 24h20l8-5-8-5h-20l-3-3h-25v16h25z" style="fill:#ffe" transform="translate(-1104 -1164)"/>
<path d="M276 15V0h256v15zM518 .82H290v13.36h228z" style="fill:#5abeda" transform="matrix(1 0 0 17.06667 0 306)"/>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

+15
View File
@@ -0,0 +1,15 @@
<svg viewBox="0 0 256 256" xmlns="http://www.w3.org/2000/svg" xml:space="preserve" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2">
<desc>Traced by Dogo314</desc>
<g transform="translate(-276 -306)">
<path style="fill:none" d="M276 306h256v256H276z"/>
<clipPath id="a">
<path d="M276 306h256v256H276z"/>
</clipPath>
<g clip-path="url(#a)">
<path style="fill:#011419;" transform="translate(0 306)" d="M276 0h256v256H276z"/>
<path d="M276 15V0h256v15zM518 .82H290v13.36h228z" style="fill:#5abeda" transform="matrix(1 0 0 17.06667 0 306)"/>
<path d="M388 1553.443V1541l17 17h19v24h32v-24h19l17-17v101l-16 16h-64v-67.357zm84-3.443h-64l-20-20v-16h104v16zm-24 8v16h-16v-16z" style="fill:#53bcda" transform="translate(0 -1164)"/>
<path d="M1412 1618v-25l20-31v16h12l8-24h16l8 24h12v-16l20 31v58l-20 31v-16h-12l-8 24h-16l-8-24h-12v16l-20-31v-25h36.684c1.649 4.659 6.095 8 11.316 8 6.623 0 12-5.377 12-12s-5.377-12-12-12c-5.221 0-9.667 3.341-11.316 8zm33.77-4.573 5.657-5.657-11.226-11.226-5.657 5.657zm18.23 24.698h-8V1654h8zm10.23-7.552-5.657 5.657 11.226 11.226 5.657-5.657zm1.895-12.573v8H1492v-8zm-7.552-10.23 5.657 5.657 11.226-11.226-5.657-5.657zm-12.573-1.895h8V1590h-8zm-4.573 30.355-5.657-5.657-11.226 11.226 5.657 5.657z" style="fill:#ffe" transform="translate(-1104 -1164)"/>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.4 KiB

+15
View File
@@ -0,0 +1,15 @@
<svg viewBox="0 0 256 256" xmlns="http://www.w3.org/2000/svg" xml:space="preserve" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2">
<desc>Traced by Dogo314</desc>
<g transform="translate(-276 -306)">
<path style="fill:none" d="M276 306h256v256H276z"/>
<clipPath id="a">
<path d="M276 306h256v256H276z"/>
</clipPath>
<g clip-path="url(#a)">
<path style="fill:#011419;" transform="translate(0 306)" d="M276 0h256v256H276z"/>
<path d="M2299.096 2483.755a.89.89 0 0 0-.869-.709c-.563-.046-1.227-.046-1.227-.046l-7 13q-1.5 3-3 3c-1 0-2-2-2-2h-2c-10 0-20-4-25-11h-10l-3-2h-9v-2h-3l-2-21h6l4-1h36l3-3h27l3-2h30v4h35v3c2 1 2 2 2 4h5v2h4v-2h8v2h38v-1h12v5h-12v-1h-38v3h3v4h-4v1h-5v-1h-4l6 37h4v4h-8l-4-4h4l-1.135-7H2380l-4-4h4l-3-26h-3l-4 4v5l-9 9v1l-8 8h-7l-3 3h-3l-2 2h-23l-4-2h-3v-31l-3 2v4a3.001 3.001 0 0 1-5.904.755M2238 2471v6h3l2-2v-4zm116-8a1 1 0 1 0 0 2 1 1 0 0 0 0-2m14-2a1 1 0 1 0 0 2 1 1 0 0 0 0-2m-6 2a1 1 0 1 0 0 2 1 1 0 0 0 0-2m22.216 41-.749-4.622.533 4.622zM2270 2478l-1 1v6.5a1 1 0 0 0 .4.8l2.582 1.937a1 1 0 0 0 1.519-.407l1.699-3.963a3 3 0 0 0-.636-3.303L2271 2477v1zm86-17a1 1 0 1 0 0 2 1 1 0 0 0 0-2m-4 0a1 1 0 1 0 0 2 1 1 0 0 0 0-2m-8 0a1 1 0 1 0 0 2 1 1 0 0 0 0-2m16 0a1 1 0 1 0 0 2 1 1 0 0 0 0-2m-68 24 1-3h-5c-1 1-1 2 0 3zm-6 10 6-9h-9l-1.728 4.32c-.176.439-.19.926-.04 1.375l.506 1.519c.168.503.788 1.549 1.262 1.786zm72-32a1 1 0 1 0 0 2 1 1 0 0 0 0-2m6-2a1 1 0 1 0 0 2 1 1 0 0 0 0-2m-18 2a1 1 0 1 0 0 2 1 1 0 0 0 0-2m20 0a1 1 0 1 0 0 2 1 1 0 0 0 0-2m-16 0a1 1 0 1 0 0 2 1 1 0 0 0 0-2m-48 19a1 1 0 1 0 0 2 1 1 0 0 0 0-2m46-21a1 1 0 1 0 0 2 1 1 0 0 0 0-2m22 2a1 1 0 1 0 0 2 1 1 0 0 0 0-2m2-2a1 1 0 1 0 0 2 1 1 0 0 0 0-2" style="fill:#53bcda" transform="translate(-1932 -1992)"/>
<path d="M356 2350v20h-8v-20zm78 16-5 4h-65v-20h65l5 4h15l11 6-11 6zm-78 12v20h-8v-20zm78 16-5 4h-65v-20h65l5 4h15l11 6-11 6zm-78 12v20h-8v-20zm78 16-5 4h-65v-20h65l5 4h15l11 6-11 6z" style="fill:#ffe" transform="translate(0 -1992)"/>
<path d="M276 15V0h256v15zM518 .82H290v13.36h228z" style="fill:#5abeda" transform="matrix(1 0 0 17.06667 0 306)"/>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.1 KiB

+15
View File
@@ -0,0 +1,15 @@
<svg viewBox="0 0 256 256" xmlns="http://www.w3.org/2000/svg" xml:space="preserve" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2">
<desc>Traced by Dogo314</desc>
<g transform="translate(-28.444 589.487)scale(.98084)">
<path style="fill:none" d="M29-601h261v261H29z"/>
<clipPath id="a">
<path d="M29-601h261v261H29z"/>
</clipPath>
<g clip-path="url(#a)">
<path style="fill:#363426" transform="translate(-252.39 -601)scale(1.01953)" d="M276 0h256v256H276z"/>
<path d="M1771 96h-17c-7.727 0-14-6.273-14-14 0-7.586 6.047-13.771 13.579-13.994C1755.3 62.223 1760.661 58 1767 58c1.194 0 2.353.15 3.46.431 1.579-6 7.046-10.431 13.54-10.431s11.961 4.431 13.54 10.431A14 14 0 0 1 1801 58c6.339 0 11.7 4.223 13.421 10.006C1821.953 68.229 1828 74.414 1828 82c0 7.727-6.273 14-14 14h-17s-9 12-9 39c0 31 4 41 4 41l24-24v36l20-20v20h20l-20 20h-104l-20-20h20v-20l20 20v-36l24 24s4-10 4-41c0-27-9-39-9-39" style="fill:#ffe" transform="translate(-1659.344 -601)scale(1.01953)"/>
<path d="M1785 118c21.525 0 39 2.689 39 6s-17.475 6-39 6-39-2.689-39-6 17.475-6 39-6m0 4c-14.902 0-27 .896-27 2s12.098 2 27 2 27-.896 27-2-12.098-2-27-2" style="fill:#ffe" transform="matrix(1.35938 0 0 2.03906 -2266.984 -727.422)"/>
<path d="M276 256V0h256v256zM518 14H290v228h228zm-10 10v32l-32-32zM300 232v-32l32 32zm0-208h32l-32 32zm208 208h-32l32-32z" style="fill:#c9b269" transform="translate(-252.39 -601)scale(1.01953)"/>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.5 KiB

+15
View File
@@ -0,0 +1,15 @@
<svg viewBox="0 0 256 256" xmlns="http://www.w3.org/2000/svg" xml:space="preserve" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2">
<desc>Traced by Dogo314</desc>
<g transform="translate(-276 -306)">
<path style="fill:none" d="M276 306h256v256H276z"/>
<clipPath id="a">
<path d="M276 306h256v256H276z"/>
</clipPath>
<g clip-path="url(#a)">
<path style="fill:#091901;" transform="translate(0 306)" d="M276 0h256v256H276z"/>
<path d="M389 662v-9h15c31.459 0 57 25.541 57 57v15h-72v-9h19.817l4.5-3h11.384l16.5-12-16.5-12 16.5-12-16.5-12h-11.384l-4.5-3zm41.849-9H485v21h-29.306a63.3 63.3 0 0 0-24.845-21M446 731v21h-42v-21zm15 27 18 21H371l18-21z" style="fill:#679452" transform="translate(-138.667 -520.667)scale(1.33333)"/>
<path d="M2254 932c7.727 0 14 6.273 14 14s-6.273 14-14 14-14-6.273-14-14 6.273-14 14-14m-14 104h-4a4 4 0 0 1-2.828-1.172A4 4 0 0 1 2232 1032v-64c0-1.061.421-2.078 1.172-2.828A4 4 0 0 1 2236 964h36c1.061 0 2.078.421 2.828 1.172A4 4 0 0 1 2276 968v64a4 4 0 0 1-1.172 2.828A4 4 0 0 1 2272 1036h-4v60a4 4 0 0 1-1.172 2.828A4 4 0 0 1 2264 1100h-20a4 4 0 0 1-2.828-1.172A4 4 0 0 1 2240 1096zm102-32-6 4h-44v-24h44l6 4h15l11 8-11 8zm0-32-6 4h-44v-24h44l6 4h15l11 8-11 8z" style="fill:#ffe" transform="translate(-1932 -582)"/>
<path d="M276 15V0h256v15zM518 .82H290v13.36h228z" style="fill:#689452" transform="matrix(1 0 0 17.06667 0 306)"/>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.4 KiB

+15
View File
@@ -0,0 +1,15 @@
<svg viewBox="0 0 256 256" xmlns="http://www.w3.org/2000/svg" xml:space="preserve" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2">
<desc>Traced by Dogo314</desc>
<g transform="translate(-276 -306)">
<path style="fill:none" d="M276 306h256v256H276z"/>
<clipPath id="a">
<path d="M276 306h256v256H276z"/>
</clipPath>
<g clip-path="url(#a)">
<path style="fill:#091901;" transform="translate(0 306)" d="M276 0h256v256H276z"/>
<path d="M516 1128H292v-18.222L332 1092l36 16 36-16 36 16 36-16 40 17.778z" style="fill:#679452" transform="translate(0 -582)"/>
<path d="M388.623 1064H360v-12a4 4 0 0 1 4-4h8.677zm44.327-16H444a4 4 0 0 1 4 4v12h-29.246zM344 1088.579V1072h119v17.023l-23 10.222-36-16-36 16zm56-24.512L376 1040v-16l20-20v-24l20 24v16l8-8 16 16-32 36.067V1048l4-8-8-4v-16l-12 20 8 8z" style="fill:#ffe" transform="translate(0 -582)"/>
<path d="M276 15V0h256v15zM518 .82H290v13.36h228z" style="fill:#689452" transform="matrix(1 0 0 17.06667 0 306)"/>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

+15
View File
@@ -0,0 +1,15 @@
<svg viewBox="0 0 256 256" xmlns="http://www.w3.org/2000/svg" xml:space="preserve" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2">
<desc>Traced by Dogo314</desc>
<g transform="translate(-276 -306)">
<path style="fill:none" d="M276 306h256v256H276z"/>
<clipPath id="a">
<path d="M276 306h256v256H276z"/>
</clipPath>
<g clip-path="url(#a)">
<path style="fill:#011419;" transform="translate(0 306)" d="M276 0h256v256H276z"/>
<path d="M4326.52 2489H4325v13h-5v4h-11v8.399a3.87 3.87 0 0 1-1.132 2.733l-.487.487a1.3 1.3 0 0 1-.919.381h-3.013q-.449 0-.887-.099l-17.234-3.917a3.002 3.002 0 0 1-1.802-4.633l5.941-8.581a3 3 0 0 0 .533-1.707v-.82a3 3 0 0 0-.879-2.122L4287 2494h-15c-4 0-6-4-9-8l-6 6v11h-2v12h-13c0-17-11-25-15-25h-6v-3l-4-5h-2v3h-10v-3h-26v3h-10v-3h-3l-2-2v-24l2-2h3v-3h10v3h26v-3h10v3h11v-18l2.684-.895c.205-.068.427-.068.632 0l2.417.806c.175.058.362.067.541.026l12.492-2.883a1 1 0 0 1 .467.004l11.305 2.827a1 1 0 0 0 .843-.171l3.2-2.4a1 1 0 0 1 .916-.148l2.187.729c.205.068.427.068.632 0l2.187-.729a1 1 0 0 1 .916.148l3.087 2.315c.303.227.708.264 1.047.095l2.802-1.402c.385-.192.85-.117 1.155.188l1.49 1.49v17h12v2h8v2h42v-2h3v-1a3.001 3.001 0 0 1 6 0v1h2v-1a3.001 3.001 0 0 1 6 0v1h2v-1a3.001 3.001 0 0 1 6 0v1h8v26h-6l-2 2h-20v4h-4v2h-5.52c.332 2.09.52 4.473.52 7 0 5.215-.8 9.812-2.013 12.5 1.213.538 2.013 1.457 2.013 2.5 0 1.656-2.016 3-4.5 3s-4.5-1.344-4.5-3c0-1.043.8-1.962 2.013-2.5-1.213-2.688-2.013-7.285-2.013-12.5 0-2.527.188-4.91.52-7m-74.52 14a.997.997 0 0 0-1 1v7a.997.997 0 0 0 1 1 .997.997 0 0 0 1-1v-7a.997.997 0 0 0-1-1m0-11a.997.997 0 0 0-1 1v7a.997.997 0 0 0 1 1 .997.997 0 0 0 1-1v-7a.997.997 0 0 0-1-1m60 2h-6c-1 2-1 3 0 5h5a.997.997 0 0 0 1-1zm-8 20a1 1 0 0 0 1-1v-10a.997.997 0 0 0-1-1h-3.446a1 1 0 0 0-.848.47l-4.554 7.287a1 1 0 0 0-.152.53v.992a1 1 0 0 0 .684.949l5.162 1.721a1 1 0 0 0 .316.051z" style="fill:#53bcda" transform="translate(-3864 -1992)"/>
<path d="M4284.473 2382.75H4201.5v-7.5h82.973c1.667-6.467 7.543-11.25 14.527-11.25 8.279 0 15 6.721 15 15s-6.721 15-15 15c-6.984 0-12.86-4.783-14.527-11.25m18.277-41.25v15h-7.5v-15zm25.418 13.635-10.606 10.607-5.304-5.304 10.607-10.606zm8.332 27.615h-15v-7.5h15zm-13.635 25.418-10.607-10.606 5.304-5.304 10.606 10.607zm-27.615 8.332v-15h7.5v15zm-25.418-13.635 10.606-10.607 5.304 5.304-10.607 10.606zm5.303-53.033 10.607 10.606-5.304 5.304-10.606-10.607z" style="fill:#ffe" transform="translate(-4149.6 -2151.6)scale(1.06667)"/>
<path d="M276 15V0h256v15zM518 .82H290v13.36h228z" style="fill:#5abeda" transform="matrix(1 0 0 17.06667 0 306)"/>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.6 KiB

+15
View File
@@ -0,0 +1,15 @@
<svg viewBox="0 0 256 256" xmlns="http://www.w3.org/2000/svg" xml:space="preserve" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2">
<desc>Traced by Dogo314</desc>
<g transform="translate(-276 -306)">
<path style="fill:none" d="M276 306h256v256H276z"/>
<clipPath id="a">
<path d="M276 306h256v256H276z"/>
</clipPath>
<g clip-path="url(#a)">
<path style="fill:#011419;" transform="translate(0 306)" d="M276 0h256v256H276z"/>
<path d="M668 1538h-40v-24h104v24h-40v96h-24zm-48 96h-24l24-44zm120 0v-44l24 44z" style="fill:#53bcda" transform="translate(-276 -1164)"/>
<path d="M660 1546v88h-32v-88zm72 0v88h-32v-88zm-92 96v40h-8l-4-40zm72 0v40h-8l-4-40zm-64 0h12l-4 40h-8zm72 0h12l-4 40h-8z" style="fill:#ffe" transform="translate(-276 -1164)"/>
<path d="M276 15V0h256v15zM518 .82H290v13.36h228z" style="fill:#5abeda" transform="matrix(1 0 0 17.06667 0 306)"/>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 981 B

+15
View File
@@ -0,0 +1,15 @@
<svg viewBox="0 0 256 256" xmlns="http://www.w3.org/2000/svg" xml:space="preserve" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2">
<desc>Traced by Dogo314</desc>
<g transform="translate(-276 -306)">
<path style="fill:none" d="M276 306h256v256H276z"/>
<clipPath id="a">
<path d="M276 306h256v256H276z"/>
</clipPath>
<g clip-path="url(#a)">
<path style="fill:#011419;" transform="translate(0 306)" d="M276 0h256v256H276z"/>
<path d="M308 2453.998a2 2 0 0 1 1.998-1.998H314c1.061 0 2.078.421 2.828 1.172A4 4 0 0 1 318 2456v1l27-4h32v-2h2l1 2h1v-2h2l1 2h1v-2h2l1 2h1v-2h2l1 2h1v-2h2l1 2h1v-2h2l1 2 1-2h6l1 2h6l6 3h88v4h-4v1h2v5h2v5h-96v11h-5v28h-20v-30h-10.622a5 5 0 0 0-4.957 4.339l-1.19 8.925a2 2 0 0 1-1.982 1.736h-4.491a4.75 4.75 0 0 1-3.364-1.394 4.75 4.75 0 0 1-1.394-3.364V2490l5-14v-.394a5.606 5.606 0 0 0-5.606-5.606H321v3l.762.381a2.24 2.24 0 0 1 1.238 2.003v.026a3.59 3.59 0 0 1-3.59 3.59h-1.993a9.1 9.1 0 0 1-4.515-1.199L308 2475a5 5 0 0 1-5 5h-1a2 2 0 0 1-2-2v-22c0-1.061.421-2.078 1.172-2.828A4 4 0 0 1 304 2452h2a2 2 0 0 1 2 1.998M376 2473a2 2 0 0 0-2 2v1a2 2 0 0 0 2 2h6a2 2 0 0 0 2-2v-1a2 2 0 0 0-2-2h-4c0 1 .5 3 1 4-1.837-.791-3-2-3-4" style="fill:#53bcda" transform="translate(0 -1992)"/>
<path d="M356 2350v20h-8v-20zm78 16-5 4h-65v-20h65l5 4h15l11 6-11 6zm-78 12v20h-8v-20zm78 16-5 4h-65v-20h65l5 4h15l11 6-11 6zm-78 12v20h-8v-20zm78 16-5 4h-65v-20h65l5 4h15l11 6-11 6z" style="fill:#ffe" transform="translate(0 -1992)"/>
<path d="M276 15V0h256v15zM518 .82H290v13.36h228z" style="fill:#5abeda" transform="matrix(1 0 0 17.06667 0 306)"/>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.6 KiB

+15
View File
@@ -0,0 +1,15 @@
<svg viewBox="0 0 256 256" xmlns="http://www.w3.org/2000/svg" xml:space="preserve" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2">
<desc>Traced by Dogo314</desc>
<g transform="translate(-276 -306)">
<path style="fill:none" d="M276 306h256v256H276z"/>
<clipPath id="a">
<path d="M276 306h256v256H276z"/>
</clipPath>
<g clip-path="url(#a)">
<path style="fill:#091901;" transform="translate(0 306)" d="M276 0h256v256H276z"/>
<path d="m358 685-3 3h-47v-16h47l3 3h13l9 5-9 5zm0 24-3 3h-47v-16h47l3 3h13l9 5-9 5zm0 24-3 3h-47v-16h47l3 3h13l9 5-9 5z" style="fill:#ffe" transform="translate(0 -306)"/>
<path d="M377 659v-6h27c31.459 0 57 25.541 57 57v15h-84v-6h7.735l2.25-2.25h8.82l17.55-9.75-16.2-9 16.2-9-16.2-9 16.2-9-17.55-9.75h-8.82l-2.25-2.25zm53.849-6H491v21h-35.306a63.3 63.3 0 0 0-24.845-21M449 731v21h-60v-21zm12 27 18 21H359l18-21z" style="fill:#679452" transform="translate(-154.667 -520.667)scale(1.33333)"/>
<path d="M276 15V0h256v15zM518 .82H290v13.36h228z" style="fill:#689452" transform="matrix(1 0 0 17.06667 0 306)"/>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

+15
View File
@@ -0,0 +1,15 @@
<svg viewBox="0 0 256 256" xmlns="http://www.w3.org/2000/svg" xml:space="preserve" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2">
<desc>Traced by Dogo314</desc>
<g transform="translate(-276 -306)">
<path style="fill:none" d="M276 306h256v256H276z"/>
<clipPath id="a">
<path d="M276 306h256v256H276z"/>
</clipPath>
<g clip-path="url(#a)">
<path style="fill:#091901;" transform="translate(0 306)" d="M276 0h256v256H276z"/>
<path d="M404 758h57l18 21H359l10.286-12H404zm-8.675-105H404c31.459 0 57 25.541 57 57v15h-65.675l12-36zM395 731h54v21h-45v-8.485l-9-9zm35.849-78H491v21h-35.306a63.3 63.3 0 0 0-24.845-21" style="fill:#679452" transform="translate(-154.667 -520.667)scale(1.33333)"/>
<path d="m2020 656 16 48-16 48v16l12 12v20h-36v-20l12-12v-16l-16-48 16-48z" style="fill:#ffe" transform="translate(-1656 -306)"/>
<path d="M276 15V0h256v15zM518 .82H290v13.36h228z" style="fill:#689452" transform="matrix(1 0 0 17.06667 0 306)"/>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.0 KiB

+15
View File
@@ -0,0 +1,15 @@
<svg viewBox="0 0 256 256" xmlns="http://www.w3.org/2000/svg" xml:space="preserve" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2">
<desc>Traced by Dogo314</desc>
<g transform="translate(-276 -306)">
<path style="fill:none" d="M276 306h256v256H276z"/>
<clipPath id="a">
<path d="M276 306h256v256H276z"/>
</clipPath>
<g clip-path="url(#a)">
<path style="fill:#190301;" transform="translate(0 306)" d="M276 0h256v256H276z"/>
<path d="M4797.944 201.687q-.495 1.099-.948 2.248h-10.185a41.3 41.3 0 0 1 7.522-7.899zm47.723-5.651a41.3 41.3 0 0 1 7.522 7.899h-10.185a51 51 0 0 0-.948-2.248zm-27.375 5.413v2.486h-17.657c3.052-7.205 7.437-12.644 12.532-15.248v4.74zm8.541-12.762c5.095 2.604 9.48 8.043 12.532 15.248h-17.657v-2.486l5.125-8.022zM4779 228c0-7.466 2-14.468 5.492-20.5h11.236c-1.956 6.138-3.061 13.11-3.061 20.5zm17.083 0v-.007c0-7.463 1.165-14.462 3.201-20.493h19.008V228zm25.625 0v-20.5h19.008c2.036 6.031 3.201 13.03 3.201 20.493V228zm25.625 0c0-7.39-1.105-14.362-3.061-20.5h11.236A40.8 40.8 0 0 1 4861 228z" style="fill:#dd6658" transform="matrix(2.34146 0 0 2.2439 -10881.854 22.39)"/>
<path d="m3432 426-4-4v-36h24v36l-4 4v28l-8 12-8-12zm20-56v8h-24v-8zm28 56-4-4v-36h24v36l-4 4v28l-8 12-8-12zm20-56v8h-24v-8zm-116 56-4-4v-36h24v36l-4 4v28l-8 12-8-12zm20-56v8h-24v-8z" style="fill:#ffe" transform="translate(-3036)"/>
<path d="M276 15V0h256v15zM518 .82H290v13.36h228z" style="fill:#e67366" transform="matrix(1 0 0 17.06667 0 306)"/>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.5 KiB

+15
View File
@@ -0,0 +1,15 @@
<svg viewBox="0 0 256 256" xmlns="http://www.w3.org/2000/svg" xml:space="preserve" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2">
<desc>Traced by Dogo314</desc>
<g transform="translate(-276 -306)">
<path style="fill:none" d="M276 306h256v256H276z"/>
<clipPath id="a">
<path d="M276 306h256v256H276z"/>
</clipPath>
<g clip-path="url(#a)">
<path style="fill:#190301;" transform="translate(0 306)" d="M276 0h256v256H276z"/>
<path d="M4801.225 195.624c-1.606 2.477-3.028 5.267-4.229 8.311h-10.185a41.3 41.3 0 0 1 11.876-10.959zm44.4.378a41.3 41.3 0 0 1 7.564 7.933h-7.564zm-4.394 13.104c1.716 5.654 2.686 12.078 2.686 18.887V228h-22.209v-20.5h9.689l5.686 5.933zm-12.689-5.171h-6.834v-2.089l6.834-7.13zm-10.25-2.089v2.089h-17.657c2.705-6.387 6.457-11.385 10.823-14.252v5.033zM4779 228c0-7.466 2-14.468 5.492-20.5h11.236c-1.956 6.138-3.061 13.11-3.061 20.5zm17.083 0v-.007c0-7.463 1.165-14.462 3.201-20.493h19.008V228zm51.25 0c0-7.39-1.105-14.362-3.061-20.5h11.236A40.8 40.8 0 0 1 4861 228z" style="fill:#dd6658" transform="matrix(2.34146 0 0 2.2439 -10881.854 22.39)"/>
<path d="m3744 442.2-4-8.2v-32h32v32l-4 8.2V478l-12 12-12-12zm28-56.2v8h-32v-8zm-68 34.2-4-8.2v-32h32v32l-4 8.2V456l-12 12-12-12zm28-56.2v8h-32v-8zm-68 42.2-4-8.2v-32h32v32l-4 8.2V442l-12 12-12-12zm28-56.2v8h-32v-8z" style="fill:#ffe" transform="translate(-3312)"/>
<path d="M276 15V0h256v15zM518 .82H290v13.36h228z" style="fill:#e67366" transform="matrix(1 0 0 17.06667 0 306)"/>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.5 KiB

+15
View File
@@ -0,0 +1,15 @@
<svg viewBox="0 0 256 256" xmlns="http://www.w3.org/2000/svg" xml:space="preserve" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2">
<desc>Traced by Dogo314</desc>
<g transform="translate(-276 -306)">
<path style="fill:none" d="M276 306h256v256H276z"/>
<clipPath id="a">
<path d="M276 306h256v256H276z"/>
</clipPath>
<g clip-path="url(#a)">
<path style="fill:#190301;" transform="translate(0 306)" d="M276 0h256v256H276z"/>
<path d="M4801.024 195.937c-1.524 2.398-2.877 5.082-4.028 7.998h-10.185a41.2 41.2 0 0 1 16.006-13.166l-1.802 5.165zm36.159-5.168a41.2 41.2 0 0 1 16.006 13.166h-10.185c-1.151-2.916-2.504-5.6-4.028-7.998l.009-.003zm-1.423 6.389c1.343 2.02 2.553 4.294 3.605 6.777h-14.24v-16.004l.186.071 4.042 11.59zm-14.052 10.342h19.008c2.036 6.031 3.201 13.03 3.201 20.493V228h-22.209zm-3.416 0V228h-22.209v-.007c0-7.463 1.165-14.462 3.201-20.493zm-3.417-3.565h-14.24c1.052-2.483 2.262-4.757 3.605-6.777l6.407 2.434 4.042-11.59.186-.071zM4779 228c0-7.466 2-14.468 5.492-20.5h11.236c-1.956 6.138-3.061 13.11-3.061 20.5zm68.333 0c0-7.39-1.105-14.362-3.061-20.5h11.236A40.8 40.8 0 0 1 4861 228z" style="fill:#dd6658" transform="matrix(2.34146 0 0 2.2439 -10881.854 22.39)"/>
<path d="m3996 370.433 8.343-6.422-3.848 10.817 11.477-.317L4002.5 381l9.472 6.489-11.477-.317 3.848 10.817-9.098-7.003L3992 402l-3.245-11.014-9.098 7.003 3.848-10.817-11.477.317L3981.5 381l-9.472-6.489 11.477.317-3.848-10.817 8.343 6.422V342h8zm0 37.567v8h-8v-8zm0 16v8h-8v-8zm0 16v8h-8v-8zm0 16v8h-8v-8zm0 16v8h-8v-8zm-11.528-64.622-2.736 7.517-7.518-2.736 2.737-7.517zM3979 422.413l-2.736 7.518-7.518-2.737 2.736-7.517zm-5.473 15.035-2.736 7.518-7.517-2.737 2.736-7.517zm-5.472 15.035-2.736 7.518-7.518-2.736 2.737-7.518zm38.99-47.841 2.737 7.517-7.518 2.736-2.736-7.517zm5.473 15.035 2.736 7.517-7.518 2.737-2.736-7.518zm5.472 15.035 2.736 7.517-7.517 2.737-2.736-7.518zm5.472 15.035 2.737 7.518-7.518 2.736-2.736-7.518z" style="fill:#ffe" transform="translate(-3588)"/>
<path d="M276 15V0h256v15zM518 .82H290v13.36h228z" style="fill:#e67366" transform="matrix(1 0 0 17.06667 0 306)"/>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.1 KiB

+15
View File
@@ -0,0 +1,15 @@
<svg viewBox="0 0 256 256" xmlns="http://www.w3.org/2000/svg" xml:space="preserve" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2">
<desc>Traced by Dogo314</desc>
<g transform="translate(-276 -306)">
<path style="fill:none" d="M276 306h256v256H276z"/>
<clipPath id="a">
<path d="M276 306h256v256H276z"/>
</clipPath>
<g clip-path="url(#a)">
<path style="fill:#190301;" transform="translate(0 306)" d="M276 0h256v256H276z"/>
<path d="M4818.292 207.5V228h-22.209v-.007c0-7.463 1.165-14.462 3.201-20.493zm0-3.565h-17.657c4.035-9.527 10.401-15.966 17.657-16.846zm9.436-14.758c4.713 2.762 8.765 7.978 11.637 14.758h-16.848zM4779 228c0-7.466 2-14.468 5.492-20.5h11.236c-1.956 6.138-3.061 13.11-3.061 20.5zm42.708 0v-20.5h19.008c2.036 6.031 3.201 13.03 3.201 20.493V228zm25.625 0c0-7.39-1.105-14.362-3.061-20.5h11.236A40.8 40.8 0 0 1 4861 228zm-60.522-24.065c4.86-6.689 11.692-11.854 19.638-14.639-3.826 3.571-7.073 8.608-9.453 14.639zm46.74-14.639c7.946 2.785 14.778 7.95 19.638 14.639h-10.185c-2.38-6.031-5.627-11.068-9.453-14.639" style="fill:#dd6658" transform="matrix(2.34146 0 0 2.2439 -10881.854 22.39)"/>
<path d="m4548 410-28 8 28-76v52l28-8-28 76zm-74.251 40.065a112.6 112.6 0 0 1 15.666-10.204l3.757 7.065a105 105 0 0 0-14.054 9.097zm22.842-13.749a114 114 0 0 1 17.386-6.196l1.937 7.767a106 106 0 0 0-15.558 5.511zm25.183-7.992a116 116 0 0 1 16.297-1.975l.143 8.003c-4.934.26-9.775.85-14.501 1.748zm50.423 1.324a114 114 0 0 1 15.729 5.167l-3.516 7.208a106 106 0 0 0-14.014-4.576zm23.018 8.47a113 113 0 0 1 14.383 8.52l-5.048 6.233a105 105 0 0 0-12.843-7.561z" style="fill:#ffe" transform="translate(-4140)"/>
<path d="M276 15V0h256v15zM518 .82H290v13.36h228z" style="fill:#e67366" transform="matrix(1 0 0 17.06667 0 306)"/>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.8 KiB

+15
View File
@@ -0,0 +1,15 @@
<svg viewBox="0 0 256 256" xmlns="http://www.w3.org/2000/svg" xml:space="preserve" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2">
<desc>Traced by Dogo314</desc>
<g transform="translate(-276 -306)">
<path style="fill:none" d="M276 306h256v256H276z"/>
<clipPath id="a">
<path d="M276 306h256v256H276z"/>
</clipPath>
<g clip-path="url(#a)">
<path style="fill:#190301;" transform="translate(0 306)" d="M276 0h256v256H276z"/>
<path d="M4798.688 200.107a51 51 0 0 0-1.692 3.828h-10.185a41.3 41.3 0 0 1 7.779-8.104zm46.722-4.276a41.3 41.3 0 0 1 7.779 8.104h-10.185a51 51 0 0 0-1.692-3.828zm-11.182 11.669h6.488c2.036 6.031 3.201 13.03 3.201 20.493V228h-22.209v-19.023l5.552 5.793zm-15.936 1.477V228h-22.209v-.007c0-7.463 1.165-14.462 3.201-20.493h6.488l6.968 7.27zM4779 228c0-7.466 2-14.468 5.492-20.5h11.236c-1.956 6.138-3.061 13.11-3.061 20.5zm68.333 0c0-7.39-1.105-14.362-3.061-20.5h11.236A40.8 40.8 0 0 1 4861 228z" style="fill:#dd6658" transform="matrix(2.34146 0 0 2.2439 -10881.854 22.39)"/>
<path d="m5074 460-30-30v-36h12c0-22.077 17.923-40 40-40s40 17.923 40 40h12v36l-30 30 6 6 12-12 8 8-31 31-8-8 11-11-6-6-.565.565c-7.42 7.42-19.45 7.42-26.87 0L5082 468l-6 6 11 11-8 8-31-31 8-8 12 12zm22-34c-2.208 0-4 1.792-4 4s1.792 4 4 4 4-1.792 4-4-1.792-4-4-4m-14 8c-2.208 0-4 1.792-4 4s1.792 4 4 4 4-1.792 4-4-1.792-4-4-4m14 24c-2.208 0-4 1.792-4 4s1.792 4 4 4 4-1.792 4-4-1.792-4-4-4m32-64h-64v24l12 12 20-12 20 12 12-12zm-32 48c-2.208 0-4 1.792-4 4s1.792 4 4 4 4-1.792 4-4-1.792-4-4-4m14-8c-2.208 0-4 1.792-4 4s1.792 4 4 4 4-1.792 4-4-1.792-4-4-4m-28 16c-2.208 0-4 1.792-4 4s1.792 4 4 4 4-1.792 4-4-1.792-4-4-4m28 0c-2.208 0-4 1.792-4 4s1.792 4 4 4 4-1.792 4-4-1.792-4-4-4" style="fill:#ffe" transform="translate(-4692)"/>
<path d="M276 15V0h256v15zM518 .82H290v13.36h228z" style="fill:#e67366" transform="matrix(1 0 0 17.06667 0 306)"/>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.9 KiB

+15
View File
@@ -0,0 +1,15 @@
<svg viewBox="0 0 256 256" xmlns="http://www.w3.org/2000/svg" xml:space="preserve" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2">
<desc>Traced by Dogo314</desc>
<g transform="translate(-276 -306)">
<path style="fill:none" d="M276 306h256v256H276z"/>
<clipPath id="a">
<path d="M276 306h256v256H276z"/>
</clipPath>
<g clip-path="url(#a)">
<path style="fill:#190301;" transform="translate(0 306)" d="M276 0h256v256H276z"/>
<path d="M4818.292 207.5V228h-22.209v-.007c0-7.463 1.165-14.462 3.201-20.493zm-3.417-3.565h-14.24c1.969-4.65 4.494-8.564 7.407-11.456v6.999h6.833zm17.083-11.456c2.913 2.892 5.438 6.806 7.407 11.456h-14.24v-4.457h6.833zm-10.25 15.021h19.008c2.036 6.031 3.201 13.03 3.201 20.493V228h-22.209zM4779 228c0-7.466 2-14.468 5.492-20.5h11.236c-1.956 6.138-3.061 13.11-3.061 20.5zm68.333 0c0-7.39-1.105-14.362-3.061-20.5h11.236A40.8 40.8 0 0 1 4861 228zm-60.522-24.065c4.86-6.689 11.692-11.854 19.638-14.639-3.826 3.571-7.073 8.608-9.453 14.639zm46.74-14.639c7.946 2.785 14.778 7.95 19.638 14.639h-10.185c-2.38-6.031-5.627-11.068-9.453-14.639" style="fill:#dd6658" transform="matrix(2.34146 0 0 2.2439 -10881.854 22.39)"/>
<path d="M2892 452v28h-8v-28zm0-36v28h-8v-28zm-16 18v28h-8v-28zm0-36v28h-8v-28zm32 36v28h-8v-28zm0-36v28h-8v-28zm-16-14v24h-8v-24zm0-32v24h-8v-24zm-16 10v28h-8v-28zm32 0v28h-8v-28z" style="fill:#ffe" transform="translate(-2484)"/>
<path d="M276 15V0h256v15zM518 .82H290v13.36h228z" style="fill:#e67366" transform="matrix(1 0 0 17.06667 0 306)"/>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.6 KiB

@@ -0,0 +1,14 @@
<svg viewBox="0 0 256 256" xmlns="http://www.w3.org/2000/svg" xml:space="preserve" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2">
<desc>Traced by Dogo314</desc>
<g transform="translate(-28.444 589.487)scale(.98084)">
<path style="fill:none" d="M29-601h261v261H29z"/>
<clipPath id="a">
<path d="M29-601h261v261H29z"/>
</clipPath>
<g clip-path="url(#a)">
<path style="fill:#363426" transform="translate(-252.39 -601)scale(1.01953)" d="M276 0h256v256H276z"/>
<path d="M1232 102c14.35 0 26 11.65 26 26s-11.65 26-26 26-26-11.65-26-26 11.65-26 26-26m-42 20v12h-62v-12zm84 12v-12h62v12zm-7.092-31.055-8.485-8.486 21.213-21.213 8.485 8.486zm-8.485 61.331 8.485-8.485 21.213 21.213-8.485 8.485zm-61.331-8.485 8.485 8.485-21.213 21.213-8.485-8.485zm8.485-61.332-8.485 8.486-21.213-21.213 8.485-8.486zM1238 86h-12V36h12zm-12 84h12v50h-12z" style="fill:#ffe" transform="translate(-1096.563 -601)scale(1.01953)"/>
<path d="M276 256V0h256v256zM518 14H290v228h228zM300 24h32l-32 32zm0 208v-32l32 32zm208 0h-32l32-32zm0-208v32l-32-32z" style="fill:#c9b269" transform="translate(-252.39 -601)scale(1.01953)"/>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.2 KiB

+15
View File
@@ -0,0 +1,15 @@
<svg viewBox="0 0 256 256" xmlns="http://www.w3.org/2000/svg" xml:space="preserve" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2">
<desc>Traced by Dogo314</desc>
<g transform="translate(-276 -306)">
<path style="fill:none" d="M276 306h256v256H276z"/>
<clipPath id="a">
<path d="M276 306h256v256H276z"/>
</clipPath>
<g clip-path="url(#a)">
<path style="fill:#190301;" transform="translate(0 306)" d="M276 0h256v256H276z"/>
<path d="M4829.801 190.582c3.829 2.956 7.123 7.589 9.564 13.353h-17.657v-8.149c3.342-.499 6.24-2.443 8.093-5.204m-11.509 5.204v8.149h-17.657c2.441-5.764 5.735-10.397 9.564-13.353 1.853 2.761 4.751 4.705 8.093 5.204M4779 228c0-7.466 2-14.468 5.492-20.5h11.236c-1.956 6.138-3.061 13.11-3.061 20.5zm17.083 0v-.007c0-7.463 1.165-14.462 3.201-20.493h19.008V228zm25.625 0v-20.5h19.008c2.036 6.031 3.201 13.03 3.201 20.493V228zm25.625 0c0-7.39-1.105-14.362-3.061-20.5h11.236A40.8 40.8 0 0 1 4861 228zm-60.522-24.065c4.86-6.689 11.692-11.854 19.638-14.639-3.826 3.571-7.073 8.608-9.453 14.639zm46.74-14.639c7.946 2.785 14.778 7.95 19.638 14.639h-10.185c-2.38-6.031-5.627-11.068-9.453-14.639" style="fill:#dd6658" transform="matrix(2.34146 0 0 2.2439 -10881.854 22.39)"/>
<path d="M5376 414.401c9.124 1.855 16 9.93 16 19.599 0 11.038-8.962 20-20 20s-20-8.962-20-20c0-9.669 6.876-17.744 16-19.599V342h8zM5424 430v8h-24v-8zm-18.059-35.598 5.657 5.657-16.971 16.97-5.656-5.656zm-73.539 5.657 5.657-5.657 16.97 16.971-5.656 5.656zM5320 438v-8h24v8z" style="fill:#ffe" transform="translate(-4968)"/>
<path d="M276 15V0h256v15zM518 .82H290v13.36h228z" style="fill:#e67366" transform="matrix(1 0 0 17.06667 0 306)"/>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.7 KiB

+15
View File
@@ -0,0 +1,15 @@
<svg viewBox="0 0 256 256" xmlns="http://www.w3.org/2000/svg" xml:space="preserve" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2">
<desc>Traced by Dogo314</desc>
<g transform="translate(-276 -306)">
<path style="fill:none" d="M276 306h256v256H276z"/>
<clipPath id="a">
<path d="M276 306h256v256H276z"/>
</clipPath>
<g clip-path="url(#a)">
<path style="fill:#190301;" transform="translate(0 306)" d="M276 0h256v256H276z"/>
<path d="M4779 228c0-7.466 2-14.468 5.492-20.5h11.236c-1.956 6.138-3.061 13.11-3.061 20.5zm17.083 0v-.007c0-7.463 1.165-14.462 3.201-20.493h19.008V228zm25.625 0v-20.5h19.008c2.036 6.031 3.201 13.03 3.201 20.493V228zm25.625 0c0-7.39-1.105-14.362-3.061-20.5h11.236A40.8 40.8 0 0 1 4861 228zm-60.522-24.065c4.86-6.689 11.692-11.854 19.638-14.639-3.826 3.571-7.073 8.608-9.453 14.639zm46.74-14.639c7.946 2.785 14.778 7.95 19.638 14.639h-10.185c-2.38-6.031-5.627-11.068-9.453-14.639m-15.259-2.207v16.846h-17.657c4.035-9.527 10.401-15.966 17.657-16.846m21.073 16.846h-17.657v-16.846c7.256.88 13.622 7.319 17.657 16.846" style="fill:#dd6658" transform="matrix(2.34146 0 0 2.2439 -10881.854 22.39)"/>
<path d="M4790.826 84 4759 36h45v48zM4812 36h16v56h15.87L4820 128l-23.87-36H4812zm24 0h45l-31.826 48H4836z" style="fill:#ffe" transform="translate(-4416 306)"/>
<path d="M276 15V0h256v15zM518 .82H290v13.36h228z" style="fill:#e67366" transform="matrix(1 0 0 17.06667 0 306)"/>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.5 KiB

@@ -0,0 +1,17 @@
<svg viewBox="0 0 256 256" xmlns="http://www.w3.org/2000/svg" xml:space="preserve" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2">
<desc>Traced by Dogo314</desc>
<g transform="translate(-276 -306)">
<path style="fill:none" d="M276 306h256v256H276z"/>
<clipPath id="a">
<path d="M276 306h256v256H276z"/>
</clipPath>
<g clip-path="url(#a)">
<path style="fill:#190301;" transform="translate(0 306)" d="M276 0h256v256H276z"/>
<path d="M4818.292 219.132V228h-22.209v-.007c0-7.463 1.165-14.462 3.201-20.493h13.883v4.279zm-5.125-15.197h-12.532c2.345-5.537 5.478-10.031 9.115-12.997v6.452l3.417 3.565zm17.083-12.997c3.637 2.966 6.77 7.46 9.115 12.997h-12.532v-2.98l3.417-3.565zm-3.417 16.562h13.883c2.036 6.031 3.201 13.03 3.201 20.493V228h-22.209v-8.868l5.125-7.353zM4779 228c0-7.466 2-14.468 5.492-20.5h11.236c-1.956 6.138-3.061 13.11-3.061 20.5zm68.333 0c0-7.39-1.105-14.362-3.061-20.5h11.236A40.8 40.8 0 0 1 4861 228zm-60.522-24.065c4.86-6.689 11.692-11.854 19.638-14.639-3.826 3.571-7.073 8.608-9.453 14.639zm46.74-14.639c7.946 2.785 14.778 7.95 19.638 14.639h-10.185c-2.38-6.031-5.627-11.068-9.453-14.639" style="fill:#dd6658" transform="matrix(2.34146 0 0 2.2439 -10881.854 22.39)"/>
<path d="m4257 455.893-5-5.435V426h20v24.458l-5 5.435v16.984l-5 7.474-5-7.474z" style="fill:#ffe" transform="matrix(1.6 0 0 1.47193 -6415.2 -201.04)"/>
<path d="M4251.833 342h8.334c0 7.977 5.381 11.744 10.419 15.733 6.964 5.513 13.581 11.241 13.581 22.267s-6.617 16.754-13.581 22.267c-5.038 3.989-10.419 7.756-10.419 15.733h-8.334c0-11.026 6.617-16.754 13.581-22.267 5.038-3.989 10.419-7.756 10.419-15.733s-5.381-11.744-10.419-15.733c-6.964-5.513-13.581-11.241-13.581-22.267" style="fill:#ffe" transform="translate(-3864)"/>
<path d="M4251.833 342h8.334c0 7.977 5.381 11.744 10.419 15.733 6.964 5.513 13.581 11.241 13.581 22.267s-6.617 16.754-13.581 22.267c-5.038 3.989-10.419 7.756-10.419 15.733h-8.334c0-11.026 6.617-16.754 13.581-22.267 5.038-3.989 10.419-7.756 10.419-15.733s-5.381-11.744-10.419-15.733c-6.964-5.513-13.581-11.241-13.581-22.267" style="fill:#ffe" transform="matrix(-1 0 0 1 4672 0)"/>
<path d="M276 15V0h256v15zM518 .82H290v13.36h228z" style="fill:#e67366" transform="matrix(1 0 0 17.06667 0 306)"/>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.3 KiB

+15
View File
@@ -0,0 +1,15 @@
<svg viewBox="0 0 256 256" xmlns="http://www.w3.org/2000/svg" xml:space="preserve" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2">
<desc>Traced by Dogo314</desc>
<g transform="translate(-276 -306)">
<path style="fill:none" d="M276 306h256v256H276z"/>
<clipPath id="a">
<path d="M276 306h256v256H276z"/>
</clipPath>
<g clip-path="url(#a)">
<path style="fill:#190301;" transform="translate(0 306)" d="M276 0h256v256H276z"/>
<path d="M4779 228c0-7.466 2-14.468 5.492-20.5h11.236c-1.956 6.138-3.061 13.11-3.061 20.5zm17.083 0v-.007c0-7.463 1.165-14.462 3.201-20.493h19.008V228zm25.625 0v-20.5h19.008c2.036 6.031 3.201 13.03 3.201 20.493V228zm25.625 0c0-7.39-1.105-14.362-3.061-20.5h11.236A40.8 40.8 0 0 1 4861 228zm-60.522-24.065c4.86-6.689 11.692-11.854 19.638-14.639-3.826 3.571-7.073 8.608-9.453 14.639zm46.74-14.639c7.946 2.785 14.778 7.95 19.638 14.639h-10.185c-2.38-6.031-5.627-11.068-9.453-14.639m-15.259-2.207v16.846h-17.657c4.035-9.527 10.401-15.966 17.657-16.846m21.073 16.846h-17.657v-16.846c7.256.88 13.622 7.319 17.657 16.846" style="fill:#dd6658" transform="matrix(2.34146 0 0 2.2439 -10881.854 22.39)"/>
<path d="M2539.007 462.941C2534.678 458.599 2532 452.61 2532 446c0-12.015 8.849-21.981 20.38-23.728A24 24 0 0 1 2556 422h20c-4-4-10-8-17-8h-6.668c1.907-11.345 11.785-20 23.668-20h21c-2.743-2.743-6.425-5.485-10.726-6.938C2590.513 377.04 2600.441 370 2612 370s21.487 7.04 25.726 17.062c-4.301 1.453-7.983 4.195-10.726 6.938h21c11.883 0 21.761 8.655 23.668 20H2665c-7 0-13 4-17 8h20q1.847.002 3.62.272c11.531 1.747 20.38 11.713 20.38 23.728 0 6.61-2.678 12.599-7.007 16.941-11.172-10.572-24.824-18.742-40.049-23.624-10.35-3.318-21.426-5.117-32.944-5.117s-22.594 1.799-32.944 5.117c-15.225 4.882-28.877 13.052-40.049 23.624" style="fill:#ffe" transform="translate(-2208)"/>
<path d="M276 15V0h256v15zM518 .82H290v13.36h228z" style="fill:#e67366" transform="matrix(1 0 0 17.06667 0 306)"/>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.0 KiB

+15
View File
@@ -0,0 +1,15 @@
<svg viewBox="0 0 256 256" xmlns="http://www.w3.org/2000/svg" xml:space="preserve" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2">
<desc>Traced by Dogo314</desc>
<g transform="translate(-276 -306)">
<path style="fill:none" d="M276 306h256v256H276z"/>
<clipPath id="a">
<path d="M276 306h256v256H276z"/>
</clipPath>
<g clip-path="url(#a)">
<path style="fill:#190301;" transform="translate(0 306)" d="M276 0h256v256H276z"/>
<path d="M4779 228c0-7.466 2-14.468 5.492-20.5h11.236c-1.956 6.138-3.061 13.11-3.061 20.5zm17.083 0v-.007c0-7.463 1.165-14.462 3.201-20.493h19.008V228zm25.625 0v-20.5h19.008c2.036 6.031 3.201 13.03 3.201 20.493V228zm25.625 0c0-7.39-1.105-14.362-3.061-20.5h11.236A40.8 40.8 0 0 1 4861 228zm-60.522-24.065c4.86-6.689 11.692-11.854 19.638-14.639-3.826 3.571-7.073 8.608-9.453 14.639zm46.74-14.639c7.946 2.785 14.778 7.95 19.638 14.639h-10.185c-2.38-6.031-5.627-11.068-9.453-14.639m-15.259-2.207v16.846h-17.657c4.035-9.527 10.401-15.966 17.657-16.846m21.073 16.846h-17.657v-16.846c7.256.88 13.622 7.319 17.657 16.846" style="fill:#dd6658" transform="matrix(2.34146 0 0 2.2439 -10881.854 22.39)"/>
<path d="M3168 346v88h-8v-88zm16 0v8h-8v-8zm0 16v8h-8v-8zm0 16v8h-8v-8zm0 16v8h-8v-8zm0 16v8h-8v-8zm0 16v8h-8v-8zm-34.815.946 1.389 7.879-7.878 1.389-1.389-7.879zm-18.364 4.199 2.736 7.518-7.518 2.736-2.736-7.518zm-17.357 7.324 4 6.928-6.928 4-4-6.928zm-15.821 10.227 5.142 6.128-6.128 5.143-5.142-6.129z" style="fill:#ffe" transform="translate(-2760)"/>
<path d="M276 15V0h256v15zM518 .82H290v13.36h228z" style="fill:#e67366" transform="matrix(1 0 0 17.06667 0 306)"/>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.7 KiB

+17
View File
@@ -0,0 +1,17 @@
<svg viewBox="0 0 256 256" xmlns="http://www.w3.org/2000/svg" xml:space="preserve" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2">
<desc>Traced by Dogo314</desc>
<g transform="translate(-276 -306)">
<path style="fill:none" d="M276 306h256v256H276z"/>
<clipPath id="a">
<path d="M276 306h256v256H276z"/>
</clipPath>
<g clip-path="url(#a)">
<path style="fill:#011419;" transform="translate(0 306)" d="M276 0h256v256H276z"/>
<path d="M688 1930h-16l-12-12v-24h-24v-28l8-8h16l8-8h24l8 8h16l8 8v28h-24v24zm4-64h-24v20h24zm-40 36v26l12 12v14l12 12h-40l12-12v-8l-12-12v-32zm56 0h16v32l-12 12v8l12 12h-40l12-12v-14l12-12z" style="fill:#53bcda" transform="translate(-276 -1440)"/>
<path d="m630 1823-3 3h-47v-16h47l3 3h13l9 5-9 5z" style="fill:#ffe" transform="translate(-276 -1464)"/>
<path d="m630 1823-3 3h-47v-16h47l3 3h13l9 5-9 5z" style="fill:#ffe" transform="translate(-276 -1440)"/>
<path d="M773 1814h-64v-16h64c4.415 0 8 3.585 8 8s-3.585 8-8 8m-64-32 12 12h-12zm0 36h12l-12 12z" style="fill:#ffe" transform="translate(-277 -1440)"/>
<path d="M276 15V0h256v15zM518 .82H290v13.36h228z" style="fill:#5abeda" transform="matrix(1 0 0 17.06667 0 306)"/>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.3 KiB

+14
View File
@@ -0,0 +1,14 @@
<svg viewBox="0 0 256 256" xmlns="http://www.w3.org/2000/svg" xml:space="preserve" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2">
<desc>Traced by Dogo314</desc>
<g transform="translate(-28.444 589.487)scale(.98084)">
<path style="fill:none" d="M29-601h261v261H29z"/>
<clipPath id="a">
<path d="M29-601h261v261H29z"/>
</clipPath>
<g clip-path="url(#a)">
<path style="fill:#363426" transform="translate(-252.39 -601)scale(1.01953)" d="M276 0h256v256H276z"/>
<path d="M442.661 126.568 356 104h40V36h16v68h40zm-82.951-13.602 79.963 20.824-6.35 15.346-65.729-17.117zm11.594 28.02 59.031 15.372-6.351 15.346-44.796-11.665zm11.595 28.019 38.097 9.921-6.35 15.346-23.863-6.214zm11.594 28.019 17.165 4.47L404 220z" style="fill:#ffe" transform="translate(-252.39 -601)scale(1.01953)"/>
<path d="M276 256V0h256v256zM518 14H290v228h228zm-10 10v32l-32-32zM300 232v-32l32 32zm0-208h32l-32 32zm208 208h-32l32-32z" style="fill:#c9b269" transform="translate(-252.39 -601)scale(1.01953)"/>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

+15
View File
@@ -0,0 +1,15 @@
<svg viewBox="0 0 256 256" xmlns="http://www.w3.org/2000/svg" xml:space="preserve" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2">
<desc>Traced by Dogo314</desc>
<g transform="translate(-276 -306)">
<path style="fill:none" d="M276 306h256v256H276z"/>
<clipPath id="a">
<path d="M276 306h256v256H276z"/>
</clipPath>
<g clip-path="url(#a)">
<path style="fill:#011419;" transform="translate(0 306)" d="M276 0h256v256H276z"/>
<path d="M4284.473 2382.75H4201.5v-7.5h82.973c1.667-6.467 7.543-11.25 14.527-11.25 8.279 0 15 6.721 15 15s-6.721 15-15 15c-6.984 0-12.86-4.783-14.527-11.25m18.277-41.25v15h-7.5v-15zm25.418 13.635-10.606 10.607-5.304-5.304 10.607-10.606zm8.332 27.615h-15v-7.5h15zm-13.635 25.418-10.607-10.606 5.304-5.304 10.606 10.607zm-27.615 8.332v-15h7.5v15zm-25.418-13.635 10.606-10.607 5.304 5.304-10.607 10.606zm5.303-53.033 10.607 10.606-5.304 5.304-10.606-10.607z" style="fill:#ffe" transform="translate(-4149.6 -2151.6)scale(1.06667)"/>
<path d="M276 15V0h256v15zM518 .82H290v13.36h228z" style="fill:#5abeda" transform="matrix(1 0 0 17.06667 0 306)"/>
<path d="M779 2755h-1v1h-2v-1h-14v1h-2v-1h-1v1h-2v-1h-1v1h-2v-1h-1v1h-2v-1h-1v1h-2v-1h-1v1h-2v-1h-2v1h-2v2h2v1l-1 1h-9v1l-1 1h-13v2h-2v14a2 2 0 0 1-2 2h-2a2 2 0 0 1-2-2v-14h-2v-2h-2v4h-17v5l1 1v1h-2l1 1v1h-3a2 2 0 0 0-2 2v.586a1 1 0 0 1-.293.707l-.414.414a1 1 0 0 1-.707.293h-.051c-.334 0-.646.167-.832.445l-1.16 1.741a2 2 0 0 0-.234 1.742l.382 1.144a2 2 0 0 1-.234 1.742l-.478.717a2 2 0 0 1-2.558.679L670 2783l8.208-10.943a3.97 3.97 0 0 0 .792-2.378 4.68 4.68 0 0 0-4.678-4.679H674v-5h-3v2h-8v2l-4 4h-8a4 4 0 0 0-2.828 1.172A4 4 0 0 0 647 2772v11a1 1 0 0 1-1 1h-4v1l-1 1h-2l-1-1c-1-10-6-20-13-20h-4v-3h-6v-2h-34a4 4 0 0 1-2.828-1.172A4 4 0 0 1 577 2756v-20c0-1.061.421-2.078 1.172-2.828A4 4 0 0 1 581 2732h10v-19h9l3 2h3v-1h26v1h4v-1h5v1h3l3-2h9v18h11l4 4h4v1h9s4-5 14-5 14 5 14 5h4v-1h5v1h22v1h2v-1h2v1h1v-1h2v1h1v-1h2v1h1v-1h2v1h1v-1h2v1h1v-1h2v1h12v-1h2v1h1v-1h2v1s4 6.927 4 10v6a2 2 0 0 1-2 2v1h-2z" style="fill:#53bcda" transform="translate(-276 -2268)"/>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.1 KiB

+17
View File
@@ -0,0 +1,17 @@
<svg viewBox="0 0 256 256" xmlns="http://www.w3.org/2000/svg" xml:space="preserve" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2">
<desc>Traced by Dogo314</desc>
<g transform="translate(-276 -306)">
<path style="fill:none" d="M276 306h256v256H276z"/>
<clipPath id="a">
<path d="M276 306h256v256H276z"/>
</clipPath>
<g clip-path="url(#a)">
<path style="fill:#011419;" transform="translate(0 306)" d="M276 0h256v256H276z"/>
<path d="M3166 2452h18l1-1h83v7h-4v4h4v13a2 2 0 0 1-2 2h-68l-3-2h-16l-3 2h-37v1.967c0 .67-.218 1.323-.62 1.86l-1.18 1.573a4 4 0 0 1-3.2 1.6h-12l-12.103 13.965a3 3 0 0 1-2.267 1.035h-.63c-3 0-16-7-18-12h-14l-4-2h-9a2 2 0 0 1-2-2v-29a2 2 0 0 1 2-2h66v-2h2v2h2v-2h2v2h2v-2h2v2h2v-2h2v2h2v-2h2v2h2v-2h2v2h2v-2h2v2h2v-2h2v2h2v-2h2v2h2v-2h2zm-62 24a2 2 0 0 0-2 2v7a2 2 0 0 0 2 2h1.172a2 2 0 0 0 1.414-.586l5.828-5.828a2 2 0 0 0 .586-1.414V2478a2 2 0 0 0-2-2zm23 4a.997.997 0 0 0 1 1h4a.997.997 0 0 0 1-1v-2a.997.997 0 0 0-1-1h-4a.997.997 0 0 0-1 1z" style="fill:#53bcda" transform="translate(-2760 -1992)"/>
<path d="m4293.25 432.794-2.5 2.717h-27.5v-21.74h27.5l2.5 2.718h20l7.5 8.152-7.5 8.153z" style="fill:#ffe" transform="matrix(1.6 0 0 1.47193 -6421.2 -231.04)"/>
<path d="M4186 440.167v-8.334c7.977 0 11.744-5.381 15.733-10.419 5.513-6.964 11.241-13.581 22.267-13.581s16.754 6.617 22.267 13.581c3.989 5.038 7.756 10.419 15.733 10.419v8.334c-11.026 0-16.754-6.617-22.267-13.581-3.989-5.038-7.756-10.419-15.733-10.419s-11.744 5.381-15.733 10.419c-5.513 6.964-11.241 13.581-22.267 13.581" style="fill:#ffe" transform="translate(-3870 -30)"/>
<path d="M4350 407.833v8.334c-7.977 0-11.744 5.381-15.733 10.419-5.513 6.964-11.241 13.581-22.267 13.581s-16.754-6.617-22.267-13.581c-3.989-5.038-7.756-10.419-15.733-10.419v-8.334c11.026 0 16.754 6.617 22.267 13.581 3.989 5.038 7.756 10.419 15.733 10.419s11.744-5.381 15.733-10.419c5.513-6.964 11.241-13.581 22.267-13.581" style="fill:#ffe" transform="matrix(-1 0 0 1 4666 -30)"/>
<path d="M276 15V0h256v15zM518 .82H290v13.36h228z" style="fill:#5abeda" transform="matrix(1 0 0 17.06667 0 306)"/>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.1 KiB

+15
View File
@@ -0,0 +1,15 @@
<svg viewBox="0 0 256 256" xmlns="http://www.w3.org/2000/svg" xml:space="preserve" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2">
<desc>Traced by Dogo314</desc>
<g transform="translate(-276 -306)">
<path style="fill:none" d="M276 306h256v256H276z"/>
<clipPath id="a">
<path d="M276 306h256v256H276z"/>
</clipPath>
<g clip-path="url(#a)">
<path style="fill:#011419;" transform="translate(0 306)" d="M276 0h256v256H276z"/>
<path d="M1490 2477h-3v30h-10l-11-25h-8v-5h-3v2h-2v-2h-2v2h-2v-2h-3v2h-2v-2h-2v2h-2v-2l-2-2h-3l-25 6-6-2v-35l6-2 25 6h29l2-4h88l4 4h29v-1h18v1h7v27h-7v1h-18v-1h-17v1h9v3h-14l-6 15h-6l-2-2v2h-10v-8h-2v3h-1.298a3.1 3.1 0 0 0-2.616 1.436l-5.461 8.581a4 4 0 0 0-.625 2.148v1.045a2.79 2.79 0 0 1-2.79 2.79h-.139a.3.3 0 0 1-.134-.032l-8.162-4.081a1.725 1.725 0 0 1-.651-2.522l9.467-13.77c.27-.393.468-.832.584-1.296L1528 2480h2v-3h-26v2h-2v-2h-2v2h-2v-2h-2v2h-2v-2h-2v2h-2zm55.882 0a1.88 1.88 0 0 0-1.882 1.882v3.048a2 2 0 0 0 .891 1.664l1.605 1.07c.329.219.715.336 1.11.336h1.566a2 2 0 0 0 1.414-.586l.828-.828a2 2 0 0 0 .586-1.414v-.344a2 2 0 0 0-.586-1.414L1550 2479h-1.197c-.492 0-.942-.278-1.162-.719l-.282-.562a1.3 1.3 0 0 0-1.162-.719z" style="fill:#53bcda" transform="translate(-1104 -1992)"/>
<path d="M276 15V0h256v15zM518 .82H290v13.36h228z" style="fill:#5abeda" transform="matrix(1 0 0 17.06667 0 306)"/>
<path d="m1436 2385-8-23h24l8 16h24l52-12 52 12v14l-52 12-52-12h-24l-8 16h-24z" style="fill:#ffe" transform="translate(-1104 -1992)"/>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.6 KiB

+14
View File
@@ -0,0 +1,14 @@
<svg viewBox="0 0 256 256" xmlns="http://www.w3.org/2000/svg" xml:space="preserve" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2">
<desc>Traced by Dogo314</desc>
<g transform="translate(-28.444 589.487)scale(.98084)">
<path style="fill:none" d="M29-601h261v261H29z"/>
<clipPath id="a">
<path d="M29-601h261v261H29z"/>
</clipPath>
<g clip-path="url(#a)">
<path style="fill:#363426" transform="translate(-252.39 -601)scale(1.01953)" d="M276 0h256v256H276z"/>
<path d="M1526 101h8v32l-40 32-40-32v-32h8c0-17.661 14.339-32 32-32s32 14.339 32 32m-56 24h12l4-8h16l4 8h12v-24h-48zm90-50.028h-27.972v-12H1560V35h12v27.972h27.972v12H1572v27.973h-12zM1546 189h-104l-16-16v-16h32l16 16h40l16-16h32v16z" style="fill:#ffe" transform="translate(-1379.992 -585.707)scale(1.01953)"/>
<path d="M276 15V0h256v15zM518 .82H290v13.36h228zm-10 12.774h-32l32-1.875zM300 1.406h32l-32 1.875zm208 0v1.875l-32-1.875zM300 13.594v-1.875l32 1.875z" style="fill:#c9b269" transform="matrix(1.01953 0 0 17.4 -252.39 -601)"/>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

+15
View File
@@ -0,0 +1,15 @@
<svg viewBox="0 0 256 256" xmlns="http://www.w3.org/2000/svg" xml:space="preserve" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2">
<desc>Traced by Dogo314</desc>
<g transform="translate(-28.444 589.487)scale(.98084)">
<path style="fill:none" d="M29-601h261v261H29z"/>
<clipPath id="a">
<path d="M29-601h261v261H29z"/>
</clipPath>
<g clip-path="url(#a)">
<path style="fill:#363426" transform="translate(-252.39 -601)scale(1.01953)" d="M276 0h256v256H276z"/>
<path d="M2592 116h16v48h-48v-48h16v16h16zm56 0h16v48h-48v-48h16v16h16zm-28-56h16v48h-48V60h16v16h16z" style="fill:#ffe" transform="translate(-2503.516 -601)scale(1.01953)"/>
<path d="M2580 60v48h-24.757L2528 60zm11.568 112h40.864L2612 208zm77.189-64H2644V60h52z" style="fill:#c9b269" transform="translate(-2503.516 -601)scale(1.01953)"/>
<path d="M276 15V0h256v15zM518 .82H290v13.36h228zm-10 12.774h-32l32-1.875zM300 1.406h32l-32 1.875zm208 0v1.875l-32-1.875zM300 13.594v-1.875l32 1.875z" style="fill:#c9b269" transform="matrix(1.01953 0 0 17.4 -252.39 -601)"/>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

+15
View File
@@ -0,0 +1,15 @@
<svg viewBox="0 0 256 256" xmlns="http://www.w3.org/2000/svg" xml:space="preserve" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2">
<desc>Traced by Dogo314</desc>
<g transform="translate(-276 -306)">
<path style="fill:none" d="M276 306h256v256H276z"/>
<clipPath id="a">
<path d="M276 306h256v256H276z"/>
</clipPath>
<g clip-path="url(#a)">
<path style="fill:#091901;" transform="translate(0 306)" d="M276 0h256v256H276z"/>
<path d="M377 689v-36h27c31.459 0 57 25.541 57 57v15h-57v-9.515l21-21V668h-26.485l-21 21zm26.485 42H449v21h-60v-6.515zm27.364-78H491v21h-35.306a63.3 63.3 0 0 0-24.845-21M461 758l18 21H359l18-21z" style="fill:#679452" transform="translate(-154.667 -520.667)scale(1.33333)"/>
<path d="M956 684v24l-28 28v20l-28 28v-44h-44l28-28h20l28-28zm-76 82 12-12v14l-12 12zm-6-6h-14l12-12h14z" style="fill:#ffe" transform="translate(-552 -306)"/>
<path d="M276 15V0h256v15zM518 .82H290v13.36h228z" style="fill:#689452" transform="matrix(1 0 0 17.06667 0 306)"/>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

+15
View File
@@ -0,0 +1,15 @@
<svg viewBox="0 0 256 256" xmlns="http://www.w3.org/2000/svg" xml:space="preserve" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2">
<desc>Traced by Dogo314</desc>
<g transform="translate(-28.444 589.487)scale(.98084)">
<path style="fill:none" d="M29-601h261v261H29z"/>
<clipPath id="a">
<path d="M29-601h261v261H29z"/>
</clipPath>
<g clip-path="url(#a)">
<path style="fill:#363426" transform="translate(-252.39 -601)scale(1.01953)" d="M276 0h256v256H276z"/>
<path d="M4779 228c0-7.466 2-14.468 5.492-20.5h11.236c-1.956 6.138-3.061 13.11-3.061 20.5zm17.083 0v-.007c0-7.463 1.165-14.462 3.201-20.493h19.008V228zm25.625 0v-20.5h19.008c2.036 6.031 3.201 13.03 3.201 20.493V228zm25.625 0c0-7.39-1.105-14.362-3.061-20.5h11.236A40.8 40.8 0 0 1 4861 228zm-60.522-24.065c4.86-6.689 11.692-11.854 19.638-14.639-3.826 3.571-7.073 8.608-9.453 14.639zm46.74-14.639c7.946 2.785 14.778 7.95 19.638 14.639h-10.185c-2.38-6.031-5.627-11.068-9.453-14.639m-15.259-2.207v16.846h-17.657c4.035-9.527 10.401-15.966 17.657-16.846m21.073 16.846h-17.657v-16.846c7.256.88 13.622 7.319 17.657 16.846" style="fill:#c9b269" transform="matrix(2.3872 0 0 2.28773 -11346.78 -890.149)"/>
<path d="M4790.826 84 4759 36h45v48zM4812 36h16v56h15.87L4820 128l-23.87-36H4812zm24 0h45l-31.826 48H4836z" style="fill:#ffe" transform="translate(-4754.64 -601)scale(1.01953)"/>
<path d="M276 15V0h256v15zM518 .82H290v13.36h228z" style="fill:#c9b269" transform="matrix(1.01953 0 0 17.4 -252.39 -601)"/>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.5 KiB

+15
View File
@@ -0,0 +1,15 @@
<svg viewBox="0 0 256 256" xmlns="http://www.w3.org/2000/svg" xml:space="preserve" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2">
<desc>Traced by Dogo314</desc>
<g transform="translate(-276 -306)">
<path style="fill:none" d="M276 306h256v256H276z"/>
<clipPath id="a">
<path d="M276 306h256v256H276z"/>
</clipPath>
<g clip-path="url(#a)">
<path style="fill:#011419;" transform="translate(0 306)" d="M276 0h256v256H276z"/>
<path d="M276 15V0h256v15zM518 .82H290v13.36h228z" style="fill:#5abeda" transform="matrix(1 0 0 17.06667 0 306)"/>
<path d="M388 1569.204V1541l17 17h19v24h32v-24h19l17-17v101l-16 16h-68v-84.448zM472 1550h-64l-20-20v-16h104v16zm-24 8v16h-16v-16z" style="fill:#53bcda" transform="translate(0 -1164)"/>
<path d="m3390 1570 46 10v75l-46 27-46-27v-75zm0 47 8-33-30 43h22l-8 33 30-43z" style="fill:#ffe" transform="translate(-3036 -1164)"/>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 984 B

+15
View File
@@ -0,0 +1,15 @@
<svg viewBox="0 0 256 256" xmlns="http://www.w3.org/2000/svg" xml:space="preserve" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2">
<desc>Traced by Dogo314</desc>
<g transform="translate(-276 -306)">
<path style="fill:none" d="M276 306h256v256H276z"/>
<clipPath id="a">
<path d="M276 306h256v256H276z"/>
</clipPath>
<g clip-path="url(#a)">
<path style="fill:#091901;" transform="translate(0 306)" d="M276 0h256v256H276z"/>
<path d="M516 1148H292v-38.222L332 1092l36 16 36-16 36 16 36-16 40 17.778z" style="fill:#679452" transform="translate(0 -602)"/>
<path d="M1784 1064.067 1738 1037v-83l46-10 46 10v83zm0-68.067 8-34-30 42h22l-8 34 30-42z" style="fill:#ffe" transform="translate(-1380 -582)"/>
<path d="M276 15V0h256v15zM518 .82H290v13.36h228z" style="fill:#689452" transform="matrix(1 0 0 17.06667 0 306)"/>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 938 B

+14
View File
@@ -0,0 +1,14 @@
<svg viewBox="0 0 256 256" xmlns="http://www.w3.org/2000/svg" xml:space="preserve" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2">
<desc>Traced by Dogo314</desc>
<g transform="translate(-28.444 589.487)scale(.98084)">
<path style="fill:none" d="M29-601h261v261H29z"/>
<clipPath id="a">
<path d="M29-601h261v261H29z"/>
</clipPath>
<g clip-path="url(#a)">
<path style="fill:#363426" transform="translate(-252.39 -601)scale(1.01953)" d="M276 0h256v256H276z"/>
<path d="M648.893 108.893C656.858 100.929 667.858 96 680 96s23.142 4.929 31.107 12.893l-5.656 5.656C698.934 108.033 689.934 104 680 104s-18.934 4.033-25.451 10.549zm-11.311-11.311C648.443 86.721 663.443 80 680 80s31.557 6.721 42.418 17.582l-5.656 5.656C707.35 93.825 694.35 88 680 88s-27.35 5.825-36.762 15.238zM626.27 86.27C640.027 72.514 659.027 64 680 64s39.973 8.514 53.73 22.27l-5.656 5.656C715.765 79.617 698.765 72 680 72s-35.765 7.617-48.074 19.926zM613 145v-8c0-3.183 1.264-6.235 3.515-8.485A12 12 0 0 1 625 125h12c3.183 0 6.235 1.264 8.485 3.515A12 12 0 0 1 649 137v6a2 2 0 0 1-2 2h-6a2 2 0 0 1-2-2v-6a2 2 0 0 0-2-2h-12a2 2 0 0 0-2 2v6c18 12 26 17 26 22v8c0 3.183-1.264 6.235-3.515 8.485A12 12 0 0 1 637 185h-12a12 12 0 0 1-8.485-3.515A12 12 0 0 1 613 173v-6a2 2 0 0 1 2-2h6a2 2 0 0 1 2 2v6a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2v-8c-17-11-26-16-26-20m97 0v-8c0-3.183 1.264-6.235 3.515-8.485A12 12 0 0 1 722 125h12c3.183 0 6.235 1.264 8.485 3.515A12 12 0 0 1 746 137v6a2 2 0 0 1-2 2h-6a2 2 0 0 1-2-2v-6a2 2 0 0 0-2-2h-12a2 2 0 0 0-2 2v6c18 12 26 17 26 22v8c0 3.183-1.264 6.235-3.515 8.485A12 12 0 0 1 734 185h-12a12 12 0 0 1-8.485-3.515A12 12 0 0 1 710 173v-6a2 2 0 0 1 2-2h6a2 2 0 0 1 2 2v6a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2v-8c-17-11-26-16-26-20m-24-20c6.627 0 12 5.373 12 12v35c0 6.627-5.373 12-12 12h-12c-6.627 0-12-5.373-12-12v-35c0-6.627 5.373-12 12-12zm-1 9h-10a4 4 0 0 0-2.828 1.172A4 4 0 0 0 671 138v33c0 1.061.421 2.078 1.172 2.828A4 4 0 0 0 675 175h10a4 4 0 0 0 2.828-1.172A4 4 0 0 0 689 171v-33a4 4 0 0 0-1.172-2.828A4 4 0 0 0 685 134" style="fill:#ffe" transform="translate(-533.781 -601)scale(1.01953)"/>
<path d="M276 256V0h256v256zM518 14H290v228h228zm-10 10v32l-32-32zm0 208h-32l32-32zm-208 0v-32l32 32zm0-208h32l-32 32z" style="fill:#c9b269" transform="translate(-252.39 -601)scale(1.01953)"/>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.3 KiB

+15
View File
@@ -0,0 +1,15 @@
<svg viewBox="0 0 256 256" xmlns="http://www.w3.org/2000/svg" xml:space="preserve" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2">
<desc>Traced by Dogo314</desc>
<g transform="translate(-276 -306)">
<path style="fill:none" d="M276 306h256v256H276z"/>
<clipPath id="a">
<path d="M276 306h256v256H276z"/>
</clipPath>
<g clip-path="url(#a)">
<path style="fill:#011419;" transform="translate(0 306)" d="M276 0h256v256H276z"/>
<path d="m3442 2517-12-3v-4l-7-6-9-18h-25v-3h-3v-2h-34v-21h34v-4h12v-3l2-2h72l2-5h44l2 5v5h6l2 2v24l-2 2h-3v1h1v3h-17.034a7 7 0 0 0-6.607 4.688L3495 2508l-8-3 1-3-8-2-1 6h-7l-15-5-15 13zm-4-27-2 13h3l11-10-7-3zm31.822 6.657a3 3 0 0 0-1.874-.657h-.489a3 3 0 0 0-2.941 2.412l-.041.201a3 3 0 0 0 1.76 3.346l2.596 1.112a3 3 0 0 0 3.582-.957l.422-.563a2 2 0 0 0-.351-2.762z" style="fill:#53bcda" transform="translate(-3036 -1992)"/>
<path d="M2949 2398h-128v-32h128c8.831 0 16 7.169 16 16s-7.169 16-16 16m0-24c-4.415 0-8 3.585-8 8s3.585 8 8 8 8-3.585 8-8-3.585-8-8-8m-128-40 24 24h-24zm0 96v-24h24z" style="fill:#ffe" transform="translate(-2485 -1992)"/>
<path d="M276 15V0h256v15zM518 .82H290v13.36h228z" style="fill:#5abeda" transform="matrix(1 0 0 17.06667 0 306)"/>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.3 KiB

+15
View File
@@ -0,0 +1,15 @@
<svg viewBox="0 0 256 256" xmlns="http://www.w3.org/2000/svg" xml:space="preserve" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2">
<desc>Traced by Dogo314</desc>
<g transform="translate(-276 -306)">
<path style="fill:none" d="M276 306h256v256H276z"/>
<clipPath id="a">
<path d="M276 306h256v256H276z"/>
</clipPath>
<g clip-path="url(#a)">
<path style="fill:#011419;" transform="translate(0 306)" d="M276 0h256v256H276z"/>
<path d="M276 15V0h256v15zM518 .82H290v13.36h228z" style="fill:#5abeda" transform="matrix(1 0 0 17.06667 0 306)"/>
<path d="m974 2371-3 3.142h-47V2358h47l3 3h13l9 5-9 5zm0 24-3 3.142h-47V2382h47l3 3h13l9 5-9 5zm0 23.858-3 3.142h-47v-16.142h47l3 3h13l9 5-9 5z" style="fill:#ffe" transform="translate(-552 -1992)"/>
<path d="M1011 2484h-2v2h-3l-3-3-4 4h-15v14h-22v-14h-17l-.215.537a7.1 7.1 0 0 1-6.592 4.463H931c-.796 0-1.559.316-2.121.879A3 3 0 0 0 928 2495v1.488c0 .835-.677 1.512-1.512 1.512h-.002c-.357 0-.695.165-.915.446a1.17 1.17 0 0 0-.211.995l.277 1.105a1.17 1.17 0 0 1-1.136 1.454h-.001a1.08 1.08 0 0 0-1.026 1.423l.986 2.956a3.5 3.5 0 0 1-.408 3.043l-.175.263a1.9 1.9 0 0 1-2.33.692l-10.411-4.462a1.998 1.998 0 0 1-.913-2.891l10.624-17.162A2 2 0 0 0 920 2483h-9l-4-3h-14l-6.243 6.243a6 6 0 0 1-4.242 1.757h-18.272a3 3 0 0 0-2.122.879l-.533.533a3 3 0 0 1-1.394.79l-2.253.563a3 3 0 0 1-1.842-.125l-2.213-.886a3 3 0 0 1-1.886-2.785V2461c0-.796.316-1.559.879-2.121A3 3 0 0 1 855 2458h56l10-2h2v-2h2v2h2v-2h2v2h2v-2h2v2h2v-2h2v2h2v-2h2v2h2v-2h2v2h2v-2h2v2h2v-2h2v2h2v-2h2v2h2v-2h2l2 2h26a2 2 0 0 1 2 2v1c0 1.061.421 2.078 1.172 2.828A4 4 0 0 0 995 2463h56l1 4 2 1h9v3h-7v2h4v4h-9l-1 3h-3l-2 2v4h-2v-2h-2v2h-2v-2h-2v2h-2v-2h-2v2h-2v-2h-2v2h-2v-2h-2v2h-2v-2h-2v2h-2v-2h-2v2h-2v-2h-2v2h-2zm-77-1h-1a2 2 0 0 0-2 2v2a2 2 0 0 0 2 2h6a4 4 0 0 0 2.828-1.172A4 4 0 0 0 943 2485a2 2 0 0 0-2-2h-5c0 2 0 3 1 5h-1c-1-1-2-2-2-5" style="fill:#53bcda" transform="translate(-552 -1992)"/>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.0 KiB

+15
View File
@@ -0,0 +1,15 @@
<svg viewBox="0 0 256 256" xmlns="http://www.w3.org/2000/svg" xml:space="preserve" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2">
<desc>Traced by Dogo314</desc>
<g transform="translate(-276 -306)">
<path style="fill:none" d="M276 306h256v256H276z"/>
<clipPath id="a">
<path d="M276 306h256v256H276z"/>
</clipPath>
<g clip-path="url(#a)">
<path style="fill:#011419;" transform="translate(0 306)" d="M276 0h256v256H276z"/>
<path d="M388 1582v-41l17 17h19v24h32v-24h19l17-17v101l-16 16h-68v-76zm84-32h-64l-20-20v-16h104v16zm-24 8v16h-16v-16z" style="fill:#53bcda" transform="translate(0 -1164)"/>
<path d="M2852 1590h32v96h-96v-96h32v32h32zm-52 76h32l4-4h25l10-8-10-8h-25l-4-4h-32z" style="fill:#ffe" transform="translate(-2484 -1164)"/>
<path d="M276 15V0h256v15zM518 .82H290v13.36h228z" style="fill:#5abeda" transform="matrix(1 0 0 17.06667 0 306)"/>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 978 B

+15
View File
@@ -0,0 +1,15 @@
<svg viewBox="0 0 256 256" xmlns="http://www.w3.org/2000/svg" xml:space="preserve" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2">
<desc>Traced by Dogo314</desc>
<g transform="translate(-276 -306)">
<path style="fill:none" d="M276 306h256v256H276z"/>
<clipPath id="a">
<path d="M276 306h256v256H276z"/>
</clipPath>
<g clip-path="url(#a)">
<path style="fill:#091901;" transform="translate(0 306)" d="M276 0h256v256H276z"/>
<path d="M516 1148H292v-38.222L332 1092l36 16 36-16 36 16 36-16 40 17.778z" style="fill:#679452" transform="translate(0 -602)"/>
<path d="M1784 996h20l-28 40 8-32h-20l28-40zm4 111.245-36 16-16.16-7.182L1748 1096v-72h12v56h16v-16l8-8v-16h8v16l8 8v16h16v-56h12v72l12.16 20.063-16.16 7.182z" style="fill:#ffe" transform="translate(-1384 -626)"/>
<path d="M276 15V0h256v15zM518 .82H290v13.36h228z" style="fill:#689452" transform="matrix(1 0 0 17.06667 0 306)"/>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1007 B

+14
View File
@@ -0,0 +1,14 @@
<svg viewBox="0 0 256 256" xmlns="http://www.w3.org/2000/svg" xml:space="preserve" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2">
<desc>Traced by Dogo314</desc>
<g transform="translate(-28.444 589.487)scale(.98084)">
<path style="fill:none" d="M29-601h261v261H29z"/>
<clipPath id="a">
<path d="M29-601h261v261H29z"/>
</clipPath>
<g clip-path="url(#a)">
<path style="fill:#363426" transform="translate(-252.39 -601)scale(1.01953)" d="M276 0h256v256H276z"/>
<path d="M4608 68v80h-128V68zm-48 72v-20h24l-40-44-40 44h24v20zm56 48h-144l-16-16.106V156h72v15.894h32V156h72v15.894z" style="fill:#ffe" transform="translate(-4473.25 -601)scale(1.01953)"/>
<path d="M276 15V0h256v15zM518 .82H290v13.36h228zm-10 12.774h-32l32-1.875zM300 1.406h32l-32 1.875zm208 0v1.875l-32-1.875zM300 13.594v-1.875l32 1.875z" style="fill:#c9b269" transform="matrix(1.01953 0 0 17.4 -252.39 -601)"/>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 977 B

+440 -81
View File
@@ -7,12 +7,13 @@
<link rel="preconnect" href="https://fonts.googleapis.com"> <link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin> <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Exo+2:wght@400;600;700&family=Rajdhani:wght@600;700&family=Share+Tech+Mono&display=swap" rel="stylesheet"> <link href="https://fonts.googleapis.com/css2?family=Exo+2:wght@400;600;700&family=Rajdhani:wght@600;700&family=Share+Tech+Mono&display=swap" rel="stylesheet">
<link rel="stylesheet" href="styles.css"> <link rel="stylesheet" href="styles.css?v=1.0.0">
</head> </head>
<body> <body>
<!-- ── Navigation ─────────────────────────────────────────────── --> <!-- ── Navigation ─────────────────────────────────────────────── -->
<nav id="main-nav" class="hidden"> <nav id="main-nav" class="hidden">
<button id="nav-hamburger" aria-label="Open menu" aria-expanded="false">&#9776;</button>
<div class="nav-brand"> <div class="nav-brand">
<span class="nav-logo"></span> <span class="nav-logo"></span>
<span>HELLDIVERS 2</span> <span>HELLDIVERS 2</span>
@@ -20,6 +21,7 @@
<div class="nav-links"> <div class="nav-links">
<button class="nav-btn" data-view="dashboard">Dashboard</button> <button class="nav-btn" data-view="dashboard">Dashboard</button>
<button class="nav-btn" data-view="practice">Training</button> <button class="nav-btn" data-view="practice">Training</button>
<button class="nav-btn" data-view="history">History</button>
<button class="nav-btn" data-view="lobby">1v1</button> <button class="nav-btn" data-view="lobby">1v1</button>
<button class="nav-btn" data-view="leaderboard">Highscores</button> <button class="nav-btn" data-view="leaderboard">Highscores</button>
<button class="nav-btn nav-btn-admin hidden" id="nav-admin" data-view="admin">Admin</button> <button class="nav-btn nav-btn-admin hidden" id="nav-admin" data-view="admin">Admin</button>
@@ -30,14 +32,54 @@
</div> </div>
</nav> </nav>
<!-- ── Mobile drawer ──────────────────────────────────────────── -->
<div id="nav-overlay"></div>
<nav id="nav-drawer" role="navigation" aria-label="Mobile navigation">
<div class="drawer-header">⚡ HELLDIVERS 2</div>
<button class="drawer-btn" data-view="dashboard">Dashboard</button>
<button class="drawer-btn" data-view="practice">Training</button>
<button class="drawer-btn" data-view="history">History</button>
<button class="drawer-btn" data-view="lobby">1v1 Arena</button>
<button class="drawer-btn" data-view="leaderboard">Highscores</button>
<button class="drawer-btn drawer-btn-admin hidden" id="drawer-admin" data-view="admin">Admin</button>
<div class="drawer-footer">
<button class="btn btn-muted btn-full btn-sm" id="btn-logout-drawer">Logout</button>
</div>
</nav>
<!-- Incoming challenge badge (shown anywhere) --> <!-- Incoming challenge badge (shown anywhere) -->
<div id="challenge-badge" class="challenge-badge hidden"></div> <div id="challenge-badge" class="challenge-badge hidden"></div>
<!-- Score popup (practice) -->
<div id="score-popup" class="score-popup hidden"></div>
<!-- ── LOGIN ─────────────────────────────────────────────────── --> <!-- ── LOGIN ─────────────────────────────────────────────────── -->
<div id="view-login" class="view view-centered"> <div id="view-login" class="view view-centered">
<div class="login-shell">
<section class="login-intel card">
<div class="eyebrow">Super Earth Command</div>
<h1 class="login-intel-title">Deploy faster. Input cleaner. Win harder.</h1>
<p class="login-intel-copy">
Train every stratagem like a live-fire drill, chase leaderboard position, and challenge active Helldivers in the arena.
</p>
<div class="login-intel-grid">
<div class="intel-stat">
<span class="intel-stat-value">4</span>
<span class="intel-stat-label">Training Modes</span>
</div>
<div class="intel-stat">
<span class="intel-stat-value">1v1</span>
<span class="intel-stat-label">Arena Duels</span>
</div>
<div class="intel-stat">
<span class="intel-stat-value">ELO</span>
<span class="intel-stat-label">Rank Tracking</span>
</div>
</div>
</section>
<div class="login-box"> <div class="login-box">
<div class="login-header"> <div class="login-header">
<div class="login-logo"></div> <span class="login-logo"></span>
<h1>HELLDIVERS 2</h1> <h1>HELLDIVERS 2</h1>
<p class="login-sub">STRATAGEM TRAINER — SUPER EARTH AUTHORIZED</p> <p class="login-sub">STRATAGEM TRAINER — SUPER EARTH AUTHORIZED</p>
</div> </div>
@@ -55,12 +97,13 @@
</form> </form>
</div> </div>
</div> </div>
</div>
<!-- ── CHANGE PASSWORD ───────────────────────────────────────── --> <!-- ── CHANGE PASSWORD ───────────────────────────────────────── -->
<div id="view-change-password" class="view view-centered hidden"> <div id="view-change-password" class="view view-centered hidden">
<div class="login-box"> <div class="login-box">
<div class="login-header"> <div class="login-header">
<h2>CHANGE ACCESS CODE</h2> <h2 style="font-family:var(--font-heading);font-size:1.4rem;letter-spacing:.1em;color:var(--accent)">CHANGE ACCESS CODE</h2>
<p class="login-sub">Temporary password must be changed before proceeding</p> <p class="login-sub">Temporary password must be changed before proceeding</p>
</div> </div>
<form id="change-password-form" class="login-form"> <form id="change-password-form" class="login-form">
@@ -84,126 +127,286 @@
<!-- ── DASHBOARD ─────────────────────────────────────────────── --> <!-- ── DASHBOARD ─────────────────────────────────────────────── -->
<div id="view-dashboard" class="view hidden"> <div id="view-dashboard" class="view hidden">
<div class="page-header"> <div class="dashboard-grid">
<h2 class="page-title">COMMAND CENTER</h2> <div class="card dashboard-briefing">
<p class="page-sub">Welcome back, Helldiver. For Super Earth.</p> <div class="briefing-copy">
<div class="eyebrow">Mission Briefing</div>
<h2 class="briefing-title">Your command deck for practice, duels, and rank progress.</h2>
<p class="briefing-text" id="dash-status-line">Loading tactical status...</p>
<div class="briefing-pills">
<span class="status-pill">
<span class="status-pill-label">Online</span>
<strong id="dash-online-count">0</strong>
</span>
<span class="status-pill">
<span class="status-pill-label">Daily</span>
<strong id="dash-daily-focus">Pending</strong>
</span>
</div>
</div>
<div class="briefing-actions">
<button class="btn btn-accent" id="btn-briefing-practice">⚡ Quick Start</button>
<button class="btn btn-muted" id="btn-briefing-lobby">⚔ Open Arena</button>
<button class="btn btn-muted" id="btn-briefing-leaderboard">Hall of Heroes</button>
</div>
</div> </div>
<div class="dashboard-grid"> <!-- Hero card -->
<!-- Stats card --> <div class="card card-hero dashboard-hero">
<div class="card"> <div class="hero-identity">
<h3 class="card-title">YOUR STATS</h3> <div class="hero-rank-icon" id="dash-rank-icon"></div>
<div class="stat-grid"> <div>
<div class="stat-item"> <div class="hero-name" id="dash-hero-name"></div>
<div class="stat-value" id="dash-total-score"></div> <div class="hero-rank-name" id="dash-rank-label">PRIVATE</div>
<div class="stat-label">Total Score</div>
</div> </div>
<div class="stat-item">
<div class="stat-value accent" id="dash-rank"></div>
<div class="stat-label">Global Rank</div>
</div> </div>
<div class="stat-item"> <div class="hero-elo">ELO <span id="dash-elo">1000</span></div>
<div class="stat-value" id="dash-sessions"></div> <div class="hero-stats">
<div class="stat-label">Sessions</div> <div class="hero-stat-item">
<div class="hero-stat-val" id="dash-total-score"></div>
<div class="hero-stat-label">Total Score</div>
</div> </div>
<div class="stat-item"> <div class="hero-stat-item">
<div class="stat-value" id="dash-win-rate"></div> <div class="hero-stat-val" id="dash-rank"></div>
<div class="stat-label">Match Win Rate</div> <div class="hero-stat-label">Global Rank</div>
</div>
<div class="hero-stat-item">
<div class="hero-stat-val" id="dash-sessions"></div>
<div class="hero-stat-label">Sessions</div>
</div>
<div class="hero-stat-item">
<div class="hero-stat-val" id="dash-win-rate"></div>
<div class="hero-stat-label">Win Rate</div>
</div> </div>
</div> </div>
</div> </div>
<!-- Daily challenge card --> <!-- Daily challenge card -->
<div class="card card-accent"> <div class="card card-accent">
<h3 class="card-title">⚡ DAILY CHALLENGE</h3> <h3 class="card-title">Daily Challenge</h3>
<div class="daily-stratagem"> <div class="daily-stratagem">
<div class="daily-icon-wrap">
<img id="dash-daily-icon" class="stratagem-icon-md" src="" alt="" style="display:none">
</div>
<div class="daily-name" id="dash-daily-name"></div> <div class="daily-name" id="dash-daily-name"></div>
<div class="daily-category" id="dash-daily-category"></div> <div class="daily-category" id="dash-daily-category"></div>
<div class="daily-best"> <div class="daily-sequence-preview" id="dash-daily-sequence"></div>
Best time: <span id="dash-daily-best"></span> <div class="daily-best">Personal best: <span id="dash-daily-best"></span></div>
</div> <button class="btn btn-accent btn-sm" id="btn-daily-challenge">⚡ Practice Now</button>
<button class="btn btn-accent" id="btn-daily-challenge">Practice this stratagem</button>
</div> </div>
</div> </div>
<!-- Online users card --> <!-- Online players -->
<div class="card"> <div class="card">
<h3 class="card-title">ONLINE HELLDIVERS</h3> <h3 class="card-title">Online Helldivers</h3>
<div id="dash-online" class="online-list"> <div id="dash-online" class="online-list">
<span class="muted">Loading...</span> <span class="muted">Loading...</span>
</div> </div>
</div> </div>
<!-- Recent sessions card --> <!-- Recent sessions -->
<div class="card"> <div class="card">
<h3 class="card-title">RECENT SESSIONS</h3> <h3 class="card-title">Recent Sessions</h3>
<div class="table-wrap">
<table class="data-table"> <table class="data-table">
<thead> <thead>
<tr><th>Stratagem</th><th>Score</th><th>Time</th></tr> <tr><th>Stratagem</th><th>Mode</th><th>Score</th><th>Time</th></tr>
</thead> </thead>
<tbody id="dash-recent"> <tbody id="dash-recent">
<tr><td colspan="3" class="muted">No sessions yet</td></tr> <tr><td colspan="4" class="muted">No sessions yet</td></tr>
</tbody> </tbody>
</table> </table>
</div> </div>
</div> </div>
</div>
</div> </div>
<!-- ── PRACTICE ───────────────────────────────────────────────── --> <!-- ── PRACTICE ───────────────────────────────────────────────── -->
<div id="view-practice" class="view hidden"> <div id="view-practice" class="view hidden">
<div class="page-header"> <div class="practice-header">
<div>
<h2 class="page-title">TRAINING PROTOCOL</h2> <h2 class="page-title">TRAINING PROTOCOL</h2>
<p class="page-sub" id="practice-mode-label">Select a mode to begin</p>
</div>
<button class="btn btn-ghost btn-icon" id="btn-practice-settings" aria-label="Practice settings" data-tooltip="Settings"></button>
</div>
<!-- Mode selector -->
<div id="practice-mode-grid" class="mode-grid">
<div class="mode-card active" data-mode="timed">
<div class="mode-icon"></div>
<div class="mode-name">Timed</div>
<div class="mode-desc">30s per stratagem. Score by speed.</div>
</div>
<div class="mode-card" data-mode="endless">
<div class="mode-icon"></div>
<div class="mode-name">Endless</div>
<div class="mode-desc">3 lives. No timer. How far can you go?</div>
</div>
<div class="mode-card" data-mode="drill">
<div class="mode-icon">🎯</div>
<div class="mode-name">Category Drill</div>
<div class="mode-desc">Master one category completely.</div>
</div>
<div class="mode-card" data-mode="speedrun">
<div class="mode-icon"></div>
<div class="mode-name">Speed Run</div>
<div class="mode-desc">All stratagems, fastest total time.</div>
</div>
</div> </div>
<!-- Category filters --> <!-- Category filters -->
<div class="category-row" id="practice-categories"></div> <div class="category-row" id="practice-categories"></div>
<!-- Idle (start screen) --> <!-- Idle -->
<div id="practice-idle" class="practice-idle"> <div id="practice-idle" class="practice-setup">
<div class="idle-hint">Select categories above, then start training</div> <div class="idle-hint" id="practice-idle-hint">Select categories above, then start training</div>
<div class="practice-start-row">
<button class="btn btn-accent btn-lg" id="btn-start-practice">⚡ START TRAINING</button> <button class="btn btn-accent btn-lg" id="btn-start-practice">⚡ START TRAINING</button>
</div> </div>
</div>
<!-- Active training --> <!-- Active training -->
<div id="practice-active" class="practice-active hidden"> <div id="practice-active" class="practice-active hidden">
<div class="stratagem-display card">
<div class="stratagem-category" id="practice-category"></div> <!-- Drill progress bar -->
<div class="stratagem-name" id="practice-name"></div> <div id="drill-progress-wrap" class="drill-progress hidden">
<div class="arrow-sequence" id="practice-sequence"></div> <div class="drill-label">
<div class="practice-hint">Use Arrow Keys or D-Pad</div> <span>Category Progress</span>
<span id="drill-progress-text">0 / 0</span>
</div>
<div class="progress-bar">
<div class="progress-fill" id="drill-progress-fill" style="width:0%"></div>
</div>
</div> </div>
<div class="practice-hud"> <div class="practice-focus-shell">
<div class="hud-item"> <div class="practice-focus-meta">
<div class="hud-label">TIME</div> <span class="focus-chip">Live Drill</span>
<div class="timer" id="practice-timer">30</div> <span class="focus-chip focus-chip-muted">Stay on target</span>
</div> </div>
<div id="practice-feedback" class="gameplay-feedback hidden" aria-live="polite"></div>
<div class="stratagem-display card">
<!-- Stratagem icon -->
<div class="stratagem-icon-wrap">
<img id="practice-icon" class="stratagem-icon-lg" src="" alt="" style="display:none">
<div id="practice-icon-fallback" class="stratagem-icon-fallback"></div>
</div>
<div class="stratagem-category" id="practice-category"></div>
<div class="stratagem-name" id="practice-name"></div>
<div class="arrow-sequence arrow-sequence-hero" id="practice-sequence"></div>
<div class="practice-hint">Arrow Keys or D-Pad · <kbd>Esc</kbd> to stop</div>
</div>
<!-- Upcoming queue -->
<div class="stratagem-queue" id="practice-queue"></div>
<div class="practice-hud">
<!-- Timer ring / lives / elapsed -->
<div class="hud-item" id="hud-timer-wrap">
<div class="hud-label" id="hud-timer-label">TIME</div>
<div class="timer-ring-wrap">
<svg class="timer-ring-svg" viewBox="0 0 80 80">
<circle class="timer-ring-bg" cx="40" cy="40" r="35"/>
<circle class="timer-ring-fill" id="timer-ring-fill" cx="40" cy="40" r="35"
stroke-dasharray="219.9" stroke-dashoffset="0"/>
</svg>
<div class="timer-ring-val" id="practice-timer">30</div>
</div>
</div>
<!-- Lives (endless mode) -->
<div class="hud-item hidden" id="hud-lives-wrap">
<div class="hud-label">LIVES</div>
<div class="lives-display" id="practice-lives">
<span class="life-icon"></span>
<span class="life-icon"></span>
<span class="life-icon"></span>
</div>
</div>
<div class="hud-item"> <div class="hud-item">
<div class="hud-label">SCORE</div> <div class="hud-label">SCORE</div>
<div class="hud-value" id="practice-score">0</div> <div class="hud-value" id="practice-score">0</div>
</div> </div>
<div class="hud-item"> <div class="hud-item" id="hud-streak-item">
<div class="hud-label">STREAK</div> <div class="hud-label">STREAK</div>
<div class="hud-value accent" id="practice-streak">0</div> <div class="hud-value accent" id="practice-streak">0</div>
<div class="combo-badge hidden" id="practice-combo">×1.0</div>
</div> </div>
</div> </div>
<!-- D-Pad (mobile) --> <!-- D-Pad -->
<div class="dpad" id="practice-dpad"> <div class="dpad" id="practice-dpad">
<div class="dpad-row"> <div class="dpad-row">
<button class="dpad-btn dpad-up" data-dir="up"></button> <button class="dpad-btn" data-dir="up" aria-label="Arrow up"><span class="dir-glyph dir-up" aria-hidden="true"><svg viewBox="0 0 64 64" focusable="false"><path class="dir-line" d="M32 50 L32 18" /><path class="dir-head" d="M32 12 L20 24 H28 V50 H36 V24 H44 Z" /></svg></span></button>
</div> </div>
<div class="dpad-row"> <div class="dpad-row">
<button class="dpad-btn dpad-left" data-dir="left"></button> <button class="dpad-btn" data-dir="left" aria-label="Arrow left"><span class="dir-glyph dir-left" aria-hidden="true"><svg viewBox="0 0 64 64" focusable="false"><path class="dir-line" d="M32 50 L32 18" /><path class="dir-head" d="M32 12 L20 24 H28 V50 H36 V24 H44 Z" /></svg></span></button>
<div class="dpad-center"></div> <div class="dpad-center"></div>
<button class="dpad-btn dpad-right" data-dir="right"></button> <button class="dpad-btn" data-dir="right" aria-label="Arrow right"><span class="dir-glyph dir-right" aria-hidden="true"><svg viewBox="0 0 64 64" focusable="false"><path class="dir-line" d="M32 50 L32 18" /><path class="dir-head" d="M32 12 L20 24 H28 V50 H36 V24 H44 Z" /></svg></span></button>
</div> </div>
<div class="dpad-row"> <div class="dpad-row">
<button class="dpad-btn dpad-down" data-dir="down"></button> <button class="dpad-btn" data-dir="down" aria-label="Arrow down"><span class="dir-glyph dir-down" aria-hidden="true"><svg viewBox="0 0 64 64" focusable="false"><path class="dir-line" d="M32 50 L32 18" /><path class="dir-head" d="M32 12 L20 24 H28 V50 H36 V24 H44 Z" /></svg></span></button>
</div> </div>
</div> </div>
<button class="btn btn-muted" id="btn-stop-practice">Stop Training</button> <button class="btn btn-muted btn-sm" id="btn-stop-practice">Stop Training</button>
</div>
</div>
</div>
<!-- ── HISTORY ────────────────────────────────────────────────── -->
<div id="view-history" class="view hidden">
<div class="page-header">
<h2 class="page-title">MISSION LOGS</h2>
<p class="page-sub">Your practice history and stratagem statistics</p>
</div>
<div class="card" style="margin-bottom:16px">
<h3 class="card-title">Score Progression</h3>
<div class="history-chart" id="history-chart">
<svg id="history-chart-svg" width="100%" height="100%" preserveAspectRatio="none"></svg>
</div>
</div>
<div class="card">
<div class="history-filters">
<select id="history-filter-mode">
<option value="">All Modes</option>
<option value="timed">Timed</option>
<option value="endless">Endless</option>
<option value="drill">Category Drill</option>
<option value="speedrun">Speed Run</option>
</select>
<select id="history-filter-cat">
<option value="">All Categories</option>
</select>
</div>
<h3 class="card-title">Session History</h3>
<table class="data-table">
<thead>
<tr><th>Stratagem</th><th>Category</th><th>Mode</th><th>Score</th><th>Time</th><th>Date</th></tr>
</thead>
<tbody id="history-table-body">
<tr><td colspan="6" class="muted">Loading...</td></tr>
</tbody>
</table>
<div class="pagination" id="history-pagination"></div>
</div>
<div class="card" style="margin-top:16px">
<h3 class="card-title">Best Times per Stratagem</h3>
<table class="data-table">
<thead>
<tr><th></th><th>Stratagem</th><th>Category</th><th>Best Time</th><th>Attempts</th></tr>
</thead>
<tbody id="best-per-stratagem-body">
<tr><td colspan="5" class="muted">No data yet</td></tr>
</tbody>
</table>
</div> </div>
</div> </div>
@@ -216,12 +419,20 @@
<div class="lobby-layout"> <div class="lobby-layout">
<div class="card"> <div class="card">
<h3 class="card-title">ONLINE HELLDIVERS</h3> <h3 class="card-title">Online Helldivers</h3>
<div id="lobby-players" class="player-list"> <div id="lobby-players" class="player-list">
<p class="muted">Loading...</p> <div class="lobby-empty">
<div class="lobby-empty-icon">📡</div>
<p>No other Helldivers online.<br>Waiting for reinforcements...</p>
</div>
</div>
</div>
<div class="card">
<h3 class="card-title">Incoming Challenges</h3>
<div id="lobby-challenges" class="challenge-list">
<p class="muted">No incoming challenges</p>
</div> </div>
</div> </div>
<div id="lobby-challenges" class="challenge-list"></div>
</div> </div>
</div> </div>
@@ -246,28 +457,42 @@
<!-- Round area --> <!-- Round area -->
<div id="match-round-area" class="match-round-area hidden"> <div id="match-round-area" class="match-round-area hidden">
<!-- Stratagem icon in match -->
<div style="text-align:center;margin-bottom:8px">
<img id="match-icon" class="stratagem-icon-md" src="" alt="" style="display:none">
</div>
<div class="match-focus-shell">
<div id="match-feedback" class="gameplay-feedback hidden" aria-live="polite"></div>
<div class="match-sequences"> <div class="match-sequences">
<div class="match-seq-col"> <div class="match-seq-col">
<div class="match-seq-label">YOU</div> <div class="match-seq-label">YOU</div>
<div class="arrow-sequence" id="match-me-sequence"></div> <div class="duel-progress">
<div class="duel-progress-bar"><div class="duel-progress-fill" id="match-me-progress-fill" style="width:0%"></div></div>
<div class="duel-progress-text" id="match-me-progress-text">0 / 0</div>
</div>
<div class="arrow-sequence arrow-sequence-hero arrow-sequence-duel" id="match-me-sequence"></div>
</div> </div>
<div class="match-seq-col"> <div class="match-seq-col">
<div class="match-seq-label">OPPONENT</div> <div class="match-seq-label">OPPONENT</div>
<div class="arrow-sequence" id="match-opp-sequence"></div> <div class="duel-progress">
<div class="duel-progress-bar"><div class="duel-progress-fill duel-progress-fill-opp" id="match-opp-progress-fill" style="width:0%"></div></div>
<div class="duel-progress-text" id="match-opp-progress-text">0 / 0</div>
</div>
<div class="arrow-sequence arrow-sequence-hero arrow-sequence-duel" id="match-opp-sequence"></div>
</div> </div>
</div> </div>
<!-- D-Pad (mobile) -->
<div class="dpad" id="match-dpad"> <div class="dpad" id="match-dpad">
<div class="dpad-row"> <div class="dpad-row">
<button class="dpad-btn dpad-up" data-dir="up"></button> <button class="dpad-btn" data-dir="up" aria-label="Arrow up"><span class="dir-glyph dir-up" aria-hidden="true"><svg viewBox="0 0 64 64" focusable="false"><path class="dir-line" d="M32 50 L32 18" /><path class="dir-head" d="M32 12 L20 24 H28 V50 H36 V24 H44 Z" /></svg></span></button>
</div> </div>
<div class="dpad-row"> <div class="dpad-row">
<button class="dpad-btn dpad-left" data-dir="left"></button> <button class="dpad-btn" data-dir="left" aria-label="Arrow left"><span class="dir-glyph dir-left" aria-hidden="true"><svg viewBox="0 0 64 64" focusable="false"><path class="dir-line" d="M32 50 L32 18" /><path class="dir-head" d="M32 12 L20 24 H28 V50 H36 V24 H44 Z" /></svg></span></button>
<div class="dpad-center"></div> <div class="dpad-center"></div>
<button class="dpad-btn dpad-right" data-dir="right"></button> <button class="dpad-btn" data-dir="right" aria-label="Arrow right"><span class="dir-glyph dir-right" aria-hidden="true"><svg viewBox="0 0 64 64" focusable="false"><path class="dir-line" d="M32 50 L32 18" /><path class="dir-head" d="M32 12 L20 24 H28 V50 H36 V24 H44 Z" /></svg></span></button>
</div> </div>
<div class="dpad-row"> <div class="dpad-row">
<button class="dpad-btn dpad-down" data-dir="down"></button> <button class="dpad-btn" data-dir="down" aria-label="Arrow down"><span class="dir-glyph dir-down" aria-hidden="true"><svg viewBox="0 0 64 64" focusable="false"><path class="dir-line" d="M32 50 L32 18" /><path class="dir-head" d="M32 12 L20 24 H28 V50 H36 V24 H44 Z" /></svg></span></button>
</div>
</div> </div>
</div> </div>
</div> </div>
@@ -285,34 +510,57 @@
<p class="page-sub">Top Helldivers ranked by total practice score</p> <p class="page-sub">Top Helldivers ranked by total practice score</p>
</div> </div>
<div class="leaderboard-tabs">
<button class="tab-btn active" data-tab="practice">Practice Score</button>
<button class="tab-btn" data-tab="elo">ELO Rating</button>
<button class="tab-btn" data-tab="speedrun">Speed Run</button>
</div>
<div class="card"> <div class="card">
<table class="data-table leaderboard-table"> <div class="table-wrap">
<thead> <table class="data-table">
<tr> <thead id="leaderboard-thead">
<th>#</th> <tr><th>#</th><th>Helldiver</th><th>Rank</th><th>Total Score</th><th>Sessions</th><th>Match W/Total</th></tr>
<th>Helldiver</th>
<th>Total Score</th>
<th>Sessions</th>
<th>Match W/Total</th>
</tr>
</thead> </thead>
<tbody id="leaderboard-table-body"> <tbody id="leaderboard-table-body">
<tr><td colspan="5" class="muted">Loading...</td></tr> <tr><td colspan="6" class="muted">Loading...</td></tr>
</tbody> </tbody>
</table> </table>
</div> </div>
</div> </div>
</div>
<!-- ── ADMIN ──────────────────────────────────────────────────── --> <!-- ── ADMIN ──────────────────────────────────────────────────── -->
<div id="view-admin" class="view hidden"> <div id="view-admin" class="view hidden">
<div class="page-header"> <div class="page-header">
<h2 class="page-title">ADMIN PANEL</h2> <h2 class="page-title">ADMIN PANEL</h2>
<p class="page-sub">User control, password operations, role management, and live system activity</p>
</div>
<div class="admin-overview" id="admin-overview">
<div class="card admin-stat-card">
<div class="card-title">Helldivers</div>
<div class="admin-stat-value" id="admin-total-users"></div>
<div class="admin-stat-meta">Registered accounts</div>
</div>
<div class="card admin-stat-card">
<div class="card-title">Admins</div>
<div class="admin-stat-value" id="admin-total-admins"></div>
<div class="admin-stat-meta">Users with command access</div>
</div>
<div class="card admin-stat-card">
<div class="card-title">Temp Passwords</div>
<div class="admin-stat-value" id="admin-temp-passwords"></div>
<div class="admin-stat-meta">Accounts requiring password change</div>
</div>
<div class="card admin-stat-card">
<div class="card-title">Practice Sessions</div>
<div class="admin-stat-value" id="admin-practice-sessions"></div>
<div class="admin-stat-meta">Total runs recorded</div>
</div>
</div> </div>
<div class="admin-layout"> <div class="admin-layout">
<!-- Create user -->
<div class="card"> <div class="card">
<h3 class="card-title">CREATE HELLDIVER</h3> <h3 class="card-title">Create Helldiver</h3>
<div class="field"> <div class="field">
<label for="new-username">Username</label> <label for="new-username">Username</label>
<input id="new-username" type="text" placeholder="helldiver_name" pattern="[a-zA-Z0-9_-]{2,32}"> <input id="new-username" type="text" placeholder="helldiver_name" pattern="[a-zA-Z0-9_-]{2,32}">
@@ -327,19 +575,130 @@
<p id="admin-error" class="error hidden"></p> <p id="admin-error" class="error hidden"></p>
<button class="btn btn-accent" id="btn-create-user">Create User</button> <button class="btn btn-accent" id="btn-create-user">Create User</button>
<div id="new-pw-display" class="pw-display hidden"></div> <div id="new-pw-display" class="pw-display hidden"></div>
<div class="divider"></div>
<div class="admin-spotlight">
<div class="admin-spotlight-label">Top performer</div>
<div class="admin-spotlight-value" id="admin-top-user"></div>
<div class="admin-spotlight-meta" id="admin-top-user-meta">Loading tactical data...</div>
</div>
</div> </div>
<!-- User list -->
<div class="card"> <div class="card">
<h3 class="card-title">ACTIVE HELLDIVERS</h3> <div class="admin-users-header">
<h3 class="card-title">User Management</h3>
<input id="admin-user-search" class="admin-search" type="text" placeholder="Search user">
</div>
<div id="admin-users" class="admin-user-list">Loading...</div> <div id="admin-users" class="admin-user-list">Loading...</div>
</div> </div>
</div> </div>
<div class="admin-activity-grid">
<div class="card">
<h3 class="card-title">Recent Practice Activity</h3>
<div id="admin-recent-practice" class="admin-activity-list">
<span class="muted">Loading...</span>
</div> </div>
</div>
<div class="card">
<h3 class="card-title">Recent Matches</h3>
<div id="admin-recent-matches" class="admin-activity-list">
<span class="muted">Loading...</span>
</div>
</div>
</div>
</div>
<!-- ── PRACTICE SETTINGS MODAL ──────────────────────────────── -->
<div id="modal-settings" class="modal-overlay hidden" role="dialog" aria-modal="true" aria-label="Practice Settings">
<div class="modal">
<div class="modal-header">
<span class="modal-title">⚙ Practice Settings</span>
<button class="modal-close" id="btn-settings-close" aria-label="Close"></button>
</div>
<div class="settings-section">
<span class="settings-label">Timer Duration (Timed mode)</span>
<div class="settings-options">
<button class="settings-option" data-setting="timer" data-value="15">15s</button>
<button class="settings-option active" data-setting="timer" data-value="30">30s</button>
<button class="settings-option" data-setting="timer" data-value="45">45s</button>
</div>
</div>
<div class="settings-section">
<span class="settings-label">Difficulty</span>
<div class="settings-options">
<button class="settings-option" data-setting="difficulty" data-value="easy">Easy<br><small>Shows category</small></button>
<button class="settings-option active" data-setting="difficulty" data-value="normal">Normal<br><small>Name only</small></button>
<button class="settings-option" data-setting="difficulty" data-value="hard">Hard<br><small>No name shown</small></button>
</div>
</div>
</div>
</div>
<!-- ── CHALLENGE MODAL ────────────────────────────────────────── -->
<div id="modal-challenge" class="modal-overlay hidden" role="dialog" aria-modal="true" aria-label="Incoming Challenge">
<div class="modal">
<div class="modal-header">
<span class="modal-title">⚔ Challenge Incoming!</span>
</div>
<p style="color:var(--text-dim);margin-bottom:8px">Challenger:</p>
<p style="font-family:var(--font-mono);font-size:1.2rem;color:var(--accent);margin-bottom:4px" id="modal-challenger-name"></p>
<p style="font-size:0.8rem;color:var(--text-muted);margin-bottom:20px">ELO: <span id="modal-challenger-elo"></span></p>
<div class="modal-actions">
<button class="btn btn-muted" id="btn-decline-challenge">Decline</button>
<button class="btn btn-accent" id="btn-accept-challenge">⚔ Accept</button>
</div>
</div>
</div>
<!-- ── POST-MATCH RESULT MODAL ───────────────────────────────── -->
<div id="modal-match-result" class="modal-overlay hidden" role="dialog" aria-modal="true" aria-label="Match Result">
<div class="modal modal-wide">
<div class="modal-header">
<span class="modal-title">Match Result</span>
</div>
<div style="text-align:center;padding:8px 0 16px">
<div class="result-winner" id="result-winner-text"></div>
</div>
<div class="elo-delta-row">
<span class="elo-delta-old" id="result-elo-old"></span>
<span class="elo-delta-arrow"></span>
<span class="elo-delta-new" id="result-elo-new"></span>
<span class="elo-delta-val" id="result-elo-delta"></span>
</div>
<div style="height:1px;background:var(--border);margin:12px 0"></div>
<div class="round-history" id="result-round-history"></div>
<div class="modal-actions">
<button class="btn btn-muted" id="btn-result-lobby">Back to Lobby</button>
<button class="btn btn-accent" id="btn-result-rematch">⚔ Rematch</button>
</div>
</div>
</div>
<!-- ── SESSION SUMMARY MODAL ─────────────────────────────────── -->
<div id="modal-session-summary" class="modal-overlay hidden" role="dialog" aria-modal="true" aria-label="Session Summary">
<div class="modal modal-wide">
<div class="modal-header">
<span class="modal-title">Session Complete</span>
</div>
<div class="summary-grid" id="summary-grid"></div>
<div style="height:1px;background:var(--border);margin:16px 0"></div>
<h4 style="font-family:var(--font-heading);font-size:0.85rem;letter-spacing:.06em;color:var(--text-muted);margin-bottom:8px">PERFORMANCE ANALYSIS</h4>
<div id="summary-insights" class="summary-insights"></div>
<div style="height:1px;background:var(--border);margin:16px 0"></div>
<h4 style="font-family:var(--font-heading);font-size:0.85rem;letter-spacing:.06em;color:var(--text-muted);margin-bottom:8px">TOP STRATAGEMS</h4>
<div id="summary-top-stratagems"></div>
<div class="modal-actions">
<button class="btn btn-muted" id="btn-summary-dashboard">Dashboard</button>
<button class="btn btn-accent" id="btn-summary-restart">⚡ Play Again</button>
</div>
</div>
</div>
<!-- ── Danger vignette (≤5s) ──────────────────────────────────── -->
<div id="danger-vignette" class="danger-vignette hidden"></div>
<div id="gameplay-countdown" class="gameplay-countdown hidden" aria-live="assertive"></div>
<!-- Toast notifications --> <!-- Toast notifications -->
<div id="toast-container"></div> <div id="toast-container"></div>
<script src="app.js"></script> <script src="app.js?v=1.0.0"></script>
</body> </body>
</html> </html>
+1944 -199
View File
File diff suppressed because it is too large Load Diff
+135
View File
@@ -0,0 +1,135 @@
#!/usr/bin/env node
// Downloads stratagem icons from helldivers.wiki.gg
// Saves as public/icons/<slug>.svg (same filenames as before)
import { createWriteStream, mkdirSync } from 'fs';
import { join, dirname } from 'path';
import { fileURLToPath } from 'url';
import https from 'https';
const __dirname = dirname(fileURLToPath(import.meta.url));
const OUT_DIR = join(__dirname, '..', 'public', 'icons');
const BASE_URL = 'https://helldivers.wiki.gg/images/';
mkdirSync(OUT_DIR, { recursive: true });
// Maps our stratagem slug → wiki filename (without _Stratagem_Icon.svg suffix)
const WIKI_MAP = {
reinforce: 'Reinforce',
resupply: 'Resupply',
sos_beacon: 'SOS_Beacon',
hellbomb: 'Hellbomb',
seaf_artillery: 'SEAF_Artillery',
upload_data: 'Start_Upload',
eagle_rearm: 'Eagle_Rearm',
prospecting_drill: 'Prospecting_Drill',
orbital_gatling_barrage: 'Orbital_Gatling_Barrage',
orbital_airburst_strike: 'Orbital_Airburst_Strike',
orbital_120mm_he_barrage: 'Orbital_120mm_HE_Barrage',
orbital_380mm_he_barrage: 'Orbital_380mm_HE_Barrage',
orbital_walking_barrage: 'Orbital_Walking_Barrage',
orbital_laser: 'Orbital_Laser',
orbital_railcannon_strike: 'Orbital_Railcannon_Strike',
orbital_precision_strike: 'Orbital_Precision_Strike',
orbital_gas_strike: 'Orbital_Gas_Strike',
orbital_ems_strike: 'Orbital_EMS_Strike',
orbital_smoke_strike: 'Orbital_Smoke_Strike',
orbital_illumination_flare: 'Orbital_Illumination_Flare',
eagle_strafing_run: 'Eagle_Strafing_Run',
eagle_airstrike: 'Eagle_Airstrike',
eagle_cluster_bomb: 'Eagle_Cluster_Bomb',
eagle_napalm_airstrike: 'Eagle_Napalm_Airstrike',
lift_850_jump_pack: 'Jump_Pack',
eagle_smoke_strike: 'Eagle_Smoke_Strike',
eagle_110mm_rocket_pods: 'Eagle_110mm_Rocket_Pods',
eagle_500kg_bomb: 'Eagle_500kg_Bomb',
patriot_exosuit: 'Patriot_Exosuit',
emancipator_exosuit: 'Emancipator_Exosuit',
tesla_tower: 'Tesla_Tower',
shield_generator_relay: 'Shield_Generator_Relay',
machine_gun: 'Machine_Gun',
anti_materiel_rifle: 'Anti-Materiel_Rifle',
stalwart: 'Stalwart',
expendable_anti_tank: 'Expendable_Anti-Tank',
recoilless_rifle: 'Recoilless_Rifle',
flamethrower: 'Flamethrower',
autocannon: 'Autocannon',
heavy_machine_gun: 'Heavy_Machine_Gun',
airburst_rocket_launcher: 'Airburst_Rocket_Launcher',
commando: 'Commando',
railgun: 'Railgun',
spear: 'Spear',
quasar_cannon: 'Quasar_Cannon',
arc_thrower: 'Arc_Thrower',
laser_cannon: 'Laser_Cannon',
grenade_launcher: 'Grenade_Launcher',
supply_pack: 'Supply_Pack',
guard_dog_rover: 'Rover',
guard_dog: 'Guard_Dog',
ballistic_shield_backpack: 'Ballistic_Shield_Backpack',
shield_generator_pack: 'Shield_Generator_Pack',
directional_shield: 'Directional_Shield',
hmg_emplacement: 'HMG_Emplacement',
anti_personnel_minefield: 'Anti-Personnel_Minefield',
incendiary_mines: 'Incendiary_Mines',
anti_tank_mines: 'Anti-Tank_Mines',
machine_gun_sentry: 'Machine_Gun_Sentry',
gatling_sentry: 'Gatling_Sentry',
mortar_sentry: 'Mortar_Sentry',
autocannon_sentry: 'Autocannon_Sentry',
rocket_sentry: 'Rocket_Sentry',
ems_mortar_sentry: 'EMS_Mortar_Sentry',
anti_tank_emplacement: 'Anti-Tank_Emplacement',
};
function download(url, dest) {
return new Promise((resolve, reject) => {
const file = createWriteStream(dest);
const request = (targetUrl) => {
https.get(targetUrl, { headers: { 'User-Agent': 'helldivers-trainer-bot/1.0' } }, (res) => {
if (res.statusCode === 301 || res.statusCode === 302) {
file.destroy();
return request(res.headers.location);
}
if (res.statusCode !== 200) {
file.destroy();
return reject(new Error(`HTTP ${res.statusCode}`));
}
res.pipe(file);
file.on('finish', () => file.close(resolve));
}).on('error', reject);
};
request(url);
});
}
async function main() {
const entries = Object.entries(WIKI_MAP);
let ok = 0, fail = 0;
for (const [slug, wikiName] of entries) {
const filename = wikiName + '_Stratagem_Icon.svg';
const url = BASE_URL + filename;
const dest = join(OUT_DIR, slug + '.svg');
try {
await download(url, dest);
console.log(`${slug}`);
ok++;
} catch (err) {
console.error(`${slug} (${err.message})`);
fail++;
}
}
console.log(`\nDone: ${ok} ok, ${fail} failed`);
}
main();
+160
View File
@@ -0,0 +1,160 @@
/**
* Download Helldivers 2 stratagem SVG icons from:
* github.com/nvigneux/Helldivers-2-Stratagems-icons-svg
*
* Run once: node scripts/download-icons.js
*/
import https from 'https';
import fs from 'fs';
import path from 'path';
import { fileURLToPath } from 'url';
const __dirname = path.dirname(fileURLToPath(import.meta.url));
const ICONS_DIR = path.join(__dirname, '..', 'public', 'icons');
const BASE_URL = 'https://raw.githubusercontent.com/nvigneux/Helldivers-2-Stratagems-icons-svg/master';
// Map: our stratagem name → { repo category folder, repo filename (without .svg) }
const ICON_MAP = [
// ── General / PAC ────────────────────────────────────────────────────────
['Reinforce', 'General Stratagems', 'Reinforce'],
['Resupply', 'General Stratagems', 'Resupply'],
['SOS Beacon', 'General Stratagems', 'SOS Beacon'],
['Hellbomb', 'General Stratagems', 'Hellbomb'],
['SEAF Artillery', 'General Stratagems', 'SEAF Artillery'],
['Upload Data', 'General Stratagems', 'Upload Data'],
['Prospecting Drill', 'General Stratagems', 'Prospecting Drill'],
['Orbital Illumination Flare', 'General Stratagems', 'Orbital Illumination Flare'],
// ── Orbital Cannons ───────────────────────────────────────────────────────
['Orbital Gatling Barrage', 'Orbital Cannons', 'Orbital Gatling Barrage'],
['Orbital Airburst Strike', 'Orbital Cannons', 'Orbital Airburst Strike'],
['Orbital 120MM HE Barrage', 'Orbital Cannons', 'Orbital 120MM HE Barrage'],
['Orbital 380MM HE Barrage', 'Orbital Cannons', 'Orbital 380MM HE Barrage'],
['Orbital Walking Barrage', 'Orbital Cannons', 'Orbital Walking Barrage'],
['Orbital Laser', 'Orbital Cannons', 'Orbital Laser'],
['Orbital Railcannon Strike', 'Orbital Cannons', 'Orbital Railcannon Strike'],
// ── Bridge ────────────────────────────────────────────────────────────────
['Orbital Precision Strike', 'Bridge', 'Orbital Precision Strike'],
['Orbital Gas Strike', 'Bridge', 'Orbital Gas Strike'],
['Orbital EMS Strike', 'Bridge', 'Orbital EMS Strike'],
['Orbital Smoke Strike', 'Bridge', 'Orbital Smoke Strike'],
['Tesla Tower', 'Bridge', 'Tesla Tower'],
['Shield Generator Relay', 'Bridge', 'Shield Generator Relay'],
['HMG Emplacement', 'Bridge', 'HMG Emplacement'],
// ── Hangar ────────────────────────────────────────────────────────────────
['Eagle Strafing Run', 'Hangar', 'Eagle Strafing Run'],
['Eagle Airstrike', 'Hangar', 'Eagle Airstrike'],
['Eagle Cluster Bomb', 'Hangar', 'Eagle Cluster Bomb'],
['Eagle Napalm Airstrike', 'Hangar', 'Eagle Napalm Airstrike'],
['LIFT-850 Jump Pack', 'Hangar', 'Jump Pack'],
['Eagle Smoke Strike', 'Hangar', 'Eagle Smoke Strike'],
['Eagle 110MM Rocket Pods', 'Hangar', 'Eagle 110MM Rocket Pods'],
['Eagle 500KG Bomb', 'Hangar', 'Eagle 500KG Bomb'],
['Eagle Rearm', 'Hangar', 'Eagle Rearm'],
// ── PAC Support Weapons ─────────────────────────────────────────────────
['Machine Gun', 'Patriotic Administration Center', 'Machine Gun'],
['Anti-Materiel Rifle', 'Patriotic Administration Center', 'Anti-Materiel Rifle'],
['Stalwart', 'Patriotic Administration Center', 'Stalwart'],
['Expendable Anti-Tank', 'Patriotic Administration Center', 'Expendable Anti-Tank'],
['Recoilless Rifle', 'Patriotic Administration Center', 'Recoilless Rifle'],
['Flamethrower', 'Patriotic Administration Center', 'Flamethrower'],
['Autocannon', 'Patriotic Administration Center', 'Autocannon'],
['Heavy Machine Gun', 'Patriotic Administration Center', 'Heavy Machine Gun'],
['Airburst Rocket Launcher', 'Patriotic Administration Center', 'Airburst Rocket Launcher'],
['Commando', 'Patriotic Administration Center', 'Commando'],
['Railgun', 'Patriotic Administration Center', 'Railgun'],
['Spear', 'Patriotic Administration Center', 'Spear'],
// ── Engineering Bay ───────────────────────────────────────────────────────
['Quasar Cannon', 'Engineering Bay', 'Quasar Cannon'],
['Arc Thrower', 'Engineering Bay', 'Arc Thrower'],
['Laser Cannon', 'Engineering Bay', 'Laser Cannon'],
['Grenade Launcher', 'Engineering Bay', 'Grenade Launcher'],
['Supply Pack', 'Engineering Bay', 'Supply Pack'],
['Guard Dog Rover', 'Engineering Bay', 'Guard Dog Rover'],
['Ballistic Shield Backpack', 'Engineering Bay', 'Ballistic Shield Backpack'],
['Shield Generator Pack', 'Engineering Bay', 'Shield Generator Pack'],
['Anti-Personnel Minefield', 'Engineering Bay', 'Anti-Personnel Minefield'],
['Incendiary Mines', 'Engineering Bay', 'Incendiary Mines'],
['Anti-Tank Mines', 'Engineering Bay', 'Anti-Tank Mines'],
// ── Robotics Workshop ─────────────────────────────────────────────────────
['Machine Gun Sentry', 'Robotics Workshop', 'Machine Gun Sentry'],
['Gatling Sentry', 'Robotics Workshop', 'Gatling Sentry'],
['Mortar Sentry', 'Robotics Workshop', 'Mortar Sentry'],
['Guard Dog', 'Robotics Workshop', 'Guard Dog'],
['Autocannon Sentry', 'Robotics Workshop', 'Autocannon Sentry'],
['Rocket Sentry', 'Robotics Workshop', 'Rocket Sentry'],
['EMS Mortar Sentry', 'Robotics Workshop', 'EMS Mortar Sentry'],
['Patriot Exosuit', 'Robotics Workshop', 'Patriot Exosuit'],
['Emancipator Exosuit', 'Robotics Workshop', 'Emancipator Exosuit'],
// ── Urban Legends / Defensive ─────────────────────────────────────────────
['Directional Shield', 'Urban Legends', 'Directional Shield'],
['Anti-Tank Emplacement', 'Urban Legends', 'Anti-Tank Emplacement'],
];
function fetchURL(url) {
return new Promise((resolve, reject) => {
const req = https.get(url, (res) => {
if (res.statusCode === 301 || res.statusCode === 302) {
return fetchURL(res.headers.location).then(resolve).catch(reject);
}
if (res.statusCode !== 200) {
reject(new Error(`HTTP ${res.statusCode} for ${url}`));
res.resume();
return;
}
const chunks = [];
res.on('data', d => chunks.push(d));
res.on('end', () => resolve(Buffer.concat(chunks)));
});
req.on('error', reject);
req.setTimeout(10000, () => { req.destroy(); reject(new Error('Timeout: ' + url)); });
});
}
async function downloadAll() {
let ok = 0, fail = 0;
const failed = [];
for (const [name, folder, file] of ICON_MAP) {
// Local output: public/icons/<slug>.svg (flat directory, slug = name)
const slug = name.replace(/[^a-z0-9]/gi, '_').toLowerCase();
const outPath = path.join(ICONS_DIR, slug + '.svg');
// Build GitHub raw URL (spaces → %20)
const encoded = encodeURIComponent(folder) + '/' + encodeURIComponent(file + '.svg');
const url = `${BASE_URL}/${encoded}`;
try {
const buf = await fetchURL(url);
fs.writeFileSync(outPath, buf);
console.log(` ↓ ok ${name}`);
ok++;
} catch (err) {
console.log(` ✗ FAIL ${name} (${err.message})`);
fail++;
failed.push({ name, url });
}
// Be polite to GitHub CDN
await new Promise(r => setTimeout(r, 80));
}
console.log(`\nDone: ${ok} ok, ${fail} failed`);
if (failed.length) {
console.log('Failed:');
failed.forEach(f => console.log(` ${f.name}${f.url}`));
}
// Output slug map for server.js
const slugMap = {};
for (const [name] of ICON_MAP) {
const slug = name.replace(/[^a-z0-9]/gi, '_').toLowerCase();
if (fs.existsSync(path.join(ICONS_DIR, slug + '.svg'))) {
slugMap[name] = '/icons/' + slug + '.svg';
}
}
const mapPath = path.join(ICONS_DIR, '_map.json');
fs.writeFileSync(mapPath, JSON.stringify(slugMap, null, 2));
console.log(`\nIcon map written to ${mapPath}`);
}
downloadAll().catch(console.error);
+57
View File
@@ -0,0 +1,57 @@
#!/usr/bin/env node
const fs = require('fs');
const path = require('path');
const repoRoot = process.cwd();
const pkgPath = path.join(repoRoot, 'package.json');
const publicDir = path.join(repoRoot, 'public');
if (!fs.existsSync(pkgPath) || !fs.existsSync(publicDir)) process.exit(0);
const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf8'));
const version = pkg.version;
if (!version) {
console.error('package.json version missing');
process.exit(1);
}
function walkHtmlFiles(dir) {
const out = [];
for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
const full = path.join(dir, entry.name);
if (entry.isDirectory()) out.push(...walkHtmlFiles(full));
else if (entry.isFile() && entry.name.endsWith('.html')) out.push(full);
}
return out;
}
function isLocalAsset(rawUrl) {
return !/^(?:[a-z]+:|\/\/|#)/i.test(rawUrl);
}
function withVersion(rawUrl) {
const [baseWithQuery, hash = ''] = rawUrl.split('#');
const [pathname, query = ''] = baseWithQuery.split('?');
const params = new URLSearchParams(query);
params.set('v', version);
const qs = params.toString();
return pathname + (qs ? '?' + qs : '') + (hash ? '#' + hash : '');
}
const htmlFiles = walkHtmlFiles(publicDir);
let changed = 0;
for (const file of htmlFiles) {
let content = fs.readFileSync(file, 'utf8');
const next = content
.replace(/(<link\b[^>]*href=["'])([^"']+\.css(?:\?[^"']*)?)(["'][^>]*>)/gi, (m, p1, url, p3) => {
return isLocalAsset(url) ? p1 + withVersion(url) + p3 : m;
})
.replace(/(<script\b(?![^>]*type=["']application\/json["'])[^>]*\bsrc=["'])([^"']+\.js(?:\?[^"']*)?)(["'][^>]*>\s*<\/script>)/gi, (m, p1, url, p3) => {
return isLocalAsset(url) ? p1 + withVersion(url) + p3 : m;
});
if (next !== content) {
fs.writeFileSync(file, next);
changed += 1;
}
}
if (changed > 0) console.log('Synced versioned assets in ' + changed + ' HTML file(s).');
+73
View File
@@ -0,0 +1,73 @@
#!/usr/bin/env node
const fs = require('fs');
const path = require('path');
const cp = require('child_process');
const repoRoot = process.cwd();
const pkgPath = path.join(repoRoot, 'package.json');
const publicDir = path.join(repoRoot, 'public');
if (!fs.existsSync(pkgPath) || !fs.existsSync(publicDir)) process.exit(0);
const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf8'));
const version = pkg.version;
const failures = [];
function git(args) {
return cp.execFileSync('git', args, { cwd: repoRoot, encoding: 'utf8' }).trim();
}
function walkHtmlFiles(dir) {
const out = [];
for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
const full = path.join(dir, entry.name);
if (entry.isDirectory()) out.push(...walkHtmlFiles(full));
else if (entry.isFile() && entry.name.endsWith('.html')) out.push(full);
}
return out;
}
function isLocalAsset(rawUrl) {
return !/^(?:[a-z]+:|\/\/|#)/i.test(rawUrl);
}
for (const file of walkHtmlFiles(publicDir)) {
const rel = path.relative(repoRoot, file);
const content = fs.readFileSync(file, 'utf8');
for (const match of content.matchAll(/<link\b[^>]*href=["']([^"']+\.css(?:\?[^"']*)?)["']/gi)) {
const url = match[1];
if (isLocalAsset(url) && !new URLSearchParams((url.split('?')[1] || '')).get('v')?.includes(version)) {
failures.push(rel + ': stylesheet version does not match package.json');
}
}
for (const match of content.matchAll(/<script\b(?![^>]*type=["']application\/json["'])[^>]*\bsrc=["']([^"']+\.js(?:\?[^"']*)?)["']/gi)) {
const url = match[1];
if (isLocalAsset(url) && !new URLSearchParams((url.split('?')[1] || '')).get('v')?.includes(version)) {
failures.push(rel + ': script version does not match package.json');
}
}
}
const staged = git(['diff', '--cached', '--name-only', '--diff-filter=ACMR']).split(/\n+/).filter(Boolean);
const codeTouched = staged.some(file => /^(public\/.*\.(html|css|js)|server\.js|package\.json|package-lock\.json)$/.test(file));
const projectMapTouched = staged.includes('PROJECT_MAP.md');
const changelogTouched = staged.includes('CHANGELOG.md');
if (codeTouched && !changelogTouched) failures.push('CHANGELOG.md must be staged when app code, assets, or version files change.');
if (codeTouched && fs.existsSync(path.join(repoRoot, 'PROJECT_MAP.md')) && !projectMapTouched) {
failures.push('PROJECT_MAP.md must be staged when app code or frontend state/routes change.');
}
const stagedPackageDiff = staged.includes('package.json')
? git(['diff', '--cached', '--', 'package.json'])
: '';
if (stagedPackageDiff.includes('"version"') && fs.existsSync(path.join(repoRoot, 'CHANGELOG.md'))) {
const changelog = fs.readFileSync(path.join(repoRoot, 'CHANGELOG.md'), 'utf8');
if (!changelog.includes('## [' + version + ']') && !changelog.includes('## [Unreleased]')) {
failures.push('CHANGELOG.md must mention the current package.json version or contain an [Unreleased] section.');
}
}
if (failures.length) {
console.error('Release verification failed:');
for (const failure of failures) console.error('- ' + failure);
process.exit(1);
}
+353 -88
View File
@@ -18,81 +18,82 @@ const DATA_DIR = path.join(__dirname, 'data');
if (!fs.existsSync(DATA_DIR)) fs.mkdirSync(DATA_DIR, { recursive: true }); if (!fs.existsSync(DATA_DIR)) fs.mkdirSync(DATA_DIR, { recursive: true });
// ── Stratagems (mirrored in public/stratagems.js) ───────────────────────────── // ── Stratagems (mirrored in public/stratagems.js) ─────────────────────────────
const ICON = (slug) => '/icons/' + slug + '.svg';
const STRATAGEMS = [ const STRATAGEMS = [
// Patriotic Administration Center // ── Patriotic Administration Center ──────────────────────────────────────
{ name: 'Reinforce', category: 'Patriotic Administration Center', sequence: ['up','down','right','left','up'] }, { name: 'Reinforce', category: 'Patriotic Administration Center', icon: ICON('reinforce'), sequence: ['up','down','right','left','up'] },
{ name: 'Resupply', category: 'Patriotic Administration Center', sequence: ['down','down','up','right'] }, { name: 'Resupply', category: 'Patriotic Administration Center', icon: ICON('resupply'), sequence: ['down','down','up','right'] },
{ name: 'SOS Beacon', category: 'Patriotic Administration Center', sequence: ['up','down','right','up'] }, { name: 'SOS Beacon', category: 'Patriotic Administration Center', icon: ICON('sos_beacon'), sequence: ['up','down','right','up'] },
{ name: 'Hellbomb', category: 'Patriotic Administration Center', sequence: ['down','up','left','down','up','right','down','up'] }, { name: 'Hellbomb', category: 'Patriotic Administration Center', icon: ICON('hellbomb'), sequence: ['down','up','left','down','up','right','down','up'] },
{ name: 'SEAF Artillery', category: 'Patriotic Administration Center', sequence: ['right','up','up','down'] }, { name: 'SEAF Artillery', category: 'Patriotic Administration Center', icon: ICON('seaf_artillery'), sequence: ['right','up','up','down'] },
{ name: 'Upload Data', category: 'Patriotic Administration Center', sequence: ['right','right','left','up','up'] }, { name: 'Upload Data', category: 'Patriotic Administration Center', icon: ICON('upload_data'), sequence: ['right','right','left','up','up'] },
{ name: 'Eagle Rearm', category: 'Patriotic Administration Center', sequence: ['up','up','left','up','right'] }, { name: 'Eagle Rearm', category: 'Patriotic Administration Center', icon: ICON('eagle_rearm'), sequence: ['up','up','left','up','right'] },
{ name: 'Prospecting Drill', category: 'Patriotic Administration Center', sequence: ['down','down','left','right','down'] }, { name: 'Prospecting Drill', category: 'Patriotic Administration Center', icon: ICON('prospecting_drill'), sequence: ['down','down','left','right','down'] },
// Orbital Cannons // ── Orbital Cannons ───────────────────────────────────────────────────────
{ name: 'Orbital Gatling Barrage', category: 'Orbital Cannons', sequence: ['right','down','left','up','up'] }, { name: 'Orbital Gatling Barrage', category: 'Orbital Cannons', icon: ICON('orbital_gatling_barrage'), sequence: ['right','down','left','up','up'] },
{ name: 'Orbital Airburst Strike', category: 'Orbital Cannons', sequence: ['right','right','right'] }, { name: 'Orbital Airburst Strike', category: 'Orbital Cannons', icon: ICON('orbital_airburst_strike'), sequence: ['right','right','right'] },
{ name: 'Orbital 120MM HE Barrage', category: 'Orbital Cannons', sequence: ['right','right','down','left','right','down'] }, { name: 'Orbital 120MM HE Barrage', category: 'Orbital Cannons', icon: ICON('orbital_120mm_he_barrage'), sequence: ['right','right','down','left','right','down'] },
{ name: 'Orbital 380MM HE Barrage', category: 'Orbital Cannons', sequence: ['right','down','up','up','left','down','down'] }, { name: 'Orbital 380MM HE Barrage', category: 'Orbital Cannons', icon: ICON('orbital_380mm_he_barrage'), sequence: ['right','down','up','up','left','down','down'] },
{ name: 'Orbital Walking Barrage', category: 'Orbital Cannons', sequence: ['right','down','right','down','right','down'] }, { name: 'Orbital Walking Barrage', category: 'Orbital Cannons', icon: ICON('orbital_walking_barrage'), sequence: ['right','down','right','down','right','down'] },
{ name: 'Orbital Laser', category: 'Orbital Cannons', sequence: ['right','down','up','right','down'] }, { name: 'Orbital Laser', category: 'Orbital Cannons', icon: ICON('orbital_laser'), sequence: ['right','down','up','right','down'] },
{ name: 'Orbital Railcannon Strike', category: 'Orbital Cannons', sequence: ['right','up','down','down','right'] }, { name: 'Orbital Railcannon Strike', category: 'Orbital Cannons', icon: ICON('orbital_railcannon_strike'), sequence: ['right','up','down','down','right'] },
{ name: 'Orbital Precision Strike', category: 'Orbital Cannons', sequence: ['right','right','up'] }, { name: 'Orbital Precision Strike', category: 'Orbital Cannons', icon: ICON('orbital_precision_strike'), sequence: ['right','right','up'] },
{ name: 'Orbital Gas Strike', category: 'Orbital Cannons', sequence: ['right','right','down','right'] }, { name: 'Orbital Gas Strike', category: 'Orbital Cannons', icon: ICON('orbital_gas_strike'), sequence: ['right','right','down','right'] },
{ name: 'Orbital EMS Strike', category: 'Orbital Cannons', sequence: ['right','right','left','down'] }, { name: 'Orbital EMS Strike', category: 'Orbital Cannons', icon: ICON('orbital_ems_strike'), sequence: ['right','right','left','down'] },
{ name: 'Orbital Smoke Strike', category: 'Orbital Cannons', sequence: ['right','right','down','up'] }, { name: 'Orbital Smoke Strike', category: 'Orbital Cannons', icon: ICON('orbital_smoke_strike'), sequence: ['right','right','down','up'] },
{ name: 'Orbital Illumination Flare', category: 'Orbital Cannons', sequence: ['right','right','left','left'] }, { name: 'Orbital Illumination Flare', category: 'Orbital Cannons', icon: ICON('orbital_illumination_flare'), sequence: ['right','right','left','left'] },
// Hangar // ── Hangar ────────────────────────────────────────────────────────────────
{ name: 'Eagle Strafing Run', category: 'Hangar', sequence: ['up','right','right'] }, { name: 'Eagle Strafing Run', category: 'Hangar', icon: ICON('eagle_strafing_run'), sequence: ['up','right','right'] },
{ name: 'Eagle Airstrike', category: 'Hangar', sequence: ['up','right','down','right'] }, { name: 'Eagle Airstrike', category: 'Hangar', icon: ICON('eagle_airstrike'), sequence: ['up','right','down','right'] },
{ name: 'Eagle Cluster Bomb', category: 'Hangar', sequence: ['up','right','down','down','right'] }, { name: 'Eagle Cluster Bomb', category: 'Hangar', icon: ICON('eagle_cluster_bomb'), sequence: ['up','right','down','down','right'] },
{ name: 'Eagle Napalm Airstrike', category: 'Hangar', sequence: ['up','right','down','up'] }, { name: 'Eagle Napalm Airstrike', category: 'Hangar', icon: ICON('eagle_napalm_airstrike'), sequence: ['up','right','down','up'] },
{ name: 'LIFT-850 Jump Pack', category: 'Hangar', sequence: ['down','up','up','down','up'] }, { name: 'LIFT-850 Jump Pack', category: 'Hangar', icon: ICON('lift_850_jump_pack'), sequence: ['down','up','up','down','up'] },
{ name: 'Eagle Smoke Strike', category: 'Hangar', sequence: ['up','right','up','down'] }, { name: 'Eagle Smoke Strike', category: 'Hangar', icon: ICON('eagle_smoke_strike'), sequence: ['up','right','up','down'] },
{ name: 'Eagle 110MM Rocket Pods', category: 'Hangar', sequence: ['up','right','up','left'] }, { name: 'Eagle 110MM Rocket Pods', category: 'Hangar', icon: ICON('eagle_110mm_rocket_pods'), sequence: ['up','right','up','left'] },
{ name: 'Eagle 500KG Bomb', category: 'Hangar', sequence: ['up','right','down','down','down'] }, { name: 'Eagle 500KG Bomb', category: 'Hangar', icon: ICON('eagle_500kg_bomb'), sequence: ['up','right','down','down','down'] },
// Bridge // ── Bridge ────────────────────────────────────────────────────────────────
{ name: 'Patriot Exosuit', category: 'Bridge', sequence: ['left','down','right','up','left','down','right'] }, { name: 'Patriot Exosuit', category: 'Bridge', icon: ICON('patriot_exosuit'), sequence: ['left','down','right','up','left','down','right'] },
{ name: 'Emancipator Exosuit', category: 'Bridge', sequence: ['left','down','right','up','left','down','down'] }, { name: 'Emancipator Exosuit', category: 'Bridge', icon: ICON('emancipator_exosuit'), sequence: ['left','down','right','up','left','down','down'] },
// Engineering Bay Support Weapons { name: 'Tesla Tower', category: 'Bridge', icon: ICON('tesla_tower'), sequence: ['down','up','right','up','left','up','up'] },
{ name: 'Machine Gun', category: 'Engineering Bay', sequence: ['down','left','down','up','right'] }, { name: 'Shield Generator Relay', category: 'Bridge', icon: ICON('shield_generator_relay'), sequence: ['down','up','left','right','left','down'] },
{ name: 'Anti-Materiel Rifle', category: 'Engineering Bay', sequence: ['down','left','right','up','down'] }, // ── Engineering Bay Support Weapons ────────────────────────────────────
{ name: 'Stalwart', category: 'Engineering Bay', sequence: ['down','left','down','up','up','left'] }, { name: 'Machine Gun', category: 'Engineering Bay', icon: ICON('machine_gun'), sequence: ['down','left','down','up','right'] },
{ name: 'Expendable Anti-Tank', category: 'Engineering Bay', sequence: ['down','down','left','up'] }, { name: 'Anti-Materiel Rifle', category: 'Engineering Bay', icon: ICON('anti_materiel_rifle'), sequence: ['down','left','right','up','down'] },
{ name: 'Recoilless Rifle', category: 'Engineering Bay', sequence: ['down','left','right','right','left'] }, { name: 'Stalwart', category: 'Engineering Bay', icon: ICON('stalwart'), sequence: ['down','left','down','up','up','left'] },
{ name: 'Flamethrower', category: 'Engineering Bay', sequence: ['down','left','up','down','up'] }, { name: 'Expendable Anti-Tank', category: 'Engineering Bay', icon: ICON('expendable_anti_tank'), sequence: ['down','down','left','up'] },
{ name: 'Autocannon', category: 'Engineering Bay', sequence: ['down','left','down','up','up','right'] }, { name: 'Recoilless Rifle', category: 'Engineering Bay', icon: ICON('recoilless_rifle'), sequence: ['down','left','right','right','left'] },
{ name: 'Heavy Machine Gun', category: 'Engineering Bay', sequence: ['down','left','up','down','down'] }, { name: 'Flamethrower', category: 'Engineering Bay', icon: ICON('flamethrower'), sequence: ['down','left','up','down','up'] },
{ name: 'Airburst Rocket Launcher', category: 'Engineering Bay', sequence: ['down','up','up','left','right'] }, { name: 'Autocannon', category: 'Engineering Bay', icon: ICON('autocannon'), sequence: ['down','left','down','up','up','right'] },
{ name: 'Commando', category: 'Engineering Bay', sequence: ['down','left','up','down','right'] }, { name: 'Heavy Machine Gun', category: 'Engineering Bay', icon: ICON('heavy_machine_gun'), sequence: ['down','left','up','down','down'] },
{ name: 'Railgun', category: 'Engineering Bay', sequence: ['down','right','down','up','left','right'] }, { name: 'Airburst Rocket Launcher', category: 'Engineering Bay', icon: ICON('airburst_rocket_launcher'), sequence: ['down','up','up','left','right'] },
{ name: 'Spear', category: 'Engineering Bay', sequence: ['down','down','up','down','down'] }, { name: 'Commando', category: 'Engineering Bay', icon: ICON('commando'), sequence: ['down','left','up','down','right'] },
{ name: 'Quasar Cannon', category: 'Engineering Bay', sequence: ['down','down','up','left','right'] }, { name: 'Railgun', category: 'Engineering Bay', icon: ICON('railgun'), sequence: ['down','right','down','up','left','right'] },
{ name: 'Arc Thrower', category: 'Engineering Bay', sequence: ['down','right','down','up','left','left'] }, { name: 'Spear', category: 'Engineering Bay', icon: ICON('spear'), sequence: ['down','down','up','down','down'] },
{ name: 'Laser Cannon', category: 'Engineering Bay', sequence: ['down','left','down','up','left'] }, { name: 'Quasar Cannon', category: 'Engineering Bay', icon: ICON('quasar_cannon'), sequence: ['down','down','up','left','right'] },
{ name: 'Grenade Launcher', category: 'Engineering Bay', sequence: ['down','left','up','left','down'] }, { name: 'Arc Thrower', category: 'Engineering Bay', icon: ICON('arc_thrower'), sequence: ['down','right','down','up','left','left'] },
// Engineering Bay Equipment { name: 'Laser Cannon', category: 'Engineering Bay', icon: ICON('laser_cannon'), sequence: ['down','left','down','up','left'] },
{ name: 'Supply Pack', category: 'Engineering Bay', sequence: ['down','left','down','up','up','down'] }, { name: 'Grenade Launcher', category: 'Engineering Bay', icon: ICON('grenade_launcher'), sequence: ['down','left','up','left','down'] },
{ name: 'Guard Dog Rover', category: 'Engineering Bay', sequence: ['down','up','left','up','right','right'] }, // ── Engineering Bay Equipment ───────────────────────────────────────────
{ name: 'Guard Dog', category: 'Engineering Bay', sequence: ['down','up','left','up','right','down'] }, { name: 'Supply Pack', category: 'Engineering Bay', icon: ICON('supply_pack'), sequence: ['down','left','down','up','up','down'] },
{ name: 'Ballistic Shield Backpack', category: 'Engineering Bay', sequence: ['down','left','down','down','up','left'] }, { name: 'Guard Dog Rover', category: 'Engineering Bay', icon: ICON('guard_dog_rover'), sequence: ['down','up','left','up','right','right'] },
{ name: 'Shield Generator Pack', category: 'Engineering Bay', sequence: ['down','up','left','right','left','right'] }, { name: 'Guard Dog', category: 'Engineering Bay', icon: ICON('guard_dog'), sequence: ['down','up','left','up','right','down'] },
{ name: 'Directional Shield', category: 'Engineering Bay', sequence: ['down','left','up','up','right'] }, { name: 'Ballistic Shield Backpack', category: 'Engineering Bay', icon: ICON('ballistic_shield_backpack'), sequence: ['down','left','down','down','up','left'] },
// Engineering Bay Mines { name: 'Shield Generator Pack', category: 'Engineering Bay', icon: ICON('shield_generator_pack'), sequence: ['down','up','left','right','left','right'] },
{ name: 'Anti-Personnel Minefield', category: 'Engineering Bay', sequence: ['down','left','up','right'] }, { name: 'Directional Shield', category: 'Engineering Bay', icon: ICON('directional_shield'), sequence: ['down','left','up','up','right'] },
{ name: 'Incendiary Mines', category: 'Engineering Bay', sequence: ['down','left','left','down'] }, // ── Engineering Bay Mines ───────────────────────────────────────────────
{ name: 'Anti-Tank Mines', category: 'Engineering Bay', sequence: ['down','down','left','left'] }, { name: 'Anti-Personnel Minefield', category: 'Engineering Bay', icon: ICON('anti_personnel_minefield'), sequence: ['down','left','up','right'] },
// Robotics Workshop { name: 'Incendiary Mines', category: 'Engineering Bay', icon: ICON('incendiary_mines'), sequence: ['down','left','left','down'] },
{ name: 'Machine Gun Sentry', category: 'Robotics Workshop', sequence: ['down','up','right','right','up'] }, { name: 'Anti-Tank Mines', category: 'Engineering Bay', icon: ICON('anti_tank_mines'), sequence: ['down','down','left','left'] },
{ name: 'Gatling Sentry', category: 'Robotics Workshop', sequence: ['down','up','right','left'] }, // ── Robotics Workshop ─────────────────────────────────────────────────────
{ name: 'Mortar Sentry', category: 'Robotics Workshop', sequence: ['down','up','right','right','down'] }, { name: 'Machine Gun Sentry', category: 'Robotics Workshop', icon: ICON('machine_gun_sentry'), sequence: ['down','up','right','right','up'] },
{ name: 'Autocannon Sentry', category: 'Robotics Workshop', sequence: ['down','up','right','up','left','up'] }, { name: 'Gatling Sentry', category: 'Robotics Workshop', icon: ICON('gatling_sentry'), sequence: ['down','up','right','left'] },
{ name: 'Rocket Sentry', category: 'Robotics Workshop', sequence: ['down','up','right','right','left'] }, { name: 'Mortar Sentry', category: 'Robotics Workshop', icon: ICON('mortar_sentry'), sequence: ['down','up','right','right','down'] },
{ name: 'EMS Mortar Sentry', category: 'Robotics Workshop', sequence: ['down','up','right','down','right'] }, { name: 'Autocannon Sentry', category: 'Robotics Workshop', icon: ICON('autocannon_sentry'), sequence: ['down','up','right','up','left','up'] },
{ name: 'Tesla Tower', category: 'Robotics Workshop', sequence: ['down','up','right','up','left','up','up'] }, { name: 'Rocket Sentry', category: 'Robotics Workshop', icon: ICON('rocket_sentry'), sequence: ['down','up','right','right','left'] },
// Defensive { name: 'EMS Mortar Sentry', category: 'Robotics Workshop', icon: ICON('ems_mortar_sentry'), sequence: ['down','up','right','down','right'] },
{ name: 'Shield Generator Relay', category: 'Defensive', sequence: ['down','up','left','right','left','down'] }, // ── Defensive ─────────────────────────────────────────────────────────────
{ name: 'Anti-Tank Emplacement', category: 'Defensive', sequence: ['down','right','right','up','left'] }, { name: 'Anti-Tank Emplacement', category: 'Defensive', icon: ICON('anti_tank_emplacement'), sequence: ['down','right','right','up','left'] },
{ name: 'Orbital Shield Generator', category: 'Defensive', sequence: ['right','right','left','down','left','down'] }, { name: 'Orbital Shield Generator', category: 'Defensive', icon: null, sequence: ['right','right','left','down','left','down'] },
]; ];
const VALID_NAMES = new Set(STRATAGEMS.map(s => s.name)); const VALID_NAMES = new Set(STRATAGEMS.map(s => s.name));
@@ -127,10 +128,35 @@ function initDB() {
loser_rounds INTEGER NOT NULL, loser_rounds INTEGER NOT NULL,
created_at TEXT NOT NULL created_at TEXT NOT NULL
); );
CREATE TABLE IF NOT EXISTS stratagem_stats (
username TEXT NOT NULL,
stratagem TEXT NOT NULL,
attempts INTEGER DEFAULT 0,
completions INTEGER DEFAULT 0,
best_time INTEGER DEFAULT NULL,
PRIMARY KEY (username, stratagem)
);
CREATE INDEX IF NOT EXISTS idx_ps_user ON practice_sessions(username); CREATE INDEX IF NOT EXISTS idx_ps_user ON practice_sessions(username);
CREATE INDEX IF NOT EXISTS idx_m_winner ON matches(winner); CREATE INDEX IF NOT EXISTS idx_m_winner ON matches(winner);
CREATE INDEX IF NOT EXISTS idx_m_loser ON matches(loser); CREATE INDEX IF NOT EXISTS idx_m_loser ON matches(loser);
`); `);
// Schema migrations (user_version tracks applied version)
const version = db.pragma('user_version', { simple: true });
if (version < 1) {
// Add elo column to users if missing
const cols = db.pragma('table_info(users)').map(c => c.name);
if (!cols.includes('elo')) {
db.exec('ALTER TABLE users ADD COLUMN elo INTEGER DEFAULT 1000');
}
// Add mode column to practice_sessions if missing
const psCols = db.pragma('table_info(practice_sessions)').map(c => c.name);
if (!psCols.includes('mode')) {
db.exec("ALTER TABLE practice_sessions ADD COLUMN mode TEXT DEFAULT 'timed'");
}
db.pragma('user_version = 1');
}
} }
async function initUsers() { async function initUsers() {
@@ -143,13 +169,33 @@ async function initUsers() {
if (!exists) { if (!exists) {
const tempPw = crypto.randomBytes(6).toString('hex'); const tempPw = crypto.randomBytes(6).toString('hex');
const hash = await bcrypt.hash(tempPw, 12); const hash = await bcrypt.hash(tempPw, 12);
db.prepare('INSERT INTO users (username, hash, role, mustChange) VALUES (?, ?, ?, 1)') db.prepare('INSERT INTO users (username, hash, role, mustChange, elo) VALUES (?, ?, ?, 1, 1000)')
.run(username, hash, role); .run(username, hash, role);
console.log(`[INIT] Created user '${username}' temp password: ${tempPw}`); console.log(`[INIT] Created user '${username}' temp password: ${tempPw}`);
} }
} }
} }
// ── ELO calculation ───────────────────────────────────────────────────────────
function calcElo(winnerElo, loserElo, k = 32) {
const expected = 1 / (1 + 10 ** ((loserElo - winnerElo) / 400));
const delta = Math.round(k * (1 - expected));
return {
winner: Math.max(0, winnerElo + delta),
loser: Math.max(0, loserElo - delta),
delta,
};
}
// ── ELO rank label ─────────────────────────────────────────────────────────────
function eloRank(elo) {
if (elo >= 1700) return 'GENERAL';
if (elo >= 1500) return 'CAPTAIN';
if (elo >= 1300) return 'LIEUTENANT';
if (elo >= 1100) return 'SERGEANT';
return 'PRIVATE';
}
// ── Session secret ──────────────────────────────────────────────────────────── // ── Session secret ────────────────────────────────────────────────────────────
function getSessionSecret() { function getSessionSecret() {
const file = path.join(DATA_DIR, '.session-secret'); const file = path.join(DATA_DIR, '.session-secret');
@@ -265,7 +311,22 @@ app.post('/api/change-password', requireAuth, async (req, res) => {
// ── User management (admin) ─────────────────────────────────────────────────── // ── User management (admin) ───────────────────────────────────────────────────
app.get('/api/users', requireAuth, requireAdmin, (req, res) => { app.get('/api/users', requireAuth, requireAdmin, (req, res) => {
const users = db.prepare('SELECT username, role, mustChange FROM users ORDER BY username').all(); const users = db.prepare(`
SELECT
u.username,
u.role,
u.mustChange,
COALESCE(u.elo, 1000) AS elo,
COALESCE(ps.sessions, 0) AS sessions,
ps.lastPlayed AS lastPlayed
FROM users u
LEFT JOIN (
SELECT username, COUNT(*) AS sessions, MAX(created_at) AS lastPlayed
FROM practice_sessions
GROUP BY username
) ps ON ps.username = u.username
ORDER BY u.username
`).all();
res.json(users.map(u => ({ ...u, mustChange: u.mustChange === 1 }))); res.json(users.map(u => ({ ...u, mustChange: u.mustChange === 1 })));
}); });
@@ -301,6 +362,95 @@ app.delete('/api/users/:username', requireAuth, requireAdmin, (req, res) => {
res.json({ ok: true }); res.json({ ok: true });
}); });
app.post('/api/users/:username/reset-password', requireAuth, requireAdmin, async (req, res) => {
const { username } = req.params;
const user = db.prepare('SELECT username FROM users WHERE username = ?').get(username);
if (!user) return res.status(404).json({ error: 'User not found' });
const tempPw = crypto.randomBytes(6).toString('hex');
const hash = await bcrypt.hash(tempPw, 12);
db.prepare('UPDATE users SET hash = ?, mustChange = 1 WHERE username = ?').run(hash, username);
res.json({ ok: true, tempPassword: tempPw });
});
app.patch('/api/users/:username', requireAuth, requireAdmin, (req, res) => {
const { username } = req.params;
const { role } = req.body || {};
if (!['admin', 'user'].includes(role)) return res.status(400).json({ error: 'Valid role required' });
const user = db.prepare('SELECT username, role FROM users WHERE username = ?').get(username);
if (!user) return res.status(404).json({ error: 'User not found' });
if (username === req.session.user && role !== 'admin') {
return res.status(400).json({ error: 'You cannot demote yourself' });
}
if (user.role === 'admin' && role !== 'admin') {
const adminCount = db.prepare("SELECT COUNT(*) AS c FROM users WHERE role = 'admin'").get().c;
if (adminCount <= 1) return res.status(400).json({ error: 'Cannot demote the last admin' });
}
db.prepare('UPDATE users SET role = ? WHERE username = ?').run(role, username);
res.json({ ok: true });
});
app.get('/api/admin/overview', requireAuth, requireAdmin, (req, res) => {
const totals = db.prepare(`
SELECT
COUNT(*) AS users,
SUM(CASE WHEN role = 'admin' THEN 1 ELSE 0 END) AS admins,
SUM(CASE WHEN mustChange = 1 THEN 1 ELSE 0 END) AS tempPasswords
FROM users
`).get();
const activity = db.prepare(`
SELECT
(SELECT COUNT(*) FROM practice_sessions) AS practiceSessions,
(SELECT COUNT(*) FROM matches) AS matches,
(SELECT COALESCE(SUM(score), 0) FROM practice_sessions) AS totalPracticeScore
`).get();
const topUser = db.prepare(`
SELECT username, COUNT(*) AS sessions, COALESCE(SUM(score), 0) AS totalScore
FROM practice_sessions
GROUP BY username
ORDER BY totalScore DESC, sessions DESC
LIMIT 1
`).get();
const latestActivity = db.prepare(`
SELECT username, stratagem, score, created_at
FROM practice_sessions
ORDER BY created_at DESC
LIMIT 1
`).get();
res.json({
totals,
activity,
topUser: topUser || null,
latestActivity: latestActivity || null,
});
});
app.get('/api/admin/activity', requireAuth, requireAdmin, (req, res) => {
const practice = db.prepare(`
SELECT username, stratagem, score, mode, created_at
FROM practice_sessions
ORDER BY created_at DESC
LIMIT 10
`).all();
const matches = db.prepare(`
SELECT winner, loser, winner_rounds, loser_rounds, created_at
FROM matches
ORDER BY created_at DESC
LIMIT 10
`).all();
res.json({ practice, matches });
});
// ── Leaderboard cache ───────────────────────────────────────────────────────── // ── Leaderboard cache ─────────────────────────────────────────────────────────
let lbCache = null; let lbCache = null;
let lbCacheTime = 0; let lbCacheTime = 0;
@@ -313,6 +463,7 @@ function getLeaderboard() {
lbCache = db.prepare(` lbCache = db.prepare(`
SELECT SELECT
u.username, u.username,
COALESCE(u.elo, 1000) AS elo,
COALESCE(ps.sessions, 0) AS sessions, COALESCE(ps.sessions, 0) AS sessions,
COALESCE(ps.totalScore, 0) AS totalScore, COALESCE(ps.totalScore, 0) AS totalScore,
COALESCE(ps.fastestTime, 0) AS fastestTime, COALESCE(ps.fastestTime, 0) AS fastestTime,
@@ -356,7 +507,7 @@ app.get('/api/dashboard', requireAuth, (req, res) => {
const rank = rankIdx >= 0 ? { position: rankIdx + 1 } : null; const rank = rankIdx >= 0 ? { position: rankIdx + 1 } : null;
const recent = db.prepare(` const recent = db.prepare(`
SELECT stratagem, category, score, time_ms, created_at SELECT stratagem, category, score, time_ms, mode, created_at
FROM practice_sessions WHERE username = ? FROM practice_sessions WHERE username = ?
ORDER BY created_at DESC LIMIT 5 ORDER BY created_at DESC LIMIT 5
`).all(u); `).all(u);
@@ -368,10 +519,26 @@ app.get('/api/dashboard', requireAuth, (req, res) => {
WHERE stratagem = ? AND username = ? WHERE stratagem = ? AND username = ?
`).get(dailyStrat.name, u); `).get(dailyStrat.name, u);
const userRow = db.prepare('SELECT elo FROM users WHERE username = ?').get(u);
const elo = userRow?.elo ?? 1000;
const onlineNames = [...userSockets.keys()];
const eloRows = onlineNames.length > 0
? db.prepare(`SELECT username, elo FROM users WHERE username IN (${onlineNames.map(() => '?').join(',')})`)
.all(...onlineNames)
: [];
const eloByUser = Object.fromEntries(eloRows.map(r => [r.username, r.elo]));
const onlineWithElo = onlineNames.map(name => {
const elo = eloByUser[name] ?? 1000;
return { name, elo, rank: eloRank(elo) };
});
res.json({ res.json({
stats: { ...stats, ...matchStats }, stats: { ...stats, ...matchStats },
rank, rank,
online: [...userSockets.keys()], elo,
eloRank: eloRank(elo),
online: onlineWithElo,
recent, recent,
daily: { stratagem: dailyStrat, bestTime: dailyBest?.bestTime ?? null }, daily: { stratagem: dailyStrat, bestTime: dailyBest?.bestTime ?? null },
}); });
@@ -379,15 +546,27 @@ app.get('/api/dashboard', requireAuth, (req, res) => {
// ── Scores ──────────────────────────────────────────────────────────────────── // ── Scores ────────────────────────────────────────────────────────────────────
app.post('/api/scores/practice', requireAuth, (req, res) => { app.post('/api/scores/practice', requireAuth, (req, res) => {
const { stratagem, category, time_ms, score } = req.body || {}; const { stratagem, category, time_ms, score, mode } = req.body || {};
if (!VALID_NAMES.has(stratagem)) return res.status(400).json({ error: 'Invalid stratagem' }); if (!VALID_NAMES.has(stratagem)) return res.status(400).json({ error: 'Invalid stratagem' });
if (typeof time_ms !== 'number' || time_ms <= 0 || time_ms > 31_000) return res.status(400).json({ error: 'Invalid time' }); if (typeof time_ms !== 'number' || time_ms <= 0 || time_ms > 600_000) return res.status(400).json({ error: 'Invalid time' });
if (typeof score !== 'number' || score < 0 || score > 15_000) return res.status(400).json({ error: 'Invalid score' }); if (typeof score !== 'number' || score < 0 || score > 50_000) return res.status(400).json({ error: 'Invalid score' });
const safeMode = ['timed','endless','drill','speedrun'].includes(mode) ? mode : 'timed';
db.prepare(` db.prepare(`
INSERT INTO practice_sessions (username, stratagem, category, time_ms, score, created_at) INSERT INTO practice_sessions (username, stratagem, category, time_ms, score, mode, created_at)
VALUES (?, ?, ?, ?, ?, ?) VALUES (?, ?, ?, ?, ?, ?, ?)
`).run(req.session.user, stratagem, category || '', time_ms, score, new Date().toISOString()); `).run(req.session.user, stratagem, category || '', time_ms, score, safeMode, new Date().toISOString());
// Update stratagem_stats (upsert)
db.prepare(`
INSERT INTO stratagem_stats (username, stratagem, attempts, completions, best_time)
VALUES (?, ?, 1, 1, ?)
ON CONFLICT(username, stratagem) DO UPDATE SET
attempts = attempts + 1,
completions = completions + 1,
best_time = CASE WHEN best_time IS NULL OR ? < best_time THEN ? ELSE best_time END
`).run(req.session.user, stratagem, time_ms, time_ms, time_ms);
invalidateLB(); invalidateLB();
res.json({ ok: true }); res.json({ ok: true });
@@ -397,10 +576,27 @@ app.get('/api/scores/leaderboard', requireAuth, (req, res) => {
res.json(getLeaderboard()); res.json(getLeaderboard());
}); });
app.get('/api/scores/leaderboard/elo', requireAuth, (req, res) => {
const rows = db.prepare(`
SELECT username, elo, role FROM users ORDER BY elo DESC LIMIT 20
`).all();
res.json(rows.map(r => ({ ...r, rank: eloRank(r.elo) })));
});
app.get('/api/scores/leaderboard/speedrun', requireAuth, (req, res) => {
// Speedrun: sum of all time_ms per user where mode = 'speedrun', order by total time ASC
const rows = db.prepare(`
SELECT username, SUM(time_ms) AS totalTime, COUNT(*) AS stratagems
FROM practice_sessions WHERE mode = 'speedrun'
GROUP BY username ORDER BY totalTime ASC LIMIT 20
`).all();
res.json(rows);
});
app.get('/api/scores/me', requireAuth, (req, res) => { app.get('/api/scores/me', requireAuth, (req, res) => {
const u = req.session.user; const u = req.session.user;
const practice = db.prepare(` const practice = db.prepare(`
SELECT stratagem, category, score, time_ms, created_at SELECT stratagem, category, score, time_ms, mode, created_at
FROM practice_sessions WHERE username = ? FROM practice_sessions WHERE username = ?
ORDER BY created_at DESC LIMIT 50 ORDER BY created_at DESC LIMIT 50
`).all(u); `).all(u);
@@ -411,6 +607,41 @@ app.get('/api/scores/me', requireAuth, (req, res) => {
res.json({ practice, matches }); res.json({ practice, matches });
}); });
// ── History (paginated) ────────────────────────────────────────────────────────
app.get('/api/history', requireAuth, (req, res) => {
const u = req.session.user;
const page = Math.max(1, parseInt(req.query.page) || 1);
const limit = Math.min(50, Math.max(1, parseInt(req.query.limit) || 10));
const mode = req.query.mode || '';
const cat = req.query.cat || '';
const offset = (page - 1) * limit;
let where = 'WHERE username = ?';
const params = [u];
if (mode) { where += ' AND mode = ?'; params.push(mode); }
if (cat) { where += ' AND category = ?'; params.push(cat); }
const total = db.prepare(`SELECT COUNT(*) AS n FROM practice_sessions ${where}`).get(...params).n;
const rows = db.prepare(`
SELECT stratagem, category, score, time_ms, mode, created_at
FROM practice_sessions ${where}
ORDER BY created_at DESC LIMIT ? OFFSET ?
`).all(...params, limit, offset);
res.json({ rows, total, page, pages: Math.ceil(total / limit) });
});
// ── Stratagem stats ────────────────────────────────────────────────────────────
app.get('/api/stats/stratagems', requireAuth, (req, res) => {
const u = req.session.user;
const rows = db.prepare(`
SELECT stratagem, attempts, completions, best_time
FROM stratagem_stats WHERE username = ?
ORDER BY best_time ASC NULLS LAST
`).all(u);
res.json(rows);
});
// ── Stratagems API (authenticated) ──────────────────────────────────────────── // ── Stratagems API (authenticated) ────────────────────────────────────────────
// Stratagem sequences are served via API not as a public static file. // Stratagem sequences are served via API not as a public static file.
app.get('/api/stratagems', requireAuth, (req, res) => { app.get('/api/stratagems', requireAuth, (req, res) => {
@@ -441,7 +672,18 @@ async function main() {
} }
function broadcastLobbyUpdate() { function broadcastLobbyUpdate() {
const online = [...userSockets.keys()]; const onlineNames = [...userSockets.keys()];
const eloMap = onlineNames.length > 0
? Object.fromEntries(
db.prepare(`SELECT username, elo FROM users WHERE username IN (${onlineNames.map(() => '?').join(',')})`)
.all(...onlineNames)
.map(r => [r.username, r.elo])
)
: {};
const online = onlineNames.map(name => {
const elo = eloMap[name] ?? 1000;
return { name, elo, rank: eloRank(elo) };
});
wss.clients.forEach(ws => { wss.clients.forEach(ws => {
if (ws.readyState !== WebSocket.OPEN || !ws.userId) return; if (ws.readyState !== WebSocket.OPEN || !ws.userId) return;
const incoming = [...pendingChallenges.entries()] const incoming = [...pendingChallenges.entries()]
@@ -470,15 +712,37 @@ async function main() {
room.matchScores[winnerId]++; room.matchScores[winnerId]++;
const matchScores = { ...room.matchScores }; const matchScores = { ...room.matchScores };
// Track round history for post-match screen
if (!room.roundHistory) room.roundHistory = [];
room.roundHistory.push({ round: room.roundHistory.length + 1, winner: winnerId });
broadcastToRoom(room, 'round-complete', { winner: winnerId, matchScores }); broadcastToRoom(room, 'round-complete', { winner: winnerId, matchScores });
if (room.matchScores[winnerId] >= 5) { if (room.matchScores[winnerId] >= 5) {
broadcastToRoom(room, 'match-end', { winner: winnerId, matchScores }); // Calculate ELO delta
const wRow = db.prepare('SELECT elo FROM users WHERE username = ?').get(winnerId);
const lRow = db.prepare('SELECT elo FROM users WHERE username = ?').get(loser.userId);
const eloResult = calcElo(wRow?.elo ?? 1000, lRow?.elo ?? 1000);
db.prepare('UPDATE users SET elo = ? WHERE username = ?').run(eloResult.winner, winnerId);
db.prepare('UPDATE users SET elo = ? WHERE username = ?').run(eloResult.loser, loser.userId);
db.prepare(` db.prepare(`
INSERT INTO matches (winner, loser, winner_rounds, loser_rounds, created_at) INSERT INTO matches (winner, loser, winner_rounds, loser_rounds, created_at)
VALUES (?, ?, ?, ?, ?) VALUES (?, ?, ?, ?, ?)
`).run(winnerId, loser.userId, room.matchScores[winnerId], room.matchScores[loser.userId], new Date().toISOString()); `).run(winnerId, loser.userId, room.matchScores[winnerId], room.matchScores[loser.userId], new Date().toISOString());
invalidateLB(); invalidateLB();
broadcastToRoom(room, 'match-end', {
winner: winnerId,
matchScores,
roundHistory: room.roundHistory,
eloChanges: {
[winnerId]: { old: wRow?.elo ?? 1000, new: eloResult.winner, delta: +eloResult.delta },
[loser.userId]: { old: lRow?.elo ?? 1000, new: eloResult.loser, delta: -eloResult.delta },
},
});
rooms.delete(room.roomId); rooms.delete(room.roomId);
} else { } else {
room.state = 'waiting'; room.state = 'waiting';
@@ -501,7 +765,8 @@ async function main() {
const { targetUser } = payload; const { targetUser } = payload;
if (!userSockets.has(targetUser) || targetUser === userId) return; if (!userSockets.has(targetUser) || targetUser === userId) return;
pendingChallenges.set(userId, targetUser); pendingChallenges.set(userId, targetUser);
send(userSockets.get(targetUser), 'challenge-received', { from: userId }); const challengerElo = db.prepare('SELECT elo FROM users WHERE username = ?').get(userId)?.elo ?? 1000;
send(userSockets.get(targetUser), 'challenge-received', { from: userId, elo: challengerElo });
broadcastLobbyUpdate(); broadcastLobbyUpdate();
break; break;
} }