Skip to content

Init/tarkov checker#2

Merged
Mosmain merged 47 commits into
masterfrom
init/tarkov-checker
May 27, 2026
Merged

Init/tarkov checker#2
Mosmain merged 47 commits into
masterfrom
init/tarkov-checker

Conversation

@Mosmain

@Mosmain Mosmain commented May 27, 2026

Copy link
Copy Markdown
Owner

No description provided.

Mosmain and others added 30 commits May 25, 2026 01:14
Add pnpm workspaces + Turborepo wiring, strict TS base config with
@shared/* path alias, ESLint flat config (TS + Vue + Prettier),
Prettier, EditorConfig, .nvmrc (Node 20), and .gitignore.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Discriminated zod union for heartbeat/raid lifecycle/position WS
payloads. Canonical Tarkov location code -> display name table
(bigmap -> Customs, etc.) with type guard and helper.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Fastify 5 with pino (pino-pretty in dev), CORS open, and a /ws route
that emits {type:'heartbeat', t} every 5 seconds per connection.
Watcher path resolver stubbed with TODOs for the log and screenshot
directories.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Vue 3 (Composition API) + Vite 5 + Pinia. Tailwind v4 wired via
@tailwindcss/vite (CSS-first @import "tailwindcss"; no JS config).
Thin imperative useLeafletMap composable with OSM placeholder tiles
and useWebSocket that validates payloads with the shared zod schema.
App.vue shows "Customs map placeholder" overlay + connection badge.
vite-plugin-pwa with iOS-friendly manifest; placeholder icon files
TODO. One Vitest placeholder spec covering the maps mapping.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Hand-written Cargo.toml + tauri.conf.json + build.rs + src/{main,lib}.rs
+ capabilities/default.json. frontendDist points at ../../client/dist;
devUrl is http://localhost:5173; beforeDevCommand left empty so Vite
stays under Turbo orchestration (documented in apps/desktop/README.md
and CLAUDE.md). Window is 800x600, decorations on; transparency and
always-on-top deferred. @tauri-apps/cli pinned as a workspace devDep.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Generated by pnpm 10.13.1 across all four workspace packages.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- apps/server/src/ws.ts: annotate socket error listener parameter
  (Fastify ws hands back a Node EventEmitter Error; explicit type
  avoids implicit-any under strict TS).
- apps/client/tsconfig.app.json: drop composite, set baseUrl
  explicitly, and include packages/shared/src so vue-tsc resolves
  @shared/* imports without project references.
- apps/client/tsconfig.node.json: same composite removal for the
  Vite/Vitest config project.
- apps/client/vite.config.ts + vitest.config.ts: switch the alias
  block from object form to array-with-regex form so @shared/foo
  resolves to packages/shared/src/foo instead of concatenating onto
  index.ts.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
README covers install, dev/build workflow with port table, lint/test
commands, and conventions. CLAUDE.md records the non-obvious bits:
@shared/* path alias scheme, the assume-running-Vite Tauri dev choice,
the Tailwind v4 CSS-first deviation from the original spec, and the
bootstrap quirk that the Rust toolchain was absent during scaffolding.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Replace OSM placeholder tiles with the SVG maps from the-hideout/
tarkov-dev-svg-maps (added as a submodule at apps/client/public/maps/,
CC BY-NC-SA 4.0). Switch Leaflet to L.CRS.Simple, fetch the SVG and
parse it with DOMParser so top-level <g> groups remain reachable for a
future floor switcher (Customs is single-level so no switcher UI yet).
useLeafletMap now takes an svgUrl, returns shallow refs for map +
loaded metadata + error.

Promote the TARKOV_MAPS table in @tarkov-checker/shared from raw-code
-> string to raw-code -> { displayName, svgFile } so PascalCase SVG
filenames (StreetsOfTarkov.svg, GroundZero.svg) can diverge from the
human-readable name shown in the UI. Add mapSvgPath() helper.

App.vue now drives the current map from a hardcoded bigmap — the WS
raid-start handler will replace that once real raid events arrive.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
CREDITS.md attributes the-hideout/tarkov-dev-svg-maps and explains how
the CC BY-NC-SA submodule stays isolated from our code license.
README adds the submodule init step for first-time clones. CLAUDE.md
gains sections covering the runtime SVG-fetch + L.CRS.Simple wiring,
the per-map nature of <g>-group semantics (feature layers vs floors),
and a note that in-game-to-SVG coord calibration is per-map and
deferred until real position events arrive.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
.claude/launch.json registers the workspace dev script so the
preview tool can attach to the Vite server on :5173 without re-spawning
it. Safe to share — no secrets, no machine-specific paths.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Promote TARKOV_MAPS entries with the in-game-to-SVG affine values
(transform, rotation, bounds) and the base SVG layer id, copied from
the-hideout/tarkov-dev frontend (MIT) — single source of truth so we
do not have to recalibrate per map empirically.

Add tarkov-api.ts with zod schemas for the GraphQL payloads we will
actually consume (Position3D, Extract, MapExtracts). Wire the new
subpath export.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
useLeafletMap now builds a per-map CRS extending L.CRS.Simple:
rotation handled in projection, affine in transformation. Marker
placement is just L.marker([z, x]) — no per-call math, calibration
lives entirely in the CRS. Mirrors tarkov-dev/src/pages/map/index.jsx.

apps/client/src/api/tarkov-dev.ts is a tiny GraphQL client (plain
fetch, zod-validated, module-level promise cache) — no Apollo/urql
for one query type. App.vue fetches extracts for the current map and
drops L.circleMarker per extract, colored by faction (pmc green,
scav yellow, shared blue), with a name tooltip on hover.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
CREDITS.md gains sections for the tarkov-dev frontend (MIT, source of
all per-map transform/rotation/bounds values) and the public tarkov.dev
GraphQL endpoint. CLAUDE.md replaces the old map-rendering section
with the custom CRS pipeline (rotation in projection, affine in
transformation) and adds a section on the GraphQL client and how
Map.nameId case-insensitively matches our raw codes.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Add FACTION_COLORS to @shared/maps so the map markers and the legend
in the new settings popover never drift. fetchExtractsForMap now takes
an explicit lang argument (en/ru/de/...) and the module-level promise
cache is keyed by language — switching languages is one HTTP hit per
language per session.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
apps/client/src/stores/settings.ts is a Pinia store backing apiLang,
extractFactions, extractsVisible, and extractLabelMode. Persists to
localStorage under a versioned key via a deep watch, with zod-validated
load (corrupt data silently falls back to defaults).

useLeafletMap grows three external setters — addExtractMarkers,
setExtractFilter, setLabelMode — and an internal state object so that
settings pushed before markers exist still apply on the first
fetch. Faction filter toggles per-marker layer membership. Smart label
mode binds tooltips with permanent: true and uses moveend / zoomend
listeners to openTooltip only for markers whose latLng is inside
map.getBounds() AND whose zoom is at least initialZoom +
SMART_LABEL_ZOOM_DELTA — so on a full-map fitBounds view there is no
text noise, and labels appear as the user zooms in.

styles.css gets a small extract-tooltip rule: dark glassy background,
no arrow, small bold text — matches the badges and stays unobtrusive.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
components/SettingsPanel.vue is a gear-icon button with a dark
popover-above-icon panel: language radio (EN/RU), an Extracts master
switch, three faction checkboxes with their map colors as legend
dots, and a hover/smart label-mode toggle with a one-liner hint.
Closes on outside click and on Escape; focus ring matches the app
theme; touch targets are at least 36px.

App.vue wires three reactive watchers — apiLang refetches, faction +
master push into setExtractFilter, labelMode pushes into setLabelMode.
Settings push happens once synchronously before the first fetch so
brand-new markers come up already filtered.

CLAUDE.md gains a User settings section documenting the store, the
versioned localStorage key, and the smart-label heuristic (with a
note that the zoom threshold lives in useLeafletMap as a tunable
constant, not as a user setting).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Three feedback-driven polish items:

- Map title at top now reads from the API localized Map.name (e.g.
  Customs becomes Таможня when apiLang=ru) instead of the hardcoded
  TARKOV_MAPS displayName. shared.tarkov-api gets a name field on
  MapExtracts; the App.vue title binding swaps to a ref updated on
  every fetch, with the hardcoded displayName as a startup fallback.

- Co-located extracts (e.g. RUAF Roadblock has both a PMC and a Scav
  variant at nearly identical x,z) used to render as a single
  obscured marker. addExtractMarkers now buckets entries by rounded
  game-coord position and, for any bucket with more than one entry,
  spreads them radially around the original point. Offset is a
  constant pixel value divided by the per-map scale so the visual
  spacing stays consistent across maps.

- SettingsPanel switches from an absolute popover anchored to the
  gear icon, to a fixed bottom-sheet on viewports below the sm
  breakpoint (covers the iPod touch 7 case at 320px wide). Tailwind
  prefix restores the desktop popover above the breakpoint, so the
  experience stays compact on big screens.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…amp pan

Markers stay at their true in-game (x, z) coordinates — the previous
spreadOverlapping shifted the marker latLng itself, which moved the
dot off the actual exit. That is reverted. Instead, computeTooltipOffsets
buckets entries by rounded (x, z) and assigns each member of a colocated
group a radial pixel offset (TOOLTIP_RING_RADIUS = 22 px). Tooltip
direction switches to center so the offset places the label centre
relative to the marker centre; bindTooltip is called per-entry with
its own offset. Singleton extracts get the same formula (offset [0,
-22] = label above the dot).

Map panning is now bounded. L.map gets maxBoundsViscosity = 1.0 and we
call setMaxBounds(bounds.pad(0.15)) after fitBounds, plus setMinZoom
to the post-fit zoom so the map cannot be zoomed-out into infinity
either. Wild swipes resist and snap; the map can no longer disappear
off-screen.

mapBoundsLatLng to mapLatLngBounds and now returns L.LatLngBounds
directly so .pad() composes; the LatLngBoundsExpression import is no
longer needed.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Faction names in the tarkov.dev API are raw enum strings (pmc/scav/
shared) with no localized variant, so UI labels are kept locally in a
small i18n module instead. apps/client/src/i18n.ts ships en/ru bundles
covering: Language/Extracts/Labels section headers, faction names
(PMC/Scav/Shared vs ЧВК/Дикие/Общие), label-mode toggle, the smart-
mode hint, and the Settings aria-label. useUiText composable returns
a computed bundle keyed off settings.apiLang, so switching language
refreshes the whole popover instantly.

Map title moved from top-center to top-right and bumped to z-1000 so
it no longer collides with Leaflet tooltip-pane content (which ships
at z 650). Settings popover lifted to z-1010, error toasts moved just
below the title row. The previous overlap visible on the iPod touch
screenshot, where extract label Pruti (Signal) mashed into the title,
is gone.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Server now watches the Tarkov screenshots directory for new F12-overlay
PNGs, parses their filename for the embedded (X, Y, Z) position triple,
and fans the result to every connected WS client as a position message.

Path resolver tries TARKOV_SCREENSHOT_DIR first, then walks the usual
OneDrive / Documents candidates under the home directory so OneDrive
setups (where the Documents folder is redirected) get picked up
without extra config. Logs a warning instead of crashing if the folder
is missing — the player marker pipeline just stays dormant.

WS plugin gains a Hub class: a Set of connected sockets plus a
broadcast helper that lets watchers fan out without knowing about
individual sockets. The 5s heartbeat stays per-socket; position and
future raid events go through broadcast.

The filename parser lives in @tarkov-checker/shared (re-exported from
the index barrel) so the client side can run unit tests against it.
Vitest covers the typical Tarkov filename, full Windows paths, .jpg
rejection, names without a coordinate triple, and integer-only
coords.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Map rendering, extracts fetching and the position-stream subscription
move out of App.vue into MapView.vue. App now drives MapView through a
:key bound to the current mapCode, so changing the selected map fully
re-mounts the composable instead of trying to mutate Leaflet state
in place. App.vue still owns the WS connection (kept stable across
map switches) and forwards lastMessage down as a prop.

useLeafletMap exposes setPlayerPosition / clearPlayerPosition. A
position WS message paints two markers under the player layer: a
solid red dot and a pulsing ring (CSS keyframe scaling stroke
outward, fading). A 90-second stale timer clears the marker if no
new position arrives.

Settings store gains a persisted mapCode field plus a zod default so
saves from older builds keep their other settings. SettingsPanel
gets a Map section with a localized dropdown built from the
fetchAllExtracts(lang) names cache, falling back to the hardcoded
displayName until the API responds. The i18n bundle gets a map
label for the section header.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Two changes:

- turbo.json dev task gains an explicit env passthrough list
  (NODE_ENV, PORT, HOST, TARKOV_LOG_DIR, TARKOV_SCREENSHOT_DIR,
  LOCALAPPDATA, USERPROFILE, OneDrive, HOME). Without this, depending
  on the turbo version, system env vars may not reach the spawned
  task and resolveWatcherPaths fell back to null.

- resolveWatcherPaths now returns the full candidate list with each
  paths existence flag, and startWatchers logs the candidates plus
  the relevant env vars at startup. So when a user reports that the
  pipeline is dormant, the logs immediately show exactly which paths
  were tried and what the env looks like.

Screenshot candidate list extended to cover OneDrive variants users
hit in the wild ($OneDrive/Documents, ~/OneDrive/Documents,
~/OneDrive - Personal/Documents, ~/Escape from Tarkov/Screenshots).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Move the two Tarkov paths out of shell env vars and OneDrive/Documents
guesswork into a single .env at the repo root. Node 22 reads it on
boot via --env-file-if-exists, so no dotenv dep, and missing file is
silent. The heuristics from the previous diagnostic commit go away
entirely — Tarkov installs vary too much for a heuristic to be
reliable, and asking the user to set two absolute paths once is
strictly less friction than walking them through what OneDrive did.

resolveWatcherPaths is now literally read TARKOV_SCREENSHOT_DIR and
TARKOV_LOG_DIR. dirExists stays the gate for actually starting a
watcher, so an unset or wrong path falls through to a warning and the
server keeps running with extracts/map intact.

turbo dev task no longer needs the LOCALAPPDATA/OneDrive/USERPROFILE
passthrough either — those mattered only for the old heuristics.

.env.example documents the two keys with example Windows paths so a
fresh clone has a one-step setup: cp .env.example .env, fill in.

A first-class UI for path config (settings panel section + server
config endpoint) can land later when it is worth the backend.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Tarkov path resolution gets a real priority chain instead of OneDrive
guesswork. Highest-priority source wins:

1. .env (TARKOV_GAME_DIR, TARKOV_SCREENSHOT_DIR, optional
   TARKOV_LOG_DIR override).
2. Manual override stored in apps/server/data/config.json (gitignored,
   written by PUT /api/config from the in-app Settings panel).
3. Windows-registry auto-detect — HKCU User Shell Folders\Personal for
   Documents (so OneDrive-redirected Documents resolves correctly),
   plus the usual Battlestate Games\EFT\InstallLocation keys for the
   game folder. reg query is invoked with chcp 65001 first so Cyrillic
   paths decode cleanly.

logsDir is derived (gameDir/Logs) unless overridden explicitly, so the
user only ever has to set the game folder.

WatcherManager replaces the one-shot startWatchers helper: stopAll +
apply(paths) so PUT /api/config can reconfigure in place without a
process restart. CORS now allows GET/POST/PUT/DELETE/OPTIONS
explicitly — its default methods list dropped PUT silently after
preflight. The Fastify port reads SERVER_PORT (not PORT) since dev
tooling sometimes sets PORT=5173 for the whole runner.

Shared adds a config-api zod module so the client gets a typed
ServerConfigResponse/Update without having to redeclare the shape.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
New Tarkov paths section at the top of the Settings panel.

- Two text inputs (Game folder, Screenshots folder), each with a small
  status dot (green = exists, amber = set but not on disk, red = no
  value) and a source badge (auto-detected, manual, from env, not
  found). Logs path is shown read-only underneath Game folder since
  it derives from it.

- Inputs become read-only on viewports below the sm breakpoint
  (configuring D-colon-EFT on an on-screen phone keyboard is painful),
  with a hint to configure on the desktop. A window resize listener
  flips isDesktop reactively so the same browser tab works after
  DevTools device emulation toggles.

- env-sourced values get the input disabled (cannot edit through UI
  when env is the priority source). Save button only enables when
  there is an actual dirty diff and at least one editable field.

- Saved pill flashes for 2s after a successful PUT.

apps/client/src/api/server-config.ts is a plain fetch wrapper
validating GET/PUT against the shared zod schemas. i18n bundle gains
a paths block (en plus ru, including source badges and the missing-
folder tooltip) keyed off apiLang as before.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
README Tarkov paths section now describes the priority chain (env
then manual UI override then registry auto-detect) instead of
pretending env is the only source. Notes that gameDir is the one
users will likely have to set manually since BSG Launcher writes the
registry key inconsistently across installs.

.env.example documents the three keys (game, screenshot, optional
log override) with explicit leave-blank-to-let-lower-priority-source-
win guidance.

CLAUDE.md gains a Tarkov path resolution section covering the
priority chain, the chcp 65001 trick for Cyrillic Documents, the
SERVER_PORT vs PORT split, and the fastify-cors PUT-method gotcha.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Parser now returns ParsedScreenshot (position, orientation Quaternion or
null), so unrelated PNGs still fall through cleanly while real Tarkov F12
screenshots also surface the orientation quaternion.

quaternionToYawDegrees extracts rotation around the world Y axis from
the quaternion (atan2 on the standard Unity Y-up formula). The
screenshot watcher computes yaw on the server and sends it as an
optional field on the position WS message, so clients do not need a
quaternion math helper.

Unit tests cover identity, plus 90 and 180 degrees around Y, plus the
parser-with-orientation case.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Player marker is now a divIcon SVG (white dot + red cone) rotated by
in-game yaw plus the maps own coordinateRotation, so the arrow points
where the player is actually looking on the rendered map. yaw comes
through the position WS message; null yaw skips the cone and shows
just the dot, so clients connecting to older servers degrade
gracefully.

Pulse animation softened from scale 0.4 to 2.2 with 0.9 opacity down
to scale 1 to 1.55 with 0.55 opacity, on a slower ease curve. Less
flashy, easier on the eye.

Extract label mode smart replaced with always — permanent
tooltips show up regardless of zoom or viewport, matching the
preferred behaviour. The settings store auto-migrates old smart
saves to always via a zod transform; default is always. i18n bundle
labels updated to match.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Mosmain and others added 17 commits May 25, 2026 22:31
Tailwind v4 plus @plugin daisyui locked to a single dark theme.
data-theme on html keeps SSR-free render predictable.

SettingsPanel rewritten with DaisyUI primitives instead of hand-rolled
classes: card+card-body for the popover, join+btn for language and
label-mode pickers, badge with semantic colour variants for the
path-source pill, input with input-bordered for path text fields,
toggle for the extracts master switch, checkbox-primary for faction
filters, select-bordered for the map dropdown, alert-error for the
inline error toast, plus a max-h scroll container on the popover
body so mobile sheets stay in viewport.

App overlays migrate to base-* tokens so they pick up the daisy
theme: ws-status pill uses bg-success/warning/error, error toasts
become alert components, the map-title chip uses bg-base-300/70.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Five small follow-ups from a feedback pass:

- Custom Leaflet pane extracts with z-index 500 holds all extract +
  player markers, so async-loaded svgOverlay (overlayPane z 400) no
  longer covers them after a map switch.

- Permanent tooltips were being closed by stray click events on the
  marker. A per-marker click handler now re-opens the tooltip on the
  next tick when label mode is always.

- Drop the zod transform that migrated old smart label-mode saves and
  bump the settings storage key v1 -> v2. Cleaner schema; the price is
  that users coming from a very old build re-pick defaults once.
  Rename i18n labelSmart -> labelAlways so naming matches behaviour.

- Faction checkboxes are now stacked vertically (flex flex-col) — the
  DaisyUI .label class is inline-flex so multiple labels in a row
  used to sit on the same line.

- Path input fields lift to bg-base-100 (vs the popovers bg-base-200)
  for visible contrast. Map dropdown gets the same.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Four interlocked UX changes:

- Settings popover replaced with a slide-in drawer (Teleport to body,
  backdrop overlay, Escape and click-outside close). Full width on
  mobile, w-96 on sm and up. Bottom of body is a single scroll area
  so long lists do not overflow on small phones.

- Each section is now a real fieldset+fieldset-legend on a base-100
  surface with a border, matching the daisy theme. Inputs inside go
  to bg-base-200 for contrast against the fieldset.

- Master extracts toggle is gone. extractsVisible removed from the
  settings store (storage key bumped v2 to v3), useLeafletMap loses
  the second arg of setExtractFilter, MapView watches just the
  factions array. Empty factions = nothing shown, which is the same
  end state but with one fewer control.

- tarkov.dev API client gains a localStorage cache keyed by language
  with a fetchedAt timestamp. fetchAllExtracts is cache-first;
  refreshExtracts forces a network round-trip and replaces the
  entry. Settings drawer gets a Data cache fieldset showing last
  updated relative age plus a Refresh button. tarkov.dev is blocked
  from some RU networks, so a stable offline copy is the difference
  between working and broken.

shadow-none on the active join buttons fixes the visible blob under
the chosen option in EN/RU and labels picker.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Move the tarkov.dev cache off the client onto the server, where it
belongs architecturally:

- apps/server/src/extracts-cache.ts: file-backed cache at
  apps/server/data/extracts-cache.json keyed by language. Concurrent
  fetches for the same language share one in-flight promise.

- GET /api/extracts?lang=<lang>&refresh=<0|1>: cache-first by default,
  refresh=1 forces a network round-trip and replaces the entry.
  Response is { lang, fetchedAt, data }, all zod-validated through
  the new extractsCacheResponse schema in @tarkov-checker/shared.

- Client tarkov-dev.ts drops its localStorage cache layer and just
  GETs the local server endpoint. refreshExtracts passes refresh=1;
  getCacheTimestamp reads from a small in-memory Map populated on
  each successful response.

- SettingsPanel loadMapNames refreshes the cache timestamp in finally,
  so the Data cache section shows a real time the moment maps load
  on mount.

The win is operational, not just architectural: tarkov.dev is blocked
from some RU networks, but the server only needs working egress once
(VPN, mobile hotspot, etc.) and every phone/desktop/Tauri client on
the LAN reads the cached data over local HTTP regardless of their
own connectivity.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
factory4_night and sandbox_high share their SVG, transform and bounds
with factory4_day and sandbox respectively, so picking between them in
the UI is noise. Their nameId still matters for log parsing — keep the
entries in TARKOV_MAPS, mark them as aliases.

TarkovMapInfo gets `canonical: TarkovMapCode | null`. Non-null means
this code is an alias of the listed code. Canonicals stay null.
factory4_day display name drops the (Day) suffix now that no second
Factory variant sits next to it in the picker.

Exported helpers:

- canonicalMapCode(code) — resolves an alias to its canonical (or
  passes the code through unchanged). Useful once the log watcher
  starts surfacing raw nameIds.

- VISIBLE_MAP_CODES — pre-filtered list of canonical codes for
  selectors. SettingsPanel now imports this instead of all
  TARKOV_MAPS keys, so the map dropdown shows 10 entries.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Two small drawer rough edges:

- backdrop-blur-sm on the overlay was blurring the visible map on
  desktop where the drawer only takes 384px on the right. The blur
  was meaningful on mobile (drawer covers everything anyway) so it
  was dead weight everywhere — dropped. Just dim with bg-black/40
  now.

- The SETTINGS header used to scroll away with the body on long
  mobile panels. Made it sticky top-0 with bg-base-200 and a small
  z-index so it stays parked at the top while the fieldsets scroll
  under it.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
A click on an extract marker reopened the tooltip (per-marker click
handler set it up), but a follow-up click on empty map space closed
it again and stayed closed until reload. Leaflet fires map.click for
the empty area, no marker.click — so the existing handler never ran.

Reworked into reopenAllPermanentTooltips: instead of re-opening just
the clicked marker, re-open every visible markers tooltip after any
click. Bound it both on each marker click (unchanged path) and on
map.click (new), so a click on empty map space now restores every
permanent tooltip too.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…itle

TARKOV_MAPS gains floors and defaultFloor per map, populated from the
actual top-level g ids in each vendored SVG (Customs, Shoreline, Streets,
Ground Zero get a five-floor stack, Factory four, Interchange three,
Labs and Reserve two; Woods and Lighthouse stay single-level and skip
the switcher).

useLeafletMap exposes setActiveFloor and a currentFloor ref. Ground
floor (the maps defaultFloor) is never hidden — when the user picks a
different level the ground stays visible at opacity 0.2 so the upper
floors interior still has a street layout behind it. Other floors are
fully hidden with display none.

New FloorSwitcher.vue lives bottom-left. A pill button shows the
current level as Floor N (i18n: Floor or Уровень), click expands a
vertical stack of small circle buttons upward. Active floor is
btn-primary, others btn-neutral. Click outside or Escape closes.
Component hides itself when the map has 0 or 1 floors.

WS status moves out of its own bottom-right chip into a small colored
dot before the map title in the top-right pill. Hover title surfaces
the raw state. Less visual clutter for the LAN/phone use case where
the connection is essentially always on.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Labs Technical_Level and Factory Basement cover the same horizontal
area as their ground floor and sit underneath it in the SVG DOM. The
old ground-stays-dim rule painted the dim ground group on top of the
underground geometry and obscured most of it.

setActiveFloor now keeps ground dim only when the active floor label
is strictly greater than ground label, i.e. when the player goes UP
the building, where the ground street layout is genuinely useful as
context. For below-ground floors the ground group goes display:none
so the underground geometry renders clean.

Above-ground behaviour is unchanged.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Ground floor is the persistent context — it is never hidden now,
just dimmed to opacity 0.15 when another level is active and shown
at full opacity when ground itself is active.

The previous fix that display:noned ground for below-ground floors
solved the occlusion symptom but lost the spatial context. The real
problem was SVG draw order: in Labs the Technical_Level group is the
first child of the SVG so the later-rendered First_Level (ground)
paints over it. Same shape on Factory.

setActiveFloor now also appendChild()s the active group on each
switch, moving it to the end of the SVG children list. SVG draws
later siblings on top of earlier ones, so the chosen floor always
renders above ground regardless of its original DOM position.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- Added PrimeVue components including Button, ConfirmDialog, and Message for enhanced UI interactions.
- Updated package dependencies to include @primeuix/themes, @tauri-apps/api, and others for improved functionality.
- Introduced a new Tarkov preset for theming with PrimeVue.
- Implemented new font styles and icons for better visual consistency.
- Enhanced overlay functionality with click-through options and hotkey management.
- Updated i18n support for new UI elements and settings.

This commit enhances the overall user experience by leveraging PrimeVue's component library and improving the application's visual design.
…on; add essential components, routing, and state management. Create CLAUDE.md for project structure and development workflow documentation. Update pnpm lockfile for dependency management.
- Updated the context menu handling to open the quick transparency panel only in Tauri environments, allowing the native context menu to function normally in browsers.
- Added a check to ensure the context menu is only triggered when right-clicking within the `.leaflet-container`, improving user experience and preventing unintended interactions.
…verlayClickThrough state

- Updated the App.vue component to only display the SettingsPanel when overlayClickThrough is false, enhancing user interaction.
- Adjusted the Button visibility to also depend on the isTauri and overlayClickThrough states, ensuring a more intuitive UI experience.
…DELTA values

- Consolidated LeafletMap imports for cleaner code.
- Updated FOLLOW_ZOOM_DELTA values to improve zoom behavior in follow modes, enhancing user experience on the map.
…te project structure

- Added a new in-process server in the Tauri application to replace the Node/Fastify backend, allowing for direct communication via Tauri events and commands.
- Updated CLAUDE.md to reflect changes in project structure and development workflow, including detailed descriptions of each package's responsibilities.
- Introduced new commands for configuration management and extracts fetching, enhancing the integration between the Rust backend and the Tauri frontend.
- Updated package.json to include a new build script for the overlay.
- Created a GitHub Actions workflow for building the overlay and attaching the executable to draft releases.
- Refactored client-side code to utilize the new server transport mechanism, improving communication efficiency in Tauri mode.
…se process

- Enhanced the build workflow to support manual dispatch and automatic releases on master and version tag pushes.
- Added permissions for content writing to facilitate release creation.
- Improved artifact handling to ensure .exe files are always uploaded as workflow artifacts.
- Updated release publishing logic to differentiate between manual and automated builds, ensuring proper tagging and release notes generation.
@Mosmain Mosmain merged commit 3a2eb5f into master May 27, 2026
@Mosmain Mosmain deleted the init/tarkov-checker branch May 31, 2026 01:03
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant