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
+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",
"scripts": {
"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": {
"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.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 rel="stylesheet" href="styles.css">
<link rel="stylesheet" href="styles.css?v=1.0.0">
</head>
<body>
<!-- ── Navigation ─────────────────────────────────────────────── -->
<nav id="main-nav" class="hidden">
<button id="nav-hamburger" aria-label="Open menu" aria-expanded="false">&#9776;</button>
<div class="nav-brand">
<span class="nav-logo"></span>
<span>HELLDIVERS 2</span>
@@ -20,6 +21,7 @@
<div class="nav-links">
<button class="nav-btn" data-view="dashboard">Dashboard</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="leaderboard">Highscores</button>
<button class="nav-btn nav-btn-admin hidden" id="nav-admin" data-view="admin">Admin</button>
@@ -30,14 +32,54 @@
</div>
</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) -->
<div id="challenge-badge" class="challenge-badge hidden"></div>
<!-- Score popup (practice) -->
<div id="score-popup" class="score-popup hidden"></div>
<!-- ── LOGIN ─────────────────────────────────────────────────── -->
<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-header">
<div class="login-logo"></div>
<span class="login-logo"></span>
<h1>HELLDIVERS 2</h1>
<p class="login-sub">STRATAGEM TRAINER — SUPER EARTH AUTHORIZED</p>
</div>
@@ -55,12 +97,13 @@
</form>
</div>
</div>
</div>
<!-- ── CHANGE PASSWORD ───────────────────────────────────────── -->
<div id="view-change-password" class="view view-centered hidden">
<div class="login-box">
<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>
</div>
<form id="change-password-form" class="login-form">
@@ -84,126 +127,286 @@
<!-- ── DASHBOARD ─────────────────────────────────────────────── -->
<div id="view-dashboard" class="view hidden">
<div class="page-header">
<h2 class="page-title">COMMAND CENTER</h2>
<p class="page-sub">Welcome back, Helldiver. For Super Earth.</p>
<div class="dashboard-grid">
<div class="card dashboard-briefing">
<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 class="dashboard-grid">
<!-- Stats card -->
<div class="card">
<h3 class="card-title">YOUR STATS</h3>
<div class="stat-grid">
<div class="stat-item">
<div class="stat-value" id="dash-total-score"></div>
<div class="stat-label">Total Score</div>
<!-- Hero card -->
<div class="card card-hero dashboard-hero">
<div class="hero-identity">
<div class="hero-rank-icon" id="dash-rank-icon"></div>
<div>
<div class="hero-name" id="dash-hero-name"></div>
<div class="hero-rank-name" id="dash-rank-label">PRIVATE</div>
</div>
<div class="stat-item">
<div class="stat-value accent" id="dash-rank"></div>
<div class="stat-label">Global Rank</div>
</div>
<div class="stat-item">
<div class="stat-value" id="dash-sessions"></div>
<div class="stat-label">Sessions</div>
<div class="hero-elo">ELO <span id="dash-elo">1000</span></div>
<div class="hero-stats">
<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 class="stat-item">
<div class="stat-value" id="dash-win-rate"></div>
<div class="stat-label">Match Win Rate</div>
<div class="hero-stat-item">
<div class="hero-stat-val" id="dash-rank"></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>
<!-- Daily challenge card -->
<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-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-category" id="dash-daily-category"></div>
<div class="daily-best">
Best time: <span id="dash-daily-best"></span>
</div>
<button class="btn btn-accent" id="btn-daily-challenge">Practice this stratagem</button>
<div class="daily-sequence-preview" id="dash-daily-sequence"></div>
<div class="daily-best">Personal best: <span id="dash-daily-best"></span></div>
<button class="btn btn-accent btn-sm" id="btn-daily-challenge">⚡ Practice Now</button>
</div>
</div>
<!-- Online users card -->
<!-- Online players -->
<div class="card">
<h3 class="card-title">ONLINE HELLDIVERS</h3>
<h3 class="card-title">Online Helldivers</h3>
<div id="dash-online" class="online-list">
<span class="muted">Loading...</span>
</div>
</div>
<!-- Recent sessions card -->
<!-- Recent sessions -->
<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">
<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>
<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>
</table>
</div>
</div>
</div>
</div>
<!-- ── PRACTICE ───────────────────────────────────────────────── -->
<div id="view-practice" class="view hidden">
<div class="page-header">
<div class="practice-header">
<div>
<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>
<!-- Category filters -->
<div class="category-row" id="practice-categories"></div>
<!-- Idle (start screen) -->
<div id="practice-idle" class="practice-idle">
<div class="idle-hint">Select categories above, then start training</div>
<!-- Idle -->
<div id="practice-idle" class="practice-setup">
<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>
</div>
</div>
<!-- Active training -->
<div id="practice-active" class="practice-active hidden">
<div class="stratagem-display card">
<div class="stratagem-category" id="practice-category"></div>
<div class="stratagem-name" id="practice-name"></div>
<div class="arrow-sequence" id="practice-sequence"></div>
<div class="practice-hint">Use Arrow Keys or D-Pad</div>
<!-- Drill progress bar -->
<div id="drill-progress-wrap" class="drill-progress hidden">
<div class="drill-label">
<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 class="practice-hud">
<div class="hud-item">
<div class="hud-label">TIME</div>
<div class="timer" id="practice-timer">30</div>
<div class="practice-focus-shell">
<div class="practice-focus-meta">
<span class="focus-chip">Live Drill</span>
<span class="focus-chip focus-chip-muted">Stay on target</span>
</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-label">SCORE</div>
<div class="hud-value" id="practice-score">0</div>
</div>
<div class="hud-item">
<div class="hud-item" id="hud-streak-item">
<div class="hud-label">STREAK</div>
<div class="hud-value accent" id="practice-streak">0</div>
<div class="combo-badge hidden" id="practice-combo">×1.0</div>
</div>
</div>
<!-- D-Pad (mobile) -->
<!-- D-Pad -->
<div class="dpad" id="practice-dpad">
<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 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>
<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 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>
<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>
@@ -216,12 +419,20 @@
<div class="lobby-layout">
<div class="card">
<h3 class="card-title">ONLINE HELLDIVERS</h3>
<h3 class="card-title">Online Helldivers</h3>
<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 id="lobby-challenges" class="challenge-list"></div>
</div>
</div>
@@ -246,28 +457,42 @@
<!-- Round area -->
<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-seq-col">
<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 class="match-seq-col">
<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>
<!-- D-Pad (mobile) -->
<div class="dpad" id="match-dpad">
<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 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>
<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 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>
@@ -285,34 +510,57 @@
<p class="page-sub">Top Helldivers ranked by total practice score</p>
</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">
<table class="data-table leaderboard-table">
<thead>
<tr>
<th>#</th>
<th>Helldiver</th>
<th>Total Score</th>
<th>Sessions</th>
<th>Match W/Total</th>
</tr>
<div class="table-wrap">
<table class="data-table">
<thead id="leaderboard-thead">
<tr><th>#</th><th>Helldiver</th><th>Rank</th><th>Total Score</th><th>Sessions</th><th>Match W/Total</th></tr>
</thead>
<tbody id="leaderboard-table-body">
<tr><td colspan="5" class="muted">Loading...</td></tr>
<tr><td colspan="6" class="muted">Loading...</td></tr>
</tbody>
</table>
</div>
</div>
</div>
<!-- ── ADMIN ──────────────────────────────────────────────────── -->
<div id="view-admin" class="view hidden">
<div class="page-header">
<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 class="admin-layout">
<!-- Create user -->
<div class="card">
<h3 class="card-title">CREATE HELLDIVER</h3>
<h3 class="card-title">Create Helldiver</h3>
<div class="field">
<label for="new-username">Username</label>
<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>
<button class="btn btn-accent" id="btn-create-user">Create User</button>
<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>
<!-- User list -->
<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>
</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 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 -->
<div id="toast-container"></div>
<script src="app.js"></script>
<script src="app.js?v=1.0.0"></script>
</body>
</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 });
// ── Stratagems (mirrored in public/stratagems.js) ─────────────────────────────
const ICON = (slug) => '/icons/' + slug + '.svg';
const STRATAGEMS = [
// Patriotic Administration Center
{ name: 'Reinforce', category: 'Patriotic Administration Center', sequence: ['up','down','right','left','up'] },
{ name: 'Resupply', category: 'Patriotic Administration Center', sequence: ['down','down','up','right'] },
{ name: 'SOS Beacon', category: 'Patriotic Administration Center', sequence: ['up','down','right','up'] },
{ name: 'Hellbomb', category: 'Patriotic Administration Center', sequence: ['down','up','left','down','up','right','down','up'] },
{ name: 'SEAF Artillery', category: 'Patriotic Administration Center', sequence: ['right','up','up','down'] },
{ name: 'Upload Data', category: 'Patriotic Administration Center', sequence: ['right','right','left','up','up'] },
{ name: 'Eagle Rearm', category: 'Patriotic Administration Center', sequence: ['up','up','left','up','right'] },
{ name: 'Prospecting Drill', category: 'Patriotic Administration Center', sequence: ['down','down','left','right','down'] },
// Orbital Cannons
{ name: 'Orbital Gatling Barrage', category: 'Orbital Cannons', sequence: ['right','down','left','up','up'] },
{ name: 'Orbital Airburst Strike', category: 'Orbital Cannons', sequence: ['right','right','right'] },
{ name: 'Orbital 120MM HE Barrage', category: 'Orbital Cannons', 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 Walking Barrage', category: 'Orbital Cannons', sequence: ['right','down','right','down','right','down'] },
{ name: 'Orbital Laser', category: 'Orbital Cannons', sequence: ['right','down','up','right','down'] },
{ name: 'Orbital Railcannon Strike', category: 'Orbital Cannons', sequence: ['right','up','down','down','right'] },
{ name: 'Orbital Precision Strike', category: 'Orbital Cannons', sequence: ['right','right','up'] },
{ name: 'Orbital Gas Strike', category: 'Orbital Cannons', sequence: ['right','right','down','right'] },
{ name: 'Orbital EMS Strike', category: 'Orbital Cannons', sequence: ['right','right','left','down'] },
{ name: 'Orbital Smoke Strike', category: 'Orbital Cannons', sequence: ['right','right','down','up'] },
{ name: 'Orbital Illumination Flare', category: 'Orbital Cannons', sequence: ['right','right','left','left'] },
// Hangar
{ name: 'Eagle Strafing Run', category: 'Hangar', sequence: ['up','right','right'] },
{ name: 'Eagle Airstrike', category: 'Hangar', sequence: ['up','right','down','right'] },
{ name: 'Eagle Cluster Bomb', category: 'Hangar', sequence: ['up','right','down','down','right'] },
{ name: 'Eagle Napalm Airstrike', category: 'Hangar', sequence: ['up','right','down','up'] },
{ name: 'LIFT-850 Jump Pack', category: 'Hangar', sequence: ['down','up','up','down','up'] },
{ name: 'Eagle Smoke Strike', category: 'Hangar', sequence: ['up','right','up','down'] },
{ name: 'Eagle 110MM Rocket Pods', category: 'Hangar', sequence: ['up','right','up','left'] },
{ name: 'Eagle 500KG Bomb', category: 'Hangar', sequence: ['up','right','down','down','down'] },
// Bridge
{ name: 'Patriot Exosuit', category: 'Bridge', sequence: ['left','down','right','up','left','down','right'] },
{ name: 'Emancipator Exosuit', category: 'Bridge', sequence: ['left','down','right','up','left','down','down'] },
// Engineering Bay Support Weapons
{ name: 'Machine Gun', category: 'Engineering Bay', sequence: ['down','left','down','up','right'] },
{ name: 'Anti-Materiel Rifle', category: 'Engineering Bay', sequence: ['down','left','right','up','down'] },
{ name: 'Stalwart', category: 'Engineering Bay', sequence: ['down','left','down','up','up','left'] },
{ name: 'Expendable Anti-Tank', category: 'Engineering Bay', sequence: ['down','down','left','up'] },
{ name: 'Recoilless Rifle', category: 'Engineering Bay', sequence: ['down','left','right','right','left'] },
{ name: 'Flamethrower', category: 'Engineering Bay', sequence: ['down','left','up','down','up'] },
{ name: 'Autocannon', category: 'Engineering Bay', sequence: ['down','left','down','up','up','right'] },
{ name: 'Heavy Machine Gun', category: 'Engineering Bay', sequence: ['down','left','up','down','down'] },
{ name: 'Airburst Rocket Launcher', category: 'Engineering Bay', sequence: ['down','up','up','left','right'] },
{ name: 'Commando', category: 'Engineering Bay', sequence: ['down','left','up','down','right'] },
{ name: 'Railgun', category: 'Engineering Bay', sequence: ['down','right','down','up','left','right'] },
{ name: 'Spear', category: 'Engineering Bay', sequence: ['down','down','up','down','down'] },
{ name: 'Quasar Cannon', category: 'Engineering Bay', sequence: ['down','down','up','left','right'] },
{ name: 'Arc Thrower', category: 'Engineering Bay', sequence: ['down','right','down','up','left','left'] },
{ name: 'Laser Cannon', category: 'Engineering Bay', sequence: ['down','left','down','up','left'] },
{ name: 'Grenade Launcher', category: 'Engineering Bay', sequence: ['down','left','up','left','down'] },
// Engineering Bay Equipment
{ name: 'Supply Pack', category: 'Engineering Bay', sequence: ['down','left','down','up','up','down'] },
{ name: 'Guard Dog Rover', category: 'Engineering Bay', sequence: ['down','up','left','up','right','right'] },
{ name: 'Guard Dog', category: 'Engineering Bay', sequence: ['down','up','left','up','right','down'] },
{ name: 'Ballistic Shield Backpack', category: 'Engineering Bay', sequence: ['down','left','down','down','up','left'] },
{ name: 'Shield Generator Pack', category: 'Engineering Bay', sequence: ['down','up','left','right','left','right'] },
{ name: 'Directional Shield', category: 'Engineering Bay', sequence: ['down','left','up','up','right'] },
// Engineering Bay Mines
{ name: 'Anti-Personnel Minefield', category: 'Engineering Bay', sequence: ['down','left','up','right'] },
{ name: 'Incendiary Mines', category: 'Engineering Bay', sequence: ['down','left','left','down'] },
{ name: 'Anti-Tank Mines', category: 'Engineering Bay', sequence: ['down','down','left','left'] },
// Robotics Workshop
{ name: 'Machine Gun Sentry', category: 'Robotics Workshop', sequence: ['down','up','right','right','up'] },
{ name: 'Gatling Sentry', category: 'Robotics Workshop', sequence: ['down','up','right','left'] },
{ name: 'Mortar Sentry', category: 'Robotics Workshop', sequence: ['down','up','right','right','down'] },
{ name: 'Autocannon Sentry', category: 'Robotics Workshop', sequence: ['down','up','right','up','left','up'] },
{ name: 'Rocket Sentry', category: 'Robotics Workshop', sequence: ['down','up','right','right','left'] },
{ name: 'EMS Mortar Sentry', category: 'Robotics Workshop', sequence: ['down','up','right','down','right'] },
{ name: 'Tesla Tower', category: 'Robotics Workshop', sequence: ['down','up','right','up','left','up','up'] },
// Defensive
{ name: 'Shield Generator Relay', category: 'Defensive', sequence: ['down','up','left','right','left','down'] },
{ name: 'Anti-Tank Emplacement', category: 'Defensive', sequence: ['down','right','right','up','left'] },
{ name: 'Orbital Shield Generator', category: 'Defensive', sequence: ['right','right','left','down','left','down'] },
// ── Patriotic Administration Center ──────────────────────────────────────
{ name: 'Reinforce', category: 'Patriotic Administration Center', icon: ICON('reinforce'), sequence: ['up','down','right','left','up'] },
{ name: 'Resupply', category: 'Patriotic Administration Center', icon: ICON('resupply'), sequence: ['down','down','up','right'] },
{ name: 'SOS Beacon', category: 'Patriotic Administration Center', icon: ICON('sos_beacon'), sequence: ['up','down','right','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', icon: ICON('seaf_artillery'), sequence: ['right','up','up','down'] },
{ name: 'Upload Data', category: 'Patriotic Administration Center', icon: ICON('upload_data'), sequence: ['right','right','left','up','up'] },
{ name: 'Eagle Rearm', category: 'Patriotic Administration Center', icon: ICON('eagle_rearm'), sequence: ['up','up','left','up','right'] },
{ name: 'Prospecting Drill', category: 'Patriotic Administration Center', icon: ICON('prospecting_drill'), sequence: ['down','down','left','right','down'] },
// ── Orbital Cannons ───────────────────────────────────────────────────────
{ 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', icon: ICON('orbital_airburst_strike'), sequence: ['right','right','right'] },
{ 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', icon: ICON('orbital_380mm_he_barrage'), sequence: ['right','down','up','up','left','down','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', icon: ICON('orbital_laser'), sequence: ['right','down','up','right','down'] },
{ 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', icon: ICON('orbital_precision_strike'), sequence: ['right','right','up'] },
{ name: 'Orbital Gas Strike', category: 'Orbital Cannons', icon: ICON('orbital_gas_strike'), sequence: ['right','right','down','right'] },
{ name: 'Orbital EMS Strike', category: 'Orbital Cannons', icon: ICON('orbital_ems_strike'), sequence: ['right','right','left','down'] },
{ name: 'Orbital Smoke Strike', category: 'Orbital Cannons', icon: ICON('orbital_smoke_strike'), sequence: ['right','right','down','up'] },
{ name: 'Orbital Illumination Flare', category: 'Orbital Cannons', icon: ICON('orbital_illumination_flare'), sequence: ['right','right','left','left'] },
// ── Hangar ────────────────────────────────────────────────────────────────
{ name: 'Eagle Strafing Run', category: 'Hangar', icon: ICON('eagle_strafing_run'), sequence: ['up','right','right'] },
{ name: 'Eagle Airstrike', category: 'Hangar', icon: ICON('eagle_airstrike'), sequence: ['up','right','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', icon: ICON('eagle_napalm_airstrike'), sequence: ['up','right','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', icon: ICON('eagle_smoke_strike'), sequence: ['up','right','up','down'] },
{ name: 'Eagle 110MM Rocket Pods', category: 'Hangar', icon: ICON('eagle_110mm_rocket_pods'), sequence: ['up','right','up','left'] },
{ name: 'Eagle 500KG Bomb', category: 'Hangar', icon: ICON('eagle_500kg_bomb'), sequence: ['up','right','down','down','down'] },
// ── Bridge ────────────────────────────────────────────────────────────────
{ name: 'Patriot Exosuit', category: 'Bridge', icon: ICON('patriot_exosuit'), sequence: ['left','down','right','up','left','down','right'] },
{ name: 'Emancipator Exosuit', category: 'Bridge', icon: ICON('emancipator_exosuit'), sequence: ['left','down','right','up','left','down','down'] },
{ name: 'Tesla Tower', category: 'Bridge', icon: ICON('tesla_tower'), sequence: ['down','up','right','up','left','up','up'] },
{ name: 'Shield Generator Relay', category: 'Bridge', icon: ICON('shield_generator_relay'), sequence: ['down','up','left','right','left','down'] },
// ── Engineering Bay Support Weapons ────────────────────────────────────
{ name: 'Machine Gun', category: 'Engineering Bay', icon: ICON('machine_gun'), sequence: ['down','left','down','up','right'] },
{ name: 'Anti-Materiel Rifle', category: 'Engineering Bay', icon: ICON('anti_materiel_rifle'), sequence: ['down','left','right','up','down'] },
{ name: 'Stalwart', category: 'Engineering Bay', icon: ICON('stalwart'), sequence: ['down','left','down','up','up','left'] },
{ name: 'Expendable Anti-Tank', category: 'Engineering Bay', icon: ICON('expendable_anti_tank'), sequence: ['down','down','left','up'] },
{ name: 'Recoilless Rifle', category: 'Engineering Bay', icon: ICON('recoilless_rifle'), sequence: ['down','left','right','right','left'] },
{ name: 'Flamethrower', category: 'Engineering Bay', icon: ICON('flamethrower'), sequence: ['down','left','up','down','up'] },
{ name: 'Autocannon', category: 'Engineering Bay', icon: ICON('autocannon'), sequence: ['down','left','down','up','up','right'] },
{ name: 'Heavy Machine Gun', category: 'Engineering Bay', icon: ICON('heavy_machine_gun'), sequence: ['down','left','up','down','down'] },
{ name: 'Airburst Rocket Launcher', category: 'Engineering Bay', icon: ICON('airburst_rocket_launcher'), sequence: ['down','up','up','left','right'] },
{ name: 'Commando', category: 'Engineering Bay', icon: ICON('commando'), sequence: ['down','left','up','down','right'] },
{ name: 'Railgun', category: 'Engineering Bay', icon: ICON('railgun'), sequence: ['down','right','down','up','left','right'] },
{ name: 'Spear', category: 'Engineering Bay', icon: ICON('spear'), sequence: ['down','down','up','down','down'] },
{ name: 'Quasar Cannon', category: 'Engineering Bay', icon: ICON('quasar_cannon'), sequence: ['down','down','up','left','right'] },
{ name: 'Arc Thrower', category: 'Engineering Bay', icon: ICON('arc_thrower'), sequence: ['down','right','down','up','left','left'] },
{ name: 'Laser Cannon', category: 'Engineering Bay', icon: ICON('laser_cannon'), sequence: ['down','left','down','up','left'] },
{ name: 'Grenade Launcher', category: 'Engineering Bay', icon: ICON('grenade_launcher'), sequence: ['down','left','up','left','down'] },
// ── Engineering Bay Equipment ───────────────────────────────────────────
{ name: 'Supply Pack', category: 'Engineering Bay', icon: ICON('supply_pack'), sequence: ['down','left','down','up','up','down'] },
{ name: 'Guard Dog Rover', category: 'Engineering Bay', icon: ICON('guard_dog_rover'), sequence: ['down','up','left','up','right','right'] },
{ name: 'Guard Dog', category: 'Engineering Bay', icon: ICON('guard_dog'), sequence: ['down','up','left','up','right','down'] },
{ name: 'Ballistic Shield Backpack', category: 'Engineering Bay', icon: ICON('ballistic_shield_backpack'), sequence: ['down','left','down','down','up','left'] },
{ name: 'Shield Generator Pack', category: 'Engineering Bay', icon: ICON('shield_generator_pack'), sequence: ['down','up','left','right','left','right'] },
{ name: 'Directional Shield', category: 'Engineering Bay', icon: ICON('directional_shield'), sequence: ['down','left','up','up','right'] },
// ── Engineering Bay Mines ───────────────────────────────────────────────
{ name: 'Anti-Personnel Minefield', category: 'Engineering Bay', icon: ICON('anti_personnel_minefield'), sequence: ['down','left','up','right'] },
{ name: 'Incendiary Mines', category: 'Engineering Bay', icon: ICON('incendiary_mines'), sequence: ['down','left','left','down'] },
{ name: 'Anti-Tank Mines', category: 'Engineering Bay', icon: ICON('anti_tank_mines'), sequence: ['down','down','left','left'] },
// ── Robotics Workshop ─────────────────────────────────────────────────────
{ name: 'Machine Gun Sentry', category: 'Robotics Workshop', icon: ICON('machine_gun_sentry'), sequence: ['down','up','right','right','up'] },
{ name: 'Gatling Sentry', category: 'Robotics Workshop', icon: ICON('gatling_sentry'), sequence: ['down','up','right','left'] },
{ name: 'Mortar Sentry', category: 'Robotics Workshop', icon: ICON('mortar_sentry'), sequence: ['down','up','right','right','down'] },
{ name: 'Autocannon Sentry', category: 'Robotics Workshop', icon: ICON('autocannon_sentry'), sequence: ['down','up','right','up','left','up'] },
{ name: 'Rocket Sentry', category: 'Robotics Workshop', icon: ICON('rocket_sentry'), sequence: ['down','up','right','right','left'] },
{ name: 'EMS Mortar Sentry', category: 'Robotics Workshop', icon: ICON('ems_mortar_sentry'), sequence: ['down','up','right','down','right'] },
// ── Defensive ─────────────────────────────────────────────────────────────
{ name: 'Anti-Tank Emplacement', category: 'Defensive', icon: ICON('anti_tank_emplacement'), sequence: ['down','right','right','up','left'] },
{ 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));
@@ -127,10 +128,35 @@ function initDB() {
loser_rounds INTEGER 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_m_winner ON matches(winner);
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() {
@@ -143,13 +169,33 @@ async function initUsers() {
if (!exists) {
const tempPw = crypto.randomBytes(6).toString('hex');
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);
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 ────────────────────────────────────────────────────────────
function getSessionSecret() {
const file = path.join(DATA_DIR, '.session-secret');
@@ -265,7 +311,22 @@ app.post('/api/change-password', requireAuth, async (req, res) => {
// ── User management (admin) ───────────────────────────────────────────────────
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 })));
});
@@ -301,6 +362,95 @@ app.delete('/api/users/:username', requireAuth, requireAdmin, (req, res) => {
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 ─────────────────────────────────────────────────────────
let lbCache = null;
let lbCacheTime = 0;
@@ -313,6 +463,7 @@ function getLeaderboard() {
lbCache = db.prepare(`
SELECT
u.username,
COALESCE(u.elo, 1000) AS elo,
COALESCE(ps.sessions, 0) AS sessions,
COALESCE(ps.totalScore, 0) AS totalScore,
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 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 = ?
ORDER BY created_at DESC LIMIT 5
`).all(u);
@@ -368,10 +519,26 @@ app.get('/api/dashboard', requireAuth, (req, res) => {
WHERE stratagem = ? AND username = ?
`).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({
stats: { ...stats, ...matchStats },
rank,
online: [...userSockets.keys()],
elo,
eloRank: eloRank(elo),
online: onlineWithElo,
recent,
daily: { stratagem: dailyStrat, bestTime: dailyBest?.bestTime ?? null },
});
@@ -379,15 +546,27 @@ app.get('/api/dashboard', requireAuth, (req, res) => {
// ── Scores ────────────────────────────────────────────────────────────────────
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 (typeof time_ms !== 'number' || time_ms <= 0 || time_ms > 31_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 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 > 50_000) return res.status(400).json({ error: 'Invalid score' });
const safeMode = ['timed','endless','drill','speedrun'].includes(mode) ? mode : 'timed';
db.prepare(`
INSERT INTO practice_sessions (username, stratagem, category, time_ms, score, created_at)
VALUES (?, ?, ?, ?, ?, ?)
`).run(req.session.user, stratagem, category || '', time_ms, score, new Date().toISOString());
INSERT INTO practice_sessions (username, stratagem, category, time_ms, score, mode, created_at)
VALUES (?, ?, ?, ?, ?, ?, ?)
`).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();
res.json({ ok: true });
@@ -397,10 +576,27 @@ app.get('/api/scores/leaderboard', requireAuth, (req, res) => {
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) => {
const u = req.session.user;
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 = ?
ORDER BY created_at DESC LIMIT 50
`).all(u);
@@ -411,6 +607,41 @@ app.get('/api/scores/me', requireAuth, (req, res) => {
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) ────────────────────────────────────────────
// Stratagem sequences are served via API not as a public static file.
app.get('/api/stratagems', requireAuth, (req, res) => {
@@ -441,7 +672,18 @@ async function main() {
}
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 => {
if (ws.readyState !== WebSocket.OPEN || !ws.userId) return;
const incoming = [...pendingChallenges.entries()]
@@ -470,15 +712,37 @@ async function main() {
room.matchScores[winnerId]++;
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 });
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(`
INSERT INTO matches (winner, loser, winner_rounds, loser_rounds, created_at)
VALUES (?, ?, ?, ?, ?)
`).run(winnerId, loser.userId, room.matchScores[winnerId], room.matchScores[loser.userId], new Date().toISOString());
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);
} else {
room.state = 'waiting';
@@ -501,7 +765,8 @@ async function main() {
const { targetUser } = payload;
if (!userSockets.has(targetUser) || targetUser === userId) return;
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();
break;
}