Skip to content

Commit 742c92c

Browse files
authored
Merge pull request #27 from coopbri/master
TypeScript types
2 parents dc56235 + cf0c4ae commit 742c92c

File tree

4 files changed

+1135
-31
lines changed

4 files changed

+1135
-31
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
# Updates
22

3+
## `0.1.2` (2025-10-31).
4+
5+
Added TypeScript types, closing [PR #14](https://github.com/AR-js-org/locar.js/issues/14).
6+
37
## `0.1.1` (2025-10-11)
48

59
Allow inline styling of the iOS permission dialogs for device orientation, as well as providing a more iOS-native style by default (PR #22). Thanks to [Luigi Mannoni](https://github.com/luigimannoni-smartify) for this.

lib/types/locar.d.ts

Lines changed: 316 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,316 @@
1+
declare module "locar" {
2+
import * as THREE from "three";
3+
4+
/**
5+
* Generic, small event emitter that only stores a single handler per event name.
6+
*/
7+
export class EventEmitter {
8+
protected eventHandlers: Record<string, (...args: any[]) => void>;
9+
on(eventName: string, handler: (...args: any[]) => void): void;
10+
emit(eventName: string, ...params: any[]): void;
11+
}
12+
13+
/**
14+
* Spherical Mercator (EPSG:3857) projection used by `LocationBased`.
15+
*/
16+
export class SphMercProjection {
17+
constructor();
18+
/**
19+
* @returns [easting, northing]
20+
*/
21+
project(lon: number, lat: number): [number, number];
22+
/**
23+
* @returns [lon, lat]
24+
*/
25+
unproject(projected: [number, number]): [number, number];
26+
getID(): "epsg:3857";
27+
}
28+
29+
/**
30+
* Options for GPS in `LocationBased`.
31+
* Mirrored from `setGpsOptions(...)`
32+
*/
33+
export interface GpsOptions {
34+
/**
35+
* Meters the device must move to accept the next GPS reading.
36+
*/
37+
gpsMinDistance?: number;
38+
/**
39+
* Minimum accuracy in meters to accept a GPS reading.
40+
*/
41+
gpsMinAccuracy?: number;
42+
}
43+
44+
/**
45+
* Optional logger object passed to `LocationBased` for debug.
46+
*/
47+
export interface ServerLogger {
48+
/**
49+
* Should send data to server. Implementation-specific in userland.
50+
*/
51+
sendData(endpoint: string, data: any): Promise<Response> | Response;
52+
}
53+
54+
/**
55+
* Main location AR class.
56+
*/
57+
export class LocationBased extends EventEmitter {
58+
readonly scene: THREE.Scene;
59+
readonly camera: THREE.Camera;
60+
61+
constructor(
62+
scene: THREE.Scene,
63+
camera: THREE.Camera,
64+
options?: GpsOptions,
65+
serverLogger?: ServerLogger | null,
66+
);
67+
68+
/**
69+
* Set the projection (must have `project(lon,lat): [x,y]`).
70+
*/
71+
setProjection(proj: {
72+
project(lon: number, lat: number): [number, number];
73+
}): void;
74+
75+
/**
76+
* Update GPS options at runtime.
77+
*/
78+
setGpsOptions(options?: GpsOptions): void;
79+
80+
/**
81+
* Start real GPS (`navigator.geolocation.watchPosition`).
82+
*/
83+
startGps(): Promise<boolean> | boolean;
84+
85+
/**
86+
* Stop real GPS.
87+
*/
88+
stopGps(): boolean;
89+
90+
/**
91+
* Send a fake GPS position.
92+
*/
93+
fakeGps(lon: number, lat: number, elev?: number | null, acc?: number): void;
94+
95+
/**
96+
* Convert lon/lat to world coordinates (needs initial position).
97+
*/
98+
lonLatToWorldCoords(lon: number, lat: number): [number, number];
99+
100+
/**
101+
* Add a THREE object at lon/lat/(elev) and put in the scene.
102+
*/
103+
add(
104+
object: THREE.Object3D,
105+
lon: number,
106+
lat: number,
107+
elev?: number,
108+
properties?: Record<string, any>,
109+
): void;
110+
111+
/**
112+
* Set camera elevation (y).
113+
*/
114+
setElevation(elev: number): void;
115+
116+
/**
117+
* Events:
118+
* - "gpsupdate": `{ position: GeolocationPosition, distMoved: number }``
119+
* - "gpserror": `GeolocationPositionError`
120+
*/
121+
on(
122+
eventName: "gpsupdate",
123+
handler: (data: {
124+
position: GeolocationPosition;
125+
distMoved: number;
126+
}) => void,
127+
): void;
128+
on(
129+
eventName: "gpserror",
130+
handler: (error: GeolocationPositionError) => void,
131+
): void;
132+
on(eventName: string, handler: (...args: any[]) => void): void;
133+
}
134+
135+
/**
136+
* Small webcam wrapper that creates a hidden `<video>` and a `THREE.VideoTexture`.
137+
*/
138+
export interface WebcamStartedEvent {
139+
texture: THREE.VideoTexture;
140+
}
141+
export interface WebcamErrorEvent {
142+
code: string;
143+
message: string;
144+
}
145+
146+
export class Webcam extends EventEmitter {
147+
/**
148+
* @param constraints `MediaDevices.getUserMedia` constraints
149+
* @param videoElementSelector selector for an existing `<video>`; if falsy, it creates one
150+
*/
151+
constructor(
152+
constraints?: MediaStreamConstraints,
153+
videoElementSelector?: string | null,
154+
);
155+
156+
/**
157+
* Texture that streams the camera feed.
158+
*/
159+
readonly texture: THREE.VideoTexture;
160+
161+
/**
162+
* Free GPU resources.
163+
*/
164+
dispose(): void;
165+
166+
// events
167+
on(
168+
eventName: "webcamstarted",
169+
handler: (e: WebcamStartedEvent) => void,
170+
): void;
171+
on(eventName: "webcamerror", handler: (e: WebcamErrorEvent) => void): void;
172+
on(eventName: string, handler: (...args: any[]) => void): void;
173+
}
174+
175+
/**
176+
* Click handler/raycaster wrapper.
177+
*/
178+
export class ClickHandler {
179+
constructor(renderer: THREE.WebGLRenderer);
180+
181+
/**
182+
* Cast a ray and return intersects with scene children.
183+
*/
184+
raycast(camera: THREE.Camera, scene: THREE.Scene): THREE.Intersection[];
185+
}
186+
187+
export interface DeviceOrientationControlsOptions {
188+
/**
189+
* 0 < k <= 1. Lower = more smoothing.
190+
*/
191+
smoothingFactor?: number;
192+
/**
193+
* Show iOS permission dialog.
194+
*/
195+
enablePermissionDialog?: boolean;
196+
/**
197+
* Apply inline styles on the created dialog.
198+
*/
199+
enableStyling?: boolean;
200+
/**
201+
* Use `window.confirm(...)` instead of building DOM.
202+
*/
203+
preferConfirmDialog?: boolean;
204+
}
205+
206+
export interface DeviceOrientationGrantedEvent {
207+
target: DeviceOrientationControls;
208+
}
209+
210+
export interface DeviceOrientationErrorEvent {
211+
code: string;
212+
message: string;
213+
error?: string;
214+
}
215+
216+
export class DeviceOrientationControls extends THREE.EventDispatcher {
217+
/**
218+
* @param object usually a `THREE.Camera`
219+
*/
220+
constructor(
221+
object: THREE.Object3D,
222+
options?: DeviceOrientationControlsOptions,
223+
);
224+
225+
/**
226+
* Initialize the device orientation controls. Should be called first to set up permission flow.
227+
*/
228+
init(): void;
229+
230+
/**
231+
* Begin listening to orientation + screenorientation (must be called after permission is granted on iOS).
232+
*/
233+
connect(): void;
234+
235+
/**
236+
* Stop listening.
237+
*/
238+
disconnect(): void;
239+
240+
/**
241+
* iOS: must be called in a user gesture to ask for perms.
242+
*/
243+
requestOrientationPermissions(): void;
244+
245+
/**
246+
* Create the DOM dialog (iOS-style) and wire it to requestOrientationPermissions.
247+
*/
248+
createObtainPermissionGestureDialog(): void;
249+
250+
/**
251+
* Choose `confirm()` vs DOM dialog.
252+
*/
253+
obtainPermissionGesture(): void;
254+
255+
/**
256+
* Call each frame.
257+
*/
258+
update(args?: { theta?: number }): void;
259+
260+
/**
261+
* iOS heading correction.
262+
*/
263+
getCorrectedHeading(): number;
264+
265+
/**
266+
* Provided in AR.js fix — forces re-evaluation of alpha offset.
267+
*/
268+
updateAlphaOffset(): void;
269+
270+
/**
271+
* Getters (radians).
272+
*/
273+
getAlpha(): number;
274+
getBeta(): number;
275+
getGamma(): number;
276+
277+
dispose(): void;
278+
279+
on(
280+
eventName: "deviceorientationgranted",
281+
handler: (ev: DeviceOrientationGrantedEvent) => void,
282+
): void;
283+
on(
284+
eventName: "deviceorientationerror",
285+
handler: (ev: DeviceOrientationErrorEvent) => void,
286+
): void;
287+
on(eventName: string, handler: (...args: any[]) => void): void;
288+
289+
enabled: boolean;
290+
}
291+
292+
/**
293+
* Version string.
294+
*/
295+
export const version: string;
296+
297+
/**
298+
* Default export from build (UMD/ES) is the namespace with all the above.
299+
* Modeled so that:
300+
* `import * as LocAR from "locar"`
301+
* and
302+
* `import LocAR from "locar"``
303+
* both typecheck.
304+
*/
305+
const LocAR: {
306+
EventEmitter: typeof EventEmitter;
307+
SphMercProjection: typeof SphMercProjection;
308+
LocationBased: typeof LocationBased;
309+
Webcam: typeof Webcam;
310+
ClickHandler: typeof ClickHandler;
311+
DeviceOrientationControls: typeof DeviceOrientationControls;
312+
version: string;
313+
};
314+
315+
export default LocAR;
316+
}

0 commit comments

Comments
 (0)