Skip to content

Sea - #2

Closed
djzet wants to merge 3 commits into
mainfrom
sea
Closed

Sea#2
djzet wants to merge 3 commits into
mainfrom
sea

Conversation

@djzet

@djzet djzet commented Aug 20, 2026

Copy link
Copy Markdown
Owner

Summary by Sourcery

Add collaborative lobbies and shared map annotation tools while modernizing coordinate input, map interaction, and interface controls.

New Features:

  • Add collaborative Supabase-backed lobbies with shared points, weapon settings, player presence, cursors, and drawings.
  • Add map drawing tools for freehand lines, rulers, markers, erasing, and configurable stroke widths.
  • Display in-game cursor coordinates and support expanded 0–160 game-coordinate input ranges.
  • Introduce a reusable SVG icon sprite and replace interface emoji and inline icons with consistent controls.

Enhancements:

  • Improve map grid rendering, zoom limits, map navigation, responsive controls, and mobile safe-area handling.
  • Load application scripts with deferred execution and inject deployment credentials from GitHub Pages secrets.

CI:

  • Allow GitHub Pages deployments from both the main and sea branches.

Deployment:

  • Configure Supabase credentials during GitHub Pages artifact preparation while preserving placeholders for forks.

Documentation:

  • Update localized interface text and usage guidance for game-coordinate inputs, drawing tools, and lobby actions.

Chores:

  • Refresh native form-control theming and consolidate SVG icon styling across dark and light themes.

@sourcery-ai

sourcery-ai Bot commented Aug 20, 2026

Copy link
Copy Markdown

Reviewer's Guide

Adds collaborative Supabase-powered lobbies and drawing tools on the map, switches coordinates to game units (0–160), refactors interactions/rendering to support drawing/eraser/cursor display, and enhances the UI (icons, layout, script loading, mobile tweaks) plus a GitHub Pages workflow update with Supabase secret injection.

Sequence diagram for collaborative drawing in a Supabase lobby

sequenceDiagram
    actor User
    participant AppDraw
    participant AppLobby
    participant Supabase
    participant OtherClient
    participant MapRenderer

    User->>AppDraw: setTool("pen")
    User->>AppDraw: startStroke(px, py)
    User->>AppDraw: continueStroke(px, py)*
    User->>AppDraw: finishStroke()
    AppDraw->>AppLobby: sendDrawing(tool, color, points, width, label)
    AppLobby->>Supabase: insert into drawings
    Supabase-->>AppLobby: postgres_changes INSERT drawings
    AppLobby->>MapRenderer: onDrawing(stroke)
    AppLobby-->>OtherClient: onDrawing callback
    OtherClient->>MapRenderer: draw(view, MAP, ...)
Loading

File-Level Changes

Change Details Files
GitHub Pages workflow updated to support sea branch and inject Supabase credentials into lobby feature, with a slight deploy action change.
  • Trigger pushes on both main and sea branches instead of only main.
  • Add a step that reads SUPABASE_URL and SUPABASE_KEY secrets and replaces placeholders in js/features/lobby.js via sed, with logging depending on secret presence.
  • Update upload-pages-artifact path quoting and downgrade deploy-pages action from v5 to v4.
.github/workflows/static.yml
HTML structure and UI are extended with SVG icon sprite, drawing controls, lobby controls, cursor coordinates overlay, and deferred script loading including Supabase SDK and new feature modules.
  • Introduce an inline SVG sprite with reusable icons (pen, line, marker, eraser, pan, target, share, sun/moon, reset, mail, gamepad, link, logout, menu, help, etc.) and replace existing inline SVG paths / emoji labels with references.
  • Add drawing tools section with buttons for pen/line/marker/eraser/pan, line width selectors, and a Clear Drawings button tied to new JS logic.
  • Add lobby controls in map toolbar (create/join lobby, leave lobby in drawer), lobby info and players list section in drawer, and a cursor coordinates overlay div over the canvas.
  • Change coordinate inputs max from 100 to 160 and adjust clear buttons to use SVG icons; add Supabase SDK script and new JS modules (lobby.js, draw.js, weapons.js) and defer attribute to most script tags for performance.
  • Update help text to describe game coordinates (0–160) instead of percentage coordinates.
  • Add preconnect links for external resources and refine multiple buttons to use SVG icons instead of emoji/unicode chars.
