@galihru/orbinexsim 0.1.0 → 0.1.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -21
- package/README.md +373 -46
- package/dist/ar-runtime.cjs +526 -0
- package/dist/ar-runtime.d.cts +100 -0
- package/dist/ar-runtime.d.ts +100 -0
- package/dist/ar-runtime.js +28 -0
- package/dist/chunk-JF7PGQOV.js +491 -0
- package/dist/index.cjs +514 -11
- package/dist/index.d.cts +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +29 -2
- package/package.json +60 -55
package/dist/index.cjs
CHANGED
|
@@ -21,15 +21,506 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
21
21
|
var index_exports = {};
|
|
22
22
|
__export(index_exports, {
|
|
23
23
|
OrbinexSim: () => OrbinexSim,
|
|
24
|
+
bindMarkerTracking: () => bindMarkerTracking,
|
|
24
25
|
constants: () => import_orbinex.constants,
|
|
26
|
+
createDefaultArMarkers: () => createDefaultArMarkers,
|
|
27
|
+
createMarkersFromCatalog: () => createMarkersFromCatalog,
|
|
25
28
|
createOrbinexSim: () => createOrbinexSim,
|
|
29
|
+
createPrimitiveModelFromCatalogEntry: () => createPrimitiveModelFromCatalogEntry,
|
|
30
|
+
ensureArMarkers: () => ensureArMarkers,
|
|
31
|
+
extractCatalogEntriesFromPayload: () => extractCatalogEntriesFromPayload,
|
|
32
|
+
loadCatalogFromProxy: () => loadCatalogFromProxy,
|
|
26
33
|
orbitSampleFromAu: () => orbitSampleFromAu,
|
|
27
|
-
|
|
34
|
+
parseArRequestFromSearch: () => parseArRequestFromSearch,
|
|
35
|
+
requestArRuntimePermissions: () => requestRuntimePermissions,
|
|
36
|
+
requestRuntimePermissions: () => requestRuntimePermissions2,
|
|
37
|
+
resolveArMarkerHint: () => resolveArMarkerHint,
|
|
38
|
+
resolveCatalogProxyUrl: () => resolveCatalogProxyUrl,
|
|
39
|
+
resolveObjectNameForMarker: () => resolveObjectNameForMarker
|
|
28
40
|
});
|
|
29
41
|
module.exports = __toCommonJS(index_exports);
|
|
30
42
|
var import_orbinex = require("@galihru/orbinex");
|
|
31
|
-
|
|
43
|
+
|
|
44
|
+
// src/ar-runtime.ts
|
|
45
|
+
var DEFAULT_CATALOG_PROXY_PARAM_KEYS = ["catalogProxy", "catalog", "proxy", "db", "catalogUrl"];
|
|
46
|
+
var MARKER_HIRO_URL = "https://raw.githubusercontent.com/AR-js-org/AR.js/master/data/images/hiro.png";
|
|
47
|
+
var MARKER_KANJI_URL = "https://raw.githubusercontent.com/AR-js-org/AR.js/master/data/images/kanji.png";
|
|
48
|
+
var DEFAULT_PERMISSION_SUMMARY = {
|
|
49
|
+
camera: "unsupported",
|
|
50
|
+
microphone: "unsupported",
|
|
51
|
+
geolocation: "unsupported",
|
|
52
|
+
motionSensors: "unsupported"
|
|
53
|
+
};
|
|
54
|
+
function normalizePermissionResult(value) {
|
|
55
|
+
return value === "granted" || value === "denied" || value === "unsupported" ? value : "unsupported";
|
|
56
|
+
}
|
|
57
|
+
function clamp(value, min, max) {
|
|
58
|
+
return Math.min(max, Math.max(min, value));
|
|
59
|
+
}
|
|
60
|
+
function normalizeCssColor(value, fallback) {
|
|
61
|
+
const candidate = (value || "").trim();
|
|
62
|
+
if (!candidate) {
|
|
63
|
+
return fallback;
|
|
64
|
+
}
|
|
65
|
+
if (typeof document === "undefined") {
|
|
66
|
+
return candidate;
|
|
67
|
+
}
|
|
68
|
+
const probe = document.createElement("span");
|
|
69
|
+
probe.style.color = "";
|
|
70
|
+
probe.style.color = candidate;
|
|
71
|
+
return probe.style.color ? candidate : fallback;
|
|
72
|
+
}
|
|
73
|
+
function isBlackLikeColor(value) {
|
|
74
|
+
const normalized = value.replace(/\s+/g, "").toLowerCase();
|
|
75
|
+
return normalized === "#000" || normalized === "#000000" || normalized === "black" || normalized === "rgb(0,0,0)" || normalized === "rgba(0,0,0,1)";
|
|
76
|
+
}
|
|
77
|
+
function asRecord(value) {
|
|
78
|
+
if (!value || typeof value !== "object") {
|
|
79
|
+
return null;
|
|
80
|
+
}
|
|
81
|
+
return value;
|
|
82
|
+
}
|
|
83
|
+
function readFirstString(source, keys) {
|
|
84
|
+
for (const key of keys) {
|
|
85
|
+
const raw = source[key];
|
|
86
|
+
if (typeof raw === "string" && raw.trim()) {
|
|
87
|
+
return raw.trim();
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
return "";
|
|
91
|
+
}
|
|
92
|
+
function readFirstNumber(source, keys) {
|
|
93
|
+
for (const key of keys) {
|
|
94
|
+
const raw = source[key];
|
|
95
|
+
const next = typeof raw === "number" ? raw : typeof raw === "string" ? Number(raw) : NaN;
|
|
96
|
+
if (Number.isFinite(next)) {
|
|
97
|
+
return next;
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
return null;
|
|
101
|
+
}
|
|
102
|
+
function toOptionalNumber(value) {
|
|
103
|
+
return value === null ? void 0 : value;
|
|
104
|
+
}
|
|
105
|
+
function toOptionalNullableNumber(value) {
|
|
106
|
+
if (value === null) {
|
|
107
|
+
return void 0;
|
|
108
|
+
}
|
|
109
|
+
return value;
|
|
110
|
+
}
|
|
111
|
+
function toOptionalText(value) {
|
|
112
|
+
return value ? value : void 0;
|
|
113
|
+
}
|
|
32
114
|
async function requestCameraPermission() {
|
|
115
|
+
if (!window.isSecureContext || !navigator.mediaDevices || typeof navigator.mediaDevices.getUserMedia !== "function") {
|
|
116
|
+
return "unsupported";
|
|
117
|
+
}
|
|
118
|
+
try {
|
|
119
|
+
const stream = await navigator.mediaDevices.getUserMedia({
|
|
120
|
+
video: { facingMode: "environment" },
|
|
121
|
+
audio: false
|
|
122
|
+
});
|
|
123
|
+
stream.getTracks().forEach((track) => track.stop());
|
|
124
|
+
return "granted";
|
|
125
|
+
} catch {
|
|
126
|
+
return "denied";
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
async function requestMicrophonePermission() {
|
|
130
|
+
if (!window.isSecureContext || !navigator.mediaDevices || typeof navigator.mediaDevices.getUserMedia !== "function") {
|
|
131
|
+
return "unsupported";
|
|
132
|
+
}
|
|
133
|
+
try {
|
|
134
|
+
const stream = await navigator.mediaDevices.getUserMedia({ audio: true, video: false });
|
|
135
|
+
stream.getTracks().forEach((track) => track.stop());
|
|
136
|
+
return "granted";
|
|
137
|
+
} catch {
|
|
138
|
+
return "denied";
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
async function requestGeolocationPermission() {
|
|
142
|
+
if (!window.isSecureContext || !("geolocation" in navigator) || !navigator.geolocation) {
|
|
143
|
+
return "unsupported";
|
|
144
|
+
}
|
|
145
|
+
return new Promise((resolve) => {
|
|
146
|
+
navigator.geolocation.getCurrentPosition(
|
|
147
|
+
() => resolve("granted"),
|
|
148
|
+
() => resolve("denied"),
|
|
149
|
+
{
|
|
150
|
+
enableHighAccuracy: false,
|
|
151
|
+
timeout: 7e3,
|
|
152
|
+
maximumAge: 0
|
|
153
|
+
}
|
|
154
|
+
);
|
|
155
|
+
});
|
|
156
|
+
}
|
|
157
|
+
async function requestMotionSensorPermission() {
|
|
158
|
+
const motionApi = window.DeviceMotionEvent;
|
|
159
|
+
if (!motionApi || typeof motionApi.requestPermission !== "function") {
|
|
160
|
+
return "unsupported";
|
|
161
|
+
}
|
|
162
|
+
try {
|
|
163
|
+
const result = await motionApi.requestPermission();
|
|
164
|
+
return result === "granted" ? "granted" : "denied";
|
|
165
|
+
} catch {
|
|
166
|
+
return "denied";
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
function resolveHostNode(target) {
|
|
170
|
+
if (typeof target !== "string") {
|
|
171
|
+
if (target instanceof Document) {
|
|
172
|
+
return target.documentElement;
|
|
173
|
+
}
|
|
174
|
+
return target;
|
|
175
|
+
}
|
|
176
|
+
const found = document.querySelector(target);
|
|
177
|
+
if (!found) {
|
|
178
|
+
throw new Error(`Target element not found for selector: ${target}`);
|
|
179
|
+
}
|
|
180
|
+
return found;
|
|
181
|
+
}
|
|
182
|
+
function normalizeMarkerConfig(config) {
|
|
183
|
+
const preset = (config.preset || "hiro").trim() || "hiro";
|
|
184
|
+
const markerImage = (config.markerImage || (preset === "kanji" ? MARKER_KANJI_URL : MARKER_HIRO_URL)).trim();
|
|
185
|
+
const markerLink = (config.markerLink || markerImage).trim();
|
|
186
|
+
const markerLabel = (config.markerLabel || (preset === "kanji" ? "Kanji" : "Hiro")).trim();
|
|
187
|
+
const id = (config.id || `orbinex-marker-${preset}`).trim();
|
|
188
|
+
return {
|
|
189
|
+
id,
|
|
190
|
+
preset,
|
|
191
|
+
model: (config.model || "Bumi").trim() || "Bumi",
|
|
192
|
+
markerLabel,
|
|
193
|
+
markerImage,
|
|
194
|
+
markerLink,
|
|
195
|
+
smooth: config.smooth ?? true,
|
|
196
|
+
smoothCount: config.smoothCount ?? 8,
|
|
197
|
+
smoothTolerance: config.smoothTolerance ?? 0.01,
|
|
198
|
+
smoothThreshold: config.smoothThreshold ?? 5
|
|
199
|
+
};
|
|
200
|
+
}
|
|
201
|
+
function ensureModelRoot(markerEl) {
|
|
202
|
+
if (markerEl.querySelector("[data-model-root]")) {
|
|
203
|
+
return;
|
|
204
|
+
}
|
|
205
|
+
const modelRoot = document.createElement("a-entity");
|
|
206
|
+
modelRoot.setAttribute("data-model-root", "");
|
|
207
|
+
modelRoot.setAttribute("position", "0 0 0");
|
|
208
|
+
markerEl.appendChild(modelRoot);
|
|
209
|
+
}
|
|
210
|
+
function applyMarkerDataset(markerEl, marker) {
|
|
211
|
+
markerEl.id = marker.id;
|
|
212
|
+
markerEl.dataset.model = marker.model;
|
|
213
|
+
markerEl.dataset.markerLabel = marker.markerLabel;
|
|
214
|
+
markerEl.dataset.markerImage = marker.markerImage;
|
|
215
|
+
markerEl.dataset.markerLink = marker.markerLink;
|
|
216
|
+
markerEl.setAttribute("preset", marker.preset);
|
|
217
|
+
markerEl.setAttribute("emitevents", "true");
|
|
218
|
+
markerEl.setAttribute("smooth", marker.smooth ? "true" : "false");
|
|
219
|
+
markerEl.setAttribute("smoothCount", String(marker.smoothCount));
|
|
220
|
+
markerEl.setAttribute("smoothTolerance", String(marker.smoothTolerance));
|
|
221
|
+
markerEl.setAttribute("smoothThreshold", String(marker.smoothThreshold));
|
|
222
|
+
}
|
|
223
|
+
function resolveObjectNameForMarker(markerNode, fallbackModel = "Bumi") {
|
|
224
|
+
const markerModel = (markerNode?.getAttribute("data-model") || markerNode?.getAttribute("data-object") || "").trim();
|
|
225
|
+
return markerModel || fallbackModel;
|
|
226
|
+
}
|
|
227
|
+
function buildMarkerDetectionSummary(markerNode, visibilityState) {
|
|
228
|
+
const markerId = markerNode.id || markerNode.dataset.markerLabel || markerNode.dataset.model || "marker";
|
|
229
|
+
const markerLabel = (markerNode.dataset.markerLabel || markerId).trim() || markerId;
|
|
230
|
+
const markerModel = resolveObjectNameForMarker(markerNode, "Bumi");
|
|
231
|
+
const visibleCount = Array.from(visibilityState.values()).filter(Boolean).length;
|
|
232
|
+
return {
|
|
233
|
+
markerId,
|
|
234
|
+
markerLabel,
|
|
235
|
+
markerModel,
|
|
236
|
+
markerNode,
|
|
237
|
+
visibleCount,
|
|
238
|
+
isAnyVisible: visibleCount > 0
|
|
239
|
+
};
|
|
240
|
+
}
|
|
241
|
+
function bindMarkerTracking(markerTargets, handlers = {}) {
|
|
242
|
+
const markerNodes = Array.from(markerTargets).filter((node) => node instanceof HTMLElement);
|
|
243
|
+
const visibilityState = /* @__PURE__ */ new Map();
|
|
244
|
+
const disposers = [];
|
|
245
|
+
markerNodes.forEach((markerNode, index) => {
|
|
246
|
+
const markerId = markerNode.id || `marker-${index + 1}`;
|
|
247
|
+
visibilityState.set(markerId, false);
|
|
248
|
+
const onFound = () => {
|
|
249
|
+
visibilityState.set(markerId, true);
|
|
250
|
+
const summary = buildMarkerDetectionSummary(markerNode, visibilityState);
|
|
251
|
+
handlers.onMarkerFound?.(summary);
|
|
252
|
+
handlers.onVisibilityChange?.(summary);
|
|
253
|
+
};
|
|
254
|
+
const onLost = () => {
|
|
255
|
+
visibilityState.set(markerId, false);
|
|
256
|
+
const summary = buildMarkerDetectionSummary(markerNode, visibilityState);
|
|
257
|
+
handlers.onMarkerLost?.(summary);
|
|
258
|
+
handlers.onVisibilityChange?.(summary);
|
|
259
|
+
};
|
|
260
|
+
markerNode.addEventListener("markerFound", onFound);
|
|
261
|
+
markerNode.addEventListener("markerLost", onLost);
|
|
262
|
+
disposers.push(() => {
|
|
263
|
+
markerNode.removeEventListener("markerFound", onFound);
|
|
264
|
+
markerNode.removeEventListener("markerLost", onLost);
|
|
265
|
+
});
|
|
266
|
+
});
|
|
267
|
+
return () => {
|
|
268
|
+
disposers.forEach((dispose) => dispose());
|
|
269
|
+
};
|
|
270
|
+
}
|
|
271
|
+
function resolveCatalogProxyUrl(search = window.location.search, paramKeys = DEFAULT_CATALOG_PROXY_PARAM_KEYS) {
|
|
272
|
+
const params = typeof search === "string" ? new URLSearchParams(search) : search;
|
|
273
|
+
for (const key of paramKeys) {
|
|
274
|
+
const value = (params.get(key) || "").trim();
|
|
275
|
+
if (!value) {
|
|
276
|
+
continue;
|
|
277
|
+
}
|
|
278
|
+
try {
|
|
279
|
+
return new URL(value, window.location.href).toString();
|
|
280
|
+
} catch {
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
return "";
|
|
284
|
+
}
|
|
285
|
+
function normalizeCatalogEntry(value) {
|
|
286
|
+
const source = asRecord(value);
|
|
287
|
+
if (!source) {
|
|
288
|
+
return null;
|
|
289
|
+
}
|
|
290
|
+
const name = readFirstString(source, ["name", "label", "title", "objectName", "id"]);
|
|
291
|
+
if (!name) {
|
|
292
|
+
return null;
|
|
293
|
+
}
|
|
294
|
+
const kind = readFirstString(source, ["kind", "type", "category", "class"]);
|
|
295
|
+
const markerPreset = readFirstString(source, ["markerPreset", "marker", "preset", "markerType"]);
|
|
296
|
+
return {
|
|
297
|
+
name,
|
|
298
|
+
kind: toOptionalText(kind),
|
|
299
|
+
massKg: toOptionalNumber(readFirstNumber(source, ["massKg", "mass_kg", "mass", "kgMass"])),
|
|
300
|
+
radiusMeters: toOptionalNumber(readFirstNumber(source, ["radiusMeters", "radius_m", "radius", "sizeMeters"])),
|
|
301
|
+
color: toOptionalText(readFirstString(source, ["color", "hexColor", "colour", "markerColor"])),
|
|
302
|
+
parentName: toOptionalText(readFirstString(source, ["parentName", "parent", "orbitParent", "parent_name"])),
|
|
303
|
+
semiMajorMeters: toOptionalNullableNumber(readFirstNumber(source, ["semiMajorMeters", "semi_major_m", "semiMajor", "semiMajorAxis"])),
|
|
304
|
+
periodDays: toOptionalNullableNumber(readFirstNumber(source, ["periodDays", "period_days", "orbitalPeriodDays", "period"])),
|
|
305
|
+
rotationHours: toOptionalNullableNumber(readFirstNumber(source, ["rotationHours", "rotation_hours", "rotationPeriodHours", "rotation"])),
|
|
306
|
+
inclinationDeg: toOptionalNullableNumber(readFirstNumber(source, ["inclinationDeg", "inclination_deg", "inclination"])),
|
|
307
|
+
markerId: toOptionalText(readFirstString(source, ["markerId", "idMarker", "marker_id"])),
|
|
308
|
+
markerPreset: toOptionalText(markerPreset),
|
|
309
|
+
markerLabel: toOptionalText(readFirstString(source, ["markerLabel", "markerName", "labelMarker", "marker_label"])),
|
|
310
|
+
markerImage: toOptionalText(readFirstString(source, ["markerImage", "marker_image", "markerUrl", "image"])),
|
|
311
|
+
markerLink: toOptionalText(readFirstString(source, ["markerLink", "marker_link", "link"])),
|
|
312
|
+
markerModel: toOptionalText(readFirstString(source, ["markerModel", "model", "target", "object"]))
|
|
313
|
+
};
|
|
314
|
+
}
|
|
315
|
+
function pickCatalogArrayCandidate(payload) {
|
|
316
|
+
if (Array.isArray(payload)) {
|
|
317
|
+
return payload;
|
|
318
|
+
}
|
|
319
|
+
const source = asRecord(payload);
|
|
320
|
+
if (!source) {
|
|
321
|
+
return [];
|
|
322
|
+
}
|
|
323
|
+
const preferredKeys = ["entries", "items", "catalog", "objects", "bodies", "data", "results"];
|
|
324
|
+
for (const key of preferredKeys) {
|
|
325
|
+
const value = source[key];
|
|
326
|
+
if (Array.isArray(value)) {
|
|
327
|
+
return value;
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
for (const value of Object.values(source)) {
|
|
331
|
+
if (Array.isArray(value)) {
|
|
332
|
+
return value;
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
return [];
|
|
336
|
+
}
|
|
337
|
+
function extractCatalogEntriesFromPayload(payload) {
|
|
338
|
+
const rawItems = pickCatalogArrayCandidate(payload);
|
|
339
|
+
const normalized = rawItems.map((item) => normalizeCatalogEntry(item)).filter((item) => !!item);
|
|
340
|
+
const dedupedByName = /* @__PURE__ */ new Map();
|
|
341
|
+
normalized.forEach((entry) => {
|
|
342
|
+
dedupedByName.set(entry.name.toLowerCase(), entry);
|
|
343
|
+
});
|
|
344
|
+
return Array.from(dedupedByName.values());
|
|
345
|
+
}
|
|
346
|
+
async function loadCatalogFromProxy(proxyUrl, options = {}) {
|
|
347
|
+
const timeoutMs = options.timeoutMs ?? 12e3;
|
|
348
|
+
const supportsAbort = typeof AbortController !== "undefined";
|
|
349
|
+
const abortController = supportsAbort ? new AbortController() : null;
|
|
350
|
+
const timeoutId = supportsAbort ? window.setTimeout(() => abortController?.abort(), timeoutMs) : 0;
|
|
351
|
+
try {
|
|
352
|
+
const response = await fetch(proxyUrl, {
|
|
353
|
+
...options.requestInit,
|
|
354
|
+
cache: "no-store",
|
|
355
|
+
signal: abortController ? abortController.signal : void 0
|
|
356
|
+
});
|
|
357
|
+
if (!response.ok) {
|
|
358
|
+
return [];
|
|
359
|
+
}
|
|
360
|
+
const payload = await response.json();
|
|
361
|
+
return extractCatalogEntriesFromPayload(payload);
|
|
362
|
+
} catch {
|
|
363
|
+
return [];
|
|
364
|
+
} finally {
|
|
365
|
+
if (supportsAbort) {
|
|
366
|
+
window.clearTimeout(timeoutId);
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
function createMarkersFromCatalog(entries, fallbackMarkers = []) {
|
|
371
|
+
const markerMap = /* @__PURE__ */ new Map();
|
|
372
|
+
const addMarker = (markerConfig) => {
|
|
373
|
+
const marker = normalizeMarkerConfig(markerConfig);
|
|
374
|
+
markerMap.set(marker.id || marker.preset, marker);
|
|
375
|
+
};
|
|
376
|
+
fallbackMarkers.forEach(addMarker);
|
|
377
|
+
entries.forEach((entry) => {
|
|
378
|
+
const markerPreset = (entry.markerPreset || "").trim();
|
|
379
|
+
const markerId = (entry.markerId || "").trim();
|
|
380
|
+
if (!markerPreset && !markerId) {
|
|
381
|
+
return;
|
|
382
|
+
}
|
|
383
|
+
addMarker({
|
|
384
|
+
id: markerId || void 0,
|
|
385
|
+
preset: markerPreset || void 0,
|
|
386
|
+
model: entry.markerModel || entry.name,
|
|
387
|
+
markerLabel: entry.markerLabel || entry.name,
|
|
388
|
+
markerImage: entry.markerImage,
|
|
389
|
+
markerLink: entry.markerLink || entry.markerImage
|
|
390
|
+
});
|
|
391
|
+
});
|
|
392
|
+
return Array.from(markerMap.values());
|
|
393
|
+
}
|
|
394
|
+
function createPrimitiveModelFromCatalogEntry(target, entry, options = {}) {
|
|
395
|
+
const hostNode = resolveHostNode(target);
|
|
396
|
+
const wrapper = document.createElement("a-entity");
|
|
397
|
+
const radiusScale = options.radiusScale ?? 1;
|
|
398
|
+
const radiusMeters = Number.isFinite(entry.radiusMeters) ? Number(entry.radiusMeters) : 6371e3;
|
|
399
|
+
const radius = clamp((0.08 + Math.log10(Math.max(radiusMeters, 1)) * 0.04) * radiusScale, 0.03, 0.68);
|
|
400
|
+
const fallbackColor = (options.defaultColor || "#84aee4").trim() || "#84aee4";
|
|
401
|
+
let color = normalizeCssColor(entry.color, fallbackColor);
|
|
402
|
+
const normalizedName = (entry.name || "").trim().toLowerCase();
|
|
403
|
+
if ((normalizedName === "matahari" || normalizedName === "sun") && isBlackLikeColor(color)) {
|
|
404
|
+
color = "#ffd37c";
|
|
405
|
+
}
|
|
406
|
+
wrapper.setAttribute("position", options.position || "0 0 0");
|
|
407
|
+
wrapper.setAttribute("data-proxy-object", entry.name);
|
|
408
|
+
const bodyEntity = document.createElement("a-entity");
|
|
409
|
+
bodyEntity.setAttribute("geometry", `primitive: sphere; radius: ${radius.toFixed(4)}`);
|
|
410
|
+
bodyEntity.setAttribute("material", `shader: flat; color: ${color}; side: double; depthTest: false; depthWrite: false`);
|
|
411
|
+
wrapper.appendChild(bodyEntity);
|
|
412
|
+
if (options.includeLabel !== false) {
|
|
413
|
+
const labelEntity = document.createElement("a-text");
|
|
414
|
+
labelEntity.setAttribute("value", entry.name);
|
|
415
|
+
labelEntity.setAttribute("align", "center");
|
|
416
|
+
labelEntity.setAttribute("width", "2.5");
|
|
417
|
+
labelEntity.setAttribute("color", "#d7e7ff");
|
|
418
|
+
labelEntity.setAttribute("position", `0 ${(radius * 1.85).toFixed(4)} 0`);
|
|
419
|
+
labelEntity.setAttribute("side", "double");
|
|
420
|
+
wrapper.appendChild(labelEntity);
|
|
421
|
+
}
|
|
422
|
+
hostNode.appendChild(wrapper);
|
|
423
|
+
return wrapper;
|
|
424
|
+
}
|
|
425
|
+
function parseArRequestFromSearch(search = window.location.search, options = {}) {
|
|
426
|
+
const params = typeof search === "string" ? new URLSearchParams(search) : search;
|
|
427
|
+
const modelParamKeys = options.modelParamKeys ?? ["model", "object", "target", "name"];
|
|
428
|
+
const defaultModel = (options.defaultModel || "Bumi").trim() || "Bumi";
|
|
429
|
+
const defaultAltModel = (options.defaultAltModel || "Mars").trim() || "Mars";
|
|
430
|
+
const defaultBuildToken = (options.defaultBuildToken || "latest").trim() || "latest";
|
|
431
|
+
let model = "";
|
|
432
|
+
for (const key of modelParamKeys) {
|
|
433
|
+
const value = (params.get(key) || "").trim();
|
|
434
|
+
if (value) {
|
|
435
|
+
model = value;
|
|
436
|
+
break;
|
|
437
|
+
}
|
|
438
|
+
}
|
|
439
|
+
return {
|
|
440
|
+
model: model || defaultModel,
|
|
441
|
+
altModel: (params.get("altModel") || defaultAltModel).trim() || defaultAltModel,
|
|
442
|
+
buildToken: (params.get("build") || defaultBuildToken).trim() || defaultBuildToken
|
|
443
|
+
};
|
|
444
|
+
}
|
|
445
|
+
function createDefaultArMarkers(model = "Bumi", altModel = "Mars") {
|
|
446
|
+
return [
|
|
447
|
+
{
|
|
448
|
+
id: "orbinex-marker-hiro",
|
|
449
|
+
preset: "hiro",
|
|
450
|
+
model,
|
|
451
|
+
markerLabel: "Hiro",
|
|
452
|
+
markerImage: MARKER_HIRO_URL,
|
|
453
|
+
markerLink: MARKER_HIRO_URL
|
|
454
|
+
},
|
|
455
|
+
{
|
|
456
|
+
id: "orbinex-marker-kanji",
|
|
457
|
+
preset: "kanji",
|
|
458
|
+
model: altModel,
|
|
459
|
+
markerLabel: "Kanji",
|
|
460
|
+
markerImage: MARKER_KANJI_URL,
|
|
461
|
+
markerLink: MARKER_KANJI_URL
|
|
462
|
+
}
|
|
463
|
+
];
|
|
464
|
+
}
|
|
465
|
+
function ensureArMarkers(sceneTarget, markerConfigs, options = {}) {
|
|
466
|
+
const sceneEl = resolveHostNode(sceneTarget);
|
|
467
|
+
const createMissing = options.createMissing ?? true;
|
|
468
|
+
const ensureModelRootEnabled = options.ensureModelRoot ?? true;
|
|
469
|
+
const ensuredMarkers = [];
|
|
470
|
+
markerConfigs.forEach((config) => {
|
|
471
|
+
const marker = normalizeMarkerConfig(config);
|
|
472
|
+
let markerEl = sceneEl.querySelector(`#${CSS.escape(marker.id)}`);
|
|
473
|
+
if (!markerEl && marker.preset) {
|
|
474
|
+
markerEl = sceneEl.querySelector(`a-marker[preset="${marker.preset}"]`);
|
|
475
|
+
}
|
|
476
|
+
if (!markerEl && createMissing) {
|
|
477
|
+
markerEl = document.createElement("a-marker");
|
|
478
|
+
sceneEl.appendChild(markerEl);
|
|
479
|
+
}
|
|
480
|
+
if (!markerEl) {
|
|
481
|
+
return;
|
|
482
|
+
}
|
|
483
|
+
markerEl.querySelectorAll("a-plane").forEach((planeNode) => planeNode.remove());
|
|
484
|
+
applyMarkerDataset(markerEl, marker);
|
|
485
|
+
if (ensureModelRootEnabled) {
|
|
486
|
+
ensureModelRoot(markerEl);
|
|
487
|
+
}
|
|
488
|
+
ensuredMarkers.push(markerEl);
|
|
489
|
+
});
|
|
490
|
+
return ensuredMarkers;
|
|
491
|
+
}
|
|
492
|
+
function resolveArMarkerHint(markerNode, fallbackUrl = MARKER_HIRO_URL) {
|
|
493
|
+
const markerImage = (markerNode?.getAttribute("data-marker-image") || fallbackUrl).trim() || fallbackUrl;
|
|
494
|
+
const markerLink = (markerNode?.getAttribute("data-marker-link") || markerImage).trim() || markerImage;
|
|
495
|
+
const markerLabel = (markerNode?.getAttribute("data-marker-label") || "Hiro").trim() || "Hiro";
|
|
496
|
+
return {
|
|
497
|
+
markerImage,
|
|
498
|
+
markerLink,
|
|
499
|
+
markerLabel
|
|
500
|
+
};
|
|
501
|
+
}
|
|
502
|
+
async function requestRuntimePermissions(options = {}) {
|
|
503
|
+
const wantsCamera = options.camera ?? false;
|
|
504
|
+
const wantsMicrophone = options.microphone ?? false;
|
|
505
|
+
const wantsGeolocation = options.geolocation ?? false;
|
|
506
|
+
const wantsMotionSensors = options.motionSensors ?? false;
|
|
507
|
+
const [camera, microphone, geolocation, motionSensors] = await Promise.all([
|
|
508
|
+
wantsCamera ? requestCameraPermission() : Promise.resolve(DEFAULT_PERMISSION_SUMMARY.camera),
|
|
509
|
+
wantsMicrophone ? requestMicrophonePermission() : Promise.resolve(DEFAULT_PERMISSION_SUMMARY.microphone),
|
|
510
|
+
wantsGeolocation ? requestGeolocationPermission() : Promise.resolve(DEFAULT_PERMISSION_SUMMARY.geolocation),
|
|
511
|
+
wantsMotionSensors ? requestMotionSensorPermission() : Promise.resolve(DEFAULT_PERMISSION_SUMMARY.motionSensors)
|
|
512
|
+
]);
|
|
513
|
+
return {
|
|
514
|
+
camera: normalizePermissionResult(camera),
|
|
515
|
+
microphone: normalizePermissionResult(microphone),
|
|
516
|
+
geolocation: normalizePermissionResult(geolocation),
|
|
517
|
+
motionSensors: normalizePermissionResult(motionSensors)
|
|
518
|
+
};
|
|
519
|
+
}
|
|
520
|
+
|
|
521
|
+
// src/index.ts
|
|
522
|
+
var DEFAULT_BASE_URL = "https://galihru.github.io/OrbinexSimulation/";
|
|
523
|
+
async function requestCameraPermission2() {
|
|
33
524
|
if (!navigator.mediaDevices || typeof navigator.mediaDevices.getUserMedia !== "function") {
|
|
34
525
|
return "unsupported";
|
|
35
526
|
}
|
|
@@ -46,7 +537,7 @@ async function requestCameraPermission() {
|
|
|
46
537
|
return "denied";
|
|
47
538
|
}
|
|
48
539
|
}
|
|
49
|
-
async function
|
|
540
|
+
async function requestMicrophonePermission2() {
|
|
50
541
|
if (!navigator.mediaDevices || typeof navigator.mediaDevices.getUserMedia !== "function") {
|
|
51
542
|
return "unsupported";
|
|
52
543
|
}
|
|
@@ -58,7 +549,7 @@ async function requestMicrophonePermission() {
|
|
|
58
549
|
return "denied";
|
|
59
550
|
}
|
|
60
551
|
}
|
|
61
|
-
async function
|
|
552
|
+
async function requestGeolocationPermission2() {
|
|
62
553
|
if (!navigator.geolocation || !window.isSecureContext) {
|
|
63
554
|
return "unsupported";
|
|
64
555
|
}
|
|
@@ -74,7 +565,7 @@ async function requestGeolocationPermission() {
|
|
|
74
565
|
);
|
|
75
566
|
});
|
|
76
567
|
}
|
|
77
|
-
async function
|
|
568
|
+
async function requestMotionSensorPermission2() {
|
|
78
569
|
const motionApi = window.DeviceMotionEvent;
|
|
79
570
|
if (!motionApi || typeof motionApi.requestPermission !== "function") {
|
|
80
571
|
return "unsupported";
|
|
@@ -169,10 +660,10 @@ var OrbinexSim = class {
|
|
|
169
660
|
const wantsMotion = options.motionSensors ?? false;
|
|
170
661
|
const unsupported = "unsupported";
|
|
171
662
|
const [camera, microphone, geolocation, motionSensors] = await Promise.all([
|
|
172
|
-
wantsCamera ?
|
|
173
|
-
wantsMic ?
|
|
174
|
-
wantsGeo ?
|
|
175
|
-
wantsMotion ?
|
|
663
|
+
wantsCamera ? requestCameraPermission2() : Promise.resolve(unsupported),
|
|
664
|
+
wantsMic ? requestMicrophonePermission2() : Promise.resolve(unsupported),
|
|
665
|
+
wantsGeo ? requestGeolocationPermission2() : Promise.resolve(unsupported),
|
|
666
|
+
wantsMotion ? requestMotionSensorPermission2() : Promise.resolve(unsupported)
|
|
176
667
|
]);
|
|
177
668
|
return {
|
|
178
669
|
camera,
|
|
@@ -221,7 +712,7 @@ var OrbinexSim = class {
|
|
|
221
712
|
function createOrbinexSim(target, options = {}) {
|
|
222
713
|
return new OrbinexSim(target, options);
|
|
223
714
|
}
|
|
224
|
-
async function
|
|
715
|
+
async function requestRuntimePermissions2(options) {
|
|
225
716
|
const simulator = document.createElement("div");
|
|
226
717
|
const instance = new OrbinexSim(simulator, { autoAppend: false });
|
|
227
718
|
return instance.requestAccess(options);
|
|
@@ -232,8 +723,20 @@ function orbitSampleFromAu(au) {
|
|
|
232
723
|
// Annotate the CommonJS export names for ESM import in node:
|
|
233
724
|
0 && (module.exports = {
|
|
234
725
|
OrbinexSim,
|
|
726
|
+
bindMarkerTracking,
|
|
235
727
|
constants,
|
|
728
|
+
createDefaultArMarkers,
|
|
729
|
+
createMarkersFromCatalog,
|
|
236
730
|
createOrbinexSim,
|
|
731
|
+
createPrimitiveModelFromCatalogEntry,
|
|
732
|
+
ensureArMarkers,
|
|
733
|
+
extractCatalogEntriesFromPayload,
|
|
734
|
+
loadCatalogFromProxy,
|
|
237
735
|
orbitSampleFromAu,
|
|
238
|
-
|
|
736
|
+
parseArRequestFromSearch,
|
|
737
|
+
requestArRuntimePermissions,
|
|
738
|
+
requestRuntimePermissions,
|
|
739
|
+
resolveArMarkerHint,
|
|
740
|
+
resolveCatalogProxyUrl,
|
|
741
|
+
resolveObjectNameForMarker
|
|
239
742
|
});
|
package/dist/index.d.cts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { OrbitSample } from '@galihru/orbinex';
|
|
2
2
|
export { constants } from '@galihru/orbinex';
|
|
3
|
+
export { bindMarkerTracking, createDefaultArMarkers, createMarkersFromCatalog, createPrimitiveModelFromCatalogEntry, ensureArMarkers, extractCatalogEntriesFromPayload, loadCatalogFromProxy, parseArRequestFromSearch, requestRuntimePermissions as requestArRuntimePermissions, resolveArMarkerHint, resolveCatalogProxyUrl, resolveObjectNameForMarker } from './ar-runtime.cjs';
|
|
3
4
|
|
|
4
5
|
type OrbinexMode = "desktop" | "ar";
|
|
5
6
|
type PermissionResult = "granted" | "denied" | "unsupported";
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { OrbitSample } from '@galihru/orbinex';
|
|
2
2
|
export { constants } from '@galihru/orbinex';
|
|
3
|
+
export { bindMarkerTracking, createDefaultArMarkers, createMarkersFromCatalog, createPrimitiveModelFromCatalogEntry, ensureArMarkers, extractCatalogEntriesFromPayload, loadCatalogFromProxy, parseArRequestFromSearch, requestRuntimePermissions as requestArRuntimePermissions, resolveArMarkerHint, resolveCatalogProxyUrl, resolveObjectNameForMarker } from './ar-runtime.js';
|
|
3
4
|
|
|
4
5
|
type OrbinexMode = "desktop" | "ar";
|
|
5
6
|
type PermissionResult = "granted" | "denied" | "unsupported";
|
package/dist/index.js
CHANGED
|
@@ -1,3 +1,18 @@
|
|
|
1
|
+
import {
|
|
2
|
+
bindMarkerTracking,
|
|
3
|
+
createDefaultArMarkers,
|
|
4
|
+
createMarkersFromCatalog,
|
|
5
|
+
createPrimitiveModelFromCatalogEntry,
|
|
6
|
+
ensureArMarkers,
|
|
7
|
+
extractCatalogEntriesFromPayload,
|
|
8
|
+
loadCatalogFromProxy,
|
|
9
|
+
parseArRequestFromSearch,
|
|
10
|
+
requestRuntimePermissions,
|
|
11
|
+
resolveArMarkerHint,
|
|
12
|
+
resolveCatalogProxyUrl,
|
|
13
|
+
resolveObjectNameForMarker
|
|
14
|
+
} from "./chunk-JF7PGQOV.js";
|
|
15
|
+
|
|
1
16
|
// src/index.ts
|
|
2
17
|
import { constants, createOrbitSample } from "@galihru/orbinex";
|
|
3
18
|
var DEFAULT_BASE_URL = "https://galihru.github.io/OrbinexSimulation/";
|
|
@@ -193,7 +208,7 @@ var OrbinexSim = class {
|
|
|
193
208
|
function createOrbinexSim(target, options = {}) {
|
|
194
209
|
return new OrbinexSim(target, options);
|
|
195
210
|
}
|
|
196
|
-
async function
|
|
211
|
+
async function requestRuntimePermissions2(options) {
|
|
197
212
|
const simulator = document.createElement("div");
|
|
198
213
|
const instance = new OrbinexSim(simulator, { autoAppend: false });
|
|
199
214
|
return instance.requestAccess(options);
|
|
@@ -203,8 +218,20 @@ function orbitSampleFromAu(au) {
|
|
|
203
218
|
}
|
|
204
219
|
export {
|
|
205
220
|
OrbinexSim,
|
|
221
|
+
bindMarkerTracking,
|
|
206
222
|
constants,
|
|
223
|
+
createDefaultArMarkers,
|
|
224
|
+
createMarkersFromCatalog,
|
|
207
225
|
createOrbinexSim,
|
|
226
|
+
createPrimitiveModelFromCatalogEntry,
|
|
227
|
+
ensureArMarkers,
|
|
228
|
+
extractCatalogEntriesFromPayload,
|
|
229
|
+
loadCatalogFromProxy,
|
|
208
230
|
orbitSampleFromAu,
|
|
209
|
-
|
|
231
|
+
parseArRequestFromSearch,
|
|
232
|
+
requestRuntimePermissions as requestArRuntimePermissions,
|
|
233
|
+
requestRuntimePermissions2 as requestRuntimePermissions,
|
|
234
|
+
resolveArMarkerHint,
|
|
235
|
+
resolveCatalogProxyUrl,
|
|
236
|
+
resolveObjectNameForMarker
|
|
210
237
|
};
|