{"_id":"@borellion/beacon","_rev":"3-55de19d5215d61198a5c01d62f863997","name":"@borellion/beacon","dist-tags":{"latest":"0.0.21"},"versions":{"0.0.19":{"name":"@borellion/beacon","version":"0.0.19","keywords":[],"author":{"name":"Borellion"},"license":"MIT","_id":"@borellion/beacon@0.0.19","maintainers":[{"name":"limbofeather","email":"elijah@zesty.xyz"}],"dist":{"shasum":"48d4483f76a24372b0bcd6b5839c0d270b12e99f","tarball":"https://registry.npmjs.org/@borellion/beacon/-/beacon-0.0.19.tgz","fileCount":5,"integrity":"sha512-Fyv0RP8WMjlxbGW90LrevZOGYVrsjvviXCx/WHFJYa9IunPUWMfl+SltJuTDr7WzNe5sfkjHOKn6GckCak3Wgg==","signatures":[{"sig":"MEQCIHGuCG0K/F/7a61BJ4qu7ycfRJtr1lgWFnArDPeL4w//AiBNGFzfY4HtgHRnSrJh360IDkEfl7XTX1DSr+wLJrOOVA==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":21395},"main":"index.js","type":"module","gitHead":"4f59c9dbf76e73a4a16902423e0e228df8ad5f29","scripts":{"test":"echo \"Error: no test specified\" && exit 1"},"_npmUser":{"name":"limbofeather","email":"elijah@zesty.xyz"},"_npmVersion":"11.4.2","description":"Connect your world to the open web","directories":{},"_nodeVersion":"24.3.0","_hasShrinkwrap":false,"_npmOperationalInternal":{"tmp":"tmp/beacon_0.0.19_1778690326064_0.020723139891024367","host":"s3://npm-registry-packages-npm-production"}},"0.0.20":{"name":"@borellion/beacon","version":"0.0.20","keywords":[],"author":{"name":"Borellion"},"license":"MIT","_id":"@borellion/beacon@0.0.20","maintainers":[{"name":"limbofeather","email":"elijah@borellion.com"}],"dist":{"shasum":"0eb0afb4b224c2fe427569846bad3242920aa887","tarball":"https://registry.npmjs.org/@borellion/beacon/-/beacon-0.0.20.tgz","fileCount":5,"integrity":"sha512-Gm3ldOepV4CakISMksj3NS/iXUn92ilu0oo6gVsJLCwXWAQFGKSfdCCD9aKTUr0c7H7qX2JDPk7B85JWYNwO7g==","signatures":[{"sig":"MEUCIQDX5TEAXcESjspQTu4hKoiNEaM4E3Uc0irwEP4L58KMkQIgTJ9snYc4vh+HAQRkP/0kkPw3PDXHabf2KXlrjrBl35k=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":21410},"main":"index.js","type":"module","gitHead":"b44956f72e63dec0b7a73d7826523c4ebe7aee84","scripts":{"test":"echo \"Error: no test specified\" && exit 1"},"_npmUser":{"name":"limbofeather","email":"elijah@borellion.com"},"_npmVersion":"11.4.2","description":"Connect your world to the open web","directories":{},"_nodeVersion":"24.3.0","_hasShrinkwrap":false,"_npmOperationalInternal":{"tmp":"tmp/beacon_0.0.20_1783052942281_0.09940399806942768","host":"s3://npm-registry-packages-npm-production"}},"0.0.21":{"name":"@borellion/beacon","version":"0.0.21","main":"index.js","scripts":{"test":"echo \"Error: no test specified\" && exit 1"},"keywords":[],"author":{"name":"Borellion"},"license":"MIT","description":"Connect your world to the open web","type":"module","_id":"@borellion/beacon@0.0.21","gitHead":"b7ee385f7db8ce2007c2f4ef67fcf9c2629e7c41","_nodeVersion":"24.3.0","_npmVersion":"11.4.2","dist":{"integrity":"sha512-3JP8vxj1zwRzitwi+1HdJpnCRKvpZURkJV1AINp1EtkeXLeSPc3A8yWii/8FNRRlcpUqmBpNM/k6Wq4Hcs5CaA==","shasum":"8a63d34a45821a8bff45daa86218224e28826179","tarball":"https://registry.npmjs.org/@borellion/beacon/-/beacon-0.0.21.tgz","fileCount":5,"unpackedSize":22627,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIHrSvJFHp8WgkzTHGElrjaO1BDsIjkCytTWY/wF9VHQgAiEAun45JKhzn8Lv2a62cckigC7qSVv2zJ0HSAN7pGv6p4E="}]},"_npmUser":{"name":"limbofeather","email":"elijah@borellion.com"},"directories":{},"maintainers":[{"name":"limbofeather","email":"elijah@borellion.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/beacon_0.0.21_1783053359907_0.8472888873656526"},"_hasShrinkwrap":false}},"time":{"created":"2026-05-13T16:38:45.998Z","modified":"2026-07-03T04:36:00.228Z","0.0.19":"2026-05-13T16:38:46.325Z","0.0.20":"2026-07-03T04:29:02.442Z","0.0.21":"2026-07-03T04:36:00.053Z"},"author":{"name":"Borellion"},"license":"MIT","keywords":[],"description":"Connect your world to the open web","maintainers":[{"name":"limbofeather","email":"elijah@borellion.com"}],"readme":"# Beacon\n\nA JavaScript library for registering spatial web experiences with [Relay](https://github.com/borellion/relay) servers. Part of the Distributed Spatial Internet Graph (DSIG).\n\n## What is a Beacon?\n\nBeacons allow 3D/spatial web applications to announce themselves to Relay discovery servers. When you add a beacon to your app:\n\n1. Your world gets indexed on the relay for discovery\n2. Active user sessions are tracked in real-time\n3. Your world appears in the relay's directory for others to find\n\n## Installation\n\n### NPM\n\n```bash\nnpm install @borellion/beacon\n```\n\n```js\nimport Beacon from '@borellion/beacon';\n```\n\n### CDN\n\n```js\nimport Beacon from \"https://cdn.jsdelivr.net/npm/@borellion/beacon/index.js\";\n```\n\n## Quick Start\n\n```js\nimport Beacon from '@borellion/beacon';\n\nconst beacon = new Beacon(\"https://relay.borellion.com\");\nawait beacon.signal();\n```\n\nThat's it! Your world will be registered with the relay and appear in its directory.\n\n## HTML Meta Tags\n\nThe beacon automatically reads metadata from your page's `<head>`. Add these meta tags for best results:\n\n```html\n<head>\n  <!-- Required -->\n  <meta name=\"application-name\" content=\"My Awesome World\">\n  <meta name=\"description\" content=\"An immersive 3D experience\">\n\n  <!-- Recommended -->\n  <meta property=\"og:url\" content=\"https://myworld.example.com\">\n  <meta property=\"og:image\" content=\"https://myworld.example.com/preview.png\">\n  <meta name=\"keywords\" content=\"vr,game,multiplayer,adventure\">\n\n  <!-- Optional: Mark as adult content -->\n  <meta name=\"rating\" content=\"adult\">\n\n  <!-- Optional: Owner verification (see below) -->\n  <meta name=\"borellion-verify\" content=\"your-verification-code\">\n</head>\n```\n\n### Meta Tag Priority\n\n| Data | Primary Source | Fallback |\n|------|---------------|----------|\n| Name | `application-name` | `document.title` |\n| Description | `description` | `og:description` |\n| URL | `og:url` | `document.location` |\n| Image | `og:image` | A-Frame screenshot → Canvas capture → None |\n| Tags | `keywords` | Empty string |\n| Adult | `rating=\"adult\"` | `false` |\n\n## Configuration Options\n\nYou can override auto-detected values by passing options to the constructor:\n\n```js\nconst beacon = new Beacon(\"https://relay.borellion.com\", {\n  name: \"Custom World Name\",\n  description: \"Custom description\",\n  url: \"https://custom-url.example.com\",\n  image: \"https://example.com/custom-preview.png\",\n  tags: \"custom,tags,here\",\n  stripQueryParams: true  // Remove query params from URL (default: true)\n});\n\nawait beacon.signal();\n```\n\n### BeaconOverride Options\n\n| Option | Type | Description |\n|--------|------|-------------|\n| `name` | string | Override the world name |\n| `description` | string | Override the description |\n| `url` | string | Override the canonical URL |\n| `image` | string | Override the preview image URL |\n| `tags` | string | Override tags (comma-separated) |\n| `stripQueryParams` | boolean | Strip query params from auto-detected URL (default: `true`) |\n\n## How It Works\n\n### Registration\n\nWhen you call `beacon.signal()`, it sends a `PUT` request to the relay's `/beacon` endpoint with your world's metadata:\n\n```json\n{\n  \"url\": \"https://myworld.example.com\",\n  \"name\": \"My Awesome World\",\n  \"description\": \"An immersive 3D experience\",\n  \"image\": \"https://myworld.example.com/preview.png\",\n  \"tags\": \"vr,game,multiplayer\",\n  \"adult\": false,\n  \"active\": true\n}\n```\n\n### Session Heartbeats\n\nAfter registration, the beacon automatically sends heartbeat signals every 5 seconds to track active sessions:\n\n```json\n{\n  \"session_id\": \"uuid-v4\",\n  \"url\": \"https://myworld.example.com\",\n  \"timestamp\": 1234567890123\n}\n```\n\nThis enables real-time \"users online\" tracking on the relay.\n\n## Owner Verification\n\nAfter your world is indexed, you can verify ownership to edit its details on the relay:\n\n1. Visit your world's edit page on the relay (e.g., `https://relay.borellion.com/world/my-world/edit`)\n2. Click \"Get Verification Code\" to receive a unique code\n3. Add the verification meta tag to your site's `<head>`:\n   ```html\n   <meta name=\"borellion-verify\" content=\"your-code-here\">\n   ```\n4. Click \"Verify Ownership\" on the relay\n5. Once verified, you can edit: name, description, image URL, tags, and adult flag\n\nVerification grants a session cookie valid for 7 days.\n\n## Iframe Support\n\nIf your world runs inside an iframe, the beacon will attempt to read meta tags from the parent document (same-origin only). For cross-origin iframes, use the override options to specify metadata directly.\n\n## A-Frame Integration\n\nFor A-Frame scenes without an `og:image` meta tag, the beacon will automatically capture a screenshot using A-Frame's built-in screenshot component as a fallback.\n\n## Example: Full Integration\n\n```html\n<!DOCTYPE html>\n<html>\n<head>\n  <meta name=\"application-name\" content=\"Space Explorer VR\">\n  <meta name=\"description\" content=\"Explore the cosmos in virtual reality\">\n  <meta property=\"og:url\" content=\"https://space-explorer.example.com\">\n  <meta property=\"og:image\" content=\"https://space-explorer.example.com/preview.jpg\">\n  <meta name=\"keywords\" content=\"vr,space,exploration,multiplayer\">\n</head>\n<body>\n  <!-- Your 3D content here -->\n\n  <script type=\"module\">\n    import Beacon from \"https://cdn.jsdelivr.net/npm/@borellion/beacon/index.js\";\n\n    const beacon = new Beacon(\"https://relay.borellion.com\");\n    await beacon.signal();\n\n    console.log(\"World registered with relay!\");\n  </script>\n</body>\n</html>\n```\n\n## Related\n\n- [Relay](https://github.com/borellion/relay) - The discovery server that indexes worlds\n- [DSIG Documentation](https://docs.borellion.com/graph/overview) - Learn more about the Distributed Spatial Internet Graph\n\n## License\n\nMIT\n","readmeFilename":"README.md"}