# ARC Community Map — Discord Activity package

This is a separate, static upload package for running the community map inside Discord. The website-only ZIP remains independent. The Activity includes all maps, icons, filtering, multiple blueprint selection, level switching, pin details, and adjustable filtered-discovery heatmaps. It preserves the newest fully valid, nonempty submission per player and rejects blank or corrupted replacements.

Hovering over overlapping discoveries expands only their clickable text labels. All map dots remain at their saved locations, with matching colored lines meeting the labels. Counted labels let viewers choose among multiple discoveries of the same blueprint.

The bottom list merges all reports of the same blueprint into one card with its count for the current filters and level. Clicking a card with multiple discoveries fits every matching marker and highlighted name label into the map. Bright outlines make the markers stand out, and the overview stays clear of the details popup. Click a marker to view its details while keeping the other highlights. Single-discovery cards zoom directly to their marker and details. Selecting a card reveals pins if disabled, and the pins toggle remains available afterward. Selected groups refit when the viewport changes. Grouped cards show player counts and best quality; Show more adds blueprint cards without limiting locations within a blueprint. Repeat reports count once when they have the same player, blueprint and level, are within 60 seconds, and are within 0.002 in normalized map coordinates (0.2% of the map). The highest-quality report is kept, with the earliest winning quality ties. Groups compare against their first report to avoid merging chains of separate finds. Counts, pins and heatmaps all use this cleaned data; the Sheet remains unchanged.

Chevrons above the bottom blueprint list and on the vertical divider between the map and “Find your next blueprint” section collapse or expand those panels independently. The map grows into the available Activity width and height when they are collapsed, and current filters remain applied. On mobile, open Filters to reach the filter section's chevron.

The lower chevron hides when collapsing the list cannot enlarge the displayed map at the current Activity size. Resizing into that condition reopens the list before hiding its control. Transparent icon backgrounds keep the divider lines visible.

In large Activity views, the blueprint list and attribution note stay together at the bottom while the map fills the available height above them. Longer lists stay scrollable in the normal page flow.

## Quick setup