index.html
Core utilities extended with game coordinate formatting helper for consistent conversion from meters to game units (0–160).
  • Add AppUtils.gameCoord(meters) to convert meters to game coordinates as meters/100 with fixed 2 decimal places.
  • Export gameCoord from AppUtils module alongside existing helpers.
js/core/utils.js
New drawing feature module implements pen/line/marker tools, eraser logic, local vs lobby-synchronized drawings, and clear functionality.
  • Define AppDraw with tool management (pen, line, marker, eraser, pan), line width management, and configuration for map size.
  • Implement stroke lifecycle: startStroke, continueStroke, finishStroke, cancelStroke, including marker label prompt and minimal point validation.
  • Implement eraseAt to remove only the current player’s strokes (local or Supabase lobby) around a screen-space radius and clearDrawings to clear local or lobby drawings (host-only in lobbies).
  • Expose getters for current tool, width, local drawings, current stroke, and drawing active state for renderer and interactions modules.
js/features/draw.js
New Supabase-based lobby feature added for realtime collaboration (shared points, weapon, drawings, cursors, and players list) with persistent state and visibility controls.
  • Configure Supabase client lazily using URL and key placeholders, with MAX_DRAWINGS and cursor throttle constants and a predefined player color palette.
  • Maintain lobby state (code, host flag, players map, drawings, hidden players set, connection status) and persist player ID in localStorage.
  • Implement create() to create a lobby record, insert host player, assign default name/color, subscribe to realtime; and join() to find lobby by code, assign unique color/name, load players and existing drawings, subscribe to realtime, and return initial point/weapon state.
  • Set up realtime channel with postgres_changes subscriptions for lobbies, players and drawings, plus broadcast cursors, updating local state and invoking callbacks (onRemoteState, onDrawing, onCursor, onPlayersChange, onInit).
  • Provide leave() to remove player, host cleanup for lobby/drawings/players, syncState() for host to push point/weapon changes, sendDrawing(), sendCursor(), clearDrawings(), deleteDrawing(id) (only own drawings), and player visibility toggling for rendering filters.
  • Expose getters (code, host/connected flags, players, drawings, my id/color/name) and callback setters for integration with UI and map logic.
js/features/lobby.js
Points and input handling changed from percentage-based (0–100) to game coordinates (0–160), with corresponding conversions and UI sync logic.
  • Update AppPoints.readPoint to interpret input fields as game coordinates (meters/100), clamping to map size-derived max, and convert back to meters for internal storage.
  • Adjust UIInputs.init to set min/max/step attributes on number inputs based on mapSize (e.g., 0–160, step 0.01).
  • Update UIInputs.sync to display coordinates using AppUtils.gameCoord instead of formatted percentage values.
js/features/points.js
js/ui/inputs.js
Main index bootstrap extended to configure drawing, integrate lobby callbacks, wire drawing UI controls, and adjust map interactions parameters.
  • Configure AppDraw with MAP.size and extend AppPoints.configure, UIPanels.init to accept renderMap/saveState for new features.
  • Wire AppLobby callbacks: onRemoteState to sync points and weapon and refresh UI, onDrawing/onCursor to re-render map, and onPlayersChange to re-render lobby players list via UIPanels.
  • Add event handlers for draw-tool and width-opt buttons to set tools/width and adjust canvas cursor, and for clearDrawingsBtn to clear drawings and rerender.
  • Update MapInteractions.handlePointerDown/Move/Up invocation to pass mapSize instead of MAP object and hook new drawing/erasing logic via options.
  • Add pointerleave handler to hide cursorCoords overlay and prevent middle-click autoscroll behavior.
