# EO-Map native embed (machine-readable) This is the public contract for putting EO-Map on a third-party page WITHOUT an iframe. Human demo: https://eo-map.com/embed-guide?integration=native Iframe contract (unchanged): https://eo-map.com/embed-guide.txt Feature overview: https://eo-map.com/embed-map/ If you are an LLM, implement from this file. Do not scrape the React app. Product: EO-Map, a free 3D map of EVE Online (New Eden). Canonical site: https://eo-map.com/ This is a genuine in-page integration. The map's canvas, labels and Open on EO-Map control live in the host document inside a shadow root. It is not an iframe with a wrapper around it. ## Script https://eo-map.com/embed/v1.js ES module. Pin that URL for v1. /embed.js is the moving latest of the same major and retargets the hashed graph on each deploy. Do not scrape index.html for chunk names. Do not webpack, Vite-bundle or copy the loader into your own origin. Types: https://eo-map.com/embed/v1.d.ts A classic non-module Jita is 30000142. Amarr is 30002187. Rens is 30002510. Useful single-system zoom is 50. Security-status colouring is the default. Performance mode is on unless you set performance="0". Open on EO-Map appears on the map and must stay. ## Factory API import { EOMap } from 'https://eo-map.com/embed/v1.js'; const map = EOMap.mount(document.getElementById('map'), { system: 30000142, zoom: 50 }); window.EOMap is the factory ({ version, tag, events, mount, define }), not a mounted map. window.EOMap.select is not a method. After a side-effect import, call window.EOMap.mount(el, opts) to get a handle. map.on('eo-ready', () => { /* enable host UI */ }); map.on('eo-selected', (event) => { const { systemId, name } = event.detail; }); map.select(30002187, { zoom: 50, highlight: true }); map.flash(30002187, { kind: 'kill' }); map.highlight([30000142, 30000144]); map.setZoom(40); map.setAngle(22); map.enterSolar(30000142); map.showUniverse(); map.destroy(); Custom element methods: select, highlight, flash, setZoom, setAngle, enterSolar, showUniverse, destroy, focusSystem. The factory handle also has on/off and focus (focus is an alias of focusSystem; do not call HTMLElement.focus and expect the camera to move). On , call focusSystem, not focus. Convenience: map.focus(id, { zoom, highlight, flash }) or el.focusSystem(id, ...) is select + optional highlight + optional flash. Use that for a kill-feed "go there". Do not name a method follow; Follow Me is a full-app SSO feature and is off here. Attributes and mount options are INITIAL STATE only. Changing the system attribute later does nothing. Call select / highlight / flash. ## Kill feed example
flash kind: kill (red, default) | capital (kill bloom plus the capital shock-ring) | positive (green) | accent (theme orange) | neutral (white). Unknown kinds fall back to kill. color: optional '#rrggbb' override of the kind palette. value: optional ISK loss on kind=capital (alias isk). Finite, non-negative, capped at 1e12. Drives the Battle Replay capital shock-ring size. Omitted value uses the default ring; supplied ISK scales it, never past 420px. Native: map.flash(id, { kind: 'capital', value: 4790000000 }) Iframe: { type: 'ef-map-flash', systemId, kind: 'capital', value: 4790000000 } Native does not accept postMessage. Drive it with methods. Do not listen for ef-map-* on window. ## Mount options (initial state) Same information as the iframe URL contract, as a JS object. system numeric CCP SDE id. Selects and centres. systems number[] accent rings. Nearby sets read better than map-wide. q exact system name, resolved then dropped. zoom 0.25-300. Omit = wide 165. Useful single-system: 50. angle -90..90. Omit = top-down north-up. 0 is edge-on. layout '2d' or '3d'. Default 3d. Does not write the visitor's prefs. coloring 'security' or 'off'. Default security unless color is set. color cinematic tint: blue, green, purple, red, yellow, white, random, realistic. NOT security colouring. realistic implies details: true (~21 MB). Named tints need orbit: true. orbit true to auto-orbit. Pointer interaction stops it. performance default TRUE for native. false opts into bloom/backdrop. details true loads Contract B (~21 MB) on a galaxy embed. fit true frames highlighted/linked systems. links 'A-B:green,...' or [{ from, to, color }]. Max 50. labels { '30000142': 'HQ' }. Factory JS only, not an HTML attribute. labelMode hover|always|off. mode cinematic or icon, for a solar first view. routing { from, to, jumpRange: 1, routeLabels? } gate-only route. Native constructs the routing worker via a blob URL when the host origin cannot new Worker() a cross-origin module. ## Events eo-ready { type: 'ef-map-ready', systemsLoaded: true } once, after the universe map and scene are up. Listen for the event NAME eo-ready, not detail.type. eo-selected { type: 'ef-map-selected', systemId, name } after each successful focus, including the initial system. eo-error { code, message } already-mounted | load-failed A 0-height box does not error; it paints black. Give the host a height. Listen with map.on('eo-ready', handler) or element.addEventListener. ## How it relates to the iframe URL params are mount options. postMessage verbs are methods. iframe ef-map-navigate -> map.select(id, { zoom }) iframe ef-map-highlight -> map.highlight(ids) iframe ef-map-flash -> map.flash(id, { kind, color }) iframe ef-map-zoom -> map.setZoom iframe ef-map-angle -> map.setAngle iframe ef-map-enter-system -> map.enterSolar iframe ef-map-show-universe -> map.showUniverse iframe ef-map-ready / selected -> eo-ready / eo-selected events Native does not accept postMessage and does not emit ef-map-* on the host window. Drive it with methods on the element or the factory handle. The iframe remains the isolation product (own process, own CSS, own WebGL context). Prefer the iframe when the host page has a strict CSP, several maps, or you do not want EO-Map's JS on the host origin. Prefer native when the host wants to drive the map from the same JS heap with no postMessage. Wire names stay ef-map-* on the iframe. Native uses eo-map / EOMap. ## Constraints One native map per page. A second EOMap.mount throws. A second in HTML fires eo-error already-mounted and does not mount. Use the iframe if you need more than one. The host element must have a non-zero height. Default height is 450px. A 0-height flex child produces a black canvas. Do not remount to change system. Call select / highlight / flash. Call destroy() on SPA route changes. Factory destroy() also removes the it created. destroy() on a still-connected you put in HTML yourself tears down WebGL and leaves a dead host; remove the node (or factory-mount again) to come back. Moving the node remounts the whole WebGL graph. Assets (universe DB, fonts, hashed JS, wasm) load from the EO-Map origin, not from the host. IndexedDB cache of the universe DB lives on the host origin. Pref writes that would pollute the host store are skipped where the iframe already skipped them; do not rely on efmap:prefs on the host. Live-events WebSocket does not connect. EVE SSO does not run. No GA tag is injected into the host page. Open on EO-Map stays visible. Cross-origin `new Worker('https://eo-map.com/…')` is a browser SecurityError. The native loader fetches the worker script (CORS), rewrites relative imports to absolute EO URLs, and starts it from a blob: URL. Host CSP needs worker-src blob: (and https://eo-map.com). If that is forbidden, use the iframe embed for routing. Host CSP needs at least: script-src https://eo-map.com connect-src https://eo-map.com https://snapshots.eo-map.com worker-src blob: https://eo-map.com style-src https://eo-map.com 'unsafe-inline' font-src https://eo-map.com img-src https://eo-map.com data: blob: Version: 1. Tag: eo-map. Script path: /embed/v1.js (pin). Moving latest: https://eo-map.com/embed.js (tracks v1). Types: https://eo-map.com/embed/v1.d.ts. Human showcase: https://eo-map.com/embed-guide?integration=native