1. Create an application in the [Discord Developer Portal](https://discord.com/developers/applications). Give it a community-facing name and copy its **Application ID** (a public value).
2. Extract this ZIP. Serve the entire `discord-activity` folder from a public **HTTPS** website. No Node.js runtime, bot process, Discord client secret, or Google API key is needed on the host.
3. Open the hosted `setup.html`. Enter the Application ID and your hosted folder URL. Download `activity-config.json`, replace the copy in the extracted folder, and upload the replacement. Alternatively edit the JSON file manually. The source default is deliberately blank, not a fabricated Application ID.
4. In the Portal under **Activities → Settings**, enable Activities. In **Activities → URL Mappings**, add the following mappings. The root target must include the uploaded folder path when using a subfolder, without `https://` or `index.html`:

   | Prefix | Target |
   | --- | --- |
   | `/` | `YOUR_WEBSITE/discord-activity` |
   | `/sheets` | `docs.google.com` |

5. Keep the default **Launch** entry point with Discord's default Activity handler. No custom interaction server is required. Configure installation contexts and use the Portal's generated install link for the intended account/server. For development, enable Discord Developer Mode and launch from the App Launcher in a text or voice channel using the application owner or team account. Portal requirements control tester and public availability; complete them before expecting all members to see the app. See [Discord's Activity setup guide](https://docs.discord.com/developers/activities/building-an-activity) and [entry point guidance](https://docs.discord.com/developers/activities/development-guides/user-actions).
6. Test the real hosted Activity in Discord. Enable iOS/Android support in the Portal when needed and test on those clients; desktop/browser support is the default.

Opening `index.html` in an ordinary browser provides a preview without attempting a Discord handshake. Discord launches the map directly; hosting instructions stay on the separate `setup.html`. Upload this package to its own folder, separate from the website-map ZIP.

## Editable settings

`activity-config.json` is a plain-text settings file included in the upload package. Both values start blank:

```json
{
  "applicationId": "",
  "hostingUrl": ""
}
```

Set `applicationId` to your public Discord Application ID, keeping the quotation marks. Set `hostingUrl` to the full HTTPS address of the uploaded folder. Use `setup.html` to edit both values and download a replacement file without rebuilding. The form also reloads saved values from the uploaded file. Upload the replacement and relaunch the Activity after a change. The hosting address is used by the setup form to show the root mapping; you must update Discord's URL Mappings separately when moving hosts. Existing settings containing only `applicationId` continue to work. Do not store private credentials in this file.

## Connection and public data

The official `@discord/embedded-app-sdk` is bundled locally. The Activity waits for Discord's `READY` handshake before loading the map. It requests no identity or guild access, performs no OAuth exchange, and does not associate Discord accounts with submitted game names. External links use Discord's `openExternalLink` confirmation flow. Each viewer has independent filters; this is not a shared multiplayer map session.

All Activity traffic must remain behind the [Discord networking proxy](https://docs.discord.com/developers/activities/development-guides/networking). The published Google CSV redirects to a variable googleusercontent.com host. To keep this browser-only, the Activity reads the **same published sheet/tab** using Google's non-redirecting `pubhtml/sheet` table endpoint through `/.proxy/sheets/...`, then converts the table to CSV in an inert document and applies the same snapshot validation. This needs only the `/sheets → docs.google.com` mapping. No HTML from the Sheet is inserted into the map. Ordinary-browser preview uses the original CSV URL directly.

The public data loads once each time the Activity opens or reloads. It does not refresh on a timer. Browser storage is optional and uses a separate Activity cache key. When the feed is unavailable, blank, or entirely invalid, the last successfully cached public data remains visible with its timestamp and warning. Malformed/empty snapshots and snapshots containing any invalid discovery are rejected; the latest prior good submission still in the Sheet remains eligible. Older Sheet rows are never deleted or changed. No private tracker data or screenshots are read.

## Hosting requirements

Keep the package's folder structure. Serve HTML, JavaScript, CSS, and JSON with their proper content types. Upload **all** generated files for each update. JavaScript, CSS, catalog metadata, maps, and icons use content-derived filenames so updated content bypasses Discord proxy caches. `activity-config.json` remains editable after building and is requested with a unique query and `cache: no-store`.

Do not block embedding with `X-Frame-Options: DENY` or `SAMEORIGIN`. If your host sends Content Security Policy headers, allow framing by the Discord clients you support (`https://discord.com`, `https://*.discord.com`, `https://discordapp.com`, and `https://*.discordapp.com`). The Activity only needs its own scripts, images, styles, and network origin inside Discord; its positioning uses style attributes. Browser preview additionally needs direct Google Sheet connections. HTTPS or localhost is required for secure browser features used by the SDK. See [Discord production readiness](https://docs.discord.com/developers/activities/development-guides/production-readiness) and [mobile guidance](https://docs.discord.com/developers/activities/development-guides/mobile).

## Troubleshooting

- **Application ID missing:** update the hosted `activity-config.json` using the setup page. Never put a client secret or bot token in it.
- **Connecting to Discord / connection timeout:** launch from Discord's App Launcher; confirm the Application ID belongs to the registered app, check its root URL mapping, and relaunch. A browser preview cannot establish a real Discord session.
- **Map assets missing:** check the complete upload, root mapping's subfolder path, and correct content types.
- **Community data unavailable:** check `/sheets → docs.google.com`, published Sheet permissions, and the Activity's network requests. The expected request is `/.proxy/sheets/spreadsheets/d/e/.../pubhtml/sheet?gid=929643861&headers=false`. The client intentionally does not retry on a timer; relaunch after fixing settings.
- **Members cannot find the app:** check installation contexts, the Launch entry point, development-team/test access, and Discord's distribution requirements.
- **External link will not open:** relaunch and try again; Discord controls its confirmation dialog.

## Build from this repository

Run `npm ci --ignore-scripts` in `discord-activity`, then run `Build-Discord-Activity.ps1` from the project root (or `npm run build` to generate the folder without a ZIP). Build dependencies are separate from the tracker. The build reuses current website-map source and assets without modifying its JavaScript. It emits `dist/discord-activity` and `dist/arc-discord-activity.zip`. Configure `discord-activity/activity-config.json` before building if you want your public Application ID included; configuring the generated upload later also works.

## Verification and credits

Automated checks cover settings validation, the real official SDK's READY exchange with a simulated parent, mapped Sheet requests under a restrictive browser policy, browser preview, invalid submission retention, links via Discord commands, setup downloads, and responsive layout. A **real Discord launch remains required** after registering and hosting your application; the test harness does not certify Discord's proxy or distribution settings.

Unofficial ARC Raiders community project; not affiliated with Embark Studios. Maps by @Cartotect / [ARC Raiders Wiki](https://arcraiders.wiki/wiki/Category:Map_overview_images); see `maps/ATTRIBUTION.md`. Item icons sourced from the [MetaForge blueprint tracker](https://metaforge.app/arc-raiders/blueprint-tracker). Game and item artwork © Embark Studios. Rarity rationale is in `RARITY.md`. Third-party JavaScript license texts are in `LICENSES.txt`; bundle dependency versions are recorded in `build-info.json`.

## Optional project support and reuse

The Designi footer provides optional project support. Donations never unlock features,
licenses, or source access. External hosting requires separate written permission;
keep the visible Designi credit and support link. See the included REUSE-LICENSE.txt
(or LICENSE.md in the tracker source package). Authorized site owners use register.html
(or public/register.html in the tracker package). Registration is owner initiated,
with no visitor reports or automatic check-ins. Blank settings leave online donations
and registration unconfigured while the map remains available. The source project's
public/support-config.json is copied into builds; rebuild after changing it.