js/index.js
Locales extended with strings for drawing tools, lobby, and updated coordinate help text, removing emoji from menu and contact labels.
  • In Russian (base) locale, add keys for drawTools, clearDrawings, markerPrompt, lineWidth, createLobby, joinLobby, leaveLobby, lobby, toolPen/toolLine/toolMarker/toolEraser/toolPan; adjust menuA/menuB/menuDel/contactLabel texts to remove emoji; and update helpP3 text to describe game coordinates (0–160).
  • Apply analogous additions/changes in other locale JSON files (en, de, es, fr, pl, ru, tr, uk, zh) for new features and updated coordinate description.
js/locales/index.js
js/locales/de.json
js/locales/en.json
js/locales/es.json
js/locales/fr.json
js/locales/pl.json
js/locales/ru.json
js/locales/tr.json
js/locales/uk.json
js/locales/zh.json
Map interactions module refactored to support drawing tools, eraser, cursor coordinate overlay, refined zoom limits, and cleaner public API.
  • Introduce MIN_SCALE/MAX_SCALE constants and use them for pinch and wheel zoom clamping; remove MAP dependency from options in favor of mapSize.
  • Enhance handlePointerDown to treat middle mouse button as pan-only, hide context menu, support eraser mode via AppDraw.eraseAt, and start drawing strokes for non-pan tools with coordinate conversion to percent space.
  • Update handlePointerMove to update cursorCoords overlay with game coordinates (using utils.gameCoord), implement continuous erasing and drawing updates via AppDraw, and use mapSize where MAP.size was previously referenced.
  • Update handlePointerUp to finalize erase/draw operations via AppDraw.finishStroke/cancelStroke and manage canvas cursor style based on current tool, simplifying tower selection code and removing isPinching/getDragging/isLongPressFired from the public API.
  • Ensure handleBlur cancels ongoing strokes via AppDraw and standardizes cursor resetting; wheel handler now uses MIN_SCALE/MAX_SCALE for scale clamping.
js/map/interactions.js
Map renderer enhanced with grid step logic tied to zoom, drawing rendering (pen/line/marker), and minor styling tweaks for grid and tower tooltips.
  • Adjust theme gridMinor colors slightly for dark/light themes, and introduce getTowerIconSize and getGridSteps with zoom-dependent grid scales (100–1000m major, 20–200m minor).
  • Implement helper getViewBox and new functions drawMinorGrid and drawGrid to render minor/major grid lines only within visible map area, with coordinate labels using fmtCoord and the configured STR strings.
  • Add drawing primitives: drawMarker, drawRuler (with distance label via fmtDist), drawPen, drawSingleStroke, drawDrawings, which render local or lobby drawings and preview current stroke, respecting player visibility from AppLobby.
  • Refactor main draw() to use new grid functions, render axes, dim outside-map area, border, zone, towers, drawings, and AB line, and export getGridSteps in addition to getThemeColors/getTowerIconSize/draw.
js/map/renderer.js
Panels UI extended to support lobby section and players visibility controls, and wired to AppLobby / AppShare / AppWeapons / AppPoints / UIResults / UIInputs, with init API expanded.
  • Add renderLobbyPlayers to build lobby section in drawer: shows lobby code, list of players with color, name, self indicator, and checkboxes to toggle visibility via AppLobby.togglePlayerVisibility/isPlayerVisible.
  • Update bind() to wire create/join/leave lobby buttons: createLobbyBtn calls AppLobby.create and shows toast via AppShare; joinLobbyBtn prompts for code, calls AppLobby.join, syncs points/weapon, updates UI and map, and shows success/error toasts; leaveLobbyBtn leaves lobby and rerenders players list.
  • Extend UIPanels.init return object and public API to include renderLobbyPlayers in addition to existing theme/towers/drawer/help methods.
js/ui/panels.js
CSS updated to support drawing tools, lobby section, cursor coordinate overlay, mobile layout tweaks, and number input spin button behavior with theme-aware native elements.
  • In base.css, add safe-area padding top/bottom, default svg vertical-align, specific sizing/margin for SVGs in draw-tool and view-reset buttons.
  • In map.css, style .cursor-coords box (positioning, typography, background, visibility toggling) and its inner spans as stacked lines.
  • In mobile.css, adjust drawer width, map-controls layout (gap, flex-wrap, max-width), and button sizing for view-reset, theme-toggle, help-toggle for better mobile ergonomics.
  • In panel.css, tune number input spin buttons appearance (inner visible, outer hidden), and add styles for draw tools grid, buttons, lobby section card, players list, line width selector controls (width-opt, w1/w2/w4 variants) and hover/active states.
  • In variables.css, set color-scheme: dark/light on :root/body.light for native elements (scrollbars, arrows) to match theme.
  • Add minor drawer / panel spacing tweaks where necessary.
styles/base.css
styles/map.css
styles/mobile.css
styles/panel.css
styles/variables.css

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey - I've found 6 security issues, 2 other issues, and left some high level feedback:

Security issues:

  • User controlled data in methods like innerHTML, outerHTML or document.write is an anti-pattern that can lead to XSS vulnerabilities (link)
  • User controlled data in a cursorCoords.innerHTML is an anti-pattern that can lead to XSS vulnerabilities (link)
  • User controlled data in methods like innerHTML, outerHTML or document.write is an anti-pattern that can lead to XSS vulnerabilities (link)
  • User controlled data in a info.innerHTML is an anti-pattern that can lead to XSS vulnerabilities (link)
  • User controlled data in methods like innerHTML, outerHTML or document.write is an anti-pattern that can lead to XSS vulnerabilities (link)
  • User controlled data in a row.innerHTML is an anti-pattern that can lead to XSS vulnerabilities (link)

General comments:

  • UIPanels now calls renderMap() inside lobby-related handlers, but renderMap isn’t defined or stored in the module scope; make sure init() accepts and saves renderMap (and any other callbacks like saveState) so those calls don’t fail at runtime.
  • The Supabase URL/KEY injection in the GitHub Pages workflow assumes js/features/lobby.js always exists and should be modified; consider guarding the sed calls (or the lobby feature itself) so forks or environments without Supabase credentials don’t hit runtime errors when AppLobby methods are invoked.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- UIPanels now calls renderMap() inside lobby-related handlers, but renderMap isn’t defined or stored in the module scope; make sure init() accepts and saves renderMap (and any other callbacks like saveState) so those calls don’t fail at runtime.
- The Supabase URL/KEY injection in the GitHub Pages workflow assumes js/features/lobby.js always exists and should be modified; consider guarding the sed calls (or the lobby feature itself) so forks or environments without Supabase credentials don’t hit runtime errors when AppLobby methods are invoked.

## Individual Comments

### Comment 1
<location path="js/ui/panels.js" line_range="103-112" />
<code_context>
+        // Lobby кнопки
</code_context>
<issue_to_address>
**issue (bug_risk):** The `bind` function references `renderMap` and other globals without them being wired into the UIPanels module.

In `bind`, you invoke `renderMap()` and use `AppPoints`, `AppWeapons`, `UIInputs`, `UIResults`, `AppShare`, and `AppLobby`. Inside the UIPanels closure, only `storage` and locals (`theme`, `showTowers`, `onChange`) are defined. `renderMap` is now passed into `UIPanels.init` from `index.js`, but `init` still appears to accept only a callback and does not persist `renderMap` or `saveState` for use in `bind`, so `renderMap` will be undefined when the lobby buttons are used.

Please update `UIPanels.init(opts)` to accept the options object, store `opts.renderMap` (and `opts.saveState` if needed) in module-level variables, and use those inside `bind`. If `renderMap` is meant to be global instead, attach it to `window` and reference `window.renderMap` explicitly.
</issue_to_address>

### Comment 2
<location path="js/features/draw.js" line_range="110-19" />
<code_context>
+  function cancelStroke() { isDrawing = false; currentStroke = null; }
+
+  // ─── Ластик: удаляет ТОЛЬКО свои штрихи (линии, линейки, метки) ───
+  function eraseAt(sx, sy, view) {
+    const connected = window.AppLobby && window.AppLobby.isConnected();
+    const strokes = connected ? window.AppLobby.getDrawings() : localDrawings;
+    const myId = connected ? window.AppLobby.getMyId() : 'local';
+    const R = 12; // радиус захвата в px
+    let removed = false;
+
+    for (let i = strokes.length - 1; i >= 0; i--) {
+      const st = strokes[i];
+      if (st.playerId !== myId) continue; // стираем только своё
+
+      let hit = false;
+      for (const p of st.points || []) {
+        const s = utils.worldToScreen(
+          utils.percentToMeters(p.x, mapSize),
+          utils.percentToMeters(p.y, mapSize),
+          view
+        );
+        if (Math.hypot(s.x - sx, s.y - sy) <= R) { hit = true; break; }
+      }
+
+      if (hit) {
</code_context>
<issue_to_address>
**suggestion (bug_risk):** Eraser hit detection ignores stroke width, which can make thick lines harder to erase consistently.

The eraser radius is fixed at `R = 12` px and doesn’t account for `stroke.width`, so thicker strokes occupy more visual area than the erase threshold, making erasing feel inconsistent.

Consider scaling `R` by `stroke.width` (e.g. `const R = 8 + 2 * (st.width || 1);`) or computing distance to the stroke segments instead of just sampled points to keep erasing behaviour consistent across different line thicknesses.

Suggested implementation:

```javascript
    const strokes = connected ? window.AppLobby.getDrawings() : localDrawings;
    const myId = connected ? window.AppLobby.getMyId() : 'local';
    const baseEraseRadius = 8; // базовый радиус захвата в px, масштабируется по толщине линии
    let removed = false;

```

```javascript
      const st = strokes[i];
      if (st.playerId !== myId) continue; // стираем только своё

      // масштабируем радиус стирания в зависимости от толщины штриха,
      // чтобы толстые линии стирались так же предсказуемо, как тонкие
      const strokeRadius = baseEraseRadius + 2 * (st.width || 1);

      let hit = false;
      for (const p of st.points || []) {
        const s = utils.worldToScreen(
          utils.percentToMeters(p.x, mapSize),
          utils.percentToMeters(p.y, mapSize),
          view
        );
        if (Math.hypot(s.x - sx, s.y - sy) <= strokeRadius) { hit = true; break; }
      }

```
</issue_to_address>

### Comment 3
<location path="js/map/interactions.js" line_range="138-140" />
<code_context>
            cursorCoords.innerHTML =
                `<span>x${utils.gameCoord(wpt.x)}</span>` +
                `<span>y${utils.gameCoord(wpt.y)}</span>`;
</code_context>
<issue_to_address>
**security (javascript.browser.security.insecure-document-method):** User controlled data in methods like `innerHTML`, `outerHTML` or `document.write` is an anti-pattern that can lead to XSS vulnerabilities

*Source: opengrep*
</issue_to_address>

### Comment 4
<location path="js/map/interactions.js" line_range="138-140" />
<code_context>
            cursorCoords.innerHTML =
                `<span>x${utils.gameCoord(wpt.x)}</span>` +
                `<span>y${utils.gameCoord(wpt.y)}</span>`;
</code_context>
<issue_to_address>
**security (javascript.browser.security.insecure-innerhtml):** User controlled data in a `cursorCoords.innerHTML` is an anti-pattern that can lead to XSS vulnerabilities

*Source: opengrep*
</issue_to_address>

### Comment 5
<location path="js/ui/panels.js" line_range="59" />
<code_context>
        info.innerHTML = `<span class="lobby-code">Код: <b>${code}</b></span>`;
</code_context>
<issue_to_address>
**security (javascript.browser.security.insecure-document-method):** User controlled data in methods like `innerHTML`, `outerHTML` or `document.write` is an anti-pattern that can lead to XSS vulnerabilities

*Source: opengrep*
</issue_to_address>

### Comment 6
<location path="js/ui/panels.js" line_range="59" />
<code_context>
        info.innerHTML = `<span class="lobby-code">Код: <b>${code}</b></span>`;
</code_context>
<issue_to_address>
**security (javascript.browser.security.insecure-innerhtml):** User controlled data in a `info.innerHTML` is an anti-pattern that can lead to XSS vulnerabilities

*Source: opengrep*
</issue_to_address>

### Comment 7
<location path="js/ui/panels.js" line_range="68-72" />
<code_context>
            row.innerHTML = `
      <span class="player-color" style="background:${p.color}"></span>
      <span class="player-name">${p.name} ${isMe ? '(вы)' : ''}</span>
      ${!isMe ? `<input type="checkbox" ${!isHidden ? 'checked' : ''} data-pid="${p.playerId}">` : ''}
    `;
</code_context>
<issue_to_address>
**security (javascript.browser.security.insecure-document-method):** User controlled data in methods like `innerHTML`, `outerHTML` or `document.write` is an anti-pattern that can lead to XSS vulnerabilities

*Source: opengrep*
</issue_to_address>

### Comment 8
<location path="js/ui/panels.js" line_range="68-72" />
<code_context>
            row.innerHTML = `
      <span class="player-color" style="background:${p.color}"></span>
      <span class="player-name">${p.name} ${isMe ? '(вы)' : ''}</span>
      ${!isMe ? `<input type="checkbox" ${!isHidden ? 'checked' : ''} data-pid="${p.playerId}">` : ''}
    `;
</code_context>
<issue_to_address>
**security (javascript.browser.security.insecure-innerhtml):** User controlled data in a `row.innerHTML` is an anti-pattern that can lead to XSS vulnerabilities

*Source: opengrep*
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

Comment thread js/ui/panels.js
Comment on lines +103 to +112
// Lobby кнопки
document.getElementById('createLobbyBtn').addEventListener('click', async () => {
const code = await AppLobby.create(AppPoints.getA(), AppPoints.getB(), AppWeapons.get());
if (code) {
AppShare.showToast(`Лобби создано: ${code}`, 'success');
renderLobbyPlayers();
}
});

document.getElementById('joinLobbyBtn').addEventListener('click', () => {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

issue (bug_risk): The bind function references renderMap and other globals without them being wired into the UIPanels module.

In bind, you invoke renderMap() and use AppPoints, AppWeapons, UIInputs, UIResults, AppShare, and AppLobby. Inside the UIPanels closure, only storage and locals (theme, showTowers, onChange) are defined. renderMap is now passed into UIPanels.init from index.js, but init still appears to accept only a callback and does not persist renderMap or saveState for use in bind, so renderMap will be undefined when the lobby buttons are used.

Please update UIPanels.init(opts) to accept the options object, store opts.renderMap (and opts.saveState if needed) in module-level variables, and use those inside bind. If renderMap is meant to be global instead, attach it to window and reference window.renderMap explicitly.

Comment thread js/features/draw.js
document.querySelectorAll('.draw-tool').forEach(btn => {
btn.classList.toggle('active', btn.dataset.tool === tool);
});
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion (bug_risk): Eraser hit detection ignores stroke width, which can make thick lines harder to erase consistently.

The eraser radius is fixed at R = 12 px and doesn’t account for stroke.width, so thicker strokes occupy more visual area than the erase threshold, making erasing feel inconsistent.

Consider scaling R by stroke.width (e.g. const R = 8 + 2 * (st.width || 1);) or computing distance to the stroke segments instead of just sampled points to keep erasing behaviour consistent across different line thicknesses.

Suggested implementation:

    const strokes = connected ? window.AppLobby.getDrawings() : localDrawings;
    const myId = connected ? window.AppLobby.getMyId() : 'local';
    const baseEraseRadius = 8; // базовый радиус захвата в px, масштабируется по толщине линии
    let removed = false;
      const st = strokes[i];
      if (st.playerId !== myId) continue; // стираем только своё

      // масштабируем радиус стирания в зависимости от толщины штриха,
      // чтобы толстые линии стирались так же предсказуемо, как тонкие
      const strokeRadius = baseEraseRadius + 2 * (st.width || 1);

      let hit = false;
      for (const p of st.points || []) {
        const s = utils.worldToScreen(
          utils.percentToMeters(p.x, mapSize),
          utils.percentToMeters(p.y, mapSize),
          view
        );
        if (Math.hypot(s.x - sx, s.y - sy) <= strokeRadius) { hit = true; break; }
      }

Comment thread js/map/interactions.js
Comment on lines +138 to +140
cursorCoords.innerHTML =
`<span>x${utils.gameCoord(wpt.x)}</span>` +
`<span>y${utils.gameCoord(wpt.y)}</span>`;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

security (javascript.browser.security.insecure-document-method): User controlled data in methods like innerHTML, outerHTML or document.write is an anti-pattern that can lead to XSS vulnerabilities

Source: opengrep

Comment thread js/map/interactions.js
Comment on lines +138 to +140
cursorCoords.innerHTML =
`<span>x${utils.gameCoord(wpt.x)}</span>` +
`<span>y${utils.gameCoord(wpt.y)}</span>`;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

security (javascript.browser.security.insecure-innerhtml): User controlled data in a cursorCoords.innerHTML is an anti-pattern that can lead to XSS vulnerabilities

Source: opengrep

Comment thread js/ui/panels.js
const players = window.AppLobby.getPlayers();
const myId = window.AppLobby.getMyId();

info.innerHTML = `<span class="lobby-code">Код: <b>${code}</b></span>`;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

security (javascript.browser.security.insecure-document-method): User controlled data in methods like innerHTML, outerHTML or document.write is an anti-pattern that can lead to XSS vulnerabilities

Source: opengrep

Comment thread js/ui/panels.js
const players = window.AppLobby.getPlayers();
const myId = window.AppLobby.getMyId();

info.innerHTML = `<span class="lobby-code">Код: <b>${code}</b></span>`;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

security (javascript.browser.security.insecure-innerhtml): User controlled data in a info.innerHTML is an anti-pattern that can lead to XSS vulnerabilities

Source: opengrep

Comment thread js/ui/panels.js
Comment on lines +68 to +72
row.innerHTML = `
<span class="player-color" style="background:${p.color}"></span>
<span class="player-name">${p.name} ${isMe ? '(вы)' : ''}</span>
${!isMe ? `<input type="checkbox" ${!isHidden ? 'checked' : ''} data-pid="${p.playerId}">` : ''}
`;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

security (javascript.browser.security.insecure-document-method): User controlled data in methods like innerHTML, outerHTML or document.write is an anti-pattern that can lead to XSS vulnerabilities

Source: opengrep

Comment thread js/ui/panels.js
Comment on lines +68 to +72
row.innerHTML = `
<span class="player-color" style="background:${p.color}"></span>
<span class="player-name">${p.name} ${isMe ? '(вы)' : ''}</span>
${!isMe ? `<input type="checkbox" ${!isHidden ? 'checked' : ''} data-pid="${p.playerId}">` : ''}
`;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

security (javascript.browser.security.insecure-innerhtml): User controlled data in a row.innerHTML is an anti-pattern that can lead to XSS vulnerabilities

Source: opengrep

@djzet djzet closed this Aug 20, 2026
